diff --git a/bun.lockb b/bun.lockb index 83a2c530..8041c00a 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/script/DeployProtocol.s.sol b/script/DeployProtocol.s.sol index 270805f7..0e8741e4 100644 --- a/script/DeployProtocol.s.sol +++ b/script/DeployProtocol.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 "@sablier/v2-core/src/SablierV2Comptroller.sol"; import { SablierV2LockupDynamic } from "@sablier/v2-core/src/SablierV2LockupDynamic.sol"; import { SablierV2LockupLinear } from "@sablier/v2-core/src/SablierV2LockupLinear.sol"; import { SablierV2LockupTranched } from "@sablier/v2-core/src/SablierV2LockupTranched.sol"; @@ -21,7 +20,6 @@ contract DeployProtocol is BaseScript { virtual broadcast returns ( - SablierV2Comptroller comptroller, SablierV2LockupDynamic lockupDynamic, SablierV2LockupLinear lockupLinear, SablierV2LockupTranched lockupTranched, @@ -31,11 +29,10 @@ contract DeployProtocol is BaseScript { ) { // Deploy V2 Core. - 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); batch = new SablierV2Batch(); merkleLockupFactory = new SablierV2MerkleLockupFactory(); diff --git a/src/SablierV2Batch.sol b/src/SablierV2Batch.sol index 12ff58e6..0b15fb74 100644 --- a/src/SablierV2Batch.sol +++ b/src/SablierV2Batch.sol @@ -3,9 +3,10 @@ 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 { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2LockupDynamic } from "@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol"; -import { LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; +import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "@sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol"; +import { LockupDynamic, LockupLinear, LockupTranched } from "@sablier/v2-core/src/types/DataTypes.sol"; import { ISablierV2Batch } from "./interfaces/ISablierV2Batch.sol"; import { Errors } from "./libraries/Errors.sol"; @@ -217,6 +218,107 @@ contract SablierV2Batch is ISablierV2Batch { } } + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-TRANCHED + //////////////////////////////////////////////////////////////////////////*/ + + /// @inheritdoc ISablierV2Batch + function createWithDurationsLT( + ISablierV2LockupTranched lockupTranched, + IERC20 asset, + Batch.CreateWithDurationsLT[] calldata batch + ) + external + override + returns (uint256[] memory streamIds) + { + // Check that the batch size is not zero. + uint256 batchSize = batch.length; + if (batchSize == 0) { + revert Errors.SablierV2Batch_BatchSizeZero(); + } + + // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create + // transactions will revert if there is overflow. + uint256 i; + uint256 transferAmount; + for (i = 0; i < batchSize; ++i) { + unchecked { + transferAmount += batch[i].totalAmount; + } + } + + // Perform the ERC-20 transfer and approve {SablierV2LockupTranched} to spend the amount of assets. + _handleTransfer(address(lockupTranched), asset, transferAmount); + + // Create a stream for each element in the parameter array. + streamIds = new uint256[](batchSize); + for (i = 0; i < batchSize; ++i) { + // Create the stream. + streamIds[i] = lockupTranched.createWithDurations( + LockupTranched.CreateWithDurations({ + sender: batch[i].sender, + recipient: batch[i].recipient, + totalAmount: batch[i].totalAmount, + asset: asset, + cancelable: batch[i].cancelable, + transferable: batch[i].transferable, + tranches: batch[i].tranches, + broker: batch[i].broker + }) + ); + } + } + + /// @inheritdoc ISablierV2Batch + function createWithTimestampsLT( + ISablierV2LockupTranched lockupTranched, + IERC20 asset, + Batch.CreateWithTimestampsLT[] calldata batch + ) + external + override + returns (uint256[] memory streamIds) + { + // Check that the batch size is not zero. + uint256 batchSize = batch.length; + if (batchSize == 0) { + revert Errors.SablierV2Batch_BatchSizeZero(); + } + + // Calculate the sum of all of stream amounts. It is safe to use unchecked addition because one of the create + // transactions will revert if there is overflow. + uint256 i; + uint256 transferAmount; + for (i = 0; i < batchSize; ++i) { + unchecked { + transferAmount += batch[i].totalAmount; + } + } + + // Perform the ERC-20 transfer and approve {SablierV2LockupTranched} to spend the amount of assets. + _handleTransfer(address(lockupTranched), asset, transferAmount); + + // Create a stream for each element in the parameter array. + streamIds = new uint256[](batchSize); + for (i = 0; i < batchSize; ++i) { + // Create the stream. + streamIds[i] = lockupTranched.createWithTimestamps( + LockupTranched.CreateWithTimestamps({ + sender: batch[i].sender, + recipient: batch[i].recipient, + totalAmount: batch[i].totalAmount, + asset: asset, + cancelable: batch[i].cancelable, + transferable: batch[i].transferable, + startTime: batch[i].startTime, + tranches: batch[i].tranches, + broker: batch[i].broker + }) + ); + } + } + /*////////////////////////////////////////////////////////////////////////// HELPER FUNCTIONS //////////////////////////////////////////////////////////////////////////*/ diff --git a/src/interfaces/ISablierV2Batch.sol b/src/interfaces/ISablierV2Batch.sol index 7b3512a4..32ec6e95 100644 --- a/src/interfaces/ISablierV2Batch.sol +++ b/src/interfaces/ISablierV2Batch.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { ISablierV2LockupDynamic } from "@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; +import { ISablierV2LockupTranched } from "@sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol"; import { Batch } from "../types/DataTypes.sol"; @@ -93,4 +94,46 @@ interface ISablierV2Batch { ) external returns (uint256[] memory streamIds); + + /*////////////////////////////////////////////////////////////////////////// + SABLIER-V2-LOCKUP-TRANCHED + //////////////////////////////////////////////////////////////////////////*/ + + /// @notice Creates a batch of Lockup Tranched streams using `createWithDurations`. + /// + /// @dev Requirements: + /// - There must be at least one element in `batch`. + /// - All requirements from {ISablierV2LockupTranched.createWithDurations} must be met for each stream. + /// + /// @param lockupTranched The address of the {SablierV2LockupTranched} contract. + /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param batch An array of structs, each encapsulating a subset of the parameters of + /// {SablierV2LockupTranched.createWithDurations}. + /// @return streamIds The ids of the newly created streams. + function createWithDurationsLT( + ISablierV2LockupTranched lockupTranched, + IERC20 asset, + Batch.CreateWithDurationsLT[] calldata batch + ) + external + returns (uint256[] memory streamIds); + + /// @notice Creates a batch of Lockup Tranched streams using `createWithTimestamps`. + /// + /// @dev Requirements: + /// - There must be at least one element in `batch`. + /// - All requirements from {ISablierV2LockupTranched.createWithTimestamps} must be met for each stream. + /// + /// @param lockupTranched The address of the {SablierV2LockupTranched} contract. + /// @param asset The contract address of the ERC-20 asset used for streaming. + /// @param batch An array of structs, each encapsulating a subset of the parameters of + /// {SablierV2LockupTranched.createWithTimestamps}. + /// @return streamIds The ids of the newly created streams. + function createWithTimestampsLT( + ISablierV2LockupTranched lockupTranched, + IERC20 asset, + Batch.CreateWithTimestampsLT[] calldata batch + ) + external + returns (uint256[] memory streamIds); } diff --git a/src/types/DataTypes.sol b/src/types/DataTypes.sol index 21cdcffb..9b84ad03 100644 --- a/src/types/DataTypes.sol +++ b/src/types/DataTypes.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.22; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { UD2x18 } from "@prb/math/src/UD2x18.sol"; import { ISablierV2Lockup } from "@sablier/v2-core/src/interfaces/ISablierV2Lockup.sol"; -import { Broker, LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; +import { Broker, LockupDynamic, LockupLinear, LockupTranched } from "@sablier/v2-core/src/types/DataTypes.sol"; library Batch { /// @notice A struct encapsulating the lockup contract's address and the stream ids to cancel. @@ -37,6 +37,18 @@ library Batch { Broker broker; } + /// @notice A struct encapsulating all parameters of {SablierV2LockupTranched.createWithDurations} except for the + /// asset. + struct CreateWithDurationsLT { + address sender; + address recipient; + uint128 totalAmount; + bool cancelable; + bool transferable; + LockupTranched.TrancheWithDuration[] tranches; + Broker broker; + } + /// @notice A struct encapsulating all parameters of {SablierV2LockupDynamic.createWithTimestamps} except for the /// asset. struct CreateWithTimestampsLD { @@ -61,6 +73,19 @@ library Batch { LockupLinear.Range range; Broker broker; } + + /// @notice A struct encapsulating all parameters of {SablierV2LockupTranched.createWithTimestamps} except for the + /// asset. + struct CreateWithTimestampsLT { + address sender; + address recipient; + uint128 totalAmount; + bool cancelable; + bool transferable; + uint40 startTime; + LockupTranched.Tranche[] tranches; + Broker broker; + } } library MerkleLockup { diff --git a/test/Base.t.sol b/test/Base.t.sol index 23fecf6d..a39bd388 100644 --- a/test/Base.t.sol +++ b/test/Base.t.sol @@ -4,11 +4,10 @@ pragma solidity >=0.8.22 <0.9.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; -import { ISablierV2Comptroller } from "@sablier/v2-core/src/interfaces/ISablierV2Comptroller.sol"; import { ISablierV2LockupDynamic } from "@sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol"; import { ISablierV2LockupLinear } from "@sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol"; import { ISablierV2LockupTranched } from "@sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol"; -import { LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; +import { LockupDynamic, LockupLinear, LockupTranched } from "@sablier/v2-core/src/types/DataTypes.sol"; import { Assertions as V2CoreAssertions } from "@sablier/v2-core/test/utils/Assertions.sol"; import { Utils as V2CoreUtils } from "@sablier/v2-core/test/utils/Utils.sol"; @@ -44,7 +43,6 @@ abstract contract Base_Test is Assertions, DeployOptimized, Events, Merkle, V2Co IERC20 internal dai; ISablierV2Batch internal batch; - ISablierV2Comptroller internal comptroller; Defaults internal defaults; ISablierV2LockupDynamic internal lockupDynamic; ISablierV2LockupLinear internal lockupLinear; @@ -108,7 +106,6 @@ abstract contract Base_Test is Assertions, DeployOptimized, Events, Merkle, V2Co vm.label({ account: address(merkleLockupFactory), newLabel: "MerkleLockupFactory" }); vm.label({ account: address(merkleLockupLL), newLabel: "MerkleLockupLL" }); vm.label({ account: address(defaults), newLabel: "Defaults" }); - 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" }); @@ -118,38 +115,6 @@ abstract contract Base_Test is Assertions, DeployOptimized, Events, Merkle, V2Co CALL EXPECTS //////////////////////////////////////////////////////////////////////////*/ - /// @dev Expects a call to {ISablierV2LockupDynamic.createWithDurations}. - function expectCallToCreateWithDurationsLD(LockupDynamic.CreateWithDurations memory params) internal { - vm.expectCall({ - callee: address(lockupDynamic), - data: abi.encodeCall(ISablierV2LockupDynamic.createWithDurations, (params)) - }); - } - - /// @dev Expects a call to {ISablierV2LockupLinear.createWithDurations}. - function expectCallToCreateWithDurationsLL(LockupLinear.CreateWithDurations memory params) internal { - vm.expectCall({ - callee: address(lockupLinear), - data: abi.encodeCall(ISablierV2LockupLinear.createWithDurations, (params)) - }); - } - - /// @dev Expects a call to {ISablierV2LockupDynamic.createWithTimestamps}. - function expectCallToCreateWithTimestampsLD(LockupDynamic.CreateWithTimestamps memory params) internal { - vm.expectCall({ - callee: address(lockupDynamic), - data: abi.encodeCall(ISablierV2LockupDynamic.createWithTimestamps, (params)) - }); - } - - /// @dev Expects a call to {ISablierV2LockupLinear.createWithTimestamps}. - function expectCallToCreateWithTimestampsLL(LockupLinear.CreateWithTimestamps memory params) internal { - vm.expectCall({ - callee: address(lockupLinear), - data: abi.encodeCall(ISablierV2LockupLinear.createWithTimestamps, (params)) - }); - } - /// @dev Expects a call to {IERC20.transfer}. function expectCallToTransfer(address to, uint256 amount) internal { expectCallToTransfer(address(dai), to, amount); @@ -200,6 +165,21 @@ abstract contract Base_Test is Assertions, DeployOptimized, Events, Merkle, V2Co }); } + /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithDurations}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithDurationsLT( + uint64 count, + LockupTranched.CreateWithDurations memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupTranched), + count: count, + data: abi.encodeCall(ISablierV2LockupTranched.createWithDurations, (params)) + }); + } + /// @dev Expects multiple calls to {ISablierV2LockupDynamic.createWithTimestamps}, each with the specified /// `params`. function expectMultipleCallsToCreateWithTimestampsLD( @@ -230,6 +210,21 @@ abstract contract Base_Test is Assertions, DeployOptimized, Events, Merkle, V2Co }); } + /// @dev Expects multiple calls to {ISablierV2LockupTranched.createWithTimestamps}, each with the specified + /// `params`. + function expectMultipleCallsToCreateWithTimestampsLT( + uint64 count, + LockupTranched.CreateWithTimestamps memory params + ) + internal + { + vm.expectCall({ + callee: address(lockupTranched), + count: count, + data: abi.encodeCall(ISablierV2LockupTranched.createWithTimestamps, (params)) + }); + } + /// @dev Expects multiple calls to {IERC20.transfer}. function expectMultipleCallsToTransfer(uint64 count, address to, uint256 amount) internal { vm.expectCall({ callee: address(dai), count: count, data: abi.encodeCall(IERC20.transfer, (to, amount)) }); diff --git a/test/fork/Fork.t.sol b/test/fork/Fork.t.sol index a106242a..69ecf8d2 100644 --- a/test/fork/Fork.t.sol +++ b/test/fork/Fork.t.sol @@ -88,6 +88,6 @@ abstract contract Fork_Test is Base_Test, V2CoreFuzzers { /// @dev Deploys the v2 core dependencies. // TODO: Remove this function once the v2 core contracts are deployed on Mainnet. function deployDependencies() private { - (, lockupDynamic, lockupLinear, lockupTranched,) = new V2CorePrecompiles().deployCore(users.admin); + (lockupDynamic, lockupLinear, lockupTranched,) = new V2CorePrecompiles().deployCore(users.admin); } } diff --git a/test/fork/assets/USDC.t.sol b/test/fork/assets/USDC.t.sol index 76b283c3..342d7f56 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 { CreateWithTimestamps_LockupDynamic_Batch_Fork_Test } from "../batch/createWithTimestampsLD.t.sol"; import { CreateWithTimestamps_LockupLinear_Batch_Fork_Test } from "../batch/createWithTimestampsLL.t.sol"; +import { CreateWithTimestamps_LockupTranched_Batch_Fork_Test } from "../batch/createWithTimestampsLT.t.sol"; import { MerkleLockupLL_Fork_Test } from "../merkle-lockup/MerkleLockupLL.t.sol"; import { MerkleLockupLT_Fork_Test } from "../merkle-lockup/MerkleLockupLT.t.sol"; @@ -19,6 +20,10 @@ contract USDC_CreateWithTimestamps_LockupLinear_Batch_Fork_Test is CreateWithTimestamps_LockupLinear_Batch_Fork_Test(usdc) { } +contract USDC_CreateWithTimestamps_LockupTranched_Batch_Fork_Test is + CreateWithTimestamps_LockupTranched_Batch_Fork_Test(usdc) +{ } + contract USDC_MerkleLockupLL_Fork_Test is MerkleLockupLL_Fork_Test(usdc) { } contract USDC_MerkleLockupLT_Fork_Test is MerkleLockupLT_Fork_Test(usdc) { } diff --git a/test/fork/assets/USDT.t.sol b/test/fork/assets/USDT.t.sol index 0e60fea1..75c4434e 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 { CreateWithTimestamps_LockupDynamic_Batch_Fork_Test } from "../batch/createWithTimestampsLD.t.sol"; import { CreateWithTimestamps_LockupLinear_Batch_Fork_Test } from "../batch/createWithTimestampsLL.t.sol"; +import { CreateWithTimestamps_LockupTranched_Batch_Fork_Test } from "../batch/createWithTimestampsLT.t.sol"; import { MerkleLockupLL_Fork_Test } from "../merkle-lockup/MerkleLockupLL.t.sol"; import { MerkleLockupLT_Fork_Test } from "../merkle-lockup/MerkleLockupLT.t.sol"; @@ -19,6 +20,10 @@ contract USDT_CreateWithTimestamps_LockupLinear_Batch_Fork_Test is CreateWithTimestamps_LockupLinear_Batch_Fork_Test(usdt) { } +contract USDT_CreateWithTimestamps_LockupTranched_Batch_Fork_Test is + CreateWithTimestamps_LockupTranched_Batch_Fork_Test(usdt) +{ } + contract USDT_MerkleLockupLL_Fork_Test is MerkleLockupLL_Fork_Test(usdt) { } contract USDT_MerkleLockupLT_Fork_Test is MerkleLockupLT_Fork_Test(usdt) { } diff --git a/test/fork/batch/createWithTimestampsLD.t.sol b/test/fork/batch/createWithTimestampsLD.t.sol index ba9e1fbf..e2704d24 100644 --- a/test/fork/batch/createWithTimestampsLD.t.sol +++ b/test/fork/batch/createWithTimestampsLD.t.sol @@ -6,9 +6,9 @@ import { LockupDynamic } from "@sablier/v2-core/src/types/DataTypes.sol"; import { Batch } from "src/types/DataTypes.sol"; -import { Fork_Test } from "../Fork.t.sol"; import { ArrayBuilder } from "../../utils/ArrayBuilder.sol"; import { BatchBuilder } from "../../utils/BatchBuilder.sol"; +import { Fork_Test } from "../Fork.t.sol"; /// @dev Runs against multiple fork assets. abstract contract CreateWithTimestamps_LockupDynamic_Batch_Fork_Test is Fork_Test { @@ -39,7 +39,6 @@ abstract contract CreateWithTimestamps_LockupDynamic_Batch_Fork_Test is Fork_Tes (params.perStreamAmount,) = fuzzDynamicStreamAmounts({ upperBound: MAX_UINT128 / params.batchSize, segments: params.segments, - protocolFee: defaults.PROTOCOL_FEE(), brokerFee: defaults.BROKER_FEE() }); diff --git a/test/fork/batch/createWithTimestampsLL.t.sol b/test/fork/batch/createWithTimestampsLL.t.sol index d01c1562..8dc3705d 100644 --- a/test/fork/batch/createWithTimestampsLL.t.sol +++ b/test/fork/batch/createWithTimestampsLL.t.sol @@ -6,9 +6,9 @@ import { LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; import { Batch } from "src/types/DataTypes.sol"; -import { Fork_Test } from "../Fork.t.sol"; import { ArrayBuilder } from "../../utils/ArrayBuilder.sol"; import { BatchBuilder } from "../../utils/BatchBuilder.sol"; +import { Fork_Test } from "../Fork.t.sol"; /// @dev Runs against multiple fork assets. abstract contract CreateWithTimestamps_LockupLinear_Batch_Fork_Test is Fork_Test { diff --git a/test/fork/batch/createWithTimestampsLT.t.sol b/test/fork/batch/createWithTimestampsLT.t.sol new file mode 100644 index 00000000..a745dd48 --- /dev/null +++ b/test/fork/batch/createWithTimestampsLT.t.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22 <0.9.0; + +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { LockupTranched } from "@sablier/v2-core/src/types/DataTypes.sol"; + +import { Batch } from "src/types/DataTypes.sol"; + +import { ArrayBuilder } from "../../utils/ArrayBuilder.sol"; +import { BatchBuilder } from "../../utils/BatchBuilder.sol"; +import { Fork_Test } from "../Fork.t.sol"; + +/// @dev Runs against multiple fork assets. +abstract contract CreateWithTimestamps_LockupTranched_Batch_Fork_Test is Fork_Test { + constructor(IERC20 asset_) Fork_Test(asset_) { } + + function setUp() public virtual override { + Fork_Test.setUp(); + } + + /*////////////////////////////////////////////////////////////////////////// + BATCH-CREATE-WITH-TIMESTAMPS + //////////////////////////////////////////////////////////////////////////*/ + + struct CreateWithTimestampsParams { + uint128 batchSize; + address sender; + address recipient; + uint128 perStreamAmount; + uint40 startTime; + LockupTranched.Tranche[] tranches; + } + + function testForkFuzz_CreateWithTimestamps(CreateWithTimestampsParams memory params) external { + vm.assume(params.tranches.length != 0); + params.batchSize = boundUint128(params.batchSize, 1, 20); + params.startTime = boundUint40(params.startTime, getBlockTimestamp(), getBlockTimestamp() + 24 hours); + fuzzTrancheTimestamps(params.tranches, params.startTime); + (params.perStreamAmount,) = fuzzTranchedStreamAmounts({ + upperBound: MAX_UINT128 / params.batchSize, + tranches: params.tranches, + brokerFee: defaults.BROKER_FEE() + }); + + checkUsers(params.sender, params.recipient); + + uint256 firstStreamId = lockupTranched.nextStreamId(); + uint128 totalTransferAmount = params.perStreamAmount * params.batchSize; + + deal({ token: address(ASSET), to: params.sender, give: uint256(totalTransferAmount) }); + approveContract({ asset_: ASSET, from: params.sender, spender: address(batch) }); + + LockupTranched.CreateWithTimestamps memory createWithTimestamps = LockupTranched.CreateWithTimestamps({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.perStreamAmount, + asset: ASSET, + cancelable: true, + transferable: true, + startTime: params.startTime, + tranches: params.tranches, + broker: defaults.broker() + }); + Batch.CreateWithTimestampsLT[] memory batchParams = + BatchBuilder.fillBatch(createWithTimestamps, params.batchSize); + + expectCallToTransferFrom({ + asset_: address(ASSET), + from: params.sender, + to: address(batch), + amount: totalTransferAmount + }); + expectMultipleCallsToCreateWithTimestampsLT({ count: uint64(params.batchSize), params: createWithTimestamps }); + expectMultipleCallsToTransferFrom({ + asset_: address(ASSET), + count: uint64(params.batchSize), + from: address(batch), + to: address(lockupTranched), + amount: params.perStreamAmount + }); + + uint256[] memory actualStreamIds = batch.createWithTimestampsLT(lockupTranched, ASSET, batchParams); + uint256[] memory expectedStreamIds = ArrayBuilder.fillStreamIds(firstStreamId, params.batchSize); + assertEq(actualStreamIds, expectedStreamIds); + } +} diff --git a/test/integration/Integration.t.sol b/test/integration/Integration.t.sol index 9d81ea0c..d26b4044 100644 --- a/test/integration/Integration.t.sol +++ b/test/integration/Integration.t.sol @@ -37,6 +37,6 @@ abstract contract Integration_Test is Base_Test { //////////////////////////////////////////////////////////////////////////*/ function deployDependencies() private { - (comptroller, lockupDynamic, lockupLinear, lockupTranched,) = new V2CorePrecompiles().deployCore(users.admin); + (lockupDynamic, lockupLinear, lockupTranched,) = new V2CorePrecompiles().deployCore(users.admin); } } diff --git a/test/integration/batch/lockup-tranched/create-with-durations/createWithDurations.t.sol b/test/integration/batch/lockup-tranched/create-with-durations/createWithDurations.t.sol new file mode 100644 index 00000000..88ac0984 --- /dev/null +++ b/test/integration/batch/lockup-tranched/create-with-durations/createWithDurations.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 { Batch } from "src/types/DataTypes.sol"; + +import { Integration_Test } from "../../../Integration.t.sol"; + +contract CreateWithDurations_LockupTranched_Integration_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + } + + function test_RevertWhen_BatchSizeZero() external { + Batch.CreateWithDurationsLT[] memory batchParams = new Batch.CreateWithDurationsLT[](0); + vm.expectRevert(Errors.SablierV2Batch_BatchSizeZero.selector); + batch.createWithDurationsLT(lockupTranched, dai, batchParams); + } + + modifier whenBatchSizeNotZero() { + _; + } + + function test_BatchCreateWithDurations() external whenBatchSizeNotZero { + // Asset flow: Alice → batch → Sablier + // Expect transfers from Alice to the batch, and then from the batch to the Sablier contract. + expectCallToTransferFrom({ from: users.alice, to: address(batch), amount: defaults.TOTAL_TRANSFER_AMOUNT() }); + expectMultipleCallsToCreateWithDurationsLT({ + count: defaults.BATCH_SIZE(), + params: defaults.createWithDurationsLT() + }); + expectMultipleCallsToTransferFrom({ + count: defaults.BATCH_SIZE(), + from: address(batch), + to: address(lockupTranched), + amount: defaults.PER_STREAM_AMOUNT() + }); + + // Assert that the batch of streams has been created successfully. + uint256[] memory actualStreamIds = + batch.createWithDurationsLT(lockupTranched, dai, defaults.batchCreateWithDurationsLT()); + uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); + assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); + } +} diff --git a/test/integration/batch/lockup-tranched/create-with-durations/createWithDurations.tree b/test/integration/batch/lockup-tranched/create-with-durations/createWithDurations.tree new file mode 100644 index 00000000..377110d8 --- /dev/null +++ b/test/integration/batch/lockup-tranched/create-with-durations/createWithDurations.tree @@ -0,0 +1,6 @@ +createWithDurations.t.sol +├── when the batch size is zero +│ └── it should revert +└── when the batch size is not zero + ├── it should create a batch of streams with durations + └── it should perform the ERC-20 transfers diff --git a/test/integration/batch/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol b/test/integration/batch/lockup-tranched/create-with-timestamps/createWithTimestamps.t.sol new file mode 100644 index 00000000..28528ac9 --- /dev/null +++ b/test/integration/batch/lockup-tranched/create-with-timestamps/createWithTimestamps.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 { Batch } from "src/types/DataTypes.sol"; + +import { Integration_Test } from "../../../Integration.t.sol"; + +contract CreateWithTimestamps_LockupTranched_Integration_Test is Integration_Test { + function setUp() public virtual override { + Integration_Test.setUp(); + } + + function test_RevertWhen_BatchSizeZero() external { + Batch.CreateWithTimestampsLT[] memory batchParams = new Batch.CreateWithTimestampsLT[](0); + vm.expectRevert(Errors.SablierV2Batch_BatchSizeZero.selector); + batch.createWithTimestampsLT(lockupTranched, dai, batchParams); + } + + modifier whenBatchSizeNotZero() { + _; + } + + function test_BatchCreateWithTimestamps() external whenBatchSizeNotZero { + // Asset flow: Alice → batch → Sablier + // Expect transfers from Alice to the batch, and then from the batch to the Sablier contract. + expectCallToTransferFrom({ from: users.alice, to: address(batch), amount: defaults.TOTAL_TRANSFER_AMOUNT() }); + expectMultipleCallsToCreateWithTimestampsLT({ + count: defaults.BATCH_SIZE(), + params: defaults.createWithTimestampsLT() + }); + expectMultipleCallsToTransferFrom({ + count: defaults.BATCH_SIZE(), + from: address(batch), + to: address(lockupTranched), + amount: defaults.PER_STREAM_AMOUNT() + }); + + // Assert that the batch of streams has been created successfully. + uint256[] memory actualStreamIds = + batch.createWithTimestampsLT(lockupTranched, dai, defaults.batchCreateWithTimestampsLT()); + uint256[] memory expectedStreamIds = defaults.incrementalStreamIds(); + assertEq(actualStreamIds, expectedStreamIds, "stream ids mismatch"); + } +} diff --git a/test/integration/batch/lockup-tranched/create-with-timestamps/createWithTimestamps.tree b/test/integration/batch/lockup-tranched/create-with-timestamps/createWithTimestamps.tree new file mode 100644 index 00000000..7769ecd1 --- /dev/null +++ b/test/integration/batch/lockup-tranched/create-with-timestamps/createWithTimestamps.tree @@ -0,0 +1,6 @@ +createWithTimestamps.t.sol +├── when the batch size is zero +│ └── it should revert +└── when the batch size is not zero + ├── it should create a batch of streams with timestamps + └── it should perform the ERC-20 transfers diff --git a/test/utils/BatchBuilder.sol b/test/utils/BatchBuilder.sol index d52e3dff..6567d193 100644 --- a/test/utils/BatchBuilder.sol +++ b/test/utils/BatchBuilder.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; -import { LockupDynamic, LockupLinear } from "@sablier/v2-core/src/types/DataTypes.sol"; +import { LockupDynamic, LockupLinear, LockupTranched } from "@sablier/v2-core/src/types/DataTypes.sol"; import { Batch } from "../../src/types/DataTypes.sol"; @@ -80,6 +80,43 @@ library BatchBuilder { batch = fillBatch(batchSingle, batchSize); } + /// @notice Generates an array containing `batchSize` copies of `batchSingle`. + function fillBatch( + Batch.CreateWithDurationsLT memory batchSingle, + uint256 batchSize + ) + internal + pure + returns (Batch.CreateWithDurationsLT[] memory batch) + { + batch = new Batch.CreateWithDurationsLT[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + batch[i] = batchSingle; + } + } + + /// @notice Turns the `params` into an array of `Batch.CreateWithDurationsLT` structs. + function fillBatch( + LockupTranched.CreateWithDurations memory params, + uint256 batchSize + ) + internal + pure + returns (Batch.CreateWithDurationsLT[] memory batch) + { + batch = new Batch.CreateWithDurationsLT[](batchSize); + Batch.CreateWithDurationsLT memory batchSingle = Batch.CreateWithDurationsLT({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, + cancelable: params.cancelable, + transferable: params.transferable, + tranches: params.tranches, + broker: params.broker + }); + batch = fillBatch(batchSingle, batchSize); + } + /// @notice Generates an array containing `batchSize` copies of `batchSingle`. function fillBatch( Batch.CreateWithTimestampsLD memory batchSingle, @@ -154,4 +191,42 @@ library BatchBuilder { }); batch = fillBatch(batchSingle, batchSize); } + + /// @notice Generates an array containing `batchSize` copies of `batchSingle`. + function fillBatch( + Batch.CreateWithTimestampsLT memory batchSingle, + uint256 batchSize + ) + internal + pure + returns (Batch.CreateWithTimestampsLT[] memory batch) + { + batch = new Batch.CreateWithTimestampsLT[](batchSize); + for (uint256 i = 0; i < batchSize; ++i) { + batch[i] = batchSingle; + } + } + + /// @notice Turns the `params` into an array of `Batch.CreateWithTimestampsLT` structs. + function fillBatch( + LockupTranched.CreateWithTimestamps memory params, + uint256 batchSize + ) + internal + pure + returns (Batch.CreateWithTimestampsLT[] memory batch) + { + batch = new Batch.CreateWithTimestampsLT[](batchSize); + Batch.CreateWithTimestampsLT memory batchSingle = Batch.CreateWithTimestampsLT({ + sender: params.sender, + recipient: params.recipient, + totalAmount: params.totalAmount, + cancelable: params.cancelable, + transferable: params.transferable, + startTime: params.startTime, + tranches: params.tranches, + broker: params.broker + }); + batch = fillBatch(batchSingle, batchSize); + } } diff --git a/test/utils/Defaults.sol b/test/utils/Defaults.sol index 7e7aa8ee..2261efac 100644 --- a/test/utils/Defaults.sol +++ b/test/utils/Defaults.sol @@ -31,7 +31,6 @@ contract Defaults is Merkle { uint256 public constant ETHER_AMOUNT = 10_000 ether; uint256 public constant MAX_SEGMENT_COUNT = 1000; uint128 public constant PER_STREAM_AMOUNT = 10_000e18; - UD60x18 public constant PROTOCOL_FEE = UD60x18.wrap(0); uint128 public constant REFUND_AMOUNT = 7500e18; // deposit - cliff amount uint40 public immutable START_TIME; uint40 public constant TOTAL_DURATION = 10_000 seconds; @@ -214,10 +213,6 @@ contract Defaults is Merkle { }); } - function dynamicRange() public view returns (LockupDynamic.Range memory) { - return LockupDynamic.Range({ start: START_TIME, end: END_TIME }); - } - /// @dev Returns a batch of `LockupDynamic.Segment` parameters. function segments() private view returns (LockupDynamic.Segment[] memory segments_) { segments_ = new LockupDynamic.Segment[](2); @@ -304,6 +299,41 @@ contract Defaults is Merkle { SABLIER-V2-LOCKUP-TRANCHED //////////////////////////////////////////////////////////////////////////*/ + function createWithDurationsLT() public view returns (LockupTranched.CreateWithDurations memory) { + return createWithDurationsLT(asset); + } + + function createWithDurationsLT(IERC20 asset_) public view returns (LockupTranched.CreateWithDurations memory) { + return LockupTranched.CreateWithDurations({ + sender: users.alice, + recipient: users.recipient0, + totalAmount: PER_STREAM_AMOUNT, + asset: asset_, + cancelable: true, + transferable: true, + tranches: tranchesWithDurations(), + broker: broker() + }); + } + + function createWithTimestampsLT() public view returns (LockupTranched.CreateWithTimestamps memory) { + return createWithTimestampsLT(asset); + } + + function createWithTimestampsLT(IERC20 asset_) public view returns (LockupTranched.CreateWithTimestamps memory) { + return LockupTranched.CreateWithTimestamps({ + sender: users.alice, + recipient: users.recipient0, + totalAmount: PER_STREAM_AMOUNT, + asset: asset_, + cancelable: true, + transferable: true, + startTime: START_TIME, + tranches: tranches(), + broker: broker() + }); + } + function tranches() public view returns (LockupTranched.Tranche[] memory tranches_) { tranches_ = new LockupTranched.Tranche[](2); tranches_[0] = LockupTranched.Tranche({ amount: 2500e18, timestamp: uint40(block.timestamp) + CLIFF_DURATION }); @@ -327,6 +357,25 @@ contract Defaults is Merkle { } } + /// @dev Returns a batch of `LockupTranched.TrancheWithDuration` parameters. + function tranchesWithDurations() public pure returns (LockupTranched.TrancheWithDuration[] memory) { + return tranchesWithDurations({ amount0: 2500e18, amount1: 7500e18 }); + } + + /// @dev Returns a batch of `LockupTranched.TrancheWithDuration` parameters. + function tranchesWithDurations( + uint128 amount0, + uint128 amount1 + ) + public + pure + returns (LockupTranched.TrancheWithDuration[] memory segments_) + { + segments_ = new LockupTranched.TrancheWithDuration[](2); + segments_[0] = LockupTranched.TrancheWithDuration({ amount: amount0, duration: 2500 seconds }); + segments_[1] = LockupTranched.TrancheWithDuration({ amount: amount1, duration: 7500 seconds }); + } + /*////////////////////////////////////////////////////////////////////////// BATCH //////////////////////////////////////////////////////////////////////////*/ @@ -341,6 +390,11 @@ contract Defaults is Merkle { batch = BatchBuilder.fillBatch(createWithDurationsLL(), BATCH_SIZE); } + /// @dev Returns a default-size batch of `Batch.CreateWithDurationsLT` parameters. + function batchCreateWithDurationsLT() public view returns (Batch.CreateWithDurationsLT[] memory batch) { + batch = BatchBuilder.fillBatch(createWithDurationsLT(), BATCH_SIZE); + } + /// @dev Returns a default-size batch of `Batch.CreateWithTimestampsLD` parameters. function batchCreateWithTimestampsLD() public view returns (Batch.CreateWithTimestampsLD[] memory batch) { batch = batchCreateWithTimestampsLD(BATCH_SIZE); @@ -368,4 +422,18 @@ contract Defaults is Merkle { { batch = BatchBuilder.fillBatch(createWithTimestampsLL(), batchSize); } + + /// @dev Returns a default-size batch of `Batch.CreateWithTimestampsLT` parameters. + function batchCreateWithTimestampsLT() public view returns (Batch.CreateWithTimestampsLT[] memory batch) { + batch = batchCreateWithTimestampsLT(BATCH_SIZE); + } + + /// @dev Returns a batch of `Batch.CreateWithTimestampsLL` parameters. + function batchCreateWithTimestampsLT(uint256 batchSize) + public + view + returns (Batch.CreateWithTimestampsLT[] memory batch) + { + batch = BatchBuilder.fillBatch(createWithTimestampsLT(), batchSize); + } } diff --git a/test/utils/Precompiles.sol b/test/utils/Precompiles.sol index bb712314..0e5247b6 100644 --- a/test/utils/Precompiles.sol +++ b/test/utils/Precompiles.sol @@ -11,9 +11,9 @@ contract Precompiles { //////////////////////////////////////////////////////////////////////////*/ bytes public constant BYTECODE_BATCH = - hex"6080806040523461001657611936908161001c8239f35b600080fdfe608080604052600436101561001357600080fd5b60003560e01c90816349a32c4014610c8657508063606ef875146108d2578063a514f83e146104a85763f7ca34eb1461004b57600080fd5b346103ab576100593661113e565b919092821561047e576000805b8482106104505761008f91508373ffffffffffffffffffffffffffffffffffffffff8416611580565b61009883611300565b9260005b8181106100b557604051806100b18782611102565b0390f35b6100c86100c3828489611540565b61134f565b906100df60206100d983868b611540565b0161134f565b876100f660406100f0858885611540565b01611219565b9361010d6060610107868986611540565b01611370565b9460a061012b8689610125608061010784848b611540565b96611540565b013564ffffffffff811681036103ab578b91889160e06101658961015d61015382888a611540565b60c0810190611429565b969097611540565b0195604051998a61012081011067ffffffffffffffff6101208d0111176104215773ffffffffffffffffffffffffffffffffffffffff8e8c60406fffffffffffffffffffffffffffffffff64ffffffffff98856102029f816101f69f61012088018752168652166020850152169101521660608c0152151560808b0152151560a08a01521660c0880152369161147d565b60e0850152369061138f565b610100830152604051917f31df3d480000000000000000000000000000000000000000000000000000000083526020600484015273ffffffffffffffffffffffffffffffffffffffff815116602484015273ffffffffffffffffffffffffffffffffffffffff60208201511660448401526fffffffffffffffffffffffffffffffff604082015116606484015273ffffffffffffffffffffffffffffffffffffffff60608201511660848401526080810151151560a484015260a0810151151560c484015264ffffffffff60c08201511660e48401528260e0820151610140610104830152805180610164840152602061018484019201906000905b8082106103c457505050819061034061010060209501516101248401906020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b0381600073ffffffffffffffffffffffffffffffffffffffff89165af180156103b857600090610380575b6001925061037982886113d5565b520161009c565b506020823d6020116103b0575b8161039a602093836112a7565b810103126103ab576001915161036b565b600080fd5b3d915061038d565b6040513d6000823e3d90fd5b91949350916020606082610412600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b019501920186939492916102fe565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6001906fffffffffffffffffffffffffffffffff61047460406100f0868a8c611540565b1601910190610066565b60046040517f763e559d000000000000000000000000000000000000000000000000000000008152fd5b346103ab5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103ab576104df6110bc565b6104e76110df565b9060443567ffffffffffffffff8082116103ab57366023830112156103ab578160040135116103ab57366024610140836004013502830101116103ab5780600401351561047e576000805b8260040135821061089d5761055f91508473ffffffffffffffffffffffffffffffffffffffff8516611580565b61056c8160040135611300565b9160005b8260040135811061058957604051806100b18682611102565b61059e6100c38285600401356024870161152f565b90836105b760206100d98484600401356024860161152f565b6105ce60406100f08585600401356024870161152f565b936105e660606101078686600401356024880161152f565b946080956fffffffffffffffffffffffffffffffff6106118861010789896004013560248b0161152f565b9273ffffffffffffffffffffffffffffffffffffffff61010061064f8a6106408160048d013560248e0161152f565b9a60248160040135910161152f565b0196816040519761065f89611236565b16875216602086015216604084015273ffffffffffffffffffffffffffffffffffffffff8b166060840152151586830152151560a082015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6084360301126103ab576108259261071460e0936040516106d98161126f565b6106e560a0850161137d565b81526107048660c0956106f987820161137d565b60208501520161137d565b604082015283850152369061138f565b83830152604051957f53b1572700000000000000000000000000000000000000000000000000000000875273ffffffffffffffffffffffffffffffffffffffff835116600488015273ffffffffffffffffffffffffffffffffffffffff60208401511660248801526fffffffffffffffffffffffffffffffff604084015116604488015273ffffffffffffffffffffffffffffffffffffffff60608401511660648801528201511515608487015260a0820151151560a4870152810151604064ffffffffff918281511660c48901528260208201511660e489015201511661010486015201516101248401906020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b60208261016481600073ffffffffffffffffffffffffffffffffffffffff88165af180156103b85760009061086a575b6001925061086382876113d5565b5201610570565b506020823d602011610895575b81610884602093836112a7565b810103126103ab5760019151610855565b3d9150610877565b6001906fffffffffffffffffffffffffffffffff6108c860406100f086886004013560248a0161152f565b1601910190610532565b346103ab576108e03661113e565b92831561047e5760009060005b858110610c58575073ffffffffffffffffffffffffffffffffffffffff6109179116918483611580565b61092084611300565b9260005b85811061093957604051806100b18782611102565b6109448187866113e9565b61094d9061134f565b906109598188876113e9565b6020016109659061134f565b878261097281838a6113e9565b60400161097e90611219565b61098982848b6113e9565b60600161099590611370565b6109a083858c6113e9565b6080016109ac90611370565b916109b884868d6113e9565b60a081016109c591611429565b946109d191968d6113e9565b60c00195604051986109e28a611236565b73ffffffffffffffffffffffffffffffffffffffff16895273ffffffffffffffffffffffffffffffffffffffff1660208901526fffffffffffffffffffffffffffffffff16604088015273ffffffffffffffffffffffffffffffffffffffff8816606088015215156080870152151560a08601523690610a619261147d565b60c084015236610a709161138f565b60e0830152604051917f54c022920000000000000000000000000000000000000000000000000000000083526004830160209052826101448101825173ffffffffffffffffffffffffffffffffffffffff166024830152602083015173ffffffffffffffffffffffffffffffffffffffff16604483015260408301516fffffffffffffffffffffffffffffffff166064830152606083015173ffffffffffffffffffffffffffffffffffffffff1660848301526080830151151560a483015260a0830151151560c483015260c08301519060e4830161012090528151809152610164830191602001906000905b808210610bfb575050508190610b9e60e060209501516101048401906020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b03816000885af180156103b857600090610bc8575b60019250610bc182886113d5565b5201610924565b506020823d602011610bf3575b81610be2602093836112a7565b810103126103ab5760019151610bb3565b3d9150610bd5565b91949350916020606082610c49600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01950192018693949291610b5d565b916001906fffffffffffffffffffffffffffffffff610c7d60406100f0878b8a6113e9565b160192016108ed565b346103ab5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103ab57610cbd6110bc565b610cc56110df565b916044359067ffffffffffffffff8083116103ab57366023840112156103ab578260040135116103ab57366024610120846004013502840101116103ab5781600401351561109457506000805b8260040135821061105f57610d3f91508473ffffffffffffffffffffffffffffffffffffffff8516611580565b610d4c8160040135611300565b9160005b82600401358110610d6957604051806100b18682611102565b610d7e6100c3828560040135602487016111d9565b9083610d9760206100d9848460040135602486016111d9565b610dae60406100f0858560040135602487016111d9565b93610dc66060610107868660040135602488016111d9565b946080956fffffffffffffffffffffffffffffffff610df18861010789896004013560248b016111d9565b9273ffffffffffffffffffffffffffffffffffffffff60e0610e2e8a610e1f8160048d013560248e016111d9565b9a6024816004013591016111d9565b01968160405197610e3e89611236565b16875216602086015216604084015273ffffffffffffffffffffffffffffffffffffffff8b166060840152151586830152151560a082015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6084360301126103ab57610fe792610ee360e093604051610eb881611253565b610ec460a0850161137d565b8152610ed360c080950161137d565b602082015283850152369061138f565b83830152604051957fab167ccc00000000000000000000000000000000000000000000000000000000875273ffffffffffffffffffffffffffffffffffffffff835116600488015273ffffffffffffffffffffffffffffffffffffffff60208401511660248801526fffffffffffffffffffffffffffffffff604084015116604488015273ffffffffffffffffffffffffffffffffffffffff60608401511660648801528201511515608487015260a0820151151560a4870152810151602064ffffffffff918281511660c489015201511660e486015201516101048401906020809173ffffffffffffffffffffffffffffffffffffffff81511684520151910152565b60208261014481600073ffffffffffffffffffffffffffffffffffffffff88165af180156103b85760009061102c575b6001925061102582876113d5565b5201610d50565b506020823d602011611057575b81611046602093836112a7565b810103126103ab5760019151611017565b3d9150611039565b6001906fffffffffffffffffffffffffffffffff61108a60406100f086886004013560248a016111d9565b1601910190610d12565b807f763e559d0000000000000000000000000000000000000000000000000000000060049252fd5b6004359073ffffffffffffffffffffffffffffffffffffffff821682036103ab57565b6024359073ffffffffffffffffffffffffffffffffffffffff821682036103ab57565b602090602060408183019282815285518094520193019160005b82811061112a575050505090565b83518552938101939281019260010161111c565b9060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8301126103ab5773ffffffffffffffffffffffffffffffffffffffff9160043583811681036103ab579260243590811681036103ab579160443567ffffffffffffffff928382116103ab57806023830112156103ab5781600401359384116103ab5760248460051b830101116103ab576024019190565b91908110156111ea57610120020190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b356fffffffffffffffffffffffffffffffff811681036103ab5790565b610100810190811067ffffffffffffffff82111761042157604052565b6040810190811067ffffffffffffffff82111761042157604052565b6060810190811067ffffffffffffffff82111761042157604052565b6080810190811067ffffffffffffffff82111761042157604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761042157604052565b67ffffffffffffffff81116104215760051b60200190565b9061130a826112e8565b61131760405191826112a7565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061134582946112e8565b0190602036910137565b3573ffffffffffffffffffffffffffffffffffffffff811681036103ab5790565b3580151581036103ab5790565b359064ffffffffff821682036103ab57565b91908260409103126103ab576040516113a781611253565b8092803573ffffffffffffffffffffffffffffffffffffffff811681036103ab578252602090810135910152565b80518210156111ea5760209160051b010190565b91908110156111ea5760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01813603018212156103ab570190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156103ab570180359067ffffffffffffffff82116103ab576020019160608202360383136103ab57565b929192611489826112e8565b60409461149960405192836112a7565b819584835260208093019160608096028501948186116103ab57925b8584106114c55750505050505050565b86848303126103ab578251906114da8261126f565b84356fffffffffffffffffffffffffffffffff811681036103ab578252858501359067ffffffffffffffff821682036103ab57828792838b95015261152086880161137d565b868201528152019301926114b5565b91908110156111ea57610140020190565b91908110156111ea5760051b810135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee1813603018212156103ab570190565b90604080516020907f23b872dd000000000000000000000000000000000000000000000000000000008282015233602482015260449030828201528660648201526064815260a081019080821067ffffffffffffffff831117610421576115e991855285611792565b73ffffffffffffffffffffffffffffffffffffffff94858516958451917fdd62ed3e0000000000000000000000000000000000000000000000000000000083523060048401521690816024820152838184818a5afa90811561176f5790889160009161173e575b5010611660575b50505050505050565b8351956000808589017f095ea7b3000000000000000000000000000000000000000000000000000000009a8b82528560248c0152868b0152858a526116a48a61128b565b89519082855af1906116b461182b565b8261170b575b5081611700575b50611657576116f4966116ef945193840152602483015260008183015281526116e98161128b565b82611792565b611792565b38808080808080611657565b90503b1515386116c1565b809192505190858215928315611726575b50505090386116ba565b611736935082018101910161177a565b38858161171c565b809250858092503d8311611768575b61175781836112a7565b810103126103ab5787905138611650565b503d61174d565b85513d6000823e3d90fd5b908160209103126103ab575180151581036103ab5790565b60008073ffffffffffffffffffffffffffffffffffffffff6117c993169360208151910182865af16117c261182b565b9083611889565b8051908115159182611810575b50506117df5750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b611823925060208091830101910161177a565b1538806117d6565b3d15611884573d9067ffffffffffffffff8211610421576040519161187860207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846112a7565b82523d6000602084013e565b606090565b906118c8575080511561189e57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580611920575b6118d9575090565b60249073ffffffffffffffffffffffffffffffffffffffff604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156118d156fea164736f6c6343000817000a"; + hex"6080806040523461001657611f10908161001c8239f35b600080fdfe608080604052600436101561001357600080fd5b60003560e01c90816337266dd31461125b5750806349a32c4014610eb7578063606ef87514610b6b5780639e743f29146107fc578063a514f83e146104295763f7ca34eb1461006157600080fd5b346103555761006f366115d6565b9283156103ff5760009060005b8581106103cb57506001600160a01b036100999116918483611b81565b6100a284611858565b9260005b8581106100bf57604051806100bb8782611664565b0390f35b6100ca818786611b1e565b6100d3906118a7565b906100df818887611b1e565b6020016100eb906118a7565b85886100f8848284611b1e565b60400161010490611725565b61010f858385611b1e565b60600161011b906118bb565b610126868486611b1e565b608001610132906118bb565b9061013e878587611b1e565b60a00161014a90611b5e565b9287610157818789611b1e565b60c0810161016491611a2a565b96610170929198611b1e565b60e00196604051996101818b6117aa565b6001600160a01b03168a526001600160a01b031660208a01526fffffffffffffffffffffffffffffffff1660408901526001600160a01b038916606089015215156080880152151560a087015264ffffffffff1660c086015236906101e592611a7e565b60e0840152366101f4916119cc565b610100830152604051917f31df3d48000000000000000000000000000000000000000000000000000000008352600483016020905280516001600160a01b0316602484015260208101516001600160a01b0316604484015260408101516fffffffffffffffffffffffffffffffff16606484015260608101516001600160a01b031660848401526080810151151560a484015260a0810151151560c484015260c081015164ffffffffff1660e48401528260e082015161010482016101409052805180610164840152610184830191602001906000905b80821061036e5750505081906103006101006020950151610124840190602080916001600160a01b0381511684520151910152565b03816000885af180156103625760009061032a575b600192506103238288611a05565b52016100a6565b506020823d60201161035a575b81610344602093836117ff565b810103126103555760019151610315565b600080fd5b3d9150610337565b6040513d6000823e3d90fd5b919493509160206060826103bc600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b019501920186939492916102cb565b916001906fffffffffffffffffffffffffffffffff6103f660406103f0878b8a611b1e565b01611725565b1601920161007c565b60046040517f763e559d000000000000000000000000000000000000000000000000000000008152fd5b346103555760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610355576104606116a0565b6104686115c0565b9060443567ffffffffffffffff8082116103555736602383011215610355578160040135116103555736602461014083600401350283010111610355578060040135156103ff576000805b826004013582106107c7576104d39150846001600160a01b038516611b81565b6104e08160040135611858565b9160005b826004013581106104fd57604051806100bb8682611664565b61051761051282856004013560248701611b70565b6118a7565b9083610536602061053084846004013560248601611b70565b016118a7565b61054d60406103f085856004013560248701611b70565b9361056b606061056586866004013560248801611b70565b016118bb565b946080956fffffffffffffffffffffffffffffffff6105968861056589896004013560248b01611b70565b926001600160a01b036101006105c78a6105b88160048d013560248e01611b70565b9a602481600401359101611b70565b019681604051976105d789611742565b1687521660208601521660408401526001600160a01b038b166060840152151586830152151560a082015260607fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6084360301126103555761075c9261067f60e093604051610644816117c7565b61065060a08501611939565b815261066f8660c095610664878201611939565b602085015201611939565b60408201528385015236906119cc565b83830152604051957f53b157270000000000000000000000000000000000000000000000000000000087526001600160a01b0383511660048801526001600160a01b0360208401511660248801526fffffffffffffffffffffffffffffffff60408401511660448801526001600160a01b0360608401511660648801528201511515608487015260a0820151151560a4870152810151604064ffffffffff918281511660c48901528260208201511660e48901520151166101048601520151610124840190602080916001600160a01b0381511684520151910152565b6020826101648160006001600160a01b0388165af1801561036257600090610794575b6001925061078d8287611a05565b52016104e4565b506020823d6020116107bf575b816107ae602093836117ff565b81010312610355576001915161077f565b3d91506107a1565b6001906fffffffffffffffffffffffffffffffff6107f260406103f086886004013560248a01611b70565b16019101906104b3565b346103555761080a366115d6565b9283156103ff5760009060005b858110610b3d57506001600160a01b036108349116918483611b81565b61083d84611858565b9260005b85811061085657604051806100bb8782611664565b610861818786611b1e565b61086a906118a7565b90610876818887611b1e565b602001610882906118a7565b858861088f848284611b1e565b60400161089b90611725565b6108a6858385611b1e565b6060016108b2906118bb565b6108bd868486611b1e565b6080016108c9906118bb565b906108d5878587611b1e565b60a0016108e190611b5e565b92876108ee818789611b1e565b60c081016108fb916118c8565b96610907929198611b1e565b60e00196604051996109188b6117aa565b6001600160a01b03168a526001600160a01b031660208a01526fffffffffffffffffffffffffffffffff1660408901526001600160a01b038916606089015215156080880152151560a087015264ffffffffff1660c0860152369061097c9261194b565b60e08401523661098b916119cc565b610100830152604051917f32fbe22b000000000000000000000000000000000000000000000000000000008352600483016020905280516001600160a01b0316602484015260208101516001600160a01b0316604484015260408101516fffffffffffffffffffffffffffffffff16606484015260608101516001600160a01b031660848401526080810151151560a484015260a0810151151560c484015260c081015164ffffffffff1660e48401528260e082015161010482016101409052805180610164840152610184830191602001906000905b808210610af4575050508190610a976101006020950151610124840190602080916001600160a01b0381511684520151910152565b03816000885af1801561036257600090610ac1575b60019250610aba8288611a05565b5201610841565b506020823d602011610aec575b81610adb602093836117ff565b810103126103555760019151610aac565b3d9150610ace565b91949350916020604082610b2e600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b01950192018693949291610a62565b916001906fffffffffffffffffffffffffffffffff610b6260406103f0878b8a611b1e565b16019201610817565b3461035557610b79366115d6565b9283156103ff5760009060005b858110610e8957506001600160a01b03610ba39116918483611b81565b610bac84611858565b9260005b858110610bc557604051806100bb8782611664565b610bd08187866116b6565b610bd9906118a7565b90610be58188876116b6565b602001610bf1906118a7565b8782610bfe81838a6116b6565b604001610c0a90611725565b610c1582848b6116b6565b606001610c21906118bb565b610c2c83858c6116b6565b608001610c38906118bb565b91610c4484868d6116b6565b60a08101610c5191611a2a565b94610c5d91968d6116b6565b60c0019560405198610c6e8a611742565b6001600160a01b031689526001600160a01b031660208901526fffffffffffffffffffffffffffffffff1660408801526001600160a01b038816606088015215156080870152151560a08601523690610cc692611a7e565b60c084015236610cd5916119cc565b60e0830152604051917f54c02292000000000000000000000000000000000000000000000000000000008352600483016020905282610144810182516001600160a01b0316602483015260208301516001600160a01b0316604483015260408301516fffffffffffffffffffffffffffffffff16606483015260608301516001600160a01b031660848301526080830151151560a483015260a0830151151560c483015260c08301519060e4830161012090528151809152610164830191602001906000905b808210610e2c575050508190610dcf60e06020950151610104840190602080916001600160a01b0381511684520151910152565b03816000885af1801561036257600090610df9575b60019250610df28288611a05565b5201610bb0565b506020823d602011610e24575b81610e13602093836117ff565b810103126103555760019151610de4565b3d9150610e06565b91949350916020606082610e7a600194895164ffffffffff604080926fffffffffffffffffffffffffffffffff815116855267ffffffffffffffff6020820151166020860152015116910152565b01950192018693949291610d9b565b916001906fffffffffffffffffffffffffffffffff610eae60406103f0878b8a6116b6565b16019201610b86565b346103555760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261035557610eee6116a0565b610ef66115c0565b9060443567ffffffffffffffff8082116103555736602383011215610355578160040135116103555736602461012083600401350283010111610355578060040135156103ff576000805b8260040135821061122657610f619150846001600160a01b038516611b81565b610f6e8160040135611858565b9160005b82600401358110610f8b57604051806100bb8682611664565b610fa061051282856004013560248701611a19565b9083610fb9602061053084846004013560248601611a19565b610fd060406103f085856004013560248701611a19565b93610fe8606061056586866004013560248801611a19565b946080956fffffffffffffffffffffffffffffffff6110138861056589896004013560248b01611a19565b926001600160a01b0360e06110438a6110348160048d013560248e01611a19565b9a602481600401359101611a19565b0196816040519761105389611742565b1687521660208601521660408401526001600160a01b038b166060840152151586830152151560a082015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff608436030112610355576111bb926110eb60e0936040516110c08161178e565b6110cc60a08501611939565b81526110db60c0809501611939565b60208201528385015236906119cc565b83830152604051957fab167ccc0000000000000000000000000000000000000000000000000000000087526001600160a01b0383511660048801526001600160a01b0360208401511660248801526fffffffffffffffffffffffffffffffff60408401511660448801526001600160a01b0360608401511660648801528201511515608487015260a0820151151560a4870152810151602064ffffffffff918281511660c489015201511660e48601520151610104840190602080916001600160a01b0381511684520151910152565b6020826101448160006001600160a01b0388165af18015610362576000906111f3575b600192506111ec8287611a05565b5201610f72565b506020823d60201161121e575b8161120d602093836117ff565b8101031261035557600191516111de565b3d9150611200565b6001906fffffffffffffffffffffffffffffffff61125160406103f086886004013560248a01611a19565b1601910190610f41565b3461035557611269366115d6565b93849391929315611598575060009060005b85811061156a57506001600160a01b036112989116918483611b81565b6112a184611858565b9260005b8581106112ba57604051806100bb8782611664565b6112c58187866116b6565b6112ce906118a7565b906112da8188876116b6565b6020016112e6906118a7565b87826112f381838a6116b6565b6040016112ff90611725565b61130a82848b6116b6565b606001611316906118bb565b61132183858c6116b6565b60800161132d906118bb565b9161133984868d6116b6565b60a08101611346916118c8565b9461135291968d6116b6565b60c00195604051986113638a611742565b6001600160a01b031689526001600160a01b031660208901526fffffffffffffffffffffffffffffffff1660408801526001600160a01b038816606088015215156080870152151560a086015236906113bb9261194b565b60c0840152366113ca916119cc565b60e0830152604051917f897f362b000000000000000000000000000000000000000000000000000000008352600483016020905282610144810182516001600160a01b0316602483015260208301516001600160a01b0316604483015260408301516fffffffffffffffffffffffffffffffff16606483015260608301516001600160a01b031660848301526080830151151560a483015260a0830151151560c483015260c08301519060e4830161012090528151809152610164830191602001906000905b8082106115215750505081906114c460e06020950151610104840190602080916001600160a01b0381511684520151910152565b03816000885af18015610362576000906114ee575b600192506114e78288611a05565b52016112a5565b506020823d602011611519575b81611508602093836117ff565b8101031261035557600191516114d9565b3d91506114fb565b9194935091602060408261155b600194895164ffffffffff602080926fffffffffffffffffffffffffffffffff8151168552015116910152565b01950192018693949291611490565b916001906fffffffffffffffffffffffffffffffff61158f60406103f0878b8a6116b6565b1601920161127b565b807f763e559d0000000000000000000000000000000000000000000000000000000060049252fd5b602435906001600160a01b038216820361035557565b9060607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc830112610355576001600160a01b0391600435838116810361035557926024359081168103610355579160443567ffffffffffffffff9283821161035557806023830112156103555781600401359384116103555760248460051b83010111610355576024019190565b602090602060408183019282815285518094520193019160005b82811061168c575050505090565b83518552938101939281019260010161167e565b600435906001600160a01b038216820361035557565b91908110156116f65760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0181360301821215610355570190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b356fffffffffffffffffffffffffffffffff811681036103555790565b610100810190811067ffffffffffffffff82111761175f57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040810190811067ffffffffffffffff82111761175f57604052565b610120810190811067ffffffffffffffff82111761175f57604052565b6060810190811067ffffffffffffffff82111761175f57604052565b6080810190811067ffffffffffffffff82111761175f57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff82111761175f57604052565b67ffffffffffffffff811161175f5760051b60200190565b9061186282611840565b61186f60405191826117ff565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061189d8294611840565b0190602036910137565b356001600160a01b03811681036103555790565b3580151581036103555790565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610355570180359067ffffffffffffffff821161035557602001918160061b3603831361035557565b35906fffffffffffffffffffffffffffffffff8216820361035557565b359064ffffffffff8216820361035557565b92919261195782611840565b60409261196760405192836117ff565b819581835260208093019160061b84019381851161035557915b84831061199057505050505050565b85838303126103555783869182516119a78161178e565b6119b08661191c565b81526119bd838701611939565b83820152815201920191611981565b9190826040910312610355576040516119e48161178e565b809280356001600160a01b0381168103610355578252602090810135910152565b80518210156116f65760209160051b010190565b91908110156116f657610120020190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610355570180359067ffffffffffffffff82116103555760200191606082023603831361035557565b929192611a8a82611840565b604094611a9a60405192836117ff565b8195848352602080930191606080960285019481861161035557925b858410611ac65750505050505050565b868483031261035557825190611adb826117c7565b611ae48561191c565b8252858501359067ffffffffffffffff8216820361035557828792838b950152611b0f868801611939565b86820152815201930192611ab6565b91908110156116f65760051b810135907ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee181360301821215610355570190565b3564ffffffffff811681036103555790565b91908110156116f657610140020190565b90604080516020907f23b872dd000000000000000000000000000000000000000000000000000000008282015233602482015260449030828201528660648201526064815260a081019080821067ffffffffffffffff83111761175f57611bea91855285611d86565b6001600160a01b0394858516958451917fdd62ed3e0000000000000000000000000000000000000000000000000000000083523060048401521690816024820152838184818a5afa908115611d6357908891600091611d32575b5010611c54575b50505050505050565b8351956000808589017f095ea7b3000000000000000000000000000000000000000000000000000000009a8b82528560248c0152868b0152858a52611c988a6117e3565b89519082855af190611ca8611e12565b82611cff575b5081611cf4575b50611c4b57611ce896611ce394519384015260248301526000818301528152611cdd816117e3565b82611d86565b611d86565b38808080808080611c4b565b90503b151538611cb5565b809192505190858215928315611d1a575b5050509038611cae565b611d2a9350820181019101611d6e565b388581611d10565b809250858092503d8311611d5c575b611d4b81836117ff565b810103126103555787905138611c44565b503d611d41565b85513d6000823e3d90fd5b90816020910312610355575180151581036103555790565b6000806001600160a01b03611db093169360208151910182865af1611da9611e12565b9083611e70565b8051908115159182611df7575b5050611dc65750565b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b611e0a9250602080918301019101611d6e565b153880611dbd565b3d15611e6b573d9067ffffffffffffffff821161175f5760405191611e5f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846117ff565b82523d6000602084013e565b606090565b90611eaf5750805115611e8557805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580611efa575b611ec0575090565b6024906001600160a01b03604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15611eb856fea164736f6c6343000817000a"; bytes public constant BYTECODE_MERKLE_LOCKUP_FACTORY = - hex"60808060405234610016576144fb908161001c8239f35b600080fdfe608060405260043610156200001357600080fd5b60003560e01c806324496a1514620003fc576360d18fed146200003557600080fd5b34620003f75760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003f75760043567ffffffffffffffff8111620003f757620000899036906004016200097d565b73ffffffffffffffffffffffffffffffffffffffff602435168060243503620003f75760407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc360112620003f757604051620000e581620008bf565b64ffffffffff926044358481168103620003f75782526064359384168403620003f75760209384830152805184820151620001386200014760408501516040519283918a80840152604083019062000a91565b03601f198101835282620008dc565b6200018260608501516200017c89604051836200016e829551809285808601910162000a6c565b8101038084520182620008dc565b62000ab8565b60808501519260a086015160c0870151151560e088015115159160405196620001c18d89018c6020908164ffffffffff91828151168552015116910152565b6040885287606081011067ffffffffffffffff60608a011117620003c8578c889760608901604052608089019a7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009788809260601b168d5260601b1660948a01528051809260a88b01920191620002389262000a6c565b87019560a887015260c886015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660e885015260f81b60ed84015260f81b60ee83015260243560601b1660ef8201528151906101038101828a850191620002a39262000a6c565b010360838101606083015260a3016060820190620002c191620008dc565b60600151902060405161180c80820182811067ffffffffffffffff821117620003c857829162000c8a83396080815262000326604062000305608084018862000b4c565b92898b82015201876020908164ffffffffff91828151168552015116910152565b03906000f5928315620003bc5760a07f3ce4d6bb8b94ee36e2248c8057e53b793a45b37e4d58038ec3b5dc21c56e925491620003a373ffffffffffffffffffffffffffffffffffffffff6200037f971696879562000bdb565b95604051928352888301906020908164ffffffffff91828151168552015116910152565b608435606082015260a4356080820152a3604051908152f35b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b34620003f75760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003f75760043567ffffffffffffffff8111620003f757620004509036906004016200097d565b73ffffffffffffffffffffffffffffffffffffffff6024351660243503620003f75760443567ffffffffffffffff8111620003f75736602382011215620003f757806004013567ffffffffffffffff8111620003c85760059060405192620004bf60208360051b0185620008dc565b8184526024602085019260061b82010190368211620003f757602401915b8183106200086b5750505060009082516000915b818310620007d657505050670de0b6b3a76400008103620007a55750620005426200068b60a38451620005d16020870151620005516040890151604051978891602080840152604083019062000a91565b03601f198101885287620008dc565b6200057960608901516200017c6020604051836200016e829551809285808601910162000a6c565b90608089015160a08a01517fffffffffff00000000000000000000000000000000000000000000000000000060c08c015115159160e08d0151151593620005e08d604051998a91602080840152604083019062000afa565b03601f1981018a5289620008dc565b604862000634604051809e819c7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009a8b809260601b16602085015260601b1660348301526020815194859301910162000a6c565b8901966048880152606887015260d81b16608885015260f81b608d84015260f81b608e83015260243560601b16608f8201526200067b825180936020878501910162000a6c565b01036083810184520182620008dc565b602081519101206040516120598082019082821067ffffffffffffffff831117620003c8578291620006fe9162002496843960608152620006d0606082018862000b4c565b9073ffffffffffffffffffffffffffffffffffffffff60243516602082015260408183039101528562000afa565b03906000f5908115620003bc576020927f431b4603d07471c22cc6557755bfeb55c0f0c1163d5df05ee2b54701ab6674ab6200078a73ffffffffffffffffffffffffffffffffffffffff62000757951694859362000bdb565b9360405191829173ffffffffffffffffffffffffffffffffffffffff602435168352608089840152608083019062000afa565b606435604083015260843560608301520390a3604051908152f35b602490604051907f5484abf20000000000000000000000000000000000000000000000000000000082526004820152fd5b90919284518410156200083c5767ffffffffffffffff602085841b87010151511681018091116200080d57926001019190620004f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b604083360312620003f757604051906200088582620008bf565b83359067ffffffffffffffff82168203620003f7578260209260409452620008af8387016200095c565b83820152815201920191620004dd565b6040810190811067ffffffffffffffff821117620003c857604052565b90601f601f19910116810190811067ffffffffffffffff821117620003c857604052565b81601f82011215620003f75780359067ffffffffffffffff8211620003c85760405192620009396020601f19601f8601160185620008dc565b82845260208383010111620003f757816000926020809301838601378301015290565b359064ffffffffff82168203620003f757565b35908115158203620003f757565b919091610100908181850312620003f75760405191820167ffffffffffffffff9083811082821117620003c8576040528294823573ffffffffffffffffffffffffffffffffffffffff908181168103620003f757855260208401359081168103620003f75760208501526040830135828111620003f7578162000a0291850162000900565b60408501526060830135918211620003f7578262000a2b60e0949262000a679486940162000900565b60608601526080810135608086015262000a4860a082016200095c565b60a086015262000a5b60c082016200096f565b60c0860152016200096f565b910152565b60005b83811062000a805750506000910152565b818101518382015260200162000a6f565b90601f19601f60209362000ab18151809281875287808801910162000a6c565b0116010190565b60208151910151906020811062000acd575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b90815180825260208080930193019160005b82811062000b1b575050505090565b8351805167ffffffffffffffff16865282015164ffffffffff16858301526040909401939281019260010162000b0c565b9060e08062000ba962000b9661010073ffffffffffffffffffffffffffffffffffffffff808851168752602088015116602087015260408701519080604088015286019062000a91565b6060860151858203606087015262000a91565b936080810151608085015264ffffffffff60a08201511660a085015260c0810151151560c08501520151151591015290565b60c0604051809273ffffffffffffffffffffffffffffffffffffffff808251168352602082015116602083015260e0601f604083015162000c2781518092602060408901910162000a6c565b601f199182910116840190601f606085015162000c4f81518092602060408801910162000a6c565b011601916080810151604084015264ffffffffff60a082015116606084015284810151151560808401520151151560a0820152030190209056fe6101608060405234620005b4576200180c8038038091620000218285620005d5565b83398101908082039160808312620005b45781516001600160401b038111620005b45782019261010084830312620005b4576040519361010085016001600160401b038111868210176200059e5760405280516001600160a01b0381168103620005b45785526020810151926001600160a01b0384168403620005b4576020860193845260408201516001600160401b038111620005b45781620000c79184016200063a565b60408701908152606083015190916001600160401b038211620005b457620000f19184016200063a565b6060870152608082015195608081019687526200011160a0840162000687565b9660a082019788526200013c60e06200012d60c087016200069a565b9560c08501968752016200069a565b60e083019081526020880151959093906001600160a01b0387168703620005b457604090603f190112620005b45760408051989089016001600160401b0381118a8210176200059e57620001a7916060916040526200019e6040820162000687565b8b520162000687565b9460208901958652606084015151602081116200057f57508351600080546001600160a01b0319166001600160a01b0392831617815598511660805251151560a052975164ffffffffff90811660c052975180516001600160401b0381116200056b5760019182548381811c9116801562000560575b60208210146200054c57601f8111620004ff575b50602090601f83116001146200049357606095949392918a918362000487575b5050600019600383901b1c191690821b1790555b5160e052015160405162000299602082816200028b818301968781519384920162000615565b8101038084520182620005d5565b519051906020811062000474575b50610100525115159461012095865261014094838652511669ffffffffff0000000000600354925160281b169160018060501b031916171760035560018060a01b03608051166040519160208301848063095ea7b360e01b9283815260018060a01b03851660248801526000196044880152604487526200032887620005b9565b86519082875af162000339620006a8565b8162000433575b508062000428575b15620003dc575b60405161104290878983620007ca8439608051838181610470015281816107440152610c36015260a05183818161076b0152610b5c015260c05183818161015d01528181610aa801528181610d8f0152610f60015260e0518381816102e2015261066201526101005183610e250152518281816107930152610b1f0152518181816101ae01526109060152f35b6200041d94620004179260405192602084015260018060a01b031660248301526044820152604481526200041081620005b9565b82620006dd565b620006dd565b38808080806200034f565b50823b151562000348565b80518015925082156200044a575b50503862000340565b8192509060209181010312620004705760206200046891016200069a565b388062000441565b8580fd5b6000199060200360031b1b1638620002a7565b01519050388062000251565b838a5260208a209190601f1984168b5b818110620004e857509185949291836060999897959310620004ce575b505050811b01905562000265565b015160001960f88460031b161c19169055388080620004c0565b8284015185559386019360209384019301620004a3565b838a5260208a20601f840160051c8101916020851062000541575b601f0160051c019084905b8281106200053557505062000231565b8b815501849062000525565b90915081906200051a565b634e487b7160e01b8a52602260045260248afd5b90607f16906200021d565b634e487b7160e01b88526041600452602488fd5b6044906040519063a52d539b60e01b8252600482015260206024820152fd5b634e487b7160e01b600052604160045260246000fd5b600080fd5b608081019081106001600160401b038211176200059e57604052565b601f909101601f19168101906001600160401b038211908210176200059e57604052565b6001600160401b0381116200059e57601f01601f191660200190565b60005b838110620006295750506000910152565b818101518382015260200162000618565b81601f82011215620005b45780516200065381620005f9565b92620006636040519485620005d5565b81845260208284010111620005b45762000684916020808501910162000615565b90565b519064ffffffffff82168203620005b457565b51908115158203620005b457565b3d15620006d8573d90620006bc82620005f9565b91620006cc6040519384620005d5565b82523d6000602084013e565b606090565b6000806200070a9260018060a01b03169360208151910182865af162000702620006a8565b908362000761565b80519081151591826200073a575b5050620007225750565b60249060405190635274afe760e01b82526004820152fd5b8192509060209181010312620005b45760206200075891016200069a565b15388062000718565b906200078a57508051156200077857805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580620007bf575b6200079d575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156200079456fe608080604052600436101561001357600080fd5b60003560e01c90816306fdde0314610e0e575080631686c90914610b8157806316c3549d14610b445780631bfd681414610b075780633bfe03a814610ad85780633f31ae3f146104945780634800d97f1461044357806349fc73dd1461030557806351e75e8b146102ca57806375829def146101ed57806390e64d13146101d25780639e93e57714610181578063bb4b57341461013f578063ce516507146100fd5763f851a440146100c457600080fd5b346100f85760006003193601126100f857602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b600080fd5b346100f85760206003193601126100f857602061013560043560ff6001918060081c6000526002602052161b60406000205416151590565b6040519015158152f35b346100f85760006003193601126100f857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f85760006003193601126100f857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f85760006003193601126100f8576020610135610f58565b346100f85760206003193601126100f857610206610ebc565b60005473ffffffffffffffffffffffffffffffffffffffff8082169233840361027d577fffffffffffffffffffffffff00000000000000000000000000000000000000009350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040517fc6cce6a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152336024820152604490fd5b346100f85760006003193601126100f85760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100f85760006003193601126100f85760405160009060018054908160011c9060018316928315610439575b602093848410811461040a578386529081156103cc5750600114610371575b61036d8461036181880382610f17565b60405191829182610e56565b0390f35b600160009081529294507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8284106103b9575050508161036d936103619282010193610351565b805485850187015292850192810161039d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016858501525050151560051b82010191506103618161036d610351565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691610332565b346100f85760006003193601126100f857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f85760806003193601126100f85760243573ffffffffffffffffffffffffffffffffffffffff811681036100f857604435906fffffffffffffffffffffffffffffffff821682036100f85767ffffffffffffffff606435116100f8573660236064350112156100f85767ffffffffffffffff60643560040135116100f8573660246064356004013560051b6064350101116100f8576040516020810190600435825273ffffffffffffffffffffffffffffffffffffffff831660408201526fffffffffffffffffffffffffffffffff841660608201526060815261057a81610efb565b519020604051602081019182526020815261059481610edf565b519020916105a0610f58565b610a7a576105c960043560ff6001918060081c6000526002602052161b60406000205416151590565b610a4857604051926105e760206064356004013560051b0185610f17565b60643560048101358552602401602085015b60246064356004013560051b60643501018210610a38575050906000915b845183101561065e5760208360051b860101519081811060001461064b57600052602052600160406000205b920191610617565b9060005260205260016040600020610643565b83907f000000000000000000000000000000000000000000000000000000000000000003610a0e5760043560081c60005260026020526040600020600160ff600435161b815417905573ffffffffffffffffffffffffffffffffffffffff60005416906040516106cd81610edf565b600081526000602082015260405192610100840184811067ffffffffffffffff8211176109df57604052835273ffffffffffffffffffffffffffffffffffffffff821660208401526fffffffffffffffffffffffffffffffff8416604084015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660608401527f0000000000000000000000000000000000000000000000000000000000000000151560808401527f0000000000000000000000000000000000000000000000000000000000000000151560a08401526040516107c581610edf565b64ffffffffff600354818116835260281c16602082015260c084015260e0830152602060e0604051937fab167ccc00000000000000000000000000000000000000000000000000000000855273ffffffffffffffffffffffffffffffffffffffff815116600486015273ffffffffffffffffffffffffffffffffffffffff838201511660248601526fffffffffffffffffffffffffffffffff604082015116604486015273ffffffffffffffffffffffffffffffffffffffff606082015116606486015260808101511515608486015260a0810151151560a486015264ffffffffff8360c08301518281511660c489015201511660e4860152015173ffffffffffffffffffffffffffffffffffffffff815116610104850152015161012483015260208261014481600073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af19182156109d35760009261099e575b506020927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d604073ffffffffffffffffffffffffffffffffffffffff85946fffffffffffffffffffffffffffffffff835195600435875216888601521692a3604051908152f35b91506020823d6020116109cb575b816109b960209383610f17565b810103126100f8579051906020610937565b3d91506109ac565b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60046040517f0fa7d73c000000000000000000000000000000000000000000000000000000008152fd5b81358152602091820191016105f9565b60246040517f712b37a30000000000000000000000000000000000000000000000000000000081526004356004820152fd5b6040517f442b18410000000000000000000000000000000000000000000000000000000081524260048201527f000000000000000000000000000000000000000000000000000000000000000064ffffffffff166024820152604490fd5b346100f85760006003193601126100f857604060035464ffffffffff825191818116835260281c166020820152f35b346100f85760006003193601126100f85760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f85760006003193601126100f85760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f85760406003193601126100f857610b9a610ebc565b6024356fffffffffffffffffffffffffffffffff81168091036100f85773ffffffffffffffffffffffffffffffffffffffff8060005416338103610dbf5750610be1610f58565b15610d61576040519060209160008083858401977fa9059cbb000000000000000000000000000000000000000000000000000000008952169687602485015286604485015260448452610c3384610efb565b847f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610d55573d67ffffffffffffffff81116109df57610cbc9160405191610cac877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610f17565b82523d60008784013e5b83610f95565b8051848115159182610d34575b50509050610d035750907f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f916000541692604051908152a3005b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b83809293500103126100f8578301518015908115036100f857808488610cc9565b610cbc90606090610cb6565b6040517fe13612970000000000000000000000000000000000000000000000000000000081524260048201527f000000000000000000000000000000000000000000000000000000000000000064ffffffffff166024820152604490fd5b6040517fc6cce6a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b346100f85760006003193601126100f85761036d907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261036181610edf565b60208082528251818301819052939260005b858110610ea8575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201610e68565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036100f857565b6040810190811067ffffffffffffffff8211176109df57604052565b6080810190811067ffffffffffffffff8211176109df57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176109df57604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610f8d575090565b905042101590565b90610fd45750805115610faa57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b8151158061102c575b610fe5575090565b60249073ffffffffffffffffffffffffffffffffffffffff604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15610fdd56fea164736f6c6343000817000a6101608060405234620006f7576200205990813803809262000022828462000743565b82396060818381010312620006f75780516001600160401b038111620006f7578101916101009283818385010312620006f757604051908482016001600160401b03811183821017620007115760405280516001600160a01b0381168103620006f757825260208101516001600160a01b0381168103620006f757602083015260408101516001600160401b038111620006f757620000c790848601908301620007a8565b604083015260608101516001600160401b038111620006f7576200013491620000f860e092868801908301620007a8565b6060850152608081015160808501526200011560a08201620007f5565b60a08501526200012860c0820162000808565b60c08501520162000808565b60e08201526020830151916001600160a01b0383168303620006f7576040840151906001600160401b038211620006f757808501601f838701011215620006f75784820151906001600160401b0382116200071157604051956200019f60208460051b018862000743565b828752602087019382820160208560061b838501010111620006f75793602085830101945b60208560061b828501010186106200069157505050505050606081015151602081116200067257508051600080546001600160a01b0319166001600160a01b03928316178155602083015190911660805260c080830151151560a090815283015164ffffffffff16905260408201518051919290916001600160401b0381116200065e5760019283548481811c9116801562000653575b60208210146200063f57601f8111620005f2575b50602090601f8311600114620005885760e09392918691836200057c575b5050600019600383901b1c191690841b1783555b608081015182526060810151604051620002db60208281620002cd818301968781519384920162000783565b810103808452018262000743565b519051906020811062000569575b5087520151151593610120948552610140938452805190835b828110620004a7575050505060018060a01b036080511660018060a01b03835116906040519160208301848063095ea7b360e01b92838152846024880152600019604488015260448752620003578762000727565b86519082875af16200036862000816565b8162000466575b50806200045b575b1562000417575b6040516117219087898b846200093885396080518481816104e2015281816107fe0152818161092001526110e2015260a0518481816109470152611008015260c05184818161022001528181610f830152818161123b015261140c015260e05184818161035401526106b2015251836112d101525182818161096f0152610fcb01525181818161012a015281816107850152610ad90152f35b62000450946200044a926040519260208401526024830152604482015260448152620004438162000727565b826200084b565b6200084b565b38808080806200037e565b50823b151562000377565b80518015925082156200047d575b5050386200036f565b8192509060209181010312620004a35760206200049b910162000808565b388062000474565b8580fd5b8151811015620005555760208160051b8301015160038054906801000000000000000082101562000541578682018082558210156200052d578752602080882083519201805493909101516cffffffffff000000000000000060409190911b166001600160401b039092166001600160681b031990931692909217179055830162000302565b634e487b7160e01b88526032600452602488fd5b634e487b7160e01b88526041600452602488fd5b634e487b7160e01b85526032600452602485fd5b6000199060200360031b1b1638620002e9565b0151905038806200028d565b92918491601f198216908388526020882091885b818110620005d95750958360e09710620005bf575b505050811b018355620002a1565b015160001960f88460031b161c19169055388080620005b1565b828801518455889590930192602092830192016200059c565b84865260208620601f840160051c8101916020851062000634575b601f0160051c019085905b828110620006285750506200026f565b87815501859062000618565b90915081906200060d565b634e487b7160e01b86526022600452602486fd5b90607f16906200025b565b634e487b7160e01b84526041600452602484fd5b6044906040519063a52d539b60e01b8252600482015260206024820152fd5b6040868585010312620006f757604080519081016001600160401b03811182821017620006fc5760405286516001600160401b0381168103620006f75760209382859260409452620006e5838b01620007f5565b838201528152019601959150620001c4565b600080fd5b60246000634e487b7160e01b81526041600452fd5b634e487b7160e01b600052604160045260246000fd5b608081019081106001600160401b038211176200071157604052565b601f909101601f19168101906001600160401b038211908210176200071157604052565b6001600160401b0381116200071157601f01601f191660200190565b60005b838110620007975750506000910152565b818101518382015260200162000786565b81601f82011215620006f7578051620007c18162000767565b92620007d1604051948562000743565b81845260208284010111620006f757620007f2916020808501910162000783565b90565b519064ffffffffff82168203620006f757565b51908115158203620006f757565b3d1562000846573d906200082a8262000767565b916200083a604051938462000743565b82523d6000602084013e565b606090565b600080620008789260018060a01b03169360208151910182865af16200087062000816565b9083620008cf565b8051908115159182620008a8575b5050620008905750565b60249060405190635274afe760e01b82526004820152fd5b8192509060209181010312620006f7576020620008c6910162000808565b15388062000886565b90620008f85750805115620008e657805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806200092d575b6200090b575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156200090256fe608080604052600436101561001357600080fd5b60003560e01c90816306fdde03146112ba575080631686c9091461102d57806316c3549d14610ff05780631bfd681414610fb35780633f31ae3f146105065780634800d97f146104b557806349fc73dd1461037757806351e75e8b1461033c57806375829def1461025f57806390e64d1314610244578063bb4b573414610202578063bf4ed03f14610190578063ce5165071461014e578063da792468146100fd5763f851a440146100c457600080fd5b346100f85760006003193601126100f857602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b600080fd5b346100f85760006003193601126100f857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f85760206003193601126100f857602061018660043560ff6001918060081c6000526002602052161b60406000205416151590565b6040519015158152f35b346100f85760006003193601126100f8576101a9611459565b6040516020918282018383528151809152836040840192019360005b8281106101d25784840385f35b8551805167ffffffffffffffff16855282015164ffffffffff1684830152948101946040909301926001016101c5565b346100f85760006003193601126100f857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f85760006003193601126100f8576020610186611404565b346100f85760206003193601126100f857610278611368565b60005473ffffffffffffffffffffffffffffffffffffffff808216923384036102ef577fffffffffffffffffffffffff00000000000000000000000000000000000000009350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040517fc6cce6a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152336024820152604490fd5b346100f85760006003193601126100f85760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100f85760006003193601126100f85760405160009060018054908160011c90600183169283156104ab575b602093848410811461047c5783865290811561043e57506001146103e3575b6103df846103d3818803826113c3565b60405191829182611302565b0390f35b600160009081529294507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b82841061042b57505050816103df936103d392820101936103c3565b805485850187015292850192810161040f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016858501525050151560051b82010191506103d3816103df6103c3565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f16916103a4565b346100f85760006003193601126100f857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f85760806003193601126100f85760243573ffffffffffffffffffffffffffffffffffffffff811681036100f857604435906fffffffffffffffffffffffffffffffff821682036100f8576064359167ffffffffffffffff83116100f857366023840112156100f85782600401359267ffffffffffffffff84116100f85760248460051b8201013681116100f8576040516020810190600435825273ffffffffffffffffffffffffffffffffffffffff861660408201526fffffffffffffffffffffffffffffffff85166060820152606081526105e5816113a7565b51902060405160208101918252602081526105ff8161138b565b5190209161060b611404565b610f555761063460043560ff6001918060081c6000526002602052161b60406000205416151590565b610f235761064186611441565b9561064f60405197886113c3565b8652602401602086015b828210610f1357505050906000915b84518310156106ae5761067b83866114f4565b51908181101561069b57600052602052600160406000205b920191610668565b9060005260205260016040600020610693565b83907f000000000000000000000000000000000000000000000000000000000000000003610ee9576106de611459565b9060008251906106ed82611441565b936106fb60405195866113c3565b8285527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe061072884611441565b0160005b818110610ec45750506000905b838210610e205750506040517f5fe3b56700000000000000000000000000000000000000000000000000000000815260208160048173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165afa908115610ba657600091610dd0575b50602073ffffffffffffffffffffffffffffffffffffffff916024604051809481937fdcf844a7000000000000000000000000000000000000000000000000000000008352817f0000000000000000000000000000000000000000000000000000000000000000166004840152165afa908115610ba657600091610d9e575b5080610cfd575b50806fffffffffffffffffffffffffffffffff861603610c1f575b505060043560081c60005260026020526040600020600160ff600435161b815417905573ffffffffffffffffffffffffffffffffffffffff6000541691604051906108a18261138b565b6000825260006020830152604051938461010081011067ffffffffffffffff61010087011117610bf0576101008501604052845273ffffffffffffffffffffffffffffffffffffffff831660208501526fffffffffffffffffffffffffffffffff8516604085015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660608501527f0000000000000000000000000000000000000000000000000000000000000000151560808501527f0000000000000000000000000000000000000000000000000000000000000000151560a085015260c084015260e0830152604051917f897f362b0000000000000000000000000000000000000000000000000000000083526020600484015282610144810173ffffffffffffffffffffffffffffffffffffffff835116602483015273ffffffffffffffffffffffffffffffffffffffff60208401511660448301526fffffffffffffffffffffffffffffffff604084015116606483015273ffffffffffffffffffffffffffffffffffffffff60608401511660848301526080830151151560a483015260a0830151151560c483015260c08301519061012060e484015281518091526020610164840192019060005b818110610bb2575050508190602060e08195015173ffffffffffffffffffffffffffffffffffffffff81511661010485015201516101248301520381600073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1918215610ba657600092610b71575b506020927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d604073ffffffffffffffffffffffffffffffffffffffff85946fffffffffffffffffffffffffffffffff835195600435875216888601521692a3604051908152f35b91506020823d602011610b9e575b81610b8c602093836113c3565b810103126100f8579051906020610b0a565b3d9150610b7f565b6040513d6000823e3d90fd5b825180516fffffffffffffffffffffffffffffffff16855260209081015164ffffffffff168186015288955060409094019390920191600101610a84565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b610c4d90610c47610c416fffffffffffffffffffffffffffffffff8816611559565b91611559565b90611537565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111610cce57610c8290846114f4565b51906fffffffffffffffffffffffffffffffff808351169116016fffffffffffffffffffffffffffffffff8111610cce576fffffffffffffffffffffffffffffffff1690528380610857565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b610d1c610d21916fffffffffffffffffffffffffffffffff88166115a7565b611559565b827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff810111610cce576fffffffffffffffffffffffffffffffff610d95610d8a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8601886114f4565b519282845116611537565b1690528561083c565b90506020813d602011610dc8575b81610db9602093836113c3565b810103126100f8575186610835565b3d9150610dac565b90506020813d602011610e18575b81610deb602093836113c3565b810103126100f8575173ffffffffffffffffffffffffffffffffffffffff811681036100f85760206107b6565b3d9150610dde565b9091610e5367ffffffffffffffff610e3885856114f4565b5151166fffffffffffffffffffffffffffffffff89166115a7565b928382018211610cce57610e6b846001930194611559565b64ffffffffff6020610e7d84876114f4565b510151166fffffffffffffffffffffffffffffffff60405192610e9f8461138b565b1682526020820152610eb182896114f4565b52610ebc81886114f4565b500190610739565b602090604051610ed38161138b565b6000815260008382015282828a0101520161072c565b60046040517f0fa7d73c000000000000000000000000000000000000000000000000000000008152fd5b8135815260209182019101610659565b60246040517f712b37a30000000000000000000000000000000000000000000000000000000081526004356004820152fd5b6040517f442b18410000000000000000000000000000000000000000000000000000000081524260048201527f000000000000000000000000000000000000000000000000000000000000000064ffffffffff166024820152604490fd5b346100f85760006003193601126100f85760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f85760006003193601126100f85760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f85760406003193601126100f857611046611368565b6024356fffffffffffffffffffffffffffffffff81168091036100f85773ffffffffffffffffffffffffffffffffffffffff806000541633810361126b575061108d611404565b1561120d576040519060209160008083858401977fa9059cbb0000000000000000000000000000000000000000000000000000000089521696876024850152866044850152604484526110df846113a7565b847f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15611201573d67ffffffffffffffff8111610bf0576111689160405191611158877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601846113c3565b82523d60008784013e5b83611674565b80518481151591826111e0575b505090506111af5750907f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f916000541692604051908152a3005b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b83809293500103126100f8578301518015908115036100f857808488611175565b61116890606090611162565b6040517fe13612970000000000000000000000000000000000000000000000000000000081524260048201527f000000000000000000000000000000000000000000000000000000000000000064ffffffffff166024820152604490fd5b6040517fc6cce6a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b346100f85760006003193601126100f8576103df907f00000000000000000000000000000000000000000000000000000000000000006020820152602081526103d38161138b565b60208082528251818301819052939260005b858110611354575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201611314565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036100f857565b6040810190811067ffffffffffffffff821117610bf057604052565b6080810190811067ffffffffffffffff821117610bf057604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610bf057604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081611439575090565b905042101590565b67ffffffffffffffff8111610bf05760051b60200190565b6003549061146682611441565b91604061147660405194856113c3565b8184528360208091019160036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000935b8585106114ba57505050505050565b600184819284516114ca8161138b565b64ffffffffff875467ffffffffffffffff81168352871c16838201528152019301940193916114ab565b80518210156115085760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6fffffffffffffffffffffffffffffffff9182169082160391908211610cce57565b6fffffffffffffffffffffffffffffffff90818111611576571690565b602490604051907f4916adce0000000000000000000000000000000000000000000000000000000082526004820152fd5b9190917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8382098382029182808310920391808303921461166357670de0b6b3a7640000908183101561162c57947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b906116b3575080511561168957805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b8151158061170b575b6116c4575090565b60249073ffffffffffffffffffffffffffffffffffffffff604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b156116bc56fea164736f6c6343000817000aa164736f6c6343000817000a"; + hex"6080806040523461001657614245908161001c8239f35b600080fdfe608060405260043610156200001357600080fd5b60003560e01c806324496a1514620003fc576360d18fed146200003557600080fd5b34620003f75760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003f75760043567ffffffffffffffff8111620003f757620000899036906004016200097d565b73ffffffffffffffffffffffffffffffffffffffff602435168060243503620003f75760407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbc360112620003f757604051620000e581620008bf565b64ffffffffff926044358481168103620003f75782526064359384168403620003f75760209384830152805184820151620001386200014760408501516040519283918a80840152604083019062000a91565b03601f198101835282620008dc565b6200018260608501516200017c89604051836200016e829551809285808601910162000a6c565b8101038084520182620008dc565b62000ab8565b60808501519260a086015160c0870151151560e088015115159160405196620001c18d89018c6020908164ffffffffff91828151168552015116910152565b6040885287606081011067ffffffffffffffff60608a011117620003c8578c889760608901604052608089019a7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009788809260601b168d5260601b1660948a01528051809260a88b01920191620002389262000a6c565b87019560a887015260c886015260d81b7fffffffffff0000000000000000000000000000000000000000000000000000001660e885015260f81b60ed84015260f81b60ee83015260243560601b1660ef8201528151906101038101828a850191620002a39262000a6c565b010360838101606083015260a3016060820190620002c191620008dc565b60600151902060405161180c80820182811067ffffffffffffffff821117620003c857829162000c8a83396080815262000326604062000305608084018862000b4c565b92898b82015201876020908164ffffffffff91828151168552015116910152565b03906000f5928315620003bc5760a07f3ce4d6bb8b94ee36e2248c8057e53b793a45b37e4d58038ec3b5dc21c56e925491620003a373ffffffffffffffffffffffffffffffffffffffff6200037f971696879562000bdb565b95604051928352888301906020908164ffffffffff91828151168552015116910152565b608435606082015260a4356080820152a3604051908152f35b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600080fd5b34620003f75760a07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112620003f75760043567ffffffffffffffff8111620003f757620004509036906004016200097d565b73ffffffffffffffffffffffffffffffffffffffff6024351660243503620003f75760443567ffffffffffffffff8111620003f75736602382011215620003f757806004013567ffffffffffffffff8111620003c85760059060405192620004bf60208360051b0185620008dc565b8184526024602085019260061b82010190368211620003f757602401915b8183106200086b5750505060009082516000915b818310620007d657505050670de0b6b3a76400008103620007a55750620005426200068b60a38451620005d16020870151620005516040890151604051978891602080840152604083019062000a91565b03601f198101885287620008dc565b6200057960608901516200017c6020604051836200016e829551809285808601910162000a6c565b90608089015160a08a01517fffffffffff00000000000000000000000000000000000000000000000000000060c08c015115159160e08d0151151593620005e08d604051998a91602080840152604083019062000afa565b03601f1981018a5289620008dc565b604862000634604051809e819c7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000009a8b809260601b16602085015260601b1660348301526020815194859301910162000a6c565b8901966048880152606887015260d81b16608885015260f81b608d84015260f81b608e83015260243560601b16608f8201526200067b825180936020878501910162000a6c565b01036083810184520182620008dc565b60208151910120604051611da38082019082821067ffffffffffffffff831117620003c8578291620006fe9162002496843960608152620006d0606082018862000b4c565b9073ffffffffffffffffffffffffffffffffffffffff60243516602082015260408183039101528562000afa565b03906000f5908115620003bc576020927f431b4603d07471c22cc6557755bfeb55c0f0c1163d5df05ee2b54701ab6674ab6200078a73ffffffffffffffffffffffffffffffffffffffff62000757951694859362000bdb565b9360405191829173ffffffffffffffffffffffffffffffffffffffff602435168352608089840152608083019062000afa565b606435604083015260843560608301520390a3604051908152f35b602490604051907ff1cd938a0000000000000000000000000000000000000000000000000000000082526004820152fd5b90919284518410156200083c5767ffffffffffffffff602085841b87010151511681018091116200080d57926001019190620004f1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b604083360312620003f757604051906200088582620008bf565b83359067ffffffffffffffff82168203620003f7578260209260409452620008af8387016200095c565b83820152815201920191620004dd565b6040810190811067ffffffffffffffff821117620003c857604052565b90601f601f19910116810190811067ffffffffffffffff821117620003c857604052565b81601f82011215620003f75780359067ffffffffffffffff8211620003c85760405192620009396020601f19601f8601160185620008dc565b82845260208383010111620003f757816000926020809301838601378301015290565b359064ffffffffff82168203620003f757565b35908115158203620003f757565b919091610100908181850312620003f75760405191820167ffffffffffffffff9083811082821117620003c8576040528294823573ffffffffffffffffffffffffffffffffffffffff908181168103620003f757855260208401359081168103620003f75760208501526040830135828111620003f7578162000a0291850162000900565b60408501526060830135918211620003f7578262000a2b60e0949262000a679486940162000900565b60608601526080810135608086015262000a4860a082016200095c565b60a086015262000a5b60c082016200096f565b60c0860152016200096f565b910152565b60005b83811062000a805750506000910152565b818101518382015260200162000a6f565b90601f19601f60209362000ab18151809281875287808801910162000a6c565b0116010190565b60208151910151906020811062000acd575090565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060200360031b1b1690565b90815180825260208080930193019160005b82811062000b1b575050505090565b8351805167ffffffffffffffff16865282015164ffffffffff16858301526040909401939281019260010162000b0c565b9060e08062000ba962000b9661010073ffffffffffffffffffffffffffffffffffffffff808851168752602088015116602087015260408701519080604088015286019062000a91565b6060860151858203606087015262000a91565b936080810151608085015264ffffffffff60a08201511660a085015260c0810151151560c08501520151151591015290565b60c0604051809273ffffffffffffffffffffffffffffffffffffffff808251168352602082015116602083015260e0601f604083015162000c2781518092602060408901910162000a6c565b601f199182910116840190601f606085015162000c4f81518092602060408801910162000a6c565b011601916080810151604084015264ffffffffff60a082015116606084015284810151151560808401520151151560a0820152030190209056fe6101608060405234620005b4576200180c8038038091620000218285620005d5565b83398101908082039160808312620005b45781516001600160401b038111620005b45782019261010084830312620005b4576040519361010085016001600160401b038111868210176200059e5760405280516001600160a01b0381168103620005b45785526020810151926001600160a01b0384168403620005b4576020860193845260408201516001600160401b038111620005b45781620000c79184016200063a565b60408701908152606083015190916001600160401b038211620005b457620000f19184016200063a565b6060870152608082015195608081019687526200011160a0840162000687565b9660a082019788526200013c60e06200012d60c087016200069a565b9560c08501968752016200069a565b60e083019081526020880151959093906001600160a01b0387168703620005b457604090603f190112620005b45760408051989089016001600160401b0381118a8210176200059e57620001a7916060916040526200019e6040820162000687565b8b520162000687565b9460208901958652606084015151602081116200057f57508351600080546001600160a01b0319166001600160a01b0392831617815598511660805251151560a052975164ffffffffff90811660c052975180516001600160401b0381116200056b5760019182548381811c9116801562000560575b60208210146200054c57601f8111620004ff575b50602090601f83116001146200049357606095949392918a918362000487575b5050600019600383901b1c191690821b1790555b5160e052015160405162000299602082816200028b818301968781519384920162000615565b8101038084520182620005d5565b519051906020811062000474575b50610100525115159461012095865261014094838652511669ffffffffff0000000000600354925160281b169160018060501b031916171760035560018060a01b03608051166040519160208301848063095ea7b360e01b9283815260018060a01b03851660248801526000196044880152604487526200032887620005b9565b86519082875af162000339620006a8565b8162000433575b508062000428575b15620003dc575b60405161104290878983620007ca8439608051838181610470015281816107440152610c36015260a05183818161076b0152610b5c015260c05183818161015d01528181610aa801528181610d8f0152610f60015260e0518381816102e2015261066201526101005183610e250152518281816107930152610b1f0152518181816101ae01526109060152f35b6200041d94620004179260405192602084015260018060a01b031660248301526044820152604481526200041081620005b9565b82620006dd565b620006dd565b38808080806200034f565b50823b151562000348565b80518015925082156200044a575b50503862000340565b8192509060209181010312620004705760206200046891016200069a565b388062000441565b8580fd5b6000199060200360031b1b1638620002a7565b01519050388062000251565b838a5260208a209190601f1984168b5b818110620004e857509185949291836060999897959310620004ce575b505050811b01905562000265565b015160001960f88460031b161c19169055388080620004c0565b8284015185559386019360209384019301620004a3565b838a5260208a20601f840160051c8101916020851062000541575b601f0160051c019084905b8281106200053557505062000231565b8b815501849062000525565b90915081906200051a565b634e487b7160e01b8a52602260045260248afd5b90607f16906200021d565b634e487b7160e01b88526041600452602488fd5b6044906040519063a52d539b60e01b8252600482015260206024820152fd5b634e487b7160e01b600052604160045260246000fd5b600080fd5b608081019081106001600160401b038211176200059e57604052565b601f909101601f19168101906001600160401b038211908210176200059e57604052565b6001600160401b0381116200059e57601f01601f191660200190565b60005b838110620006295750506000910152565b818101518382015260200162000618565b81601f82011215620005b45780516200065381620005f9565b92620006636040519485620005d5565b81845260208284010111620005b45762000684916020808501910162000615565b90565b519064ffffffffff82168203620005b457565b51908115158203620005b457565b3d15620006d8573d90620006bc82620005f9565b91620006cc6040519384620005d5565b82523d6000602084013e565b606090565b6000806200070a9260018060a01b03169360208151910182865af162000702620006a8565b908362000761565b80519081151591826200073a575b5050620007225750565b60249060405190635274afe760e01b82526004820152fd5b8192509060209181010312620005b45760206200075891016200069a565b15388062000718565b906200078a57508051156200077857805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580620007bf575b6200079d575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b156200079456fe608080604052600436101561001357600080fd5b60003560e01c90816306fdde0314610e0e575080631686c90914610b8157806316c3549d14610b445780631bfd681414610b075780633bfe03a814610ad85780633f31ae3f146104945780634800d97f1461044357806349fc73dd1461030557806351e75e8b146102ca57806375829def146101ed57806390e64d13146101d25780639e93e57714610181578063bb4b57341461013f578063ce516507146100fd5763f851a440146100c457600080fd5b346100f85760006003193601126100f857602073ffffffffffffffffffffffffffffffffffffffff60005416604051908152f35b600080fd5b346100f85760206003193601126100f857602061013560043560ff6001918060081c6000526002602052161b60406000205416151590565b6040519015158152f35b346100f85760006003193601126100f857602060405164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f85760006003193601126100f857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f85760006003193601126100f8576020610135610f58565b346100f85760206003193601126100f857610206610ebc565b60005473ffffffffffffffffffffffffffffffffffffffff8082169233840361027d577fffffffffffffffffffffffff00000000000000000000000000000000000000009350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b6040517fc6cce6a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152336024820152604490fd5b346100f85760006003193601126100f85760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b346100f85760006003193601126100f85760405160009060018054908160011c9060018316928315610439575b602093848410811461040a578386529081156103cc5750600114610371575b61036d8461036181880382610f17565b60405191829182610e56565b0390f35b600160009081529294507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8284106103b9575050508161036d936103619282010193610351565b805485850187015292850192810161039d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016858501525050151560051b82010191506103618161036d610351565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f1691610332565b346100f85760006003193601126100f857602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346100f85760806003193601126100f85760243573ffffffffffffffffffffffffffffffffffffffff811681036100f857604435906fffffffffffffffffffffffffffffffff821682036100f85767ffffffffffffffff606435116100f8573660236064350112156100f85767ffffffffffffffff60643560040135116100f8573660246064356004013560051b6064350101116100f8576040516020810190600435825273ffffffffffffffffffffffffffffffffffffffff831660408201526fffffffffffffffffffffffffffffffff841660608201526060815261057a81610efb565b519020604051602081019182526020815261059481610edf565b519020916105a0610f58565b610a7a576105c960043560ff6001918060081c6000526002602052161b60406000205416151590565b610a4857604051926105e760206064356004013560051b0185610f17565b60643560048101358552602401602085015b60246064356004013560051b60643501018210610a38575050906000915b845183101561065e5760208360051b860101519081811060001461064b57600052602052600160406000205b920191610617565b9060005260205260016040600020610643565b83907f000000000000000000000000000000000000000000000000000000000000000003610a0e5760043560081c60005260026020526040600020600160ff600435161b815417905573ffffffffffffffffffffffffffffffffffffffff60005416906040516106cd81610edf565b600081526000602082015260405192610100840184811067ffffffffffffffff8211176109df57604052835273ffffffffffffffffffffffffffffffffffffffff821660208401526fffffffffffffffffffffffffffffffff8416604084015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660608401527f0000000000000000000000000000000000000000000000000000000000000000151560808401527f0000000000000000000000000000000000000000000000000000000000000000151560a08401526040516107c581610edf565b64ffffffffff600354818116835260281c16602082015260c084015260e0830152602060e0604051937fab167ccc00000000000000000000000000000000000000000000000000000000855273ffffffffffffffffffffffffffffffffffffffff815116600486015273ffffffffffffffffffffffffffffffffffffffff838201511660248601526fffffffffffffffffffffffffffffffff604082015116604486015273ffffffffffffffffffffffffffffffffffffffff606082015116606486015260808101511515608486015260a0810151151560a486015264ffffffffff8360c08301518281511660c489015201511660e4860152015173ffffffffffffffffffffffffffffffffffffffff815116610104850152015161012483015260208261014481600073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af19182156109d35760009261099e575b506020927f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d604073ffffffffffffffffffffffffffffffffffffffff85946fffffffffffffffffffffffffffffffff835195600435875216888601521692a3604051908152f35b91506020823d6020116109cb575b816109b960209383610f17565b810103126100f8579051906020610937565b3d91506109ac565b6040513d6000823e3d90fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60046040517f0fa7d73c000000000000000000000000000000000000000000000000000000008152fd5b81358152602091820191016105f9565b60246040517f712b37a30000000000000000000000000000000000000000000000000000000081526004356004820152fd5b6040517f442b18410000000000000000000000000000000000000000000000000000000081524260048201527f000000000000000000000000000000000000000000000000000000000000000064ffffffffff166024820152604490fd5b346100f85760006003193601126100f857604060035464ffffffffff825191818116835260281c166020820152f35b346100f85760006003193601126100f85760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f85760006003193601126100f85760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b346100f85760406003193601126100f857610b9a610ebc565b6024356fffffffffffffffffffffffffffffffff81168091036100f85773ffffffffffffffffffffffffffffffffffffffff8060005416338103610dbf5750610be1610f58565b15610d61576040519060209160008083858401977fa9059cbb000000000000000000000000000000000000000000000000000000008952169687602485015286604485015260448452610c3384610efb565b847f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610d55573d67ffffffffffffffff81116109df57610cbc9160405191610cac877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8401160184610f17565b82523d60008784013e5b83610f95565b8051848115159182610d34575b50509050610d035750907f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f916000541692604051908152a3005b602490604051907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b83809293500103126100f8578301518015908115036100f857808488610cc9565b610cbc90606090610cb6565b6040517fe13612970000000000000000000000000000000000000000000000000000000081524260048201527f000000000000000000000000000000000000000000000000000000000000000064ffffffffff166024820152604490fd5b6040517fc6cce6a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b346100f85760006003193601126100f85761036d907f000000000000000000000000000000000000000000000000000000000000000060208201526020815261036181610edf565b60208082528251818301819052939260005b858110610ea8575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b818101830151848201604001528201610e68565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036100f857565b6040810190811067ffffffffffffffff8211176109df57604052565b6080810190811067ffffffffffffffff8211176109df57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176109df57604052565b64ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168015159081610f8d575090565b905042101590565b90610fd45750805115610faa57805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b8151158061102c575b610fe5575090565b60249073ffffffffffffffffffffffffffffffffffffffff604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b15610fdd56fea164736f6c6343000817000a6101608060405234620006e95762001da390813803809262000022828462000735565b82396060818381010312620006e95780516001600160401b038111620006e9578101916101009283818385010312620006e957604051908482016001600160401b03811183821017620007035760405280516001600160a01b0381168103620006e957825260208101516001600160a01b0381168103620006e957602083015260408101516001600160401b038111620006e957620000c7908486019083016200079a565b604083015260608101516001600160401b038111620006e9576200013491620000f860e0928688019083016200079a565b6060850152608081015160808501526200011560a08201620007e7565b60a08501526200012860c08201620007fa565b60c085015201620007fa565b60e08201526020830151916001600160a01b0383168303620006e9576040840151906001600160401b038211620006e957808501601f838701011215620006e95784820151906001600160401b0382116200070357604051956200019f60208460051b018862000735565b828752602087019382820160208560061b838501010111620006e95793602085830101945b60208560061b828501010186106200068357505050505050606081015151602081116200066457508051600080546001600160a01b0319166001600160a01b03928316178155602083015190911660805260c080830151151560a090815283015164ffffffffff16905260408201518051919290916001600160401b038111620006505760019283548481811c9116801562000645575b60208210146200063157601f8111620005e4575b50602090601f83116001146200057a5760e09392918691836200056e575b5050600019600383901b1c191690841b1783555b608081015182526060810151604051620002db60208281620002cd818301968781519384920162000775565b810103808452018262000735565b51905190602081106200055b575b5087520151151593610120948552610140938452805190835b82811062000499575050505060018060a01b036080511660018060a01b03835116906040519160208301848063095ea7b360e01b92838152846024880152600019604488015260448752620003578762000719565b86519082875af16200036862000808565b8162000458575b50806200044d575b1562000409575b6040516114799087898b846200092a85396080518481816104f4015281816107e60152610e5f015260a05184818161080d0152610d84015260c05184818161022c01528181610cff01528181610fb40152611186015260e05184818161036601526106b00152518361104b0152518281816108350152610d4701525181818161012c01526109a00152f35b62000442946200043c926040519260208401526024830152604482015260448152620004358162000719565b826200083d565b6200083d565b38808080806200037e565b50823b151562000377565b80518015925082156200046f575b5050386200036f565b8192509060209181010312620004955760206200048d9101620007fa565b388062000466565b8580fd5b8151811015620005475760208160051b8301015160038054906801000000000000000082101562000533578682018082558210156200051f578752602080882083519201805493909101516cffffffffff000000000000000060409190911b166001600160401b039092166001600160681b031990931692909217179055830162000302565b634e487b7160e01b88526032600452602488fd5b634e487b7160e01b88526041600452602488fd5b634e487b7160e01b85526032600452602485fd5b6000199060200360031b1b1638620002e9565b0151905038806200028d565b92918491601f198216908388526020882091885b818110620005cb5750958360e09710620005b1575b505050811b018355620002a1565b015160001960f88460031b161c19169055388080620005a3565b828801518455889590930192602092830192016200058e565b84865260208620601f840160051c8101916020851062000626575b601f0160051c019085905b8281106200061a5750506200026f565b8781550185906200060a565b9091508190620005ff565b634e487b7160e01b86526022600452602486fd5b90607f16906200025b565b634e487b7160e01b84526041600452602484fd5b6044906040519063a52d539b60e01b8252600482015260206024820152fd5b6040868585010312620006e957604080519081016001600160401b03811182821017620006ee5760405286516001600160401b0381168103620006e95760209382859260409452620006d7838b01620007e7565b838201528152019601959150620001c4565b600080fd5b60246000634e487b7160e01b81526041600452fd5b634e487b7160e01b600052604160045260246000fd5b608081019081106001600160401b038211176200070357604052565b601f909101601f19168101906001600160401b038211908210176200070357604052565b6001600160401b0381116200070357601f01601f191660200190565b60005b838110620007895750506000910152565b818101518382015260200162000778565b81601f82011215620006e9578051620007b38162000759565b92620007c3604051948562000735565b81845260208284010111620006e957620007e4916020808501910162000775565b90565b519064ffffffffff82168203620006e957565b51908115158203620006e957565b3d1562000838573d906200081c8262000759565b916200082c604051938462000735565b82523d6000602084013e565b606090565b6000806200086a9260018060a01b03169360208151910182865af16200086262000808565b9083620008c1565b80519081151591826200089a575b5050620008825750565b60249060405190635274afe760e01b82526004820152fd5b8192509060209181010312620006e9576020620008b89101620007fa565b15388062000878565b90620008ea5750805115620008d857805190602001fd5b604051630a12f52160e11b8152600490fd5b815115806200091f575b620008fd575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15620008f456fe6080604090808252600436101561001557600080fd5b60003560e01c90816306fdde0314611032575080631686c90914610da957806316c3549d14610d6c5780631bfd681414610d2f5780633f31ae3f146105185780634800d97f146104c757806349fc73dd1461038957806351e75e8b1461034e57806375829def1461026d57806390e64d1314610250578063bb4b57341461020e578063bf4ed03f14610193578063ce51650714610150578063da792468146100ff5763f851a440146100c657600080fd5b346100fa5760006003193601126100fa5760209073ffffffffffffffffffffffffffffffffffffffff600054169051908152f35b600080fd5b50346100fa5760006003193601126100fa576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346100fa5760206003193601126100fa5760209061018a60043560ff6001918060081c6000526002602052161b60406000205416151590565b90519015158152f35b50346100fa5760006003193601126100fa576101ad6111d3565b9080519182916020808401908085528351809252808386019401926000905b8382106101d95786860387f35b8451805167ffffffffffffffff16875283015164ffffffffff16868401528796509485019493820193600191909101906101cc565b50346100fa5760006003193601126100fa576020905164ffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346100fa5760006003193601126100fa5760209061018a61117e565b50346100fa5760206003193601126100fa576102876110e2565b6000549073ffffffffffffffffffffffffffffffffffffffff9081831633810361030057507fffffffffffffffffffffffff00000000000000000000000000000000000000009350169182911617600055337fbdd36143ee09de60bdefca70680e0f71189b2ed7acee364b53917ad433fdaf80600080a3005b84517fc6cce6a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b50346100fa5760006003193601126100fa57602090517f00000000000000000000000000000000000000000000000000000000000000008152f35b50346100fa5760006003193601126100fa57805160009160018054908160011c90600183169283156104bd575b602093848410811461048e5783875290811561045057506001146103f5575b5050506103e7826103f194038361113d565b519182918261107c565b0390f35b600160009081529295507fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b82841061043d57505050826103f1946103e792820101946103d5565b8054868501880152928601928101610421565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016868501525050151560051b83010192506103e7826103f16103d5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b91607f16916103b6565b50346100fa5760006003193601126100fa576020905173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50346100fa5760806003193601126100fa5760243573ffffffffffffffffffffffffffffffffffffffff811681036100fa57604435916fffffffffffffffffffffffffffffffff83168093036100fa5767ffffffffffffffff9283606435116100fa573660236064350112156100fa5760643560040135908482116100fa5760248260051b60643501013681116100fa5783516020810190600435825273ffffffffffffffffffffffffffffffffffffffff871686820152836060820152606081526105e381611121565b519020845160208101918252602081526105fc81611105565b5190209061060861117e565b610cd25761063160043560ff6001918060081c6000526002602052161b60406000205416151590565b610ca15761063e846111bb565b9361064b8651958661113d565b8452606435602401602085015b828210610c9157505050946000955b83518710156106ab5761067a878561126e565b519081811015610699576000526020526001846000205b960195610667565b90600052602052600184600020610691565b8585917f000000000000000000000000000000000000000000000000000000000000000003610c68576106dc6111d3565b805160006106e9826111bb565b926106f68651948561113d565b8284527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0610723846111bb565b0160005b818110610c445750506000905b838210610bbc575050808703610acd575b505060043560081c600052600260205282600020600160ff600435161b815417905573ffffffffffffffffffffffffffffffffffffffff600054169083519161078d83611105565b60008084526020840152845195610100870190811187821017610a9e578552855273ffffffffffffffffffffffffffffffffffffffff83166020860152858486015273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001660608601527f0000000000000000000000000000000000000000000000000000000000000000151560808601527f0000000000000000000000000000000000000000000000000000000000000000151560a086015260c085015260e08401528151927f897f362b000000000000000000000000000000000000000000000000000000008452602060048501528361014481019173ffffffffffffffffffffffffffffffffffffffff815116602483015273ffffffffffffffffffffffffffffffffffffffff60208201511660448301526fffffffffffffffffffffffffffffffff8582015116606483015273ffffffffffffffffffffffffffffffffffffffff60608201511660848301526080810151151560a483015260a0810151151560c483015260c08101519261012060e484015283518091526020610164840194019060005b87828210610a6357505050506020928360e08493015173ffffffffffffffffffffffffffffffffffffffff81511661010485015201516101248301520381600073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1928315610a5857600093610a23575b506020937f28b58397e03322f670d6b223cc863f8c148e368b8b615412e6798a641a22842d8373ffffffffffffffffffffffffffffffffffffffff86948251946004358652898601521692a351908152f35b92506020833d602011610a50575b81610a3e6020938361113d565b810103126100fa5791519160206109d1565b3d9150610a31565b82513d6000823e3d90fd5b835180516fffffffffffffffffffffffffffffffff16885260209081015164ffffffffff168189015296019589955090920191600101610949565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6fffffffffffffffffffffffffffffffff80610af1610aeb8a6112b1565b936112b1565b16911603906fffffffffffffffffffffffffffffffff8211610b8d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101908111610b8d57610b41908361126e565b51906fffffffffffffffffffffffffffffffff808351169116016fffffffffffffffffffffffffffffffff8111610b8d576fffffffffffffffffffffffffffffffff1690528580610745565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9091610bd588610bcc858561126e565b5151168a6112ff565b92838201809211610b8d57610bec600192946112b1565b64ffffffffff6020610bfe848761126e565b510151166fffffffffffffffffffffffffffffffff8a5192610c1f84611105565b1682526020820152610c31828861126e565b52610c3c818761126e565b500190610734565b6020908851610c5281611105565b6000815260008382015282828901015201610727565b600482517f0fa7d73c000000000000000000000000000000000000000000000000000000008152fd5b8135815260209182019101610658565b602485517f712b37a30000000000000000000000000000000000000000000000000000000081526004356004820152fd5b84517f442b18410000000000000000000000000000000000000000000000000000000081524260048201527f000000000000000000000000000000000000000000000000000000000000000064ffffffffff166024820152604490fd5b50346100fa5760006003193601126100fa57602090517f000000000000000000000000000000000000000000000000000000000000000015158152f35b50346100fa5760006003193601126100fa57602090517f000000000000000000000000000000000000000000000000000000000000000015158152f35b50346100fa57806003193601126100fa57610dc26110e2565b602435916fffffffffffffffffffffffffffffffff83168093036100fa5773ffffffffffffffffffffffffffffffffffffffff928360005416338103610fe45750610e0b61117e565b15610f875781519060209160008087858401977fa9059cbb000000000000000000000000000000000000000000000000000000008952169687602485015284604485015260448452610e5c84611121565b887f00000000000000000000000000000000000000000000000000000000000000001693519082855af13d15610f7b573d67ffffffffffffffff8111610a9e57610ee491865191610ed4877fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116018461113d565b82523d60008784013e5b836113cc565b8051848115159182610f5a575b50509050610f2a57507f2e9d425ba8b27655048400b366d7b6a1f7180ebdb088e06bb7389704860ffe1f929394600054169351908152a3005b6024908451907f5274afe70000000000000000000000000000000000000000000000000000000082526004820152fd5b83809293500103126100fa578301518015908115036100fa57808438610ef1565b610ee490606090610ede565b50517fe13612970000000000000000000000000000000000000000000000000000000081524260048201527f000000000000000000000000000000000000000000000000000000000000000064ffffffffff166024820152604490fd5b82517fc6cce6a400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff919091166004820152336024820152604490fd5b9050346100fa5760006003193601126100fa576103f1917f00000000000000000000000000000000000000000000000000000000000000006020830152602082526103e782611105565b60208082528251818301819052939260005b8581106110ce575050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8460006040809697860101520116010190565b81810183015184820160400152820161108e565b6004359073ffffffffffffffffffffffffffffffffffffffff821682036100fa57565b6040810190811067ffffffffffffffff821117610a9e57604052565b6080810190811067ffffffffffffffff821117610a9e57604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610a9e57604052565b64ffffffffff7f00000000000000000000000000000000000000000000000000000000000000001680151590816111b3575090565b905042101590565b67ffffffffffffffff8111610a9e5760051b60200190565b600354906111e0826111bb565b9160406111f0604051948561113d565b8184528360208091019160036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b906000935b85851061123457505050505050565b6001848192845161124481611105565b64ffffffffff875467ffffffffffffffff81168352871c1683820152815201930194019391611225565b80518210156112825760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6fffffffffffffffffffffffffffffffff908181116112ce571690565b602490604051907f4916adce0000000000000000000000000000000000000000000000000000000082526004820152fd5b9190917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff838209838202918280831092039180830392146113bb57670de0b6b3a7640000908183101561138457947faccb18165bd6fe31ae1cf318dc5b51eee0e1ba569b88cd74c1773b91fac1066994950990828211900360ee1b910360121c170290565b60449086604051917f5173648d00000000000000000000000000000000000000000000000000000000835260048301526024820152fd5b5050670de0b6b3a764000090049150565b9061140b57508051156113e157805190602001fd5b60046040517f1425ea42000000000000000000000000000000000000000000000000000000008152fd5b81511580611463575b61141c575090565b60249073ffffffffffffffffffffffffffffffffffffffff604051917f9996b315000000000000000000000000000000000000000000000000000000008352166004820152fd5b50803b1561141456fea164736f6c6343000817000aa164736f6c6343000817000a"; /*////////////////////////////////////////////////////////////////////////// DEPLOYERS