@zoralabs/coins 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/.turbo/turbo-build$colon$js.log +119 -101
  2. package/CHANGELOG.md +31 -1
  3. package/README.md +1 -0
  4. package/abis/AddressConstants.json +7 -0
  5. package/abis/BaseTest.json +65 -3
  6. package/abis/BuySupplyWithV4SwapHook.json +429 -0
  7. package/abis/FeeEstimatorHook.json +23 -0
  8. package/abis/ITrustedMsgSenderProviderLookup.json +21 -0
  9. package/abis/IUniswapV4Router04.json +484 -0
  10. package/abis/IZoraV4CoinHook.json +5 -0
  11. package/abis/MockAirlock.json +39 -0
  12. package/abis/SimpleERC20.json +326 -0
  13. package/abis/TrustedMsgSenderProviderLookup.json +215 -0
  14. package/abis/VmContractHelper242.json +233 -0
  15. package/abis/ZoraV4CoinHook.json +21 -3
  16. package/addresses/8453.json +7 -9
  17. package/audits/report-cantinacode-zora-1021.pdf +0 -0
  18. package/dist/index.cjs +140 -19
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.js +139 -18
  21. package/dist/index.js.map +1 -1
  22. package/dist/wagmiGenerated.d.ts +205 -28
  23. package/dist/wagmiGenerated.d.ts.map +1 -1
  24. package/foundry.toml +5 -1
  25. package/package/wagmiGenerated.ts +139 -18
  26. package/package.json +3 -3
  27. package/script/DeployPostDeploymentHooks.s.sol +1 -3
  28. package/script/DeployTrustedMsgSenderLookup.s.sol +20 -0
  29. package/src/deployment/CoinsDeployerBase.sol +31 -9
  30. package/src/hooks/ZoraV4CoinHook.sol +19 -55
  31. package/src/hooks/deployment/BuySupplyWithV4SwapHook.sol +310 -0
  32. package/src/interfaces/ITrustedMsgSenderProviderLookup.sol +18 -0
  33. package/src/interfaces/IZoraV4CoinHook.sol +3 -0
  34. package/src/libs/HooksDeployment.sol +9 -8
  35. package/src/libs/V4Liquidity.sol +50 -6
  36. package/src/utils/AutoSwapper.sol +1 -1
  37. package/src/utils/TrustedMsgSenderProviderLookup.sol +73 -0
  38. package/src/version/ContractVersionBase.sol +1 -1
  39. package/test/BuySupplyWithV4SwapHook.t.sol +509 -0
  40. package/test/Coin.t.sol +21 -9
  41. package/test/CoinUniV4.t.sol +1 -2
  42. package/test/ContentCoinRewards.t.sol +1 -3
  43. package/test/CreatorCoin.t.sol +1 -4
  44. package/test/CreatorCoinRewards.t.sol +5 -3
  45. package/test/Factory.t.sol +3 -3
  46. package/test/HooksDeployment.t.sol +58 -6
  47. package/test/LiquidityMigration.t.sol +6 -2
  48. package/test/MultiOwnable.t.sol +4 -4
  49. package/test/TrustedMsgSenderProviderLookup.t.sol +112 -0
  50. package/test/Upgrades.t.sol +41 -27
  51. package/test/ZoraHookRegistry.t.sol +19 -9
  52. package/test/mocks/MockAirlock.sol +22 -0
  53. package/test/mocks/SimpleERC20.sol +8 -0
  54. package/test/utils/BaseTest.sol +185 -6
  55. package/test/utils/FeeEstimatorHook.sol +3 -1
  56. package/test/utils/TrustedSenderTestHelper.sol +18 -0
  57. package/test/utils/hookmate/README.md +50 -0
  58. package/test/utils/hookmate/artifacts/DeployHelper.sol +20 -0
  59. package/test/utils/hookmate/artifacts/Permit2.sol +16 -0
  60. package/test/utils/hookmate/artifacts/UniversalRouter.sol +29 -0
  61. package/test/utils/hookmate/artifacts/V4PoolManager.sol +17 -0
  62. package/test/utils/hookmate/artifacts/V4PositionManager.sol +23 -0
  63. package/test/utils/hookmate/artifacts/V4Quoter.sol +17 -0
  64. package/test/utils/hookmate/artifacts/V4Router.sol +18 -0
  65. package/test/utils/hookmate/constants/AddressConstants.sol +193 -0
  66. package/test/utils/hookmate/interfaces/router/IUniswapV4Router04.sol +173 -0
  67. package/test/utils/hookmate/interfaces/router/PathKey.sol +34 -0
  68. package/test/utils/hookmate/test/utils/SwapFeeEventAsserter.sol +24 -0
  69. package/wagmi.config.ts +1 -1
  70. package/src/utils/uniswap/BytesLib.sol +0 -35
  71. package/src/utils/uniswap/Path.sol +0 -31
  72. /package/abis/{VmContractHelper226.json → VmContractHelper235.json} +0 -0
@@ -44,6 +44,20 @@ import {ContractAddresses} from "./ContractAddresses.sol";
44
44
  import {IHooks} from "@uniswap/v4-core/src/interfaces/IHooks.sol";
45
45
  import {HookUpgradeGate} from "../../src/hooks/HookUpgradeGate.sol";
46
46
  import {ZoraHookRegistry} from "../../src/hook-registry/ZoraHookRegistry.sol";
47
+ import {TrustedMsgSenderProviderLookup} from "../../src/utils/TrustedMsgSenderProviderLookup.sol";
48
+ import {ITrustedMsgSenderProviderLookup} from "../../src/interfaces/ITrustedMsgSenderProviderLookup.sol";
49
+ import {TrustedSenderTestHelper} from "./TrustedSenderTestHelper.sol";
50
+
51
+ // Hookmate imports for non-forked testing
52
+ import {V4PoolManagerDeployer} from "./hookmate/artifacts/V4PoolManager.sol";
53
+ import {V4QuoterDeployer} from "./hookmate/artifacts/V4Quoter.sol";
54
+ import {Permit2Deployer} from "./hookmate/artifacts/Permit2.sol";
55
+ import {DeployHelper} from "./hookmate/artifacts/DeployHelper.sol";
56
+ import {AddressConstants} from "./hookmate/constants/AddressConstants.sol";
57
+ import {UniversalRouterDeployer, RouterParameters} from "./hookmate/artifacts/UniversalRouter.sol";
58
+ import {MockERC20} from "../mocks/MockERC20.sol";
59
+ import {MockAirlock} from "../mocks/MockAirlock.sol";
60
+ import {SimpleERC20} from "../mocks/SimpleERC20.sol";
47
61
 
48
62
  contract BaseTest is Test, ContractAddresses {
49
63
  using stdStorage for StdStorage;
@@ -63,6 +77,7 @@ contract BaseTest is Test, ContractAddresses {
63
77
  address seller;
64
78
  address coinRecipient;
65
79
  address tradeReferrer;
80
+ address dopplerRecipient;
66
81
  }
67
82
 
68
83
  uint256 internal forkId;
@@ -203,13 +218,23 @@ contract BaseTest is Test, ContractAddresses {
203
218
  }
204
219
 
205
220
  function _deployFeeEstimatorHook(address hooks) internal {
206
- deployCodeTo("FeeEstimatorHook.sol", abi.encode(V4_POOL_MANAGER, address(factory), hookUpgradeGate), hooks);
221
+ // Deploy a new lookup with the same trusted senders
222
+ address[] memory trustedMessageSenders = new address[](2);
223
+ trustedMessageSenders[0] = UNIVERSAL_ROUTER;
224
+ trustedMessageSenders[1] = V4_POSITION_MANAGER;
225
+ ITrustedMsgSenderProviderLookup newLookup = TrustedSenderTestHelper.deployTrustedMessageSender(users.factoryOwner, trustedMessageSenders);
226
+
227
+ deployCodeTo(
228
+ "FeeEstimatorHook.sol",
229
+ HooksDeployment.hookConstructorArgs(address(poolManager), address(factory), newLookup, address(hookUpgradeGate)),
230
+ hooks
231
+ );
207
232
  }
208
233
 
209
- function getSalt(address[] memory trustedMessageSenders) public returns (bytes32 hookSalt) {
234
+ function getSalt(ITrustedMsgSenderProviderLookup trustedMsgSenderLookup) public returns (bytes32 hookSalt) {
210
235
  address deployer = address(this);
211
236
 
212
- (, hookSalt) = HooksDeployment.mineForCoinSalt(deployer, V4_POOL_MANAGER, address(factory), trustedMessageSenders, address(hookUpgradeGate));
237
+ (, hookSalt) = HooksDeployment.mineForCoinSalt(deployer, V4_POOL_MANAGER, address(factory), trustedMsgSenderLookup, address(hookUpgradeGate));
213
238
  }
214
239
 
215
240
  function _deployHooks() internal {
@@ -217,13 +242,20 @@ contract BaseTest is Test, ContractAddresses {
217
242
  trustedMessageSenders[0] = UNIVERSAL_ROUTER;
218
243
  trustedMessageSenders[1] = V4_POSITION_MANAGER;
219
244
 
220
- bytes32 hookSalt = getSalt(trustedMessageSenders);
245
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup = TrustedSenderTestHelper.deployTrustedMessageSender(users.factoryOwner, trustedMessageSenders);
246
+
247
+ bytes32 hookSalt = getSalt(trustedMsgSenderLookup);
221
248
 
222
249
  hook = ZoraV4CoinHook(
223
250
  payable(
224
251
  address(
225
252
  HooksDeployment.deployHookWithSalt(
226
- HooksDeployment.makeHookCreationCode(V4_POOL_MANAGER, address(factory), trustedMessageSenders, address(hookUpgradeGate)),
253
+ HooksDeployment.makeHookCreationCode(
254
+ V4_POOL_MANAGER,
255
+ address(factory),
256
+ ITrustedMsgSenderProviderLookup(address(trustedMsgSenderLookup)),
257
+ address(hookUpgradeGate)
258
+ ),
227
259
  hookSalt
228
260
  )
229
261
  )
@@ -258,7 +290,8 @@ contract BaseTest is Test, ContractAddresses {
258
290
  buyer: makeAddr("buyer"),
259
291
  seller: makeAddr("seller"),
260
292
  coinRecipient: makeAddr("coinRecipient"),
261
- tradeReferrer: makeAddr("tradeReferrer")
293
+ tradeReferrer: makeAddr("tradeReferrer"),
294
+ dopplerRecipient: makeAddr("dopplerRecipient")
262
295
  });
263
296
 
264
297
  ProxyShim mockUpgradeableImpl = new ProxyShim();
@@ -302,6 +335,152 @@ contract BaseTest is Test, ContractAddresses {
302
335
  vm.label(address(hook), "HOOK");
303
336
  }
304
337
 
338
+ function setUpNonForked() public {
339
+ // Initialize users first
340
+ users = Users({
341
+ factoryOwner: makeAddr("factoryOwner"),
342
+ feeRecipient: makeAddr("feeRecipient"),
343
+ creator: makeAddr("creator"),
344
+ platformReferrer: makeAddr("platformReferrer"),
345
+ buyer: makeAddr("buyer"),
346
+ seller: makeAddr("seller"),
347
+ coinRecipient: makeAddr("coinRecipient"),
348
+ tradeReferrer: makeAddr("tradeReferrer"),
349
+ dopplerRecipient: makeAddr("dopplerRecipient")
350
+ });
351
+
352
+ // Deploy mock airlock with the dopplerRecipient as owner (for doppler rewards)
353
+ MockAirlock mockAirlock = new MockAirlock(users.dopplerRecipient);
354
+
355
+ // Deploy V4 infrastructure using hookmate
356
+ _deployV4InfrastructureNonForked();
357
+
358
+ // Deploy mock ZORA token at the correct address
359
+ deployCodeTo("SimpleERC20.sol:SimpleERC20", abi.encode("ZORA", "$ZORA"), ZORA_TOKEN_ADDRESS);
360
+ zoraToken = IERC20Metadata(ZORA_TOKEN_ADDRESS);
361
+
362
+ // Fund the pool manager with ZORA tokens
363
+ deal(address(zoraToken), address(poolManager), 1_000_000_000e18);
364
+
365
+ // Deploy protocol rewards
366
+ protocolRewards = new ProtocolRewards();
367
+
368
+ // Deploy factory proxy
369
+ ProxyShim mockUpgradeableImpl = new ProxyShim();
370
+ factory = IZoraFactory(address(new ZoraFactory(address(mockUpgradeableImpl))));
371
+
372
+ // Deploy hook upgrade gate
373
+ hookUpgradeGate = new HookUpgradeGate(users.factoryOwner);
374
+
375
+ // Deploy zora hook registry
376
+ zoraHookRegistry = new ZoraHookRegistry();
377
+ address[] memory initialOwners = new address[](2);
378
+ initialOwners[0] = users.factoryOwner;
379
+ initialOwners[1] = address(factory);
380
+ zoraHookRegistry.initialize(initialOwners);
381
+
382
+ // Deploy hooks for non-forked environment
383
+ _deployHooksNonForked();
384
+
385
+ // Deploy coin implementations
386
+ coinV4Impl = new ContentCoin(users.feeRecipient, address(protocolRewards), poolManager, address(mockAirlock));
387
+ creatorCoinImpl = new CreatorCoin(users.feeRecipient, address(protocolRewards), poolManager, address(mockAirlock));
388
+
389
+ // Deploy and initialize factory implementation
390
+ factoryImpl = new ZoraFactoryImpl(address(coinV4Impl), address(creatorCoinImpl), address(hook), address(zoraHookRegistry));
391
+ UUPSUpgradeable(address(factory)).upgradeToAndCall(address(factoryImpl), "");
392
+ ZoraFactoryImpl(address(factory)).initialize(users.factoryOwner);
393
+
394
+ // Labels for easier debugging
395
+ vm.label(address(factory), "ZORA_FACTORY");
396
+ vm.label(address(protocolRewards), "PROTOCOL_REWARDS");
397
+ vm.label(address(poolManager), "V4_POOL_MANAGER");
398
+ vm.label(address(permit2), "V4_PERMIT2");
399
+ vm.label(address(router), "UNIVERSAL_ROUTER");
400
+ vm.label(address(hook), "HOOK");
401
+ vm.label(address(mockAirlock), "MOCK_AIRLOCK");
402
+ }
403
+
404
+ function _deployV4InfrastructureNonForked() internal {
405
+ // Deploy Permit2 to canonical address
406
+ _deployPermit2NonForked();
407
+
408
+ // Deploy PoolManager
409
+ _deployPoolManagerNonForked();
410
+
411
+ // Deploy Quoter
412
+ _deployQuoterNonForked();
413
+
414
+ // Deploy Universal Router
415
+ _deployUniversalRouterNonForked();
416
+ }
417
+
418
+ function _deployPermit2NonForked() internal {
419
+ address permit2Address = AddressConstants.getPermit2Address();
420
+
421
+ if (permit2Address.code.length > 0) {
422
+ // Permit2 is already deployed
423
+ } else {
424
+ address tempDeployAddress = address(Permit2Deployer.deploy());
425
+ vm.etch(permit2Address, tempDeployAddress.code);
426
+ }
427
+
428
+ permit2 = IPermit2(permit2Address);
429
+ vm.label(address(permit2), "V4_PERMIT2");
430
+ }
431
+
432
+ function _deployPoolManagerNonForked() internal {
433
+ if (block.chainid == 31337) {
434
+ poolManager = IPoolManager(address(V4PoolManagerDeployer.deploy(address(0x4444))));
435
+ } else {
436
+ poolManager = IPoolManager(AddressConstants.getPoolManagerAddress(block.chainid));
437
+ }
438
+
439
+ deal(address(poolManager), 10000 ether);
440
+ vm.label(address(poolManager), "V4_POOL_MANAGER");
441
+ }
442
+
443
+ function _deployQuoterNonForked() internal {
444
+ quoter = IV4Quoter(V4QuoterDeployer.deploy(address(poolManager)));
445
+ vm.label(address(quoter), "V4_QUOTER");
446
+ }
447
+
448
+ function _deployUniversalRouterNonForked() internal {
449
+ RouterParameters memory params = RouterParameters({
450
+ permit2: address(permit2),
451
+ weth9: address(0),
452
+ v2Factory: address(0),
453
+ v3Factory: address(0),
454
+ pairInitCodeHash: bytes32(0),
455
+ poolInitCodeHash: bytes32(0),
456
+ v4PoolManager: address(poolManager),
457
+ v3NFTPositionManager: address(0),
458
+ v4PositionManager: address(0)
459
+ });
460
+ router = IUniversalRouter(UniversalRouterDeployer.deploy(params));
461
+ vm.label(address(router), "UNIVERSAL_ROUTER");
462
+ }
463
+
464
+ function _deployHooksNonForked() internal {
465
+ address[] memory trustedMessageSenders = new address[](1);
466
+ trustedMessageSenders[0] = address(router);
467
+
468
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup = TrustedSenderTestHelper.deployTrustedMessageSender(users.factoryOwner, trustedMessageSenders);
469
+
470
+ // Use proper salt mining for hook deployment
471
+ address deployer = address(this);
472
+ (, bytes32 salt) = HooksDeployment.mineForCoinSalt(deployer, address(poolManager), address(factory), trustedMsgSenderLookup, address(hookUpgradeGate));
473
+
474
+ bytes memory hookCreationCode = HooksDeployment.makeHookCreationCode(
475
+ address(poolManager),
476
+ address(factory),
477
+ trustedMsgSenderLookup,
478
+ address(hookUpgradeGate)
479
+ );
480
+
481
+ hook = ZoraV4CoinHook(payable(DeployHelper.deploy(hookCreationCode, salt)));
482
+ }
483
+
305
484
  struct TradeRewards {
306
485
  uint256 creator;
307
486
  uint256 platformReferrer;
@@ -16,6 +16,7 @@ import {UniV4SwapToCurrency} from "../../src/libs/UniV4SwapToCurrency.sol";
16
16
  import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
17
17
  import {CoinRewardsV4} from "../../src/libs/CoinRewardsV4.sol";
18
18
  import {IHooksUpgradeGate} from "../../src/interfaces/IHooksUpgradeGate.sol";
19
+ import {ITrustedMsgSenderProviderLookup} from "../../src/interfaces/ITrustedMsgSenderProviderLookup.sol";
19
20
 
20
21
  /// @dev Test util - meant to be able to etched where a normal zora hook is, to gather the fees from swaps but not distribute them
21
22
  contract FeeEstimatorHook is ZoraV4CoinHook {
@@ -33,8 +34,9 @@ contract FeeEstimatorHook is ZoraV4CoinHook {
33
34
  constructor(
34
35
  IPoolManager _poolManager,
35
36
  IDeployedCoinVersionLookup _coinVersionLookup,
37
+ ITrustedMsgSenderProviderLookup trustedMsgSenderLookup,
36
38
  IHooksUpgradeGate upgradeGate
37
- ) ZoraV4CoinHook(_poolManager, _coinVersionLookup, new address[](0), upgradeGate) {}
39
+ ) ZoraV4CoinHook(_poolManager, _coinVersionLookup, trustedMsgSenderLookup, upgradeGate) {}
38
40
 
39
41
  FeeEstimatorState public feeState;
40
42
 
@@ -0,0 +1,18 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.13;
3
+
4
+ import {TrustedMsgSenderProviderLookup} from "../../src/utils/TrustedMsgSenderProviderLookup.sol";
5
+ import {ITrustedMsgSenderProviderLookup} from "../../src/interfaces/ITrustedMsgSenderProviderLookup.sol";
6
+
7
+ /// @title TrustedSenderTestHelper
8
+ /// @notice Helper library for deploying TrustedMsgSenderProviderLookup in tests
9
+ library TrustedSenderTestHelper {
10
+ /// @notice Deploys a TrustedMsgSenderProviderLookup with direct constructor
11
+ /// @param owner The owner address for the deployed contract
12
+ /// @param initialTrustedSenders Array of initially trusted sender addresses
13
+ /// @return The deployed ITrustedMsgSenderProviderLookup contract
14
+ function deployTrustedMessageSender(address owner, address[] memory initialTrustedSenders) internal returns (ITrustedMsgSenderProviderLookup) {
15
+ // Deploy the contract directly using constructor
16
+ return ITrustedMsgSenderProviderLookup(address(new TrustedMsgSenderProviderLookup(initialTrustedSenders, owner)));
17
+ }
18
+ }
@@ -0,0 +1,50 @@
1
+ # Hookmate Library
2
+
3
+ This directory contains the hookmate library for deploying Uniswap V4 infrastructure in non-forked test environments.
4
+
5
+ ## Overview
6
+
7
+ [Hookmate](https://github.com/akshatmittal/hookmate) provides deployer libraries that wrap contract initcode and constructor arguments, enabling deterministic deployment of V4 contracts without requiring mainnet forks.
8
+
9
+ ## Added Contracts
10
+
11
+ The following contracts were **not** part of the original hookmate library and were added to support the Zora coins testing infrastructure:
12
+
13
+ ### V4Quoter.sol
14
+ - Used for simulating swaps and getting quote amounts
15
+ - Added to `artifacts/V4Quoter.sol`
16
+
17
+ ### UniversalRouter.sol
18
+ - Handles multi-protocol routing and swap execution
19
+ - Added to `artifacts/UniversalRouter.sol`
20
+
21
+ ## How These Contracts Were Added
22
+
23
+ 1. **Extract bytecode** from deployed mainnet contract using Etherscan
24
+ 2. **Create deployer library** with structure:
25
+ ```solidity
26
+ library ContractNameDeployer {
27
+ function deploy(/* constructor args */) internal returns (address deployed) {
28
+ bytes memory args = abi.encode(/* constructor args */);
29
+ bytes memory initcode_ = abi.encodePacked(initcode(), args);
30
+ deployed = DeployHelper.deploy(initcode_);
31
+ }
32
+
33
+ function initcode() internal pure returns (bytes memory) {
34
+ return hex"<bytecode from etherscan>";
35
+ }
36
+ }
37
+ ```
38
+ 3. **Save to** `artifacts/ContractName.sol`
39
+ 4. **Import and use** in `BaseTest.sol` or test files
40
+
41
+ ## Adding Future Contracts
42
+
43
+ To add a new contract to hookmate:
44
+
45
+ 1. Find deployed contract on Etherscan
46
+ 2. Copy the contract creation bytecode
47
+ 3. Create new file `artifacts/ContractName.sol` following the pattern above
48
+ 4. Define constructor parameters struct if needed
49
+ 5. Implement `deploy()` and `initcode()` functions
50
+ 6. Test deployment in non-forked environment
@@ -0,0 +1,20 @@
1
+ //SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.26;
3
+
4
+ library DeployHelper {
5
+ function deploy(bytes memory initcode, bytes32 salt) internal returns (address contractAddress) {
6
+ assembly ("memory-safe") {
7
+ contractAddress := create2(0, add(initcode, 32), mload(initcode), salt)
8
+ if iszero(contractAddress) {
9
+ let ptr := mload(0x40)
10
+ let errorSize := returndatasize()
11
+ returndatacopy(ptr, 0, errorSize)
12
+ revert(ptr, errorSize)
13
+ }
14
+ }
15
+ }
16
+
17
+ function deploy(bytes memory initcode) internal returns (address contractAddress) {
18
+ return deploy(initcode, hex"00");
19
+ }
20
+ }
@@ -0,0 +1,16 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.26;
3
+
4
+ import {DeployHelper} from "./DeployHelper.sol";
5
+
6
+ library Permit2Deployer {
7
+ function deploy() internal returns (address permit2) {
8
+ bytes memory initcode_ = abi.encodePacked(initcode());
9
+ permit2 = DeployHelper.deploy(initcode_);
10
+ }
11
+
12
+ function initcode() internal pure returns (bytes memory) {
13
+ return
14
+ hex"60c0346100bb574660a052602081017f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a60408301524660608301523060808301526080825260a082019180831060018060401b038411176100a557826040525190206080526123c090816100c1823960805181611b47015260a05181611b210152f35b634e487b7160e01b600052604160045260246000fd5b600080fdfe6040608081526004908136101561001557600080fd5b600090813560e01c80630d58b1db1461126c578063137c29fe146110755780632a2d80d114610db75780632b67b57014610bde57806330f28b7a14610ade5780633644e51514610a9d57806336c7851614610a285780633ff9dcb1146109a85780634fe02b441461093f57806365d9723c146107ac57806387517c451461067a578063927da105146105c3578063cc53287f146104a3578063edd9444b1461033a5763fe8ec1a7146100c657600080fd5b346103365760c07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff833581811161033257610114903690860161164b565b60243582811161032e5761012b903690870161161a565b6101336114e6565b9160843585811161032a5761014b9036908a016115c1565b98909560a43590811161032657610164913691016115c1565b969095815190610173826113ff565b606b82527f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208301527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c61646472838301527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608301527f3620646561646c696e652c000000000000000000000000000000000000000000608083015282519a8b9181610222602085018096611f93565b918237018a8152039961025b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09b8c8101835282611437565b5190209085515161026b81611ebb565b908a5b8181106102f95750506102f6999a6102ed9183516102a081610294602082018095611f66565b03848101835282611437565b519020602089810151858b015195519182019687526040820192909252336060820152608081019190915260a081019390935260643560c08401528260e081015b03908101835282611437565b51902093611cf7565b80f35b8061031161030b610321938c5161175e565b51612054565b61031b828661175e565b52611f0a565b61026e565b8880fd5b8780fd5b8480fd5b8380fd5b5080fd5b5091346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103365767ffffffffffffffff9080358281116103325761038b903690830161164b565b60243583811161032e576103a2903690840161161a565b9390926103ad6114e6565b9160643590811161049f576103c4913691016115c1565b949093835151976103d489611ebb565b98885b81811061047d5750506102f697988151610425816103f9602082018095611f66565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282611437565b5190206020860151828701519083519260208401947ffcf35f5ac6a2c28868dc44c302166470266239195f02b0ee408334829333b7668652840152336060840152608083015260a082015260a081526102ed8161141b565b808b61031b8261049461030b61049a968d5161175e565b9261175e565b6103d7565b8680fd5b5082346105bf57602090817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126103325780359067ffffffffffffffff821161032e576104f49136910161161a565b929091845b848110610504578580f35b8061051a610515600193888861196c565b61197c565b61052f84610529848a8a61196c565b0161197c565b3389528385528589209173ffffffffffffffffffffffffffffffffffffffff80911692838b528652868a20911690818a5285528589207fffffffffffffffffffffffff000000000000000000000000000000000000000081541690558551918252848201527f89b1add15eff56b3dfe299ad94e01f2b52fbcb80ae1a3baea6ae8c04cb2b98a4853392a2016104f9565b8280fd5b50346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610676816105ff6114a0565b936106086114c3565b6106106114e6565b73ffffffffffffffffffffffffffffffffffffffff968716835260016020908152848420928816845291825283832090871683528152919020549251938316845260a083901c65ffffffffffff169084015260d09190911c604083015281906060820190565b0390f35b50346103365760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336576106b26114a0565b906106bb6114c3565b916106c46114e6565b65ffffffffffff926064358481169081810361032a5779ffffffffffff0000000000000000000000000000000000000000947fda9fa7c1b00402c17d0161b249b1ab8bbec047c5a52207b9c112deffd817036b94338a5260016020527fffffffffffff0000000000000000000000000000000000000000000000000000858b209873ffffffffffffffffffffffffffffffffffffffff809416998a8d5260205283878d209b169a8b8d52602052868c209486156000146107a457504216925b8454921697889360a01b16911617179055815193845260208401523392a480f35b905092610783565b5082346105bf5760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576107e56114a0565b906107ee6114c3565b9265ffffffffffff604435818116939084810361032a57338852602091600183528489209673ffffffffffffffffffffffffffffffffffffffff80911697888b528452858a20981697888a5283528489205460d01c93848711156109175761ffff9085840316116108f05750907f55eb90d810e1700b35a8e7e25395ff7f2b2259abd7415ca2284dfb1c246418f393929133895260018252838920878a528252838920888a5282528389209079ffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffff000000000000000000000000000000000000000000000000000083549260d01b16911617905582519485528401523392a480f35b84517f24d35a26000000000000000000000000000000000000000000000000000000008152fd5b5084517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b503461033657807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610336578060209273ffffffffffffffffffffffffffffffffffffffff61098f6114a0565b1681528084528181206024358252845220549051908152f35b5082346105bf57817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf577f3704902f963766a4e561bbaab6e6cdc1b1dd12f6e9e99648da8843b3f46b918d90359160243533855284602052818520848652602052818520818154179055815193845260208401523392a280f35b8234610a9a5760807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610a9a57610a606114a0565b610a686114c3565b610a706114e6565b6064359173ffffffffffffffffffffffffffffffffffffffff8316830361032e576102f6936117a1565b80fd5b503461033657817ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657602090610ad7611b1e565b9051908152f35b508290346105bf576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf57610b1a3661152a565b90807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c36011261033257610b4c611478565b9160e43567ffffffffffffffff8111610bda576102f694610b6f913691016115c1565b939092610b7c8351612054565b6020840151828501519083519260208401947f939c21a48a8dbe3a9a2404a1d46691e4d39f6583d6ec6b35714604c986d801068652840152336060840152608083015260a082015260a08152610bd18161141b565b51902091611c25565b8580fd5b509134610336576101007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033657610c186114a0565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc360160c08112610332576080855191610c51836113e3565b1261033257845190610c6282611398565b73ffffffffffffffffffffffffffffffffffffffff91602435838116810361049f578152604435838116810361049f57602082015265ffffffffffff606435818116810361032a5788830152608435908116810361049f576060820152815260a435938285168503610bda576020820194855260c4359087830182815260e43567ffffffffffffffff811161032657610cfe90369084016115c1565b929093804211610d88575050918591610d786102f6999a610d7e95610d238851611fbe565b90898c511690519083519260208401947ff3841cd1ff0085026a6327b620b67997ce40f282c88a8e905a7a5626e310f3d086528401526060830152608082015260808152610d70816113ff565b519020611bd9565b916120c7565b519251169161199d565b602492508a51917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b5091346103365760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc93818536011261033257610df36114a0565b9260249081359267ffffffffffffffff9788851161032a578590853603011261049f578051978589018981108282111761104a578252848301358181116103265785019036602383011215610326578382013591610e50836115ef565b90610e5d85519283611437565b838252602093878584019160071b83010191368311611046578801905b828210610fe9575050508a526044610e93868801611509565b96838c01978852013594838b0191868352604435908111610fe557610ebb90369087016115c1565b959096804211610fba575050508998995151610ed681611ebb565b908b5b818110610f9757505092889492610d7892610f6497958351610f02816103f98682018095611f66565b5190209073ffffffffffffffffffffffffffffffffffffffff9a8b8b51169151928551948501957faf1b0d30d2cab0380e68f0689007e3254993c596f2fdd0aaa7f4d04f794408638752850152830152608082015260808152610d70816113ff565b51169082515192845b848110610f78578580f35b80610f918585610f8b600195875161175e565b5161199d565b01610f6d565b80610311610fac8e9f9e93610fb2945161175e565b51611fbe565b9b9a9b610ed9565b8551917fcd21db4f000000000000000000000000000000000000000000000000000000008352820152fd5b8a80fd5b6080823603126110465785608091885161100281611398565b61100b85611509565b8152611018838601611509565b838201526110278a8601611607565b8a8201528d611037818701611607565b90820152815201910190610e7a565b8c80fd5b84896041867f4e487b7100000000000000000000000000000000000000000000000000000000835252fd5b5082346105bf576101407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126105bf576110b03661152a565b91807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7c360112610332576110e2611478565b67ffffffffffffffff93906101043585811161049f5761110590369086016115c1565b90936101243596871161032a57611125610bd1966102f6983691016115c1565b969095825190611134826113ff565b606482527f5065726d69745769746e6573735472616e7366657246726f6d28546f6b656e5060208301527f65726d697373696f6e73207065726d69747465642c6164647265737320737065848301527f6e6465722c75696e74323536206e6f6e63652c75696e7432353620646561646c60608301527f696e652c0000000000000000000000000000000000000000000000000000000060808301528351948591816111e3602085018096611f93565b918237018b8152039361121c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe095868101835282611437565b5190209261122a8651612054565b6020878101518589015195519182019687526040820192909252336060820152608081019190915260a081019390935260e43560c08401528260e081016102e1565b5082346105bf576020807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261033257813567ffffffffffffffff92838211610bda5736602383011215610bda5781013592831161032e576024906007368386831b8401011161049f57865b8581106112e5578780f35b80821b83019060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc83360301126103265761139288876001946060835161132c81611398565b611368608461133c8d8601611509565b9485845261134c60448201611509565b809785015261135d60648201611509565b809885015201611509565b918291015273ffffffffffffffffffffffffffffffffffffffff80808093169516931691166117a1565b016112da565b6080810190811067ffffffffffffffff8211176113b457604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6060810190811067ffffffffffffffff8211176113b457604052565b60a0810190811067ffffffffffffffff8211176113b457604052565b60c0810190811067ffffffffffffffff8211176113b457604052565b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176113b457604052565b60c4359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b600080fd5b6004359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b6044359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b359073ffffffffffffffffffffffffffffffffffffffff8216820361149b57565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc01906080821261149b576040805190611563826113e3565b8082941261149b57805181810181811067ffffffffffffffff8211176113b457825260043573ffffffffffffffffffffffffffffffffffffffff8116810361149b578152602435602082015282526044356020830152606435910152565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020838186019501011161149b57565b67ffffffffffffffff81116113b45760051b60200190565b359065ffffffffffff8216820361149b57565b9181601f8401121561149b5782359167ffffffffffffffff831161149b576020808501948460061b01011161149b57565b91909160608184031261149b576040805191611666836113e3565b8294813567ffffffffffffffff9081811161149b57830182601f8201121561149b578035611693816115ef565b926116a087519485611437565b818452602094858086019360061b8501019381851161149b579086899897969594939201925b8484106116e3575050505050855280820135908501520135910152565b90919293949596978483031261149b578851908982019082821085831117611730578a928992845261171487611509565b81528287013583820152815201930191908897969594936116c6565b602460007f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b80518210156117725760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b92919273ffffffffffffffffffffffffffffffffffffffff604060008284168152600160205282828220961695868252602052818120338252602052209485549565ffffffffffff8760a01c16804211611884575082871696838803611812575b5050611810955016926118b5565b565b878484161160001461184f57602488604051907ff96fb0710000000000000000000000000000000000000000000000000000000082526004820152fd5b7fffffffffffffffffffffffff000000000000000000000000000000000000000084846118109a031691161790553880611802565b602490604051907fd81b2f2e0000000000000000000000000000000000000000000000000000000082526004820152fd5b9060006064926020958295604051947f23b872dd0000000000000000000000000000000000000000000000000000000086526004860152602485015260448401525af13d15601f3d116001600051141617161561190e57565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152fd5b91908110156117725760061b0190565b3573ffffffffffffffffffffffffffffffffffffffff8116810361149b5790565b9065ffffffffffff908160608401511673ffffffffffffffffffffffffffffffffffffffff908185511694826020820151169280866040809401511695169560009187835260016020528383208984526020528383209916988983526020528282209184835460d01c03611af5579185611ace94927fc6a377bfc4eb120024a8ac08eef205be16b817020812c73223e81d1bdb9708ec98979694508715600014611ad35779ffffffffffff00000000000000000000000000000000000000009042165b60a01b167fffffffffffff00000000000000000000000000000000000000000000000000006001860160d01b1617179055519384938491604091949373ffffffffffffffffffffffffffffffffffffffff606085019616845265ffffffffffff809216602085015216910152565b0390a4565b5079ffffffffffff000000000000000000000000000000000000000087611a60565b600484517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b467f000000000000000000000000000000000000000000000000000000000000000003611b69577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86682527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a604082015246606082015230608082015260808152611bd3816113ff565b51902090565b611be1611b1e565b906040519060208201927f190100000000000000000000000000000000000000000000000000000000000084526022830152604282015260428152611bd381611398565b9192909360a435936040840151804211611cc65750602084510151808611611c955750918591610d78611c6594611c60602088015186611e47565b611bd9565b73ffffffffffffffffffffffffffffffffffffffff809151511692608435918216820361149b57611810936118b5565b602490604051907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b602490604051907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b959093958051519560409283830151804211611e175750848803611dee57611d2e918691610d7860209b611c608d88015186611e47565b60005b868110611d42575050505050505050565b611d4d81835161175e565b5188611d5a83878a61196c565b01359089810151808311611dbe575091818888886001968596611d84575b50505050505001611d31565b611db395611dad9273ffffffffffffffffffffffffffffffffffffffff6105159351169561196c565b916118b5565b803888888883611d78565b6024908651907f3728b83d0000000000000000000000000000000000000000000000000000000082526004820152fd5b600484517fff633a38000000000000000000000000000000000000000000000000000000008152fd5b6024908551907fcd21db4f0000000000000000000000000000000000000000000000000000000082526004820152fd5b9073ffffffffffffffffffffffffffffffffffffffff600160ff83161b9216600052600060205260406000209060081c6000526020526040600020818154188091551615611e9157565b60046040517f756688fe000000000000000000000000000000000000000000000000000000008152fd5b90611ec5826115ef565b611ed26040519182611437565b8281527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0611f0082946115ef565b0190602036910137565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611f375760010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b805160208092019160005b828110611f7f575050505090565b835185529381019392810192600101611f71565b9081519160005b838110611fab575050016000815290565b8060208092840101518185015201611f9a565b60405160208101917f65626cad6cb96493bf6f5ebea28756c966f023ab9e8a83a7101849d5573b3678835273ffffffffffffffffffffffffffffffffffffffff8082511660408401526020820151166060830152606065ffffffffffff9182604082015116608085015201511660a082015260a0815260c0810181811067ffffffffffffffff8211176113b45760405251902090565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a1845273ffffffffffffffffffffffffffffffffffffffff81511660408401520151606082015260608152611bd381611398565b919082604091031261149b576020823592013590565b6000843b61222e5750604182036121ac576120e4828201826120b1565b939092604010156117725760209360009360ff6040608095013560f81c5b60405194855216868401526040830152606082015282805260015afa156121a05773ffffffffffffffffffffffffffffffffffffffff806000511691821561217657160361214c57565b60046040517f815e1d64000000000000000000000000000000000000000000000000000000008152fd5b60046040517f8baa579f000000000000000000000000000000000000000000000000000000008152fd5b6040513d6000823e3d90fd5b60408203612204576121c0918101906120b1565b91601b7f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84169360ff1c019060ff8211611f375760209360009360ff608094612102565b60046040517f4be6321b000000000000000000000000000000000000000000000000000000008152fd5b929391601f928173ffffffffffffffffffffffffffffffffffffffff60646020957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0604051988997889687947f1626ba7e000000000000000000000000000000000000000000000000000000009e8f8752600487015260406024870152816044870152868601378b85828601015201168101030192165afa9081156123a857829161232a575b507fffffffff000000000000000000000000000000000000000000000000000000009150160361230057565b60046040517fb0669cbc000000000000000000000000000000000000000000000000000000008152fd5b90506020813d82116123a0575b8161234460209383611437565b810103126103365751907fffffffff0000000000000000000000000000000000000000000000000000000082168203610a9a57507fffffffff0000000000000000000000000000000000000000000000000000000090386122d4565b3d9150612337565b6040513d84823e3d90fdfea164736f6c6343000811000a";
15
+ }
16
+ }
@@ -0,0 +1,29 @@
1
+ // SPDX-License-Identifier: MIT
2
+ pragma solidity ^0.8.26;
3
+
4
+ import {DeployHelper} from "./DeployHelper.sol";
5
+
6
+ struct RouterParameters {
7
+ address permit2;
8
+ address weth9;
9
+ address v2Factory;
10
+ address v3Factory;
11
+ bytes32 pairInitCodeHash;
12
+ bytes32 poolInitCodeHash;
13
+ address v4PoolManager;
14
+ address v3NFTPositionManager;
15
+ address v4PositionManager;
16
+ }
17
+
18
+ library UniversalRouterDeployer {
19
+ function deploy(RouterParameters memory params) internal returns (address universalRouter) {
20
+ bytes memory args = abi.encode(params);
21
+ bytes memory initcode_ = abi.encodePacked(initcode(), args);
22
+ universalRouter = DeployHelper.deploy(initcode_);
23
+ }
24
+
25
+ function initcode() internal pure returns (bytes memory) {
26
+ return
27
+ hex"6101a0604052346102d657604051601f614f3938819003918201601f19168301916001600160401b038311848410176102c257808492610120946040528339810103126102d6576040519061012082016001600160401b038111838210176102c25760405261006d816102f9565b825261007b602082016102f9565b6020830190815261008e604083016102f9565b604084019081526100a1606084016102f9565b93606081019485526080840151946080820195865260a08501519560a083019687526100cf60c087016102f9565b9660c084019788526100f66101006100e960e08a016102f9565b988960e0880152016102f9565b97886101008601526101066102da565b6001600160a01b03988916815298881660208a0190815290519451965190989796871696908116959416936101396102da565b968752602087019586525192519151905160405190936001600160a01b0393841693169060808101906001600160401b038211818310176102c257604091825282815260208101948552808201938452606001948552608091909152905160a05290516001600160a01b0390811660c052915160e052610100929092529151821661012052915181166101405291518216610160529151166101805251614c2b908161030e82396080518181816115d90152818161182701526137e4015260a0518181816115b80152818161184901526137c3015260c05181612ee6015260e05181612f39015261010051818181609e01528181610449015281816105b1015281816123240152818161288d0152818161431b015281816143ac015281816144b4015281816146350152614a45015261012051818181602f01528181611cb40152611e270152610140518181816112450152818161206201526133610152610160518181816106e301528181612458015261255101526101805181818161052701526129860152f35b634e487b7160e01b5f52604160045260245ffd5b5f80fd5b60408051919082016001600160401b038111838210176102c257604052565b51906001600160a01b03821682036102d65756fe60c060405260043610156100c6575b3615610018575f80fd5b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633141580610086575b61005e57005b7f38bbd576000000000000000000000000000000000000000000000000000000005f5260045ffd5b5073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016331415610058565b5f3560e01c806324856bc3146108685780633593564c14610707578063817122dc1461069957806391dd73461461054b578063d0c9f6cb146104dd578063d737d0c71461046d578063dc4c90d3146103ff5763fa461e330361000e57346102e05760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102e05760243560043560443567ffffffffffffffff81116102e057610177903690600401610942565b5f8313918215806103f5575b6103cd578181016040828203126102e057813567ffffffffffffffff81116102e057820181601f820112156102e05780356101bd81612c69565b926101cb6040519485612c28565b818452602082840101116102e0575f928160208094018483013701015260208101359173ffffffffffffffffffffffffffffffffffffffff83168093036102e05761021591612e12565b90601790602b83106103a5578035968760601c9561024362ffffff8585013560601c9a60481c168a89612e65565b73ffffffffffffffffffffffffffffffffffffffff3391160361037d571561037357508685105b156102805750505061027e93503391612f86565b005b91935091939482602b0180602b116103465784106102e457508282116102e05781019103907f80000000000000000000000000000000000000000000000000000000000000008410156102e05761027e936102db3391612ca3565b613018565b5f80fd5b925050507faf28d9864a81dfdf71cab65f4e5d79a0cf9b083905fb8971425e6cb581b3f6929291925c821161031e5761027e923391612f86565b7f739dbe52000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b955084871061026a565b7f32b13d91000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f3b99b53d000000000000000000000000000000000000000000000000000000005f5260045ffd5b7f316cf0eb000000000000000000000000000000000000000000000000000000005f5260045ffd5b505f851315610183565b346102e0575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102e057602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102e0575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102e05760207f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c73ffffffffffffffffffffffffffffffffffffffff60405191168152f35b346102e0575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102e057602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b346102e05760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102e05760043567ffffffffffffffff81116102e05761059a903690600401610942565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610671576105e091613404565b90818303610649575f5b83811061061d57610619604051610602602082612c28565b5f81526040519182916020835260208301906109a1565b0390f35b8061064361062e60019387896109e4565b3560f81c61063d838787610a6e565b91613ac3565b016105ea565b7faaad13f7000000000000000000000000000000000000000000000000000000005f5260045ffd5b7fae18210a000000000000000000000000000000000000000000000000000000005f5260045ffd5b346102e0575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102e057602060405173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b60607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102e05760043567ffffffffffffffff81116102e057610751903690600401610942565b60243567ffffffffffffffff81116102e057610771903690600401610970565b916044354211610840573330146108375773ffffffffffffffffffffffffffffffffffffffff7f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c1661080f576107ea93337f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085d610a89565b5f7f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085d005b7f6f5ffb7e000000000000000000000000000000000000000000000000000000005f5260045ffd5b61027e93610a89565b7f5bf6f916000000000000000000000000000000000000000000000000000000005f5260045ffd5b60407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126102e05760043567ffffffffffffffff81116102e0576108b2903690600401610942565b60243567ffffffffffffffff81116102e0576108d2903690600401610970565b913330146108375773ffffffffffffffffffffffffffffffffffffffff7f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c1661080f576107ea93337f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085d610a89565b9181601f840112156102e05782359167ffffffffffffffff83116102e057602083818601950101116102e057565b9181601f840112156102e05782359167ffffffffffffffff83116102e0576020808501948460051b0101116102e057565b907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f602080948051918291828752018686015e5f8582860101520116010190565b908210156109f0570190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102e0570180359067ffffffffffffffff82116102e0576020019181360383136102e057565b908210156109f057610a859160051b810190610a1d565b9091565b9290808203612bb7579291905f915b848310610aa6575050505050565b9091929394610ab68487876109e4565b3592610ac3858285610a6e565b979092606097603f8760f81c1695600196602181105f14612a1c5760108110156122b15760088110156115245780610eeb5750610b0560208701359b87612e3a565b9590608088013515610ee4577f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c9c5b610b3f89356131e2565b9d9188816080527f80000000000000000000000000000000000000000000000000000000000000008314610e58575b50505b604260a052602b7f80000000000000000000000000000000000000000000000000000000000000008210156102e05760a0518f908a10610e52575030915b8982116102e05760409173ffffffffffffffffffffffffffffffffffffffff5f6080513595610cb2610c2b610c5d85610c018b60601c6017608051013560601c62ffffff8183109e60481c1691612e65565b16968a8614610e37576401000276a49b5b878b519485938d60208601526060850190608051612ccf565b91168b830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612c28565b8488519a8b98899788967f128acb080000000000000000000000000000000000000000000000000000000088521660048701528b6024870152604486015216606484015260a0608484015260a48301906109a1565b03925af1908115610e2c575f905f92610df0575b610cd6935015610de95750612ca3565b60a0519096908110610d1d573090806017116102e0576080805160170190527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe90196610b71565b50979396929a50979490989360409091013511610dc1575b159081610d96575b50610d4f575060010191909392610a98565b90610d926040519283927f2c4029e900000000000000000000000000000000000000000000000000000000845260048401526040602484015260448301906109a1565b0390fd5b7f8000000000000000000000000000000000000000000000000000000000000000915016155f610d3d565b7f39d35496000000000000000000000000000000000000000000000000000000005f5260045ffd5b9050612ca3565b9150506040823d8211610e24575b81610e0b60409383612c28565b810103126102e057816020610cd6935191015191610cc6565b3d9150610dfe565b6040513d5f823e3d90fd5b73fffd8963efd1fc6a506488495d951d5263988d259b610c12565b91610baf565b6014919250106103a5576020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301523560601c5afa908115610e2c575f91610eb3575b505f80610b6e565b90506020813d8211610edc575b81610ecd60209383612c28565b810103126102e057515f610eab565b3d9150610ec0565b309c610b35565b6001819c929a97939b96999598949c145f14611024575090610f1260208201359282612e3a565b60808301351561101d577f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c915b6040610f4c85356131e2565b9401357faf28d9864a81dfdf71cab65f4e5d79a0cf9b083905fb8971425e6cb581b3f6925d7f80000000000000000000000000000000000000000000000000000000000000008510156102e057610fa6936102db86612ca3565b9091901561100e5750610fb890612ca3565b03610fe6575f7faf28d9864a81dfdf71cab65f4e5d79a0cf9b083905fb8971425e6cb581b3f6925d5b610d35565b7fd4e0248e000000000000000000000000000000000000000000000000000000005f5260045ffd5b6110189150612ca3565b610fb8565b3091610f40565b6002810361106e5750610fe191604081013591507f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c61106760208301356131e2565b9135613348565b93949193909290600381036112a1575050508135820163ffffffff60208401351683019163ffffffff83351693602080850194860101910110611294577f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c926040519273ffffffffffffffffffffffffffffffffffffffff60208501957f2a2d80d10000000000000000000000000000000000000000000000000000000087521660248501526060604485015260e484019280357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1823603018112156102e05781016020813591019467ffffffffffffffff82116102e0578160071b360386136102e05781906060608489015252610104860194905f905b80821061127657505050936111ff5f9694829461122b9460408973ffffffffffffffffffffffffffffffffffffffff6111c360208e9d01612d3c565b1660a4880152013560c48601527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc858403016064860152612ccf565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612c28565b51908273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af190611270612d0d565b91610d35565b909195608080826112896001948b612d9d565b019701920190611187565b633b99b53d5f526004601cfd5b91949390925090600481036113fa57506112be60208201356131e2565b9073ffffffffffffffffffffffffffffffffffffffff8060408301351691351680155f1461133457504790811061130c57806112fc575b5050610d35565b611305916134c8565b5f806112f5565b7f6a12f104000000000000000000000000000000000000000000000000000000005f5260045ffd5b91604051917f70a08231000000000000000000000000000000000000000000000000000000008352306004840152602083602481875afa928315610e2c575f936113c7575b50821061139f578161138e575b505050610d35565b61139792613a14565b5f8080611386565b7f675cae38000000000000000000000000000000000000000000000000000000005f5260045ffd5b9092506020813d82116113f2575b816113e260209383612c28565b810103126102e05751915f611379565b3d91506113d5565b600581036114215750806040610fe19201359061141a60208201356131e2565b903561326c565b600681036114f9575060408101359073ffffffffffffffffffffffffffffffffffffffff61145260208301356131e2565b9135168061146e5750611468610fe192476139d2565b906134c8565b906040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152602081602481865afa908115610e2c575f916114c6575b50610fe1936114c0916139d2565b91613a14565b90506020813d82116114f1575b816114e060209383612c28565b810103126102e05751610fe16114b2565b3d91506114d3565b7fd76a1e9e000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b6008819c929a97939b96999598949c145f146117d9575061154a6020830135918361319d565b906080840135156117d2577f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c915b61158385356131e2565b9282156109f057611593826131c1565b83600110156109f0576115b56115fd916115af602086016131c1565b906141ee565b907f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000614226565b9485816117b8575b5050507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82018281116103465761165a61165573ffffffffffffffffffffffffffffffffffffffff92858561324f565b6131c1565b1693604051927f70a0823100000000000000000000000000000000000000000000000000000000845273ffffffffffffffffffffffffffffffffffffffff8516928360048601526020856024818a5afa948515610e2c575f9561177b575b50946116c8929160209596613586565b6024604051809581937f70a0823100000000000000000000000000000000000000000000000000000000835260048301525afa918215610e2c575f92611747575b506040611719929301359261325f565b1015610d35577f849eaf98000000000000000000000000000000000000000000000000000000005f5260045ffd5b91506020823d8211611773575b8161176160209383612c28565b810103126102e0579051906040611709565b3d9150611754565b92919450946020833d82116117b0575b8161179860209383612c28565b810103126102e05791519194919390916116c86116b8565b3d915061178b565b6117ca926117c5856131c1565b612f86565b5f8085611605565b3091611579565b60098103611b4357506117ec908261319d565b608083013515611b3c577f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c915b61182484356131e2565b917f0000000000000000000000000000000000000000000000000000000000000000937f0000000000000000000000000000000000000000000000000000000000000000955f9560028510611b14576020820135977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8601868111610346579190825b6118fd575050506040013586116118d55782156109f057610fe195856118d0926117c5856131c1565b613586565b7f8ab0bc16000000000000000000000000000000000000000000000000000000005f5260045ffd5b90919897507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8901978989116103465761193e6116556119609a898961324f565b61195561194f6116558d8b8b61324f565b826141ee565b8185879d939d614226565b90604051907f0902f1ac00000000000000000000000000000000000000000000000000000000825260608260048173ffffffffffffffffffffffffffffffffffffffff87165afa918215610e2c575f905f93611ab7575b5073ffffffffffffffffffffffffffffffffffffffff6dffffffffffffffffffffffffffff8082931694169d169116145f14611ab15799905b9980158015611aa9575b611a815782611a0891613988565b916103e88302928084046103e8149015171561034657611a279161325f565b6103e58102908082046103e5149015171561034657611a459161399b565b6001810180911161034657988015610346577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019190826118a7565b7f7b9c8916000000000000000000000000000000000000000000000000000000005f5260045ffd5b5081156119fa565b906119f0565b6dffffffffffffffffffffffffffff80945073ffffffffffffffffffffffffffffffffffffffff9250611b01839260603d8111611b0d575b611af98183612c28565b810190613550565b509590935050506119b7565b503d611aef565b7f20db8267000000000000000000000000000000000000000000000000000000005f5260045ffd5b309161181a565b93949193909290600a8103611c445750505063ffffffff60c08301351682019063ffffffff82351690836020808501948401019101106112945760a061122b5f946111ff86957f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c9560405195869473ffffffffffffffffffffffffffffffffffffffff60208701997f2b67b570000000000000000000000000000000000000000000000000000000008b52166024870152611c026044870182612d9d565b73ffffffffffffffffffffffffffffffffffffffff611c2360808301612d3c565b1660c4870152013560e4850152610100610104850152610124840191612ccf565b91949390929091600b8103611dfb575050611c64602082013591356131e2565b90807f80000000000000000000000000000000000000000000000000000000000000008103611dcc575050475b80611c9d575050610d35565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691823b156102e057604051907fd0e30db00000000000000000000000000000000000000000000000000000000082525f8260048186885af1918215610e2c5773ffffffffffffffffffffffffffffffffffffffff92611dbc575b501690308203611d3f575b506112f5565b60446020925f60405195869485937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af18015610e2c57611d8e575b8080611d39565b611dae9060203d8111611db5575b611da68183612c28565b810190613237565b505f611d87565b503d611d9c565b5f611dc691612c28565b5f611d2e565b471015611c91577f6a12f104000000000000000000000000000000000000000000000000000000005f5260045ffd5b600c8103611f65575050611e0f81356131e2565b9073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016604051917f70a08231000000000000000000000000000000000000000000000000000000008352306004840152602083602481855afa928315610e2c575f93611f31575b5060200135821061130c5781611ea357505050610d35565b803b156102e0575f80916024604051809481937f2e1a7d4d0000000000000000000000000000000000000000000000000000000083528760048401525af18015610e2c57611f21575b503073ffffffffffffffffffffffffffffffffffffffff831603611f11575b80611386565b611f1a916134c8565b5f80611f0b565b5f611f2b91612c28565b5f611eec565b9092506020813d8211611f5d575b81611f4c60209383612c28565b810103126102e05751916020611e8b565b3d9150611f3f565b600d819c939c9b929597989b99949699145f146121ac57508a358b0198893594611f976020808d019e8d030187612f79565b116103a55773ffffffffffffffffffffffffffffffffffffffff7f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c169a935f5b8681101561203d578c73ffffffffffffffffffffffffffffffffffffffff61200760208f8560071b01016131c1565b160361201557600101611fd8565b7fe7002877000000000000000000000000000000000000000000000000000000005f5260045ffd5b50989593979694929b919a50985073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690813b156102e0576040517f0d58b1db000000000000000000000000000000000000000000000000000000008152602060048201526024810184905292839160448301915f905b8082106120fe5750505091815f81819503925af18015610e2c576120ee575b50610d35565b5f6120f891612c28565b5f6120e8565b9193509160808060019273ffffffffffffffffffffffffffffffffffffffff61212688612d3c565b16815273ffffffffffffffffffffffffffffffffffffffff61214a60208901612d3c565b16602082015273ffffffffffffffffffffffffffffffffffffffff61217160408901612d3c565b16604082015273ffffffffffffffffffffffffffffffffffffffff61219860608901612d3c565b1660608201520194019201859392916120c9565b80929b93989550600e919a97969450145f146114f95750604051907f70a0823100000000000000000000000000000000000000000000000000000000825273ffffffffffffffffffffffffffffffffffffffff813516600483015260208260248173ffffffffffffffffffffffffffffffffffffffff84860135165afa918215610e2c575f9261227d575b5060400135111580610fe15791506040517fa328167200000000000000000000000000000000000000000000000000000000602082015260048152611270602482612c28565b9091506020813d82116122a9575b8161229860209383612c28565b810103126102e05751906040612237565b3d915061228b565b6010819c929a97939b96999598949c145f146123cc575061230a915f9160405193849283927f48c89491000000000000000000000000000000000000000000000000000000008452602060048501526024840191612ccf565b03818373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af18015610e2c576123565750610d35565b3d805f833e6123658183612c28565b8101906020818303126102e05780519067ffffffffffffffff82116102e0570181601f820112156102e057805161239b81612c69565b926123a96040519485612c28565b818452602082840101116102e0575f928160208094018483015e0101525f6120e8565b80929495506011919350145f146124ae5750907fffffffff000000000000000000000000000000000000000000000000000000008135167f7ac2ff7b0000000000000000000000000000000000000000000000000000000081036124835750815f929183926040519283928337810183815203908273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af190611270612d0d565b7ff801e525000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b601281036127ad57507f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c917fffffffff000000000000000000000000000000000000000000000000000000008135167f0c49ccbe0000000000000000000000000000000000000000000000000000000081148015612784575b801561275b575b156124835750600481013573ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016936040517f6352211e000000000000000000000000000000000000000000000000000000008152826004820152602081602481895afa908115610e2c5773ffffffffffffffffffffffffffffffffffffffff9182915f9161273d575b50169116908082149182156126a9575b8215612638575b50501561260d575091815f809481946040519384928337810182815203925af190611270612d0d565b7fbb25d4c5000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b909150604051917fe985e9c500000000000000000000000000000000000000000000000000000000835260048301526024820152602081604481885afa908115610e2c575f9161268b575b505f806125e4565b6126a3915060203d8111611db557611da68183612c28565b5f612683565b91506040517f081812fc0000000000000000000000000000000000000000000000000000000081528360048201526020816024818a5afa908115610e2c57839173ffffffffffffffffffffffffffffffffffffffff915f9161270f575b501614916125dd565b612730915060203d8111612736575b6127288183612c28565b81019061349c565b5f612706565b503d61271e565b612755915060203d8111612736576127288183612c28565b5f6125cd565b507f42966c6800000000000000000000000000000000000000000000000000000000811461252f565b507ffc6f7865000000000000000000000000000000000000000000000000000000008114612528565b601381036128b85750505f809160405173ffffffffffffffffffffffffffffffffffffffff60a060208301937f6276cbbe0000000000000000000000000000000000000000000000000000000085528261280682612d3c565b1660248501528261281960208301612d3c565b16604485015262ffffff61282f60408301612d5d565b16606485015261284160608201612d6d565b60020b60848501528261285660808301612d3c565b1660a485015201351660c482015260c4815261287360e482612c28565b51908273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af190611270612d0d565b601481036114f957507fffffffff000000000000000000000000000000000000000000000000000000008235167fdd46508f0000000000000000000000000000000000000000000000000000000081036124835750806004116102e05761294d6129477ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc830160048501612e12565b90612e12565b5f5b8181106129b1575050505f91829147918160405192839283378101848152039173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af190611270612d0d565b6129bc8183856109e4565b3560f81c8015908115612a11575b8115612a06575b506129de5760010161294f565b7f5d1d0f9f000000000000000000000000000000000000000000000000000000005f5260045ffd5b60039150145f6129d1565b6001811491506129ca565b9098959199506021819b939b989598979497145f146114f9575090612a4091613404565b612a836040959395519460208601967f24856bc3000000000000000000000000000000000000000000000000000000008852604060248801526064870191612ccf565b927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc858503016044860152818452602084019160208160051b86010194845f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603015b848310612b3d5750505050505050509181612b2e5f94938594037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612c28565b519082305af190611270612d0d565b90919293949596977fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08582030188528835828112156102e0578301906020823592019167ffffffffffffffff81116102e05780360383136102e057612ba760209283928b95612ccf565b9a01980196959493019190612ae9565b7fff633a38000000000000000000000000000000000000000000000000000000005f5260045ffd5b60a0810190811067ffffffffffffffff821117612bfb57604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117612bfb57604052565b67ffffffffffffffff8111612bfb57601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b7f80000000000000000000000000000000000000000000000000000000000000008114610346575f0390565b601f82602094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe093818652868601375f8582860101520116010190565b3d15612d37573d90612d1e82612c69565b91612d2c6040519384612c28565b82523d5f602084013e565b606090565b359073ffffffffffffffffffffffffffffffffffffffff821682036102e057565b359062ffffff821682036102e057565b35908160020b82036102e057565b908160209103126102e0575190565b359065ffffffffffff821682036102e057565b65ffffffffffff612e0c6060809373ffffffffffffffffffffffffffffffffffffffff612dc982612d3c565b16865273ffffffffffffffffffffffffffffffffffffffff612ded60208301612d3c565b16602087015283612e0060408301612d8a565b16604087015201612d8a565b16910152565b909163ffffffff82351682019263ffffffff8435169260208086019585010191011061129457565b909163ffffffff60608301351682019263ffffffff8435169260208086019585010191011061129457565b9073ffffffffffffffffffffffffffffffffffffffff9283821684841611612f71575b62ffffff90846040519381602086019616865216604084015216606082015260608152612eb6608082612c28565b5190206040517fff00000000000000000000000000000000000000000000000000000000000000602082019081527f000000000000000000000000000000000000000000000000000000000000000060601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602183015260358201929092527f00000000000000000000000000000000000000000000000000000000000000006055820152612f6a81607581016111ff565b5190201690565b909190612e88565b9190820180921161034657565b9092919073ffffffffffffffffffffffffffffffffffffffff84163003612fb357612fb1935061326c565b565b919273ffffffffffffffffffffffffffffffffffffffff8411612ff05773ffffffffffffffffffffffffffffffffffffffff612fb1941692613348565b7fc4bd89a9000000000000000000000000000000000000000000000000000000005f5260045ffd5b939290602b82106103a5578235938460601c92601785013560601c9380851094859760481c62ffffff169061304c92612e65565b73ffffffffffffffffffffffffffffffffffffffff1692845f1460409673ffffffffffffffffffffffffffffffffffffffff80956130e15f9661313495613182576401000276a4925b846130af8e51978f94899560208701526060860191612ccf565b91168d830152037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101855284612c28565b89519b8c998a9889977f128acb080000000000000000000000000000000000000000000000000000000089521660048801526024870152604486015216606484015260a0608484015260a48301906109a1565b03925af18015610e2c575f925f9161314b57509192565b9250506040823d60401161317a575b8161316760409383612c28565b810103126102e057602082519201519192565b3d915061315a565b73fffd8963efd1fc6a506488495d951d5263988d2592613095565b9160608301358301916131ba602084359581860195030185612f79565b116103a557565b3573ffffffffffffffffffffffffffffffffffffffff811681036102e05790565b73ffffffffffffffffffffffffffffffffffffffff8116600181036132285750507f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c90565b60020361323457503090565b90565b908160209103126102e0575180151581036102e05790565b91908110156109f05760051b0190565b9190820391821161034657565b90919073ffffffffffffffffffffffffffffffffffffffff16806132945750612fb1916134c8565b7f800000000000000000000000000000000000000000000000000000000000000082146132c6575b91612fb192613a14565b9050604051917f70a08231000000000000000000000000000000000000000000000000000000008352306004840152602083602481855afa8015610e2c575f90613314575b909250906132bc565b506020833d602011613340575b8161332e60209383612c28565b810103126102e057612fb1925161330b565b3d9150613321565b919273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691823b156102e0575f73ffffffffffffffffffffffffffffffffffffffff9384829681608496816040519b8c9a8b997f36c78516000000000000000000000000000000000000000000000000000000008b521660048a01521660248801521660448601521660648401525af18015610e2c576133fa5750565b5f612fb191612c28565b604081351891606082019363ffffffff6040840135169363ffffffe0601f8601169060608201602086013518179084019260608401359463ffffffff861694641fffffffe0608082019760051b1680915f925b80841061346f57506080925001019101101761129457565b90916020809163ffffffe0601f60808089890101359b848d18179b88010135011601019301929190613457565b908160209103126102e0575173ffffffffffffffffffffffffffffffffffffffff811681036102e05790565b5f80809381935af1156134d757565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f4554485f5452414e534645525f4641494c4544000000000000000000000000006044820152fd5b51906dffffffffffffffffffffffffffff821682036102e057565b908160609103126102e05761356481613535565b91604061357360208401613535565b92015163ffffffff811681036102e05790565b91600282106139605781156109f05761359e836131c1565b82600110156109f0576135ba906115af602086979596016131c1565b50927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101937ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe8201955f906020937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08501965b8884106136415750505050505050505050565b61364f61165585848661324f565b9473ffffffffffffffffffffffffffffffffffffffff61367661165560018801868861324f565b921695604051917f0902f1ac0000000000000000000000000000000000000000000000000000000083526060836004818b5afa918215610e2c57895f945f9461390d575b5073ffffffffffffffffffffffffffffffffffffffff806dffffffffffffffffffffffffffff80602496979816971693169416841494855f146139075791935b604051938480927f70a082310000000000000000000000000000000000000000000000000000000082528d60048301525afa918215610e2c575f926138d8575b50808203928115928380156138d0575b611a8157826103e586029586046103e514911417156103465761376d9084613988565b916103e882029182046103e8141715610346576137939261378d91612f79565b9061399b565b90156138c9575f90915b8b8610156138c057906137be613808926115af61165560028a01888a61324f565b8193917f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000614226565b915b96604051906138198a83612c28565b5f82528b368b840137803b156102e057613894945f8094604051978895869485937f022c0d9f0000000000000000000000000000000000000000000000000000000085526004850152602484015273ffffffffffffffffffffffffffffffffffffffff891660448401526080606484015260848301906109a1565b03925af1918215610e2c576001926138b0575b5093019261362e565b5f6138ba91612c28565b5f6138a7565b5087905f61380a565b5f9161379d565b50811561374a565b9091508981813d8311613900575b6138f08183612c28565b810103126102e05751905f61373a565b503d6138e6565b936136fa565b6dffffffffffffffffffffffffffff9550602493945073ffffffffffffffffffffffffffffffffffffffff86613951829360603d8111611b0d57611af98183612c28565b509890989796505050506136ba565b7fae52ad0c000000000000000000000000000000000000000000000000000000005f5260045ffd5b8181029291811591840414171561034657565b81156139a5570490565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b61271082116139ec57612710916139e891613988565b0490565b7fdeaa01e6000000000000000000000000000000000000000000000000000000005f5260045ffd5b5f9182604492602095604051937fa9059cbb000000000000000000000000000000000000000000000000000000008552600485015260248401525af13d15601f3d1160015f511416171615613a6557565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152fd5b929190600b84101561401c5760078403613c3557613ae292935061474f565b6020810190613af1828261475d565b90505f92613afe836131c1565b90613b0b604085016146bc565b906fffffffffffffffffffffffffffffffff821615613c1c575b92915f915b838310613bab5750505050506060016fffffffffffffffffffffffffffffffff80613b54836146bc565b169216918210613b62575050565b613b7c6fffffffffffffffffffffffffffffffff916146bc565b7f8b063d73000000000000000000000000000000000000000000000000000000005f521660045260245260445ffd5b8496506fffffffffffffffffffffffffffffffff613c0091613be7613be086613bda613c059798999a8c61475d565b906147b1565b9586614ad8565b613bf46080880188610a1d565b949093165f0391614938565b614bff565b946001613c1287936131c1565b9194930191613b2a565b9050613c2f613c2a83614314565b6148f3565b90613b25565b60068403613d2c57613c489293506146ad565b613c5460c082016146bc565b6fffffffffffffffffffffffffffffffff811615613cdb575b613cbe613c0060e092613c9d6fffffffffffffffffffffffffffffffff613c9660a088016146d9565b9216612ca3565b90613cac610100870187610a1d565b929091613cb936896146e6565b614938565b91016fffffffffffffffffffffffffffffffff80613b54836146bc565b50613ce860a082016146d9565b15613d125760e0613cbe613c00613d09613c2a613d04866131c1565b614314565b92505050613c6d565b60e0613cbe613c00613d09613c2a613d04602087016131c1565b60098403613ecf57613d3f92935061474f565b6020810190613d4e828261475d565b5f939150613d5e604084016146bc565b613d67846131c1565b916fffffffffffffffffffffffffffffffff821615613ebb575b92919290815b613e0457505050506060016fffffffffffffffffffffffffffffffff80613dad836146bc565b169216918211613dbb575050565b613dd56fffffffffffffffffffffffffffffffff916146bc565b7f12bacdd3000000000000000000000000000000000000000000000000000000005f521660045260245260445ffd5b829395506fffffffffffffffffffffffffffffffff613e7b91613e61613e5a613e31613e8596978a61475d565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8901916147b1565b9889614ad8565b90613e6f60808b018b610a1d565b94909316911590614938565b600f0b5f036148f3565b937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613eb186926131c1565b9392019081613d87565b9050613ec9613c2a8361462e565b90613d81565b60088414613f06575050505b7f5cda29d7000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b613f119293506146ad565b613f1d60c082016146bc565b6fffffffffffffffffffffffffffffffff811615613fa1575b613f84613c2a613f7c6fffffffffffffffffffffffffffffffff60e094613f5f60a088016146d9565b613f6d610100890189610a1d565b9390921690613cb9368a6146e6565b600f0b612ca3565b91016fffffffffffffffffffffffffffffffff80613dad836146bc565b50613fae60a082016146d9565b15613ff15760e0613f84613c2a613f7c6fffffffffffffffffffffffffffffffff613fe6613c2a613fe1602089016131c1565b61462e565b945050505050613f36565b60e0613f84613c2a613f7c6fffffffffffffffffffffffffffffffff613fe6613c2a613fe1886131c1565b92600c81036140a05750614030919261461b565b9061403a8161462e565b91808311614070575090612fb1917f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c90614495565b90507f12bacdd3000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b600f810361412357506140b3919261461b565b906140bd81614314565b918083106140f3575090612fb1917f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c9061438d565b90507f8b063d73000000000000000000000000000000000000000000000000000000005f5260045260245260445ffd5b600b810361417c575061413a90612fb192936142fc565b156141715761416b827f0e87e1788ebd9ed6a7e63c70a374cd3283e41cad601d21fbe27863899ed4a7085c92614454565b91614495565b61416b823092614454565b600e81036141af57506141a36141996141a992612fb194956142fc565b92829492916131e2565b92614440565b9161438d565b92601084146141c057505050613edb565b612fb19293506141d66141df926141a9926142fc565b929193906131e2565b916141e984614314565b6139d2565b73ffffffffffffffffffffffffffffffffffffffff821673ffffffffffffffffffffffffffffffffffffffff8216105f14610a855791565b91612f6a9073ffffffffffffffffffffffffffffffffffffffff947fffffffffffffffffffffffffffffffffffffffff0000000000000000000000006040519181602084019460601b16845260601b1660348201526028815261428a604882612c28565b5190206111ff604051938492602084019687917fffffffffffffffffffffffffffffffffffffffff000000000000000000000000605594927fff00000000000000000000000000000000000000000000000000000000000000855260601b166001840152601583015260358201520190565b90606011611294578035916040602083013592013590565b61433f81307f00000000000000000000000000000000000000000000000000000000000000006147f1565b905f821261434b575090565b73ffffffffffffffffffffffffffffffffffffffff907f4c085bf1000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b9091801561443b5773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016803b156102e0575f928360649273ffffffffffffffffffffffffffffffffffffffff948560405198899788967f0b0d9c0900000000000000000000000000000000000000000000000000000000885216600487015216602485015260448401525af18015610e2c576133fa5750565b505050565b9081614450576132349150614314565b5090565b907f8000000000000000000000000000000000000000000000000000000000000000820361448657613234915061488b565b8161445057613234915061462e565b5f9183156146155773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001691823b156102e05773ffffffffffffffffffffffffffffffffffffffff604051917fa584119400000000000000000000000000000000000000000000000000000000835216908160048201525f8160248183885af18015610e2c57614600575b50806145b35750506020906004604051809581937f11da60b40000000000000000000000000000000000000000000000000000000083525af19081156145a7575061457c5750565b61459d9060203d6020116145a0575b6145958183612c28565b810190612d7b565b50565b503d61458b565b604051903d90823e3d90fd5b839483602094936145c393612f86565b6004604051809581937f11da60b40000000000000000000000000000000000000000000000000000000083525af19081156145a7575061457c5750565b61460d9194505f90612c28565b5f925f614534565b50505050565b9190604011611294576020823592013590565b61465981307f00000000000000000000000000000000000000000000000000000000000000006147f1565b905f821361466b575061323490612ca3565b73ffffffffffffffffffffffffffffffffffffffff907f3351b260000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b90610140116112945780350190565b356fffffffffffffffffffffffffffffffff811681036102e05790565b3580151581036102e05790565b91908260a09103126102e0576040516146fe81612bdf565b608061474a81839561470f81612d3c565b855261471d60208201612d3c565b602086015261472e60408201612d5d565b604086015261473f60608201612d6d565b606086015201612d3c565b910152565b9060a0116112945780350190565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1813603018212156102e0570180359067ffffffffffffffff82116102e057602001918160051b360383136102e057565b91908110156109f05760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff61813603018212156102e0570190565b73ffffffffffffffffffffffffffffffffffffffff809381602094165f52168252602460405f2060405194859384927ff135baaa0000000000000000000000000000000000000000000000000000000084526004840152165afa908115610e2c575f9161485c575090565b90506020813d602011614883575b8161487760209383612c28565b810103126102e0575190565b3d915061486a565b73ffffffffffffffffffffffffffffffffffffffff16806148ab57504790565b6020602491604051928380927f70a082310000000000000000000000000000000000000000000000000000000082523060048301525afa908115610e2c575f9161485c575090565b906fffffffffffffffffffffffffffffffff821680920361491057565b7f93dafdf1000000000000000000000000000000000000000000000000000000005f5260045ffd5b9092908315614abd576401000276a4905b60405194606086019386851067ffffffffffffffff861117612bfb5773ffffffffffffffffffffffffffffffffffffffff9788608095614a2b946020986040521515998a8152888101908a82528360408201931683526040519c8d998a997ff3cd914c000000000000000000000000000000000000000000000000000000008b528281511660048c0152828d8201511660248c015262ffffff60408201511660448c0152606081015160020b60648c0152015116608489015251151560a48801525160c4870152511660e4850152610120610104850152610124840191612ccf565b03815f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000165af1928315610e2c575f93614a89575b505f1303614a8357600f0b90565b60801d90565b9092506020813d602011614ab5575b81614aa560209383612c28565b810103126102e05751915f614a75565b3d9150614a98565b73fffd8963efd1fc6a506488495d951d5263988d2590614949565b905f6080604051614ae881612bdf565b8281528260208201528260408201528260608201520152614b08826131c1565b73ffffffffffffffffffffffffffffffffffffffff82169173ffffffffffffffffffffffffffffffffffffffff82168084105f14614be0575073ffffffffffffffffffffffffffffffffffffffff905b1680921492602081013562ffffff81168091036102e0576040820135918260020b8093036102e057606001359273ffffffffffffffffffffffffffffffffffffffff84168094036102e05773ffffffffffffffffffffffffffffffffffffffff9060405195614bc687612bdf565b865216602085015260408401526060830152608082015291565b91505073ffffffffffffffffffffffffffffffffffffffff8291614b58565b5f81600f0b12614910576fffffffffffffffffffffffffffffffff169056fea164736f6c634300081a000a";
28
+ }
29
+ }