From d6cadaf9e8d51252bd34a722eadaf6576d48679b Mon Sep 17 00:00:00 2001 From: David Meister Date: Wed, 10 Jun 2026 20:13:55 +0000 Subject: [PATCH 1/8] feat(raindex): track per-(user, token) dust credit across token moves Lossy float->fixed-decimal token moves leave a sub-base-unit remainder: `pullTokens` rounds the transfer UP (the orderbook receives the excess), `pushTokens` rounds it DOWN (the orderbook keeps the shortfall). Both residues are real tokens the orderbook already holds on behalf of the user. Rather than stranding them as orphaned dust, book the residue into a new `sDustCredit[user][token]` ledger (token units) and realize it into the next move for the same `(user, token)`: - pull reduces the amount pulled by any standing credit, so a whole base unit of accumulated credit is recovered instead of re-pulled; - push increases the amount pushed by any standing credit, so an accumulated whole base unit is paid out instead of re-truncated. Each conversion stays conservative (pull rounds up, push rounds down) but the remainder is now exactly accounted instead of lost. The credit is always non-negative and under one base unit, and is always backed by tokens the orderbook provably holds for that user, so realizing it never dips into a vault balance: the solvency invariant (real balance >= sum of vault balances + tracked credits) is preserved. To keep RaindexV6 under EIP-170, factor the duplicated TOFU decimals-read that opened both pull/push into a shared `_tokenDecimals` helper. Closes #2673 Co-Authored-By: Claude Opus 4.8 --- src/concrete/raindex/RaindexV6.sol | 98 ++++-- .../raindex/RaindexV6.dustCredit.t.sol | 299 ++++++++++++++++++ 2 files changed, 374 insertions(+), 23 deletions(-) create mode 100644 test/concrete/raindex/RaindexV6.dustCredit.t.sol diff --git a/src/concrete/raindex/RaindexV6.sol b/src/concrete/raindex/RaindexV6.sol index 6a476a300a..d08b8be81c 100644 --- a/src/concrete/raindex/RaindexV6.sol +++ b/src/concrete/raindex/RaindexV6.sol @@ -212,6 +212,20 @@ contract RaindexV6 is IRaindexV6, IMetaV1_2, ReentrancyGuard, Multicall, Raindex mapping(address owner => mapping(address token => mapping(bytes32 vaultId => Float balance))) internal sVaultBalances; + /// @dev Per `(user, token)` ledger of the sub-base-unit remainder that the + /// orderbook holds on behalf of `user` but has not yet moved, because a + /// lossy float->fixed-decimal conversion in `pullTokens`/`pushTokens` cannot + /// transfer a fraction of a base unit. The credit is always non-negative and + /// strictly less than one base unit: whenever it reaches a whole base unit it + /// is realized into the next token move for that `(user, token)`. It is + /// denominated in token units (a `Float`) so it is independent of the token's + /// decimals. Every credit is backed by real tokens the orderbook already + /// holds (a pull rounds the transfer up, a push rounds it down), so realizing + /// it only ever releases provable excess and never dips into a vault balance. + // Solhint and slither disagree on this. Slither wins. + //solhint-disable-next-line private-vars-leading-underscore + mapping(address user => mapping(address token => Float credit)) internal sDustCredit; + /// @inheritdoc IRaindexV6 function vaultBalance2(address owner, address token, bytes32 vaultId) external view override returns (Float) { return _vaultBalance(owner, token, vaultId); @@ -1133,6 +1147,16 @@ contract RaindexV6 is IRaindexV6, IMetaV1_2, ReentrancyGuard, Multicall, Raindex } } + /// @dev Reads `token`'s decimals via TOFU, reverting if the read is not + /// consistent with what was seen before. Shared by `pullTokens`/`pushTokens`. + function _tokenDecimals(address token) internal returns (uint8) { + (TOFUOutcome tofuOutcome, uint8 decimals) = LibTOFUTokenDecimals.decimalsForToken(token); + if (tofuOutcome != TOFUOutcome.Consistent && tofuOutcome != TOFUOutcome.Initial) { + revert ITOFUTokenDecimals.TokenDecimalsReadFailure(token, tofuOutcome); + } + return decimals; + } + /// @dev Pulls `amount` of `token` from `account` via `safeTransferFrom`. /// Returns the fixed-decimal amount transferred and the token decimals. /// @@ -1140,29 +1164,46 @@ contract RaindexV6 is IRaindexV6, IMetaV1_2, ReentrancyGuard, Multicall, Raindex /// never pulls in less than the vault accounting credits. `pushTokens` rounds /// DOWN for the same protocol-favoring reason. Together this keeps the /// orderbook solvent — its real token balance is always >= the sum of the - /// vault balances — but each lossy conversion leaves a sub-token-unit residue - /// in the contract that is not attributed to any vault and has no recovery - /// path. Such dust is under one base unit per conversion and can never cause - /// insolvency. + /// vault balances. The sub-base-unit residue each lossy conversion would + /// otherwise strand is instead booked into `sDustCredit[account][token]` and + /// realized into the next move for the same `(account, token)`: the pull is + /// reduced by any whole base unit of standing credit, and the fresh over-pull + /// is added to it. The credit is always backed by tokens the orderbook holds + /// for `account`, so this is exactly conservative and never insolvent. function pullTokens(address account, address token, Float amount) internal returns (uint256, uint8) { - (TOFUOutcome tofuOutcome, uint8 decimals) = LibTOFUTokenDecimals.decimalsForToken(token); - if (tofuOutcome != TOFUOutcome.Consistent && tofuOutcome != TOFUOutcome.Initial) { - revert ITOFUTokenDecimals.TokenDecimalsReadFailure(token, tofuOutcome); - } + uint8 decimals = _tokenDecimals(token); if (amount.lt(LibDecimalFloat.FLOAT_ZERO)) { revert NegativePull(); } - (uint256 amount18, bool lossless) = LibDecimalFloat.toFixedDecimalLossy(amount, decimals); - // Round truncation up when pulling. - if (!lossless) { - // This needs to be checked math as an overflow would cause tokens - // to silently not be pulled (wraps to 0). - ++amount18; - } - if (amount18 > 0) { + // The orderbook already holds the standing credit (token units) for + // `account` from prior over-pulls / under-pushes, so it only needs to + // pull in the part of `amount` that the credit does not already cover. + Float effective = amount.sub(sDustCredit[account][token]); + + uint256 amount18; + // A non-positive `effective` means the credit already covers the whole + // pull, so no tokens move; `toFixedDecimalLossy` also rejects negatives. + if (effective.gt(LibDecimalFloat.FLOAT_ZERO)) { + bool lossless; + (amount18, lossless) = LibDecimalFloat.toFixedDecimalLossy(effective, decimals); + // Round truncation up when pulling. + if (!lossless) { + // This needs to be checked math as an overflow would cause tokens + // to silently not be pulled (wraps to 0). + ++amount18; + } IERC20(token).safeTransferFrom(account, address(this), amount18); } + + // The new credit is the transferred amount minus what `effective` + // required: the over-pull when tokens moved (rounded up, so non-negative + // and under one base unit), or the leftover credit when none did. It is + // backed by tokens the orderbook holds for `account`. + //slither-disable-next-line unused-return + (Float pulled,) = LibDecimalFloat.fromFixedDecimalLossyPacked(amount18, decimals); + sDustCredit[account][token] = pulled.sub(effective); + return (amount18, decimals); } @@ -1171,20 +1212,31 @@ contract RaindexV6 is IRaindexV6, IMetaV1_2, ReentrancyGuard, Multicall, Raindex /// /// A lossy float->fixed-decimal conversion is truncated (rounded DOWN) here /// so the contract never sends more than the vault accounting debits. See - /// `pullTokens` for the full rounding policy and its solvency / residual-dust - /// tradeoff. + /// `pullTokens` for the full rounding policy. The sub-base-unit residue each + /// lossy conversion would otherwise strand is booked into + /// `sDustCredit[account][token]` and realized into the next move for the same + /// `(account, token)`: the push is increased by any whole base unit of + /// standing credit, and the fresh under-push is added to it. function pushTokens(address account, address token, Float amountFloat) internal returns (uint256, uint8) { - (TOFUOutcome tofuOutcome, uint8 decimals) = LibTOFUTokenDecimals.decimalsForToken(token); - if (tofuOutcome != TOFUOutcome.Consistent && tofuOutcome != TOFUOutcome.Initial) { - revert ITOFUTokenDecimals.TokenDecimalsReadFailure(token, tofuOutcome); - } + uint8 decimals = _tokenDecimals(token); if (amountFloat.lt(LibDecimalFloat.FLOAT_ZERO)) { revert NegativePush(); } + // The orderbook also owes `account` the standing credit from prior + // under-pushes, so the total it may send is `amountFloat + credit`. + Float effective = amountFloat.add(sDustCredit[account][token]); + + //slither-disable-next-line unused-return + (uint256 amount,) = LibDecimalFloat.toFixedDecimalLossy(effective, decimals); + // The shortfall truncated away is the new credit. It is non-negative + // because the transfer was rounded down, and under one base unit because + // truncation drops less than one base unit. //slither-disable-next-line unused-return - (uint256 amount,) = LibDecimalFloat.toFixedDecimalLossy(amountFloat, decimals); + (Float pushed,) = LibDecimalFloat.fromFixedDecimalLossyPacked(amount, decimals); + sDustCredit[account][token] = effective.sub(pushed); + if (amount > 0) { IERC20(token).safeTransfer(account, amount); } diff --git a/test/concrete/raindex/RaindexV6.dustCredit.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.t.sol new file mode 100644 index 0000000000..bc5338b01e --- /dev/null +++ b/test/concrete/raindex/RaindexV6.dustCredit.t.sol @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {Test} from "forge-std-1.16.1/src/Test.sol"; +import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; +import {MockToken} from "test/util/concrete/MockToken.sol"; +import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; +import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; + +/// @dev Exposes RaindexV6's internal token-move helpers and the dust-credit +/// ledger for testing. +contract RaindexV6DustCreditHarness is RaindexV6 { + function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { + return pullTokens(account, token, amount); + } + + function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { + return pushTokens(account, token, amount); + } + + function exposedDustCredit(address user, address token) external view returns (Float) { + return sDustCredit[user][token]; + } +} + +/// @title RaindexV6DustCreditTest +/// @notice L01 follow-up (#2673): every lossy float->fixed-decimal token move +/// leaves a sub-base-unit remainder. `pullTokens` rounds the transfer UP (the +/// orderbook receives the excess) and `pushTokens` rounds it DOWN (the orderbook +/// keeps the shortfall); in both cases the residue is real tokens the orderbook +/// holds on behalf of `account`. Rather than stranding it, the residue is booked +/// into `sDustCredit[account][token]` (token units) and realized into the next +/// move for the same `(account, token)`. +/// +/// The solvency invariant is paramount: the orderbook's real token balance must +/// always cover every vault obligation plus every tracked credit, and a credit +/// can only ever release tokens the orderbook provably already holds for that +/// user, so no move can over-credit or dip into a vault balance. The conservation +/// invariant exercised throughout is, in token units: +/// +/// realBalanceDelta == netRequested + credit +/// +/// where `netRequested` is the sum of requested pull amounts minus push amounts +/// (the exact economic value the vault accounting moved) and `credit` is the +/// standing ledger entry. It holds exactly after every move. +contract RaindexV6DustCreditTest is Test { + using LibDecimalFloat for Float; + + RaindexV6DustCreditHarness internal harness; + address internal owner = makeAddr("owner"); + // 6-decimal token: one base unit is 1e-6 token units. + MockToken internal token; + + function setUp() external { + // pullTokens/pushTokens read token decimals via the deployed TOFU + // contract, so it must exist before any move. + LibRainDeploy.etchZoltuFactory(vm); + LibRainDeploy.deployZoltu(LibTOFUTokenDecimals.TOFU_DECIMALS_EXPECTED_CREATION_CODE); + + // Etch the runtime code so the large RaindexV6-derived harness isn't + // subject to the EIP-170 creation size limit. + harness = RaindexV6DustCreditHarness(payable(address(uint160(uint256(keccak256("dust.credit.harness")))))); + vm.etch(address(harness), type(RaindexV6DustCreditHarness).runtimeCode); + + token = new MockToken("Token", "TKN", 6); + // Both sides are funded generously so transfers never fail for lack of + // balance/approval; the tests assert exact deltas, not absolute balances. + token.mint(owner, 1e18); + token.mint(address(harness), 1e18); + vm.prank(owner); + token.approve(address(harness), type(uint256).max); + } + + /// At rest the ledger is empty. + function testDustCreditStartsZero() external view { + assertTrue(harness.exposedDustCredit(owner, address(token)).isZero(), "credit starts zero"); + } + + /// Two consecutive pulls of 1.5 base units. The first is lossy and rounds the + /// transfer up to 2, booking 0.5 base units of credit. The second consumes + /// that credit: it only needs to pull 1.0 base unit (lossless), so exactly 1 + /// is transferred and the ledger returns to zero. Total moved is 3 base units + /// for 3.0 requested - the round-up dust is recovered, not stranded. + /// Pins the realize-into-next-pull path: a mutation that ignores the standing + /// credit pulls 2 again on the second move (4 total) and leaves a stale + /// credit. + function testPullRealizesCreditIntoNextPull() external { + // 1.5 base units = 15e-7 token units. + Float amount = LibDecimalFloat.packLossless(15, -7); + + (uint256 moved1,) = harness.exposedPull(owner, address(token), amount); + assertEq(moved1, 2, "first pull rounds up to 2"); + // Credit is 2 - 1.5 = 0.5 base units = 5e-7 token units. + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(5, -7)), "credit 0.5" + ); + + (uint256 moved2,) = harness.exposedPull(owner, address(token), amount); + assertEq(moved2, 1, "second pull consumes credit and moves only 1"); + assertTrue(harness.exposedDustCredit(owner, address(token)).isZero(), "credit cleared"); + + // Exactly 3 base units moved into the harness for 3.0 requested. + assertEq(moved1 + moved2, 3, "exact conservation across two pulls"); + } + + /// Two consecutive pushes of 1.5 base units. The first rounds the transfer + /// down to 1, booking 0.5 base units of credit (owed to the user). The second + /// realizes it: 1.5 + 0.5 = 2.0 base units, so exactly 2 are transferred and + /// the ledger returns to zero. Total moved is 3 base units for 3.0 owed - the + /// round-down dust is paid out, not stranded. + /// Pins the realize-into-next-push path: a mutation that ignores the standing + /// credit pushes 1 again on the second move (2 total) and leaves a stale + /// credit. + function testPushRealizesCreditIntoNextPush() external { + Float amount = LibDecimalFloat.packLossless(15, -7); + + (uint256 moved1,) = harness.exposedPush(owner, address(token), amount); + assertEq(moved1, 1, "first push rounds down to 1"); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(5, -7)), "credit 0.5" + ); + + (uint256 moved2,) = harness.exposedPush(owner, address(token), amount); + assertEq(moved2, 2, "second push realizes the whole-unit credit"); + assertTrue(harness.exposedDustCredit(owner, address(token)).isZero(), "credit cleared"); + + assertEq(moved1 + moved2, 3, "exact conservation across two pushes"); + } + + /// Sub-base-unit pushes accumulate until they cross a whole base unit. Three + /// pushes of 0.4 base units each: 0.4 -> 0.8 -> 1.2. Only the third move + /// transfers a token (1 base unit), leaving 0.2 base units of credit. The + /// orderbook never over-pays: it pays a whole unit only once the owed + /// fraction has provably accumulated past one. + /// Pins the sub-unit accumulation crossing a whole unit: a mutation that + /// resets the credit each move never reaches the boundary and transfers 0 + /// three times. + function testPushAccumulatesSubUnitToWholeUnit() external { + // 0.4 base units = 4e-7 token units. + Float amount = LibDecimalFloat.packLossless(4, -7); + + (uint256 moved1,) = harness.exposedPush(owner, address(token), amount); + assertEq(moved1, 0, "0.4 pushes nothing"); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(4, -7)), "credit 0.4" + ); + + (uint256 moved2,) = harness.exposedPush(owner, address(token), amount); + assertEq(moved2, 0, "0.8 pushes nothing"); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(8, -7)), "credit 0.8" + ); + + (uint256 moved3,) = harness.exposedPush(owner, address(token), amount); + assertEq(moved3, 1, "1.2 crosses a whole unit, pushes 1"); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(2, -7)), "credit 0.2" + ); + } + + /// A pull whose amount is smaller than the standing credit moves no tokens at + /// all and only shrinks the credit. First a 1.5 base-unit pull books 0.5 base + /// units of credit; then a 0.3 base-unit pull is fully covered by that credit, + /// so nothing is pulled and the credit drops to 0.2 base units. This is the + /// conservative "credit covers the whole pull" branch. + /// Pins the no-transfer credit-shrink path: a mutation that always pulls at + /// least one base unit (ignoring the covering credit) moves a token here and + /// over-charges the owner. + function testPullCoveredEntirelyByCredit() external { + // Seed 0.5 base units of credit with a 1.5 base-unit pull. + (uint256 seeded,) = harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(15, -7)); + assertEq(seeded, 2, "seed pull moves 2"); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(5, -7)), "seed credit 0.5" + ); + + uint256 ownerBefore = token.balanceOf(owner); + // 0.3 base units < 0.5 credit, so no tokens move. + (uint256 moved,) = harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(3, -7)); + assertEq(moved, 0, "covered pull moves nothing"); + assertEq(token.balanceOf(owner), ownerBefore, "owner balance unchanged"); + // Credit shrinks by the requested 0.3 to 0.2 base units. + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(2, -7)), "credit 0.2" + ); + } + + /// A push that realizes accumulated credit DOES pay an extra base unit out of + /// the orderbook. Seed 0.8 base units of credit (two 0.4 pushes), then a push + /// of 0.5 base units: 0.5 + 0.8 = 1.3, so the orderbook transfers 1 base unit + /// it would otherwise have truncated away, and 0.3 base units of credit + /// remain. Confirms credit can only ADD to a push (never subtract), keeping it + /// solvent. + function testPushCreditAddsExtraUnit() external { + harness.exposedPush(owner, address(token), LibDecimalFloat.packLossless(4, -7)); + harness.exposedPush(owner, address(token), LibDecimalFloat.packLossless(4, -7)); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(8, -7)), "credit 0.8" + ); + + uint256 ownerBefore = token.balanceOf(owner); + // 0.5 + 0.8 = 1.3 base units -> transfer 1, keep 0.3. + (uint256 moved,) = harness.exposedPush(owner, address(token), LibDecimalFloat.packLossless(5, -7)); + assertEq(moved, 1, "0.5 push with 0.8 credit transfers a realized unit"); + assertEq(token.balanceOf(owner) - ownerBefore, 1, "owner received exactly 1 base unit"); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(3, -7)), "credit 0.3" + ); + } + + /// A lossless move never touches the ledger. A 3-base-unit pull (3e-6, exact + /// at 6 decimals) transfers exactly 3 and leaves the credit at zero. Pins that + /// the ledger is only written when there is a genuine remainder. + function testLosslessMoveLeavesCreditZero() external { + (uint256 moved,) = harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(3, -6)); + assertEq(moved, 3, "lossless pull moves exactly 3"); + assertTrue(harness.exposedDustCredit(owner, address(token)).isZero(), "lossless leaves credit zero"); + } + + /// The credit ledger is keyed per `(user, token)`: a remainder accrued for one + /// user is never visible to or realized by another. Two different owners each + /// pulling 1.5 base units both round up independently to 2 and each carry their + /// own 0.5 base-unit credit. Pins the mapping key so a mutation collapsing the + /// ledger to a single global slot is caught. + function testCreditIsolatedPerUser() external { + address other = makeAddr("other"); + token.mint(other, 1e18); + vm.prank(other); + token.approve(address(harness), type(uint256).max); + + Float amount = LibDecimalFloat.packLossless(15, -7); + (uint256 movedOwner,) = harness.exposedPull(owner, address(token), amount); + (uint256 movedOther,) = harness.exposedPull(other, address(token), amount); + + assertEq(movedOwner, 2, "owner rounds up independently"); + assertEq(movedOther, 2, "other rounds up independently"); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(5, -7)), "owner credit" + ); + assertTrue( + harness.exposedDustCredit(other, address(token)).eq(LibDecimalFloat.packLossless(5, -7)), "other credit" + ); + } + + /// Fuzz: an arbitrary sequence of pulls and pushes preserves the conservation + /// and solvency invariants after EVERY move. + /// + /// - Conservation (exact): the harness's real token-balance delta in token + /// units equals `netRequested + credit`. Every base unit that physically + /// moved is accounted for by the requested economic value plus the standing + /// credit - no dust is created or destroyed. + /// - Solvency: the credit is always non-negative and strictly less than one + /// base unit, so the orderbook can never over-credit (a credit is always + /// backed by real tokens it already holds) and never strands a whole base + /// unit it should have realized. + /// forge-config: default.fuzz.runs = 2000 + function testConservationAndSolvencyInvariant(bool[] memory isPull, uint8[] memory units) external { + vm.assume(isPull.length > 0); + uint256 n = isPull.length < units.length ? isPull.length : units.length; + vm.assume(n > 0); + + // One base unit is 1e-6 token units at 6 decimals. + Float oneBaseUnit = LibDecimalFloat.packLossless(1, -6); + + int256 harnessStart = int256(token.balanceOf(address(harness))); + // netRequested is tracked in tenths of a base unit (each move is units/10 + // base units) to stay in exact integer arithmetic; compared as a Float. + int256 netRequestedTenths = 0; + + for (uint256 i = 0; i < n; i++) { + // Each move is between 0.0 and 25.5 base units (units/10), spanning + // sub-unit, whole, and mixed magnitudes. + uint256 u = units[i]; + // requested amount in token units: u * 1e-7 (u tenths of a base unit). + Float amount = LibDecimalFloat.packLossless(int256(u), -7); + + if (isPull[i]) { + harness.exposedPull(owner, address(token), amount); + netRequestedTenths += int256(u); + } else { + harness.exposedPush(owner, address(token), amount); + netRequestedTenths -= int256(u); + } + + // Conservation: realBalanceDelta == netRequested + credit (token units). + int256 harnessDeltaBaseUnits = int256(token.balanceOf(address(harness))) - harnessStart; + Float realDelta = LibDecimalFloat.packLossless(harnessDeltaBaseUnits, -6); + Float credit = harness.exposedDustCredit(owner, address(token)); + Float netRequested = LibDecimalFloat.packLossless(netRequestedTenths, -7); + assertTrue(realDelta.eq(netRequested.add(credit)), "conservation: realDelta == netRequested + credit"); + + // Solvency: 0 <= credit < 1 base unit. + assertTrue(!credit.lt(LibDecimalFloat.FLOAT_ZERO), "credit non-negative"); + assertTrue(credit.lt(oneBaseUnit), "credit under one base unit"); + } + } +} From e58285913274559f58dedb8300871142922a6a87 Mon Sep 17 00:00:00 2001 From: David Meister Date: Wed, 10 Jun 2026 20:39:38 +0000 Subject: [PATCH 2/8] test(raindex): harvest adversarial dust-credit verification tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These tests were written by independent skeptic reviewers during the #2702 solvency verification to attack the per-(user, token) dust-credit ledger. They are committed here verbatim (tests only — no source changes) so the adversarial coverage and the regression they uncovered are preserved on the PR branch. - test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol Passing coverage. Cross-account pooled solvency, same-tx arrive-and-leave on one token, large-amount push (credit-not-inflated), and cumulative never-over-pay. All green against the current bytecode. - test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol Passing coverage. Round-trip/boundary conservation across decimals (0..60), int224 boundary, high-decimals credit-not-dropped, and a wide fuzz. All green. - test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol CURRENTLY-FAILING regression gate. Two tests fail against #2702's current (buggy) code and document a solvency shortfall that appears at very large amounts (above ~1e50 token units): testTwoPullSolvencySlack shows the orderbook taking in fewer base units than it books as owed (a 1e68-base-unit obligation backed by 1e68 - 8), and testPullMagnitudeScanConservation shows movedTotal != netRequested + credit once the exponent gap drops the standing credit. These are intentionally red — they pin the regression and must not be made green by touching source. Co-Authored-By: Claude Opus 4.8 --- ...ndexV6.dustCredit.conservationAttack.t.sol | 312 +++++++++++++ ...RaindexV6.dustCredit.precisionAttack.t.sol | 440 ++++++++++++++++++ .../RaindexV6.dustCredit.solvencyAttack.t.sol | 254 ++++++++++ 3 files changed, 1006 insertions(+) create mode 100644 test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol create mode 100644 test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol create mode 100644 test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol diff --git a/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol new file mode 100644 index 0000000000..3c56dc5215 --- /dev/null +++ b/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {Test} from "forge-std-1.16.1/src/Test.sol"; +import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; +import {MockToken} from "test/util/concrete/MockToken.sol"; +import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; +import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; + +contract RaindexV6DustCreditConservationAttackHarness is RaindexV6 { + function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { + return pullTokens(account, token, amount); + } + + function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { + return pushTokens(account, token, amount); + } + + function exposedDustCredit(address user, address token) external view returns (Float) { + return sDustCredit[user][token]; + } +} + +/// @title Adversarial conservation attack on the dust-credit ledger. +contract RaindexV6DustCreditConservationAttackTest is Test { + using LibDecimalFloat for Float; + + RaindexV6DustCreditConservationAttackHarness internal harness; + address internal owner = makeAddr("owner"); + + function setUp() external { + LibRainDeploy.etchZoltuFactory(vm); + LibRainDeploy.deployZoltu(LibTOFUTokenDecimals.TOFU_DECIMALS_EXPECTED_CREATION_CODE); + harness = RaindexV6DustCreditConservationAttackHarness( + payable(address(uint160(uint256(keccak256("dust.credit.conservation.attack.harness"))))) + ); + vm.etch(address(harness), type(RaindexV6DustCreditConservationAttackHarness).runtimeCode); + } + + function _mkToken(uint8 decimals) internal returns (MockToken token) { + token = new MockToken("Token", "TKN", decimals); + // Stay well under int256 max so the int256 casts in the conservation + // checks never overflow on the harness side (this is a test-harness + // limit, not a contract limit). + uint256 supply = uint256(type(int256).max) / 4; + token.mint(owner, supply); + token.mint(address(harness), supply); + vm.prank(owner); + token.approve(address(harness), type(uint256).max); + } + + // Helper: assert 0 <= credit < 1 base unit (1 base unit = 10^-decimals token units). + function _assertCreditInvariant(MockToken token, uint8 decimals) internal view { + Float credit = harness.exposedDustCredit(owner, address(token)); + assertTrue(!credit.lt(LibDecimalFloat.FLOAT_ZERO), "credit negative"); + Float oneBaseUnit = LibDecimalFloat.packLossless(1, -int256(uint256(decimals))); + assertTrue(credit.lt(oneBaseUnit), "credit >= 1 base unit"); + } + + /// ATTACK 1: very large amount on a low-decimals token, near uint256 transfer + /// limits, to probe the int224 truncation in the from-fixed round trip. + /// We use an amount with significant low-order digits so any truncation in + /// packLossy would show up as a wrong credit / wrong conservation. + function testLargeAmountRoundTripPull() external { + uint8 decimals = 6; + MockToken token = _mkToken(decimals); + + // amount = 1.2345...e40 token units with a fractional sub-base-unit tail. + // coefficient 123456789012345678901234567890123456789 (39 sig digits), + // exponent -7 => value has a 0.x base-unit fractional remainder. + Float amount = LibDecimalFloat.packLossless(123456789012345678901234567890123456789, -7); + + uint256 balBefore = token.balanceOf(address(harness)); + (uint256 moved,) = harness.exposedPull(owner, address(token), amount); + uint256 balAfter = token.balanceOf(address(harness)); + assertEq(balAfter - balBefore, moved, "moved matches real transfer"); + + _assertCreditInvariant(token, decimals); + + // Conservation: realDelta(token units) == amount + credit (no prior credit). + Float realDelta = LibDecimalFloat.fromFixedDecimalLosslessPacked(moved, decimals); + Float credit = harness.exposedDustCredit(owner, address(token)); + // realDelta should equal amount + credit (pull over-pulls so realDelta>=amount). + assertTrue(realDelta.eq(amount.add(credit)), "conservation pull large"); + } + + /// ATTACK 2: alternate pull/push at sub-base-unit boundaries across many + /// steps, tracking conservation exactly, on an 18-decimal token. + function testAlternatingBoundary() external { + uint8 decimals = 18; + MockToken token = _mkToken(decimals); + + int256 netRequestedTenths = 0; + int256 startBal = int256(token.balanceOf(address(harness))); + + // Sequence of (isPull, tenthsOfBaseUnit). + int256[10] memory amounts = [int256(15), 7, 23, 4, 99, 1, 250, 13, 6, 88]; + bool[10] memory pulls = [true, false, true, true, false, false, true, false, true, false]; + + for (uint256 i = 0; i < 10; i++) { + Float amount = LibDecimalFloat.packLossless(amounts[i], -int256(uint256(decimals)) - 1); + if (pulls[i]) { + harness.exposedPull(owner, address(token), amount); + netRequestedTenths += amounts[i]; + } else { + harness.exposedPush(owner, address(token), amount); + netRequestedTenths -= amounts[i]; + } + int256 delta = int256(token.balanceOf(address(harness))) - startBal; + Float realDelta = LibDecimalFloat.packLossless(delta, -int256(uint256(decimals))); + Float netReq = LibDecimalFloat.packLossless(netRequestedTenths, -int256(uint256(decimals)) - 1); + Float credit = harness.exposedDustCredit(owner, address(token)); + assertTrue(realDelta.eq(netReq.add(credit)), "conservation alt"); + _assertCreditInvariant(token, decimals); + } + } + + /// ATTACK 3: high-decimals token (36) with a large amount. Probes whether the + /// credit (very small, ~1e-36) can be silently dropped by the float sub when + /// subtracting from a large amount (exponent gap), and whether toFixed reverts. + function testHighDecimalsCreditNotDropped() external { + uint8 decimals = 36; + MockToken token = _mkToken(decimals); + + // Seed a credit with a sub-base-unit pull: 0.5 base units = 5e-37. + Float seed = LibDecimalFloat.packLossless(5, -37); + harness.exposedPull(owner, address(token), seed); + Float credit0 = harness.exposedDustCredit(owner, address(token)); + // 0.5 base unit pull rounds up to 1 base unit, credit = 1e-36 - 5e-37 = 5e-37. + assertTrue(credit0.eq(LibDecimalFloat.packLossless(5, -37)), "seed credit"); + + // Now a large pull: 1e30 token units (huge). Exponent gap to credit ~ 66. + Float big = LibDecimalFloat.packLossless(1, 30); + uint256 balBefore = token.balanceOf(address(harness)); + (uint256 moved,) = harness.exposedPull(owner, address(token), big); + uint256 realMoved = token.balanceOf(address(harness)) - balBefore; + assertEq(realMoved, moved, "moved matches transfer"); + + _assertCreditInvariant(token, decimals); + + // Conservation: realDelta(token units) == effective_requested + creditNew. + // Total requested across both moves = seed + big. + Float totalRequested = seed.add(big); + // realDelta total = first move (1 base unit = 1e-36) + this move. + Float realDeltaTotal = LibDecimalFloat.fromFixedDecimalLosslessPacked(1, decimals).add( + LibDecimalFloat.fromFixedDecimalLosslessPacked(realMoved, decimals) + ); + Float creditNew = harness.exposedDustCredit(owner, address(token)); + assertTrue(realDeltaTotal.eq(totalRequested.add(creditNew)), "conservation high-decimals"); + } + + /// ATTACK 4: push where amount + credit must realize, with an amount large + /// enough relative to the credit that the float add might drop the credit. + function testHighDecimalsPushCreditNotDropped() external { + uint8 decimals = 36; + MockToken token = _mkToken(decimals); + + // Seed credit via a sub-base-unit push: 0.5 base units -> pushes 0, credit 0.5. + Float seed = LibDecimalFloat.packLossless(5, -37); + harness.exposedPush(owner, address(token), seed); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(5, -37)), "push seed credit" + ); + + // Large push. + Float big = LibDecimalFloat.packLossless(1, 30); + uint256 balBefore = token.balanceOf(address(harness)); + (uint256 moved,) = harness.exposedPush(owner, address(token), big); + uint256 realMoved = balBefore - token.balanceOf(address(harness)); + assertEq(realMoved, moved, "push moved matches"); + _assertCreditInvariant(token, decimals); + } + + /// ATTACK 5: extreme decimals (60). One base unit = 1e-60. Does the machinery + /// hold and not revert / not break the invariant? + function testExtremeDecimals() external { + uint8 decimals = 60; + MockToken token = _mkToken(decimals); + + Float amount = LibDecimalFloat.packLossless(15, -61); // 1.5 base units + (uint256 moved,) = harness.exposedPull(owner, address(token), amount); + assertEq(moved, 2, "1.5 rounds up to 2 at 60 decimals"); + _assertCreditInvariant(token, decimals); + assertTrue( + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(5, -61)), "credit 0.5" + ); + } + + /// ATTACK 7: deliberately force the exponent-gap drop in `effective = + /// amount.sub(credit)`. After maximization both coefficients are ~67 digits; + /// when their exponents differ by > 76 the smaller operand (the credit) is + /// dropped entirely by LibDecimalFloatImplementation.add. With decimals=18, + /// a seeded ~1e-18 credit (normalized exp ~ -85) versus an amount ~1e70 token + /// units (normalized exp ~ +3) has a gap > 76. If the credit is dropped the + /// PRIOR credit is silently stranded (re-introducing the original L01 dust + /// loss) even though per-move 0<=credit<1 still holds. This probes the + /// cross-move "every credit is realized" property, the PR's central claim. + function testExponentGapDropsCredit() external { + uint8 decimals = 18; + MockToken token = _mkToken(decimals); // supply ~1.4e76 base units + + // Seed a credit: pull 0.5 base units -> rounds up to 1, credit 0.5 base + // units = 5e-19 token units. + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(5, -19)); + Float seededCredit = harness.exposedDustCredit(owner, address(token)); + assertTrue(seededCredit.eq(LibDecimalFloat.packLossless(5, -19)), "seeded 0.5 credit"); + + // A huge amount in token units. supply/4 ~ 1.4e76 base units = 1.4e58 + // token units. Use coefficient*10^exp with enough magnitude that the + // normalized exponent gap to the ~5e-19 credit exceeds 76, but the base + // unit count stays within the minted supply and toFixed does not overflow. + // 1.4e58 token units -> exponent gap ~ 58+19 = 77 (> 76). Use 1e58. + Float big = LibDecimalFloat.packLossless(1, 58); + + uint256 balBefore = token.balanceOf(address(harness)); + (uint256 moved,) = harness.exposedPull(owner, address(token), big); + uint256 realMoved = token.balanceOf(address(harness)) - balBefore; + assertEq(realMoved, moved, "moved matches transfer"); + + Float creditAfter = harness.exposedDustCredit(owner, address(token)); + // Hard invariants must still hold regardless of any drop. + _assertCreditInvariant(token, decimals); + + // Now drive the credit toward realization with a sub-unit pull and see if + // the previously-seeded 0.5 was preserved. If the big pull dropped it, the + // ledger lost track of real tokens the orderbook holds. + emit log_named_bytes32("seededCredit", Float.unwrap(seededCredit)); + emit log_named_bytes32("creditAfterBig", Float.unwrap(creditAfter)); + emit log_named_uint("movedBig", moved); + + // Characterize the stranding: the big pull moved exactly the requested + // base units (1e76) with NO over-pull, and the previously-seeded 0.5 + // credit was silently dropped to zero rather than realized. + assertEq(moved, 1e76, "big pull moved exactly the requested base units"); + assertTrue(creditAfter.isZero(), "STRANDING: seeded 0.5 credit silently dropped to zero by exponent gap"); + + // The 0.5 base unit (5e-19 token units) that was stranded is BELOW the + // Float resolution next to a 1e58-token-unit amount (77 OOM apart), so at + // Float precision the stated conservation invariant still appears to hold: + // realDeltaTotal and (totalRequested + creditAfter) are the SAME Float. + // The physical stranding is real (the contract's raw ERC20 balance carries + // the extra 0.5 base unit with no ledger entry) but invisible/irrecoverable + // at this magnitude. This is the pre-PR L01 dust, re-stranded at extreme + // amounts; it does NOT violate 0<=credit<1 or the Float-precision + // conservation equation. + (Float realBigDelta,) = LibDecimalFloat.fromFixedDecimalLossyPacked(realMoved, decimals); + Float realDeltaTotal = LibDecimalFloat.fromFixedDecimalLosslessPacked(1, decimals).add(realBigDelta); + Float totalRequested = LibDecimalFloat.packLossless(5, -19).add(big); + Float conserved = totalRequested.add(creditAfter); + // At Float precision they ARE equal: the stated invariant survives even as + // the credit is physically stranded. + assertTrue(realDeltaTotal.eq(conserved), "Float-precision conservation still holds; stranding is sub-resolution"); + } + + /// ATTACK 8: broaden the PR fuzz beyond its 6-decimal / 25.5-base-unit cap. + /// Random decimals in [0,30] and amounts spanning sub-unit to ~6.5e9 base + /// units, asserting hard invariants after every move. Catches any rounding / + /// sign bug the narrow PR fuzz misses. + /// forge-config: default.fuzz.runs = 1500 + function testWideFuzz(uint8 decimalsRaw, bool[] memory isPull, uint64[] memory amts) external { + uint8 decimals = uint8(bound(decimalsRaw, 0, 30)); + MockToken token = _mkToken(decimals); + + vm.assume(isPull.length > 0 && amts.length > 0); + uint256 n = isPull.length < amts.length ? isPull.length : amts.length; + vm.assume(n > 0); + if (n > 40) n = 40; + + Float oneBaseUnit = LibDecimalFloat.packLossless(1, -int256(uint256(decimals))); + + for (uint256 i = 0; i < n; i++) { + // amount in token units: amts[i] base units, expressed as a Float at + // exponent -decimals, but offset the exponent by -1 half the time to + // exercise genuine sub-base-unit fractions. + int256 exp = -int256(uint256(decimals)) - int256(i % 2); + Float amount = LibDecimalFloat.packLossless(int256(uint256(amts[i])), exp); + if (isPull[i]) { + harness.exposedPull(owner, address(token), amount); + } else { + harness.exposedPush(owner, address(token), amount); + } + Float credit = harness.exposedDustCredit(owner, address(token)); + assertTrue(!credit.lt(LibDecimalFloat.FLOAT_ZERO), "fuzz: credit negative"); + assertTrue(credit.lt(oneBaseUnit), "fuzz: credit >= 1 base unit"); + } + } + + /// ATTACK 6: stress the int224 boundary directly. Pull an amount whose base + /// unit count exceeds int224 max (~6.7e66) WITH significant low digits, on a + /// 0-decimals token (so amount==base units and there are no trailing zeros to + /// rescue the round trip). If packLossy truncation corrupts the round trip the + /// derived credit goes wrong / negative. + function testInt224BoundaryZeroDecimals() external { + uint8 decimals = 0; + MockToken token = _mkToken(decimals); + + // A 60-significant-digit integer amount of base units, no trailing zeros. + // 123...789 repeated. int224 max ~ 1.35e67 so 60 digits (~1e59) is safe; + // push to ~67 digits to flirt with the boundary but stay representable. + Float amount = LibDecimalFloat.packLossless(123456789012345678901234567890123456789012345678901234567891, 0); + uint256 balBefore = token.balanceOf(address(harness)); + (uint256 moved,) = harness.exposedPull(owner, address(token), amount); + assertEq(token.balanceOf(address(harness)) - balBefore, moved, "moved matches"); + _assertCreditInvariant(token, decimals); + // 0 decimals => integer amount is lossless, credit must be exactly zero. + assertTrue(harness.exposedDustCredit(owner, address(token)).isZero(), "0-dec lossless => no credit"); + Float realDelta = LibDecimalFloat.fromFixedDecimalLosslessPacked(moved, decimals); + assertTrue(realDelta.eq(amount), "0-dec conservation exact"); + } +} diff --git a/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol new file mode 100644 index 0000000000..3482e0391b --- /dev/null +++ b/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol @@ -0,0 +1,440 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {Test} from "forge-std-1.16.1/src/Test.sol"; +import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; +import {MockToken} from "test/util/concrete/MockToken.sol"; +import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; +import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; +import {ITOFUTokenDecimals, TOFUOutcome} from "rain-tofu-erc20-decimals-0.1.1/src/interface/ITOFUTokenDecimals.sol"; +import {ERC20} from "@openzeppelin-contracts-5.6.1/token/ERC20/ERC20.sol"; + +contract RaindexV6DustCreditPrecisionAttackHarness is RaindexV6 { + function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { + return pullTokens(account, token, amount); + } + + function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { + return pushTokens(account, token, amount); + } + + function exposedDustCredit(address user, address token) external view returns (Float) { + return sDustCredit[user][token]; + } +} + +/// @dev Token whose reported decimals can be flipped at runtime, to probe the +/// TOFU decimals-change behaviour. +contract PrecisionAttackMutableDecimalsToken is ERC20 { + uint8 public dec; + + constructor(uint8 d) ERC20("Mut", "MUT") { + dec = d; + } + + function setDecimals(uint8 d) external { + dec = d; + } + + function decimals() public view override returns (uint8) { + return dec; + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} + +contract RaindexV6DustCreditPrecisionAttackTest is Test { + using LibDecimalFloat for Float; + + RaindexV6DustCreditPrecisionAttackHarness internal harness; + address internal owner = makeAddr("owner"); + + function setUp() external { + LibRainDeploy.etchZoltuFactory(vm); + LibRainDeploy.deployZoltu(LibTOFUTokenDecimals.TOFU_DECIMALS_EXPECTED_CREATION_CODE); + harness = RaindexV6DustCreditPrecisionAttackHarness(payable(address(uint160(uint256(keccak256("dust.credit.precision.attack")))))); + vm.etch(address(harness), type(RaindexV6DustCreditPrecisionAttackHarness).runtimeCode); + } + + function _newToken(uint8 dec) internal returns (MockToken token) { + token = new MockToken("Token", "TKN", dec); + // Mint enough that huge-magnitude moves succeed, but keep balances below + // int256 max so the test's own int256 delta arithmetic does not overflow. + // int256 max ~5.7e76; keep balances ~ <= 2e76 base units. + uint256 fund = 2 * 10 ** 76; + token.mint(owner, fund); + token.mint(address(harness), fund); + vm.prank(owner); + token.approve(address(harness), type(uint256).max); + } + + /// ATTACK 1: scan pull magnitudes from 1e50 up to the largest that does not + /// overflow uint256 base units, seeding a 0.5 base-unit credit first. At each + /// magnitude assert conservation: realDelta == netRequested + credit, and the + /// solvency bound 0 <= credit < 1 base unit. The hypothesis is that at some + /// magnitude `effective = amount.sub(credit)` silently drops the credit (the + /// add/sub helper ignores operand B when the exponent gap exceeds 76), which + /// would strand the 0.5 base-unit credit -> conservation broken. + function testPullMagnitudeScanConservation() external { + // exponent of the requested token-unit amount. At 6 decimals the base + // unit count is coefficient * 10^(exp+6); must stay < ~1.157e77. + // 1 * 10^exp token units -> 10^(exp+6) base units. exp <= 70 keeps it + // under uint256 max (1e76 base units). exp=71 -> 1e77 base units (still + // < 1.157e77, fits). exp=72 -> 1e78 overflows. + for (int256 exp = 50; exp <= 70; exp++) { + MockToken token = _newToken(6); + + // Seed 0.5 base-unit credit via a 1.5 base-unit pull. + Float r1 = LibDecimalFloat.packLossless(15, -7); + (uint256 moved1,) = harness.exposedPull(owner, address(token), r1); + + Float r2 = LibDecimalFloat.packLossless(1, exp); + (uint256 moved2,) = harness.exposedPull(owner, address(token), r2); + + // Total physically pulled, expressed in token units (Float), built + // from the two uint256 returns so the test never overflows int256. + Float movedTotal = + _floatFromBaseUnits(moved1).add(_floatFromBaseUnits(moved2)); + + Float netRequested = r1.add(r2); + Float credit = harness.exposedDustCredit(owner, address(token)); + Float expected = netRequested.add(credit); + + // Conservation: tokens physically pulled == requested + standing credit. + if (!movedTotal.eq(expected)) { + emit log_named_int("PULL BROKEN at exp", exp); + emit log_named_uint("moved1", moved1); + emit log_named_uint("moved2", moved2); + emit log_named_int("movedTotal coeff", _coeff(movedTotal)); + emit log_named_int("movedTotal exp", _exp(movedTotal)); + emit log_named_int("expected coeff", _coeff(expected)); + emit log_named_int("expected exp", _exp(expected)); + emit log_named_int("credit coeff", _coeff(credit)); + emit log_named_int("credit exp", _exp(credit)); + } + assertTrue(movedTotal.eq(expected), "conservation: movedTotal == netRequested + credit"); + assertTrue(!credit.lt(LibDecimalFloat.FLOAT_ZERO), "credit non-negative"); + assertTrue(credit.lt(LibDecimalFloat.packLossless(1, -6)), "credit < 1 base unit"); + } + } + + /// REALISM PROBE (18 decimals): find the minimum WHOLE-TOKEN count at which + /// the PR under-holds vs the vault obligation, for an 18-decimal token (the + /// common case). Reports the threshold in whole tokens. + function testFindMinInsolventExponent18dp() external { + for (int256 exp = 0; exp <= 59; exp++) { + PrecisionAttackMutableDecimalsToken token = new PrecisionAttackMutableDecimalsToken(18); + // fund generously but keep below int range issues; base units = 10^(exp+18) + // need that to fit uint256 (< 1.15e77) => exp <= 59 keeps 10^77. + token.mint(owner, 2 * 10 ** 76); + token.mint(address(harness), 2 * 10 ** 76); + vm.prank(owner); + token.approve(address(harness), type(uint256).max); + + uint256 heldBefore = token.balanceOf(address(harness)); + // seed 0.5 base units credit at 18dp = 5e-19 token units * 1.5 ... use + // 1.5 base units = 15e-19. + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(15, -19)); + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(1, exp)); + uint256 takenIn = token.balanceOf(address(harness)) - heldBefore; + + Float vaultBalance = LibDecimalFloat.packLossless(15, -19).add(LibDecimalFloat.packLossless(1, exp)); + (uint256 obligation,) = LibDecimalFloat.toFixedDecimalLossy(vaultBalance, 18); + Float credit = harness.exposedDustCredit(owner, address(token)); + (uint256 creditBase,) = LibDecimalFloat.toFixedDecimalLossy(credit, 18); + + if (takenIn < obligation + creditBase) { + emit log_named_int("18dp FIRST INSOLVENT: whole tokens = 10^exp, exp", exp); + emit log_named_uint("shortfall (base units)", (obligation + creditBase) - takenIn); + return; + } + } + emit log("18dp: no insolvent exponent up to 10^59 whole tokens"); + } + + /// A/B vs MAIN: replicate main's pullTokens intake (round-up, no credit) for + /// the same two-pull sequence and compare to the PR harness intake and to the + /// vault obligation. Confirms the PR (credit ledger) is what flips the sign of + /// the solvency slack at 10^62 token units. + function testABMainVsPRAtExp62() external { + int256 exp = 62; + + // --- PR harness intake --- + MockToken token = _newToken(6); + uint256 heldBefore = token.balanceOf(address(harness)); + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(15, -7)); + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(1, exp)); + uint256 prTakenIn = token.balanceOf(address(harness)) - heldBefore; + Float prCredit = harness.exposedDustCredit(owner, address(token)); + (uint256 prCreditBase,) = LibDecimalFloat.toFixedDecimalLossy(prCredit, 6); + + // --- main intake replicated inline (round-up per pull, no credit) --- + uint256 mainTakenIn = _mainPull(LibDecimalFloat.packLossless(15, -7)) + _mainPull(LibDecimalFloat.packLossless(1, exp)); + + // --- vault obligation (Float vault balance -> base units, round down) --- + Float vaultBalance = LibDecimalFloat.packLossless(15, -7).add(LibDecimalFloat.packLossless(1, exp)); + (uint256 obligation,) = LibDecimalFloat.toFixedDecimalLossy(vaultBalance, 6); + + emit log_named_uint("PR takenIn", prTakenIn); + emit log_named_uint("PR credit liability (base)", prCreditBase); + emit log_named_uint("MAIN takenIn", mainTakenIn); + emit log_named_uint("vault obligation", obligation); + + // MAIN is solvent: intake >= obligation. + assertGe(mainTakenIn, obligation, "MAIN: intake >= obligation (solvent)"); + // PR is insolvent: intake + creditLiability < obligation. + // (credit liability is itself a liability, so even adding it back the PR + // holds less than it owes.) + assertLt(prTakenIn + prCreditBase, obligation, "PR: intake+credit < obligation (insolvent)"); + } + + /// main's pullTokens intake: toFixedDecimalLossy rounded UP on lossy. + function _mainPull(Float amount) internal pure returns (uint256 amount18) { + bool lossless; + (amount18, lossless) = LibDecimalFloat.toFixedDecimalLossy(amount, 6); + if (!lossless) { + ++amount18; + } + } + + /// MINIMUM-MAGNITUDE PROBE: find the smallest pull exponent at which the + /// seeded-credit path takes in FEWER base units than the vault obligation it + /// books (i.e. the credit machinery flips a harmless over-hold into an + /// untracked under-hold). Also reports the equivalent main-branch intake to + /// confirm the PR is the cause. + function testFindMinInsolventExponent() external { + for (int256 exp = 0; exp <= 71; exp++) { + MockToken token = _newToken(6); + uint256 heldBefore = token.balanceOf(address(harness)); + + // seed 1.5 base units (-> credit 0.5), then 1*10^exp token units. + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(15, -7)); + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(1, exp)); + uint256 takenIn = token.balanceOf(address(harness)) - heldBefore; + + Float vaultBalance = LibDecimalFloat.packLossless(15, -7).add(LibDecimalFloat.packLossless(1, exp)); + (uint256 obligation,) = LibDecimalFloat.toFixedDecimalLossy(vaultBalance, 6); + Float credit = harness.exposedDustCredit(owner, address(token)); + (uint256 creditBase,) = LibDecimalFloat.toFixedDecimalLossy(credit, 6); + + if (takenIn < obligation + creditBase) { + emit log_named_int("FIRST INSOLVENT exponent (token units 10^exp)", exp); + emit log_named_uint("takenIn", takenIn); + emit log_named_uint("obligation+credit", obligation + creditBase); + emit log_named_uint("shortfall", (obligation + creditBase) - takenIn); + // Stop at the first insolvent exponent. + return; + } + } + emit log("no insolvent exponent found up to 10^71 token units"); + } + + /// SOLVENCY END-TO-END: compare, for an identical (seed 1.5 base units) + + /// (1e62 token units) two-pull deposit sequence, the orderbook's net token + /// intake against the vault obligation it books, and against the standing + /// credit liability. Solvency requires: + /// heldForUser (real tokens in) + 0 >= vaultObligation - creditLiability + /// equivalently the orderbook must hold at least (vault balance it owes the + /// user) minus (credit it owes the user). A negative slack means the + /// orderbook took in fewer tokens than it now claims to owe -> insolvent. + function testTwoPullSolvencySlack() external { + MockToken token = _newToken(6); + + uint256 heldBefore = token.balanceOf(address(harness)); + + // Two pulls: seed 1.5 base units, then 1e62 token units. + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(15, -7)); + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(1, 62)); + + uint256 heldAfter = token.balanceOf(address(harness)); + uint256 takenIn = heldAfter - heldBefore; // base units the orderbook received + + // Vault obligation in base units the orderbook now owes the user: + // a vault crediting 1.5 + 1e62 token units. When the user withdraws the + // FULL float vault balance, pushTokens converts it to base units (rounded + // down). Compute that exact realizable base-unit obligation. + Float vaultBalance = LibDecimalFloat.packLossless(15, -7).add(LibDecimalFloat.packLossless(1, 62)); + (uint256 obligationBaseUnits,) = LibDecimalFloat.toFixedDecimalLossy(vaultBalance, 6); + + // Standing credit the orderbook ALSO owes the user (base units, rounded + // down for what it could pay). + Float credit = harness.exposedDustCredit(owner, address(token)); + (uint256 creditBaseUnits,) = LibDecimalFloat.toFixedDecimalLossy(credit, 6); + + emit log_named_uint("takenIn (base units)", takenIn); + emit log_named_uint("vault obligation (base units)", obligationBaseUnits); + emit log_named_uint("credit liability (base units)", creditBaseUnits); + + // The orderbook owes the user, on full withdrawal + credit realization, + // at most (obligation + credit) base units; it took in `takenIn`. + // Solvency: takenIn >= obligation + credit (it must hold at least what it + // owes). Report the slack. + uint256 owed = obligationBaseUnits + creditBaseUnits; + emit log_named_uint("owed (obligation+credit)", owed); + if (takenIn < owed) { + emit log_named_uint("INSOLVENT shortfall (base units)", owed - takenIn); + } + assertGe(takenIn, owed, "orderbook holds at least what it owes the user"); + } + + /// DIAGNOSTIC: isolate exp=62 pull. Compare the PR's pulled base units, with + /// and without a seeded 0.5 credit, against the ideal 1e68 base units the + /// vault accounting credits. The solvency-critical question is whether the + /// contract pulls AT LEAST as many base units as the vault is credited + /// (rounding the user's deposit UP for the protocol), or whether the credit + /// machinery causes an UNDER-pull that leaves the vault over-credited. + function testPullExp62SolvencyDiagnostic() external { + // No-seed baseline: a single 1e62 pull. + { + MockToken token = _newToken(6); + (uint256 moved,) = harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(1, 62)); + emit log_named_uint("no-seed moved (base units)", moved); + // Ideal vault-accounting base units for 1e62 token units at 6 dp. + // = 1e68. Solvency requires moved >= 1e68 (pull rounds up). + emit log_named_uint("ideal 1e68", 10 ** 68); + // Does the orderbook receive at least what the vault is credited? + assertGe(moved, 10 ** 68, "no-seed: pulled >= vault-credited (solvent)"); + } + // Seeded 0.5 credit then 1e62 pull. + { + MockToken token = _newToken(6); + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(15, -7)); + (uint256 moved,) = harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(1, 62)); + Float creditAfter = harness.exposedDustCredit(owner, address(token)); + emit log_named_uint("seeded moved (base units)", moved); + emit log_named_int("seeded creditAfter coeff", _coeff(creditAfter)); + emit log_named_int("seeded creditAfter exp", _exp(creditAfter)); + // The vault is credited 1.5 + 1e62 token units across the two pulls + // = 1e68 + 1.5 base units (the 1.5 from the seed). The orderbook + // physically received 2 (seed) + `moved`. Solvency requires + // 2 + moved + creditReleased relationship to hold. Concretely the + // orderbook must hold >= vault total. vault total base units = + // ceil-ish 1e68 + 2 (seed credited 1.5 -> but seed pulled 2). + // Simplest solvency statement at the boundary: total physically held + // for these two pulls (2 + moved) must be >= total vault-credited + // base units (1e68 + ceil(1.5)=2) MINUS the standing credit (which is + // a liability the orderbook owes back). + // total held = 2 + moved ; vault credited (base units) approx 1e68 + 2 + // standing credit (base units) = creditAfter. + // Require: heldBaseUnits + creditAfterBaseUnits >= vaultCreditedBaseUnits + // i.e. orderbook is not under-funded. + // We assert the weaker, decisive check: moved >= 1e68 - 1 (it must not + // fall materially short of the vault-credited 1e68 for the big pull). + emit log_named_uint("shortfall vs 1e68", moved >= 10 ** 68 ? 0 : (10 ** 68 - moved)); + } + } + + /// ATTACK 2: TOFU decimals change between moves. Seed credit at 6 decimals, + /// flip token to 18 decimals, then attempt to realize. If the contract does + /// NOT revert, the stored Float credit could realize at the wrong base-unit + /// scale. Expectation: TOFU forces a revert, neutralizing the attack. + function testDecimalsChangeRevertsAndProtectsCredit() external { + PrecisionAttackMutableDecimalsToken token = new PrecisionAttackMutableDecimalsToken(6); + token.mint(owner, type(uint128).max); + token.mint(address(harness), type(uint128).max); + vm.prank(owner); + token.approve(address(harness), type(uint256).max); + + // First move initializes TOFU at 6 decimals and seeds 0.5 base unit credit. + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(15, -7)); + Float seeded = harness.exposedDustCredit(owner, address(token)); + assertTrue(seeded.eq(LibDecimalFloat.packLossless(5, -7)), "seed credit 0.5"); + + // Token changes decimals to 18. + token.setDecimals(18); + + // Any subsequent pull/push must revert (TOFU Inconsistent), so the stored + // credit can never be realized at the wrong scale. + vm.expectRevert( + abi.encodeWithSelector( + ITOFUTokenDecimals.TokenDecimalsReadFailure.selector, address(token), TOFUOutcome.Inconsistent + ) + ); + harness.exposedPull(owner, address(token), LibDecimalFloat.packLossless(15, -7)); + + vm.expectRevert( + abi.encodeWithSelector( + ITOFUTokenDecimals.TokenDecimalsReadFailure.selector, address(token), TOFUOutcome.Inconsistent + ) + ); + harness.exposedPush(owner, address(token), LibDecimalFloat.packLossless(15, -7)); + + // Credit is frozen, unchanged. + assertTrue(harness.exposedDustCredit(owner, address(token)).eq(seeded), "credit frozen after decimals change"); + } + + /// ATTACK 3: high-decimals token (18 dp) sub-unit accumulation. A push of + /// 0.5 base units (5e-19 token units) repeatedly. Confirm the sub-unit + /// crossing math still holds at 18 decimals where the base unit is tiny. + function testHighDecimalsSubUnitAccumulation() external { + MockToken token = _newToken(18); + // 0.5 base units at 18 dp = 5e-19 token units. + Float half = LibDecimalFloat.packLossless(5, -19); + + (uint256 m1,) = harness.exposedPush(owner, address(token), half); + assertEq(m1, 0, "0.5 pushes nothing"); + (uint256 m2,) = harness.exposedPush(owner, address(token), half); + assertEq(m2, 1, "1.0 crosses whole unit"); + assertTrue(harness.exposedDustCredit(owner, address(token)).isZero(), "credit cleared at 18dp"); + } + + /// ATTACK 4: scan push magnitudes. Seed 0.5 base-unit credit (owed to user), + /// then push a huge amount at each magnitude. Conservation for pushes: + /// harnessDelta == -netRequested + credit (the harness sends netRequested and + /// retains the standing credit). If the credit gets dropped in + /// `effective = amount.add(credit)`, the orderbook either over-pays or strands + /// value -> conservation broken. + function testPushMagnitudeScanConservation() external { + for (int256 exp = 50; exp <= 70; exp++) { + MockToken token = _newToken(6); + + Float r1 = LibDecimalFloat.packLossless(15, -7); // rounds down to 1, credit 0.5 + (uint256 moved1,) = harness.exposedPush(owner, address(token), r1); + + Float r2 = LibDecimalFloat.packLossless(1, exp); + (uint256 moved2,) = harness.exposedPush(owner, address(token), r2); + + // Conservation for pushes: tokens physically sent + retained credit + // == requested. i.e. movedTotal + credit == netRequested. + Float movedTotal = + _floatFromBaseUnits(moved1).add(_floatFromBaseUnits(moved2)); + Float netRequested = r1.add(r2); + Float credit = harness.exposedDustCredit(owner, address(token)); + Float expected = netRequested.sub(credit); + + if (!movedTotal.eq(expected)) { + emit log_named_int("PUSH BROKEN at exp", exp); + emit log_named_uint("moved1", moved1); + emit log_named_uint("moved2", moved2); + emit log_named_int("movedTotal coeff", _coeff(movedTotal)); + emit log_named_int("movedTotal exp", _exp(movedTotal)); + emit log_named_int("expected coeff", _coeff(expected)); + emit log_named_int("expected exp", _exp(expected)); + emit log_named_int("credit coeff", _coeff(credit)); + emit log_named_int("credit exp", _exp(credit)); + } + assertTrue(movedTotal.eq(expected), "push conservation: movedTotal == netRequested - credit"); + assertTrue(!credit.lt(LibDecimalFloat.FLOAT_ZERO), "credit non-negative"); + assertTrue(credit.lt(LibDecimalFloat.packLossless(1, -6)), "credit < 1 base unit"); + } + } + + /// Converts a base-unit count (6 dp) to a token-unit Float exactly as the + /// contract does, so comparisons are apples-to-apples with the contract's own + /// `pulled`/`pushed` derivation. + function _floatFromBaseUnits(uint256 baseUnits) internal pure returns (Float f) { + (f,) = LibDecimalFloat.fromFixedDecimalLossyPacked(baseUnits, 6); + } + + function _coeff(Float f) internal pure returns (int256 c) { + (c,) = LibDecimalFloat.unpack(f); + } + + function _exp(Float f) internal pure returns (int256 e) { + (, e) = LibDecimalFloat.unpack(f); + } +} diff --git a/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol new file mode 100644 index 0000000000..613a697691 --- /dev/null +++ b/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {Test} from "forge-std-1.16.1/src/Test.sol"; +import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; +import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; +import {MockToken} from "test/util/concrete/MockToken.sol"; +import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; +import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; + +/// @dev Same harness as the PR's test, exposing the internal helpers. +contract RaindexV6DustCreditSolvencyAttackHarness is RaindexV6 { + function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { + return pullTokens(account, token, amount); + } + + function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { + return pushTokens(account, token, amount); + } + + function exposedDustCredit(address user, address token) external view returns (Float) { + return sDustCredit[user][token]; + } +} + +/// @title Adversarial solvency attack on the dust-credit ledger. +/// @notice Tries to construct a sequence where realizing a credit pays out +/// tokens the orderbook does not hold for that user (draining a pooled balance / +/// a third party), or where a credit is backed by nothing. +contract RaindexV6DustCreditSolvencyAttackTest is Test { + using LibDecimalFloat for Float; + + RaindexV6DustCreditSolvencyAttackHarness internal harness; + address internal alice = makeAddr("alice"); + address internal bob = makeAddr("bob"); + + function _deployHarness() internal { + LibRainDeploy.etchZoltuFactory(vm); + LibRainDeploy.deployZoltu(LibTOFUTokenDecimals.TOFU_DECIMALS_EXPECTED_CREATION_CODE); + harness = RaindexV6DustCreditSolvencyAttackHarness(payable(address(uint160(uint256(keccak256("dust.credit.solvency.attack")))))); + vm.etch(address(harness), type(RaindexV6DustCreditSolvencyAttackHarness).runtimeCode); + } + + function _token(uint8 decimals) internal returns (MockToken token) { + token = new MockToken("Token", "TKN", decimals); + // Mint a huge but bounded supply so big transfers don't run out of + // balance: the point of these tests is the credit math, not ERC20 limits. + uint256 supply = type(uint256).max / 4; + token.mint(alice, supply); + token.mint(bob, supply); + token.mint(address(harness), supply); + vm.prank(alice); + token.approve(address(harness), type(uint256).max); + vm.prank(bob); + token.approve(address(harness), type(uint256).max); + } + + /// Cross-account pooled solvency. Two users churn pulls and pushes for the + /// SAME token against ONE pooled real balance. After every move the global + /// solvency identity must hold: + /// realDelta == netRequested(alice) + netRequested(bob) + /// + credit(alice) + credit(bob) + /// and each credit stays in [0, 1 base unit). If two users' credits ever + /// double-counted the same real balance, this identity would break (real + /// would fall short of the obligations). + /// forge-config: default.fuzz.runs = 4000 + function testCrossAccountPooledSolvency(uint8[] memory moves, uint8[] memory units) external { + _deployHarness(); + MockToken token = _token(6); + + vm.assume(moves.length > 0 && units.length > 0); + uint256 n = moves.length < units.length ? moves.length : units.length; + + int256 startReal = int256(token.balanceOf(address(harness))); + // net requested per user in tenths of a base unit (exact integer math). + int256 netAliceTenths = 0; + int256 netBobTenths = 0; + + Float oneBaseUnit = LibDecimalFloat.packLossless(1, -6); + + for (uint256 i = 0; i < n; i++) { + uint8 m = moves[i]; + uint256 u = units[i]; + Float amount = LibDecimalFloat.packLossless(int256(u), -7); + // 2 low bits select account+direction: 00 alice pull, 01 alice push, + // 10 bob pull, 11 bob push. + address who = (m & 2) == 0 ? alice : bob; + bool isPull = (m & 1) == 0; + + if (isPull) { + harness.exposedPull(who, address(token), amount); + if (who == alice) netAliceTenths += int256(u); + else netBobTenths += int256(u); + } else { + harness.exposedPush(who, address(token), amount); + if (who == alice) netAliceTenths -= int256(u); + else netBobTenths -= int256(u); + } + + _checkPooled(token, startReal, netAliceTenths, netBobTenths, oneBaseUnit); + } + } + + function _checkPooled( + MockToken token, + int256 startReal, + int256 netAliceTenths, + int256 netBobTenths, + Float oneBaseUnit + ) internal view { + int256 realDeltaBaseUnits = int256(token.balanceOf(address(harness))) - startReal; + Float realDelta = LibDecimalFloat.packLossless(realDeltaBaseUnits, -6); + + Float creditAlice = harness.exposedDustCredit(alice, address(token)); + Float creditBob = harness.exposedDustCredit(bob, address(token)); + + Float netAlice = LibDecimalFloat.packLossless(netAliceTenths, -7); + Float netBob = LibDecimalFloat.packLossless(netBobTenths, -7); + + Float expected = netAlice.add(netBob).add(creditAlice).add(creditBob); + assertTrue(realDelta.eq(expected), "global pooled solvency identity"); + + // Solvency bounds on each per-user credit. + assertTrue(!creditAlice.lt(LibDecimalFloat.FLOAT_ZERO), "alice credit >= 0"); + assertTrue(creditAlice.lt(oneBaseUnit), "alice credit < 1 base unit"); + assertTrue(!creditBob.lt(LibDecimalFloat.FLOAT_ZERO), "bob credit >= 0"); + assertTrue(creditBob.lt(oneBaseUnit), "bob credit < 1 base unit"); + } + + /// Same-token same-tx arrive-and-leave, mirroring clear3: token X is pulled + /// from alice (over-pull, +credit alice) and pushed to bob (under-push, + /// +credit bob) in the same logical clear. Verify neither credit is backed by + /// the other's tokens: realDelta must equal netRequested + both credits. + function testArriveAndLeaveSameTxSameToken() external { + _deployHarness(); + MockToken token = _token(6); + + int256 startReal = int256(token.balanceOf(address(harness))); + + // alice's vault-0 output of 1.5 base units -> pulled, rounds up to 2. + Float aliceOut = LibDecimalFloat.packLossless(15, -7); + // bob's vault-0 input of 1.5 base units -> pushed, rounds down to 1. + Float bobIn = LibDecimalFloat.packLossless(15, -7); + + // clear3 ordering: pull outputs first, then push inputs. + (uint256 pulled,) = harness.exposedPull(alice, address(token), aliceOut); + (uint256 pushed,) = harness.exposedPush(bob, address(token), bobIn); + + assertEq(pulled, 2, "alice over-pull rounds up"); + assertEq(pushed, 1, "bob under-push rounds down"); + + int256 realDelta = int256(token.balanceOf(address(harness))) - startReal; + // Net real: +2 (from alice) -1 (to bob) = +1 base unit. + assertEq(realDelta, 1, "net real +1"); + + Float creditAlice = harness.exposedDustCredit(alice, address(token)); + Float creditBob = harness.exposedDustCredit(bob, address(token)); + // alice credit 0.5 (over-pull), bob credit 0.5 (under-push). + assertTrue(creditAlice.eq(LibDecimalFloat.packLossless(5, -7)), "alice credit 0.5"); + assertTrue(creditBob.eq(LibDecimalFloat.packLossless(5, -7)), "bob credit 0.5"); + + // Global identity: realDelta(token units) == netRequested + credits. + // netRequested = +1.5 (alice pull) - 1.5 (bob push) = 0. + Float realDeltaF = LibDecimalFloat.packLossless(realDelta, -6); + Float expected = creditAlice.add(creditBob); // net requested == 0 + assertTrue(realDeltaF.eq(expected), "arrive-and-leave solvency identity"); + } + + /// Large-amount precision attack on PUSH. A huge push amount whose integer + /// transfer exceeds ~67 significant digits could make `pushed` (the Float + /// round-trip of the integer) smaller than the integer actually sent, + /// inflating the recorded credit beyond what was withheld -> a credit backed + /// by nothing. We push amounts spanning the full uint256 magnitude range + /// (mantissa * 10^expDigits base units) and assert the recorded credit equals + /// the TRUE withheld dust (requestedTokenUnits - sentTokenUnits), and stays in + /// [0, 1 base unit). If the lossy round-trip inflated the credit, this breaks. + /// forge-config: default.fuzz.runs = 5000 + function testLargeAmountPushCreditNotInflated(uint256 mantissa, uint8 expDigits, uint8 decimals) external { + decimals = uint8(bound(decimals, 0, 36)); + // mantissa fits in int224 (<= ~66 digits) so our own assertion-side + // packLossless never overflows; expDigits supplies the extra magnitude. + mantissa = bound(mantissa, 1, uint256(uint224(type(int224).max))); + // Keep mantissa * 10^expDigits within the minted supply (uint256.max/4). + expDigits = uint8(bound(expDigits, 0, 70)); + _deployHarness(); + MockToken token = _token(decimals); + + Float oneBaseUnit = LibDecimalFloat.packLossless(1, -int256(uint256(decimals))); + + // value = mantissa * 10^expDigits base units. Ensure it fits in supply. + uint256 maxMantissa = (type(uint256).max / 4) / (10 ** uint256(expDigits)); + if (maxMantissa == 0) return; + if (mantissa > maxMantissa) mantissa = maxMantissa; + if (mantissa == 0) return; + + // requested in TOKEN units = mantissa * 10^(expDigits - decimals). + Float requested = + LibDecimalFloat.packLossless(int256(mantissa), int256(uint256(expDigits)) - int256(uint256(decimals))); + + uint256 balBefore = token.balanceOf(address(harness)); + (uint256 sent,) = harness.exposedPush(alice, address(token), requested); + + // The orderbook never sends out more than it held. + assertLe(sent, balBefore, "never sends more than held"); + + Float credit = harness.exposedDustCredit(alice, address(token)); + assertTrue(!credit.lt(LibDecimalFloat.FLOAT_ZERO), "post-big credit >= 0"); + assertTrue(credit.lt(oneBaseUnit), "post-big credit < 1 base unit"); + + // Core solvency check: the recorded credit must not exceed the TRUE + // withheld dust = requested - sent (token units). If a lossy round-trip + // inflated `credit` above the real shortfall, the orderbook would be + // recording a debt it never withheld -> a credit backed by nothing. + // `sent` can exceed int224; pack it lossily and use >= so any inflation + // of `credit` beyond the real (possibly under-counted) shortfall trips. + (Float sentTokenUnits,) = + LibDecimalFloat.fromFixedDecimalLossyPacked(sent, decimals); + Float trueWithheld = requested.sub(sentTokenUnits); + // credit must be <= trueWithheld (never inflated above what was withheld). + assertTrue(!credit.gt(trueWithheld), "credit <= true withheld dust (not inflated)"); + } + + /// Direct seed-then-drain attack: can an accumulated push credit ever pay out + /// tokens that were not actually withheld? Build up credit to just under a + /// base unit, then realize it, and confirm the realized base unit was indeed + /// covered by tokens previously NOT sent (i.e. total sent over the whole + /// sequence equals floor(total requested + 0) exactly, never more). + function testPushNeverPaysMoreThanRequestedPlusWithheld() external { + _deployHarness(); + MockToken token = _token(6); + + // Request 0.9 base units nine times = 8.1 base units total requested. + // floor accounting: cumulative sent must always equal + // floor(cumulativeRequested) and never exceed it. + Float amount = LibDecimalFloat.packLossless(9, -7); // 0.9 base units + uint256 totalSent = 0; + // requested cumulative in tenths of a base unit. + uint256 reqTenths = 0; + for (uint256 k = 0; k < 12; k++) { + (uint256 sent,) = harness.exposedPush(alice, address(token), amount); + totalSent += sent; + reqTenths += 9; + // Invariant: never sent more than the whole-base-units requested. + assertLe(totalSent, reqTenths / 10, "never over-pays cumulatively"); + // And the shortfall is exactly the standing credit. + Float credit = harness.exposedDustCredit(alice, address(token)); + // requested - sent (token units) must equal credit. + Float requested = LibDecimalFloat.packLossless(int256(reqTenths), -7); + Float sentF = LibDecimalFloat.packLossless(int256(totalSent), -6); + assertTrue(requested.sub(sentF).eq(credit), "withheld == credit exactly"); + } + } +} From 982a4f78df8f2428f3333033b23f269a78e21114 Mon Sep 17 00:00:00 2001 From: David Meister Date: Thu, 11 Jun 2026 09:21:15 +0000 Subject: [PATCH 3/8] fix(raindex): clamp dust-credit pull to the vault obligation near the Float ceiling (#2673) `pullTokens` computed `effective = amount - credit` then rounded the fixed-decimal conversion UP only when `toFixedDecimalLossy` reported the conversion lossy. Near the Float int224 coefficient ceiling (~1e50 whole tokens) two effects compound: `amount.sub(credit)` drops the sub-base-unit credit, and the conversion of the resulting `effective` reports a spuriously-lossless value that truncates DOWN by more than one base unit. The round-up never fires, so the orderbook pulled in fewer base units than the vault obligation it booked - an untracked shortfall that broke solvency (real balance < sum of vault balances + credits) at high magnitudes. Fix: alongside the credit-reduced `effective`, also convert the full requested `amount` to base units (the conservative obligation a zero-credit pull would take). The standing credit can only ever reduce the pull by under one base unit, so when the rounded pull lands two or more base units below the obligation the credit was dropped; clamp the pull up to the obligation so the orderbook is never short. A clamped pull moved exactly `amount` in base units (the standing credit was sub-resolution beside it and could not reduce the pull), so the standing credit carries forward unchanged; the normal path keeps the original `pulled - effective` credit. RaindexV6 deployed runtime is 24,566 bytes (10 under the EIP-170 24,576 limit). The new precisionAttack regression gates (testTwoPullSolvencySlack, testPullMagnitudeScanConservation) and the conservation/solvency fuzz suites pass; the bug-characterizing precisionAttack diagnostics are updated to assert the now-solvent behaviour. Co-Authored-By: Claude Opus 4.8 --- src/concrete/raindex/RaindexV6.sol | 35 ++++++++-- ...RaindexV6.dustCredit.precisionAttack.t.sol | 65 ++++++++----------- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/src/concrete/raindex/RaindexV6.sol b/src/concrete/raindex/RaindexV6.sol index d08b8be81c..0a01284915 100644 --- a/src/concrete/raindex/RaindexV6.sol +++ b/src/concrete/raindex/RaindexV6.sol @@ -1169,7 +1169,10 @@ contract RaindexV6 is IRaindexV6, IMetaV1_2, ReentrancyGuard, Multicall, Raindex /// realized into the next move for the same `(account, token)`: the pull is /// reduced by any whole base unit of standing credit, and the fresh over-pull /// is added to it. The credit is always backed by tokens the orderbook holds - /// for `account`, so this is exactly conservative and never insolvent. + /// for `account`, so this is exactly conservative and never insolvent. Near + /// the Float coefficient ceiling, where the credit subtraction and conversion + /// can truncate the pull below the requested base units, the pull is clamped + /// up to the full requested amount so solvency still holds. function pullTokens(address account, address token, Float amount) internal returns (uint256, uint8) { uint8 decimals = _tokenDecimals(token); if (amount.lt(LibDecimalFloat.FLOAT_ZERO)) { @@ -1179,9 +1182,11 @@ contract RaindexV6 is IRaindexV6, IMetaV1_2, ReentrancyGuard, Multicall, Raindex // The orderbook already holds the standing credit (token units) for // `account` from prior over-pulls / under-pushes, so it only needs to // pull in the part of `amount` that the credit does not already cover. - Float effective = amount.sub(sDustCredit[account][token]); + Float credit = sDustCredit[account][token]; + Float effective = amount.sub(credit); uint256 amount18; + bool clamped; // A non-positive `effective` means the credit already covers the whole // pull, so no tokens move; `toFixedDecimalLossy` also rejects negatives. if (effective.gt(LibDecimalFloat.FLOAT_ZERO)) { @@ -1193,16 +1198,38 @@ contract RaindexV6 is IRaindexV6, IMetaV1_2, ReentrancyGuard, Multicall, Raindex // to silently not be pulled (wraps to 0). ++amount18; } + + // Near the Float coefficient ceiling the `amount.sub(credit)` above + // can drop the sub-unit credit AND `toFixedDecimalLossy` can report a + // spuriously-lossless conversion that truncates `effective` DOWN by + // more than one base unit, so the round-up never fires and the pull + // falls short of the vault obligation it books. `obligation` is the + // full requested `amount` in base units (what a zero-credit pull would + // take); the standing credit can only ever reduce the pull by under one + // base unit, so when the rounded `amount18` lands two or more base units + // below `obligation` the credit was dropped. Clamp up to `obligation` + // so the orderbook is never short; the credit is then carried forward + // below rather than re-derived from the unreliable `effective`. + //slither-disable-next-line unused-return + (uint256 obligation,) = LibDecimalFloat.toFixedDecimalLossy(amount, decimals); + if (amount18 + 1 < obligation) { + amount18 = obligation; + clamped = true; + } + IERC20(token).safeTransferFrom(account, address(this), amount18); } // The new credit is the transferred amount minus what `effective` // required: the over-pull when tokens moved (rounded up, so non-negative // and under one base unit), or the leftover credit when none did. It is - // backed by tokens the orderbook holds for `account`. + // backed by tokens the orderbook holds for `account`. A clamped pull moved + // exactly `amount` in base units (the standing credit was sub-resolution + // beside it and could not reduce the pull), so the standing credit carries + // forward unchanged. //slither-disable-next-line unused-return (Float pulled,) = LibDecimalFloat.fromFixedDecimalLossyPacked(amount18, decimals); - sDustCredit[account][token] = pulled.sub(effective); + sDustCredit[account][token] = clamped ? credit : pulled.sub(effective); return (amount18, decimals); } diff --git a/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol index 3482e0391b..ef6bbfbcd1 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol @@ -56,7 +56,9 @@ contract RaindexV6DustCreditPrecisionAttackTest is Test { function setUp() external { LibRainDeploy.etchZoltuFactory(vm); LibRainDeploy.deployZoltu(LibTOFUTokenDecimals.TOFU_DECIMALS_EXPECTED_CREATION_CODE); - harness = RaindexV6DustCreditPrecisionAttackHarness(payable(address(uint160(uint256(keccak256("dust.credit.precision.attack")))))); + harness = RaindexV6DustCreditPrecisionAttackHarness( + payable(address(uint160(uint256(keccak256("dust.credit.precision.attack"))))) + ); vm.etch(address(harness), type(RaindexV6DustCreditPrecisionAttackHarness).runtimeCode); } @@ -97,8 +99,7 @@ contract RaindexV6DustCreditPrecisionAttackTest is Test { // Total physically pulled, expressed in token units (Float), built // from the two uint256 returns so the test never overflows int256. - Float movedTotal = - _floatFromBaseUnits(moved1).add(_floatFromBaseUnits(moved2)); + Float movedTotal = _floatFromBaseUnits(moved1).add(_floatFromBaseUnits(moved2)); Float netRequested = r1.add(r2); Float credit = harness.exposedDustCredit(owner, address(token)); @@ -122,14 +123,13 @@ contract RaindexV6DustCreditPrecisionAttackTest is Test { } } - /// REALISM PROBE (18 decimals): find the minimum WHOLE-TOKEN count at which - /// the PR under-holds vs the vault obligation, for an 18-decimal token (the - /// common case). Reports the threshold in whole tokens. + /// REALISM REGRESSION GUARD (18 decimals): the clamp keeps the orderbook + /// solvent for the common 18-decimal token at every whole-token magnitude + /// whose base unit count fits the funded supply (exp <= 58 keeps 10^(exp+18) + /// <= 2e76). Assert intake >= obligation + standing credit at each. function testFindMinInsolventExponent18dp() external { - for (int256 exp = 0; exp <= 59; exp++) { + for (int256 exp = 0; exp <= 58; exp++) { PrecisionAttackMutableDecimalsToken token = new PrecisionAttackMutableDecimalsToken(18); - // fund generously but keep below int range issues; base units = 10^(exp+18) - // need that to fit uint256 (< 1.15e77) => exp <= 59 keeps 10^77. token.mint(owner, 2 * 10 ** 76); token.mint(address(harness), 2 * 10 ** 76); vm.prank(owner); @@ -147,19 +147,15 @@ contract RaindexV6DustCreditPrecisionAttackTest is Test { Float credit = harness.exposedDustCredit(owner, address(token)); (uint256 creditBase,) = LibDecimalFloat.toFixedDecimalLossy(credit, 18); - if (takenIn < obligation + creditBase) { - emit log_named_int("18dp FIRST INSOLVENT: whole tokens = 10^exp, exp", exp); - emit log_named_uint("shortfall (base units)", (obligation + creditBase) - takenIn); - return; - } + assertGe(takenIn, obligation + creditBase, "18dp solvent at every whole-token magnitude"); } - emit log("18dp: no insolvent exponent up to 10^59 whole tokens"); } /// A/B vs MAIN: replicate main's pullTokens intake (round-up, no credit) for /// the same two-pull sequence and compare to the PR harness intake and to the - /// vault obligation. Confirms the PR (credit ledger) is what flips the sign of - /// the solvency slack at 10^62 token units. + /// vault obligation at 10^62 token units, the magnitude where the unclamped + /// credit ledger used to under-hold. The precision-loss clamp restores parity: + /// the PR intake is solvent against the obligation just like main. function testABMainVsPRAtExp62() external { int256 exp = 62; @@ -173,7 +169,8 @@ contract RaindexV6DustCreditPrecisionAttackTest is Test { (uint256 prCreditBase,) = LibDecimalFloat.toFixedDecimalLossy(prCredit, 6); // --- main intake replicated inline (round-up per pull, no credit) --- - uint256 mainTakenIn = _mainPull(LibDecimalFloat.packLossless(15, -7)) + _mainPull(LibDecimalFloat.packLossless(1, exp)); + uint256 mainTakenIn = + _mainPull(LibDecimalFloat.packLossless(15, -7)) + _mainPull(LibDecimalFloat.packLossless(1, exp)); // --- vault obligation (Float vault balance -> base units, round down) --- Float vaultBalance = LibDecimalFloat.packLossless(15, -7).add(LibDecimalFloat.packLossless(1, exp)); @@ -186,10 +183,9 @@ contract RaindexV6DustCreditPrecisionAttackTest is Test { // MAIN is solvent: intake >= obligation. assertGe(mainTakenIn, obligation, "MAIN: intake >= obligation (solvent)"); - // PR is insolvent: intake + creditLiability < obligation. - // (credit liability is itself a liability, so even adding it back the PR - // holds less than it owes.) - assertLt(prTakenIn + prCreditBase, obligation, "PR: intake+credit < obligation (insolvent)"); + // PR is solvent too: the clamp pulls in at least the vault obligation plus + // the standing credit liability it now also owes the user. + assertGe(prTakenIn, obligation + prCreditBase, "PR: intake >= obligation + credit (solvent)"); } /// main's pullTokens intake: toFixedDecimalLossy rounded UP on lossy. @@ -201,13 +197,13 @@ contract RaindexV6DustCreditPrecisionAttackTest is Test { } } - /// MINIMUM-MAGNITUDE PROBE: find the smallest pull exponent at which the - /// seeded-credit path takes in FEWER base units than the vault obligation it - /// books (i.e. the credit machinery flips a harmless over-hold into an - /// untracked under-hold). Also reports the equivalent main-branch intake to - /// confirm the PR is the cause. + /// MINIMUM-MAGNITUDE REGRESSION GUARD: the precision-loss clamp keeps the + /// orderbook solvent at every pull magnitude, so no exponent flips a harmless + /// over-hold into an untracked under-hold. Scan every magnitude whose base + /// unit count fits the funded supply (exp <= 70 keeps 10^(exp+6) <= 2e76) and + /// assert intake >= obligation + standing credit at each. function testFindMinInsolventExponent() external { - for (int256 exp = 0; exp <= 71; exp++) { + for (int256 exp = 0; exp <= 70; exp++) { MockToken token = _newToken(6); uint256 heldBefore = token.balanceOf(address(harness)); @@ -221,16 +217,8 @@ contract RaindexV6DustCreditPrecisionAttackTest is Test { Float credit = harness.exposedDustCredit(owner, address(token)); (uint256 creditBase,) = LibDecimalFloat.toFixedDecimalLossy(credit, 6); - if (takenIn < obligation + creditBase) { - emit log_named_int("FIRST INSOLVENT exponent (token units 10^exp)", exp); - emit log_named_uint("takenIn", takenIn); - emit log_named_uint("obligation+credit", obligation + creditBase); - emit log_named_uint("shortfall", (obligation + creditBase) - takenIn); - // Stop at the first insolvent exponent. - return; - } + assertGe(takenIn, obligation + creditBase, "solvent at every pull magnitude"); } - emit log("no insolvent exponent found up to 10^71 token units"); } /// SOLVENCY END-TO-END: compare, for an identical (seed 1.5 base units) + @@ -400,8 +388,7 @@ contract RaindexV6DustCreditPrecisionAttackTest is Test { // Conservation for pushes: tokens physically sent + retained credit // == requested. i.e. movedTotal + credit == netRequested. - Float movedTotal = - _floatFromBaseUnits(moved1).add(_floatFromBaseUnits(moved2)); + Float movedTotal = _floatFromBaseUnits(moved1).add(_floatFromBaseUnits(moved2)); Float netRequested = r1.add(r2); Float credit = harness.exposedDustCredit(owner, address(token)); Float expected = netRequested.sub(credit); From 22485cb6f029dcd8502b4c06b7fb312abdeaa67f Mon Sep 17 00:00:00 2001 From: David Meister Date: Thu, 11 Jun 2026 09:45:20 +0000 Subject: [PATCH 4/8] test(raindex): fix dust-credit fallout in read-counts and takeOrder.precision The dust-credit ledger adds an sDustCredit Float slot that pullTokens and pushTokens always SLOAD and SSTORE, and whose realization shifts the exact base-unit transfer amounts when a single address is both depositor/taker/owner. Both effects are legitimate new behavior; this updates the test expectations to match it. No source change is required. Read/write-count assertions (each Float slot access is 2 SLOADs; the unconditional store is 1 SSTORE): - deposit testDepositMany: reads 5 -> 7 (+2 dust SLOAD in pullTokens), writes pinned to 4 (+1 dust SSTORE). - withdraw testWithdrawEmptyVault: reads 6 -> 8, writes 3 -> 4 (the noop still calls pushTokens, which reads and writes the dust slot). - deposit.entask checkReentrancyRW: reads 5 -> 7, writes 3 -> 4. - withdraw.entask checkReentrancyRW: reads 6 -> 8, writes 3 -> 4. takeOrder.precision KnownBad07-11 and KnownBad01BothVaultIdZero: investigated and confirmed a boundary shift, NOT a precision regression. checkPrecision reuses address(this) as depositor, taker, and order owner, so the lossy seed deposit (or taker-payment pull) over-pulls by ceil-exact and books it as dust credit for that (account, token); the matching push then realizes it, sending floor(exact + credit) == ceil instead of the truncated floor(exact). The Float accounting (totalTakerInput/Output equality and the output vault ending at zero) is unchanged and conservation holds: the taker receives back exactly the sub-unit dust it over-paid. The transfer mocks now expect the ceil amount in those coupled cases. forge test --match-path 'test/concrete/raindex/*' is green (0 failures) with pointers regenerated locally. Co-Authored-By: Claude Opus 4.8 --- .../raindex/RaindexV6.deposit.entask.t.sol | 7 +++++-- test/concrete/raindex/RaindexV6.deposit.t.sol | 11 +++++----- ...ndexV6.dustCredit.conservationAttack.t.sol | 12 ++++++----- .../RaindexV6.dustCredit.solvencyAttack.t.sol | 7 ++++--- .../RaindexV6.takeOrder.precision.t.sol | 21 +++++++++++++++++-- .../raindex/RaindexV6.withdraw.entask.t.sol | 8 ++++--- .../concrete/raindex/RaindexV6.withdraw.t.sol | 7 +++++-- 7 files changed, 51 insertions(+), 22 deletions(-) diff --git a/test/concrete/raindex/RaindexV6.deposit.entask.t.sol b/test/concrete/raindex/RaindexV6.deposit.entask.t.sol index b398fb3457..004512d864 100644 --- a/test/concrete/raindex/RaindexV6.deposit.entask.t.sol +++ b/test/concrete/raindex/RaindexV6.deposit.entask.t.sol @@ -26,12 +26,15 @@ contract RaindexV6DepositEnactTest is RaindexV6ExternalRealTest { // ReentrancyGuard.REENTRANCY_GUARD_STORAGE bytes32 reentrancyGuardStorage = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; - assertEq(reads.length, 5); + // pullTokens reads sDustCredit (2 SLOADs of the Float slot) and writes it + // back (1 SSTORE), adding 2 reads and 1 write over the pre-dust-credit + // 5 reads (reentrancy x3 + vault balance x2) / 3 writes. + assertEq(reads.length, 7); assertEq(reads[0], reentrancyGuardStorage); assertEq(reads[1], reentrancyGuardStorage); assertEq(reads[reads.length - 1], reentrancyGuardStorage); - assertEq(writes.length, 3); + assertEq(writes.length, 4); assertEq(writes[0], reentrancyGuardStorage); assertEq(writes[writes.length - 1], reentrancyGuardStorage); } diff --git a/test/concrete/raindex/RaindexV6.deposit.t.sol b/test/concrete/raindex/RaindexV6.deposit.t.sol index 2d450ec2a6..e7705a5ac9 100644 --- a/test/concrete/raindex/RaindexV6.deposit.t.sol +++ b/test/concrete/raindex/RaindexV6.deposit.t.sol @@ -199,11 +199,12 @@ contract RaindexV6DepositTest is RaindexV6ExternalMockTest { assertEq(vm.getRecordedLogs().length, 1, "logs"); // - reentrancy guard x3 // - vault balance floats x2 - // - token decimals x2 - assertTrue(reads.length == 5, "reads"); - // // - reentrancy guard x2 - // // - vault balance x1 - assertTrue(writes.length == 4 || writes.length == 3, "writes"); + // - dust credit floats x2 (sDustCredit SLOAD in pullTokens) + assertTrue(reads.length == 7, "reads"); + // - reentrancy guard x2 + // - vault balance x1 + // - dust credit x1 (sDustCredit SSTORE in pullTokens) + assertTrue(writes.length == 4, "writes"); assertTrue( iRaindex.vaultBalance2(actions[i].depositor, actions[i].token, actions[i].vaultId) .eq(actions[i].amount.add(vaultBalanceBefore)), diff --git a/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol index 3c56dc5215..f4207e73fa 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol @@ -144,9 +144,8 @@ contract RaindexV6DustCreditConservationAttackTest is Test { // Total requested across both moves = seed + big. Float totalRequested = seed.add(big); // realDelta total = first move (1 base unit = 1e-36) + this move. - Float realDeltaTotal = LibDecimalFloat.fromFixedDecimalLosslessPacked(1, decimals).add( - LibDecimalFloat.fromFixedDecimalLosslessPacked(realMoved, decimals) - ); + Float realDeltaTotal = LibDecimalFloat.fromFixedDecimalLosslessPacked(1, decimals) + .add(LibDecimalFloat.fromFixedDecimalLosslessPacked(realMoved, decimals)); Float creditNew = harness.exposedDustCredit(owner, address(token)); assertTrue(realDeltaTotal.eq(totalRequested.add(creditNew)), "conservation high-decimals"); } @@ -161,7 +160,8 @@ contract RaindexV6DustCreditConservationAttackTest is Test { Float seed = LibDecimalFloat.packLossless(5, -37); harness.exposedPush(owner, address(token), seed); assertTrue( - harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(5, -37)), "push seed credit" + harness.exposedDustCredit(owner, address(token)).eq(LibDecimalFloat.packLossless(5, -37)), + "push seed credit" ); // Large push. @@ -251,7 +251,9 @@ contract RaindexV6DustCreditConservationAttackTest is Test { Float conserved = totalRequested.add(creditAfter); // At Float precision they ARE equal: the stated invariant survives even as // the credit is physically stranded. - assertTrue(realDeltaTotal.eq(conserved), "Float-precision conservation still holds; stranding is sub-resolution"); + assertTrue( + realDeltaTotal.eq(conserved), "Float-precision conservation still holds; stranding is sub-resolution" + ); } /// ATTACK 8: broaden the PR fuzz beyond its 6-decimal / 25.5-base-unit cap. diff --git a/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol index 613a697691..2deeb66f01 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol @@ -38,7 +38,9 @@ contract RaindexV6DustCreditSolvencyAttackTest is Test { function _deployHarness() internal { LibRainDeploy.etchZoltuFactory(vm); LibRainDeploy.deployZoltu(LibTOFUTokenDecimals.TOFU_DECIMALS_EXPECTED_CREATION_CODE); - harness = RaindexV6DustCreditSolvencyAttackHarness(payable(address(uint160(uint256(keccak256("dust.credit.solvency.attack")))))); + harness = RaindexV6DustCreditSolvencyAttackHarness( + payable(address(uint160(uint256(keccak256("dust.credit.solvency.attack"))))) + ); vm.etch(address(harness), type(RaindexV6DustCreditSolvencyAttackHarness).runtimeCode); } @@ -214,8 +216,7 @@ contract RaindexV6DustCreditSolvencyAttackTest is Test { // recording a debt it never withheld -> a credit backed by nothing. // `sent` can exceed int224; pack it lossily and use >= so any inflation // of `credit` beyond the real (possibly under-counted) shortfall trips. - (Float sentTokenUnits,) = - LibDecimalFloat.fromFixedDecimalLossyPacked(sent, decimals); + (Float sentTokenUnits,) = LibDecimalFloat.fromFixedDecimalLossyPacked(sent, decimals); Float trueWithheld = requested.sub(sentTokenUnits); // credit must be <= trueWithheld (never inflated above what was withheld). assertTrue(!credit.gt(trueWithheld), "credit <= true withheld dust (not inflated)"); diff --git a/test/concrete/raindex/RaindexV6.takeOrder.precision.t.sol b/test/concrete/raindex/RaindexV6.takeOrder.precision.t.sol index 19b3f543b2..4e9365e755 100644 --- a/test/concrete/raindex/RaindexV6.takeOrder.precision.t.sol +++ b/test/concrete/raindex/RaindexV6.takeOrder.precision.t.sol @@ -85,7 +85,15 @@ contract RaindexV6TakeOrderPrecisionTest is RaindexV6ExternalRealTest { { (uint256 absoluteTakerInputAmount, bool lossless) = expectedTakerTotalInput.toFixedDecimalLossy(outputTokenDecimals); - (lossless); + // When the output vault is non-zero the taker is also the depositor, + // so the lossy seed deposit above over-pulled by `ceil - exact` and + // booked it as dust credit for `(this, outputToken)`. The matching + // push to the taker realizes that credit, sending `floor(exact + + // credit) == ceil` rather than the truncated `floor(exact)`. A vault-0 + // output has no seed deposit so the push is the plain truncation. + if (!lossless && outputVaultId != bytes32(0)) { + ++absoluteTakerInputAmount; + } vm.mockCall( outputToken, abi.encodeWithSelector(IERC20.transfer.selector, address(this), absoluteTakerInputAmount), @@ -109,7 +117,16 @@ contract RaindexV6TakeOrderPrecisionTest is RaindexV6ExternalRealTest { } if (inputVaultId == bytes32(0)) { - (uint256 absoluteInputAmount,) = expectedTakerTotalOutput.toFixedDecimalLossy(inputTokenDecimals); + // The vault-0 input is pushed back out to the owner, who is also the + // taker here. The taker payment pull above over-pulled by `ceil - + // exact` and booked it as dust credit for `(this, inputToken)`, so the + // vault-0 push realizes that credit and sends `floor(exact + credit) + // == ceil` rather than the truncated `floor(exact)`. + (uint256 absoluteInputAmount, bool lossless) = + expectedTakerTotalOutput.toFixedDecimalLossy(inputTokenDecimals); + if (!lossless) { + ++absoluteInputAmount; + } mockVault0Input(inputToken, address(this), absoluteInputAmount); } diff --git a/test/concrete/raindex/RaindexV6.withdraw.entask.t.sol b/test/concrete/raindex/RaindexV6.withdraw.entask.t.sol index aa2536e577..b5fe6ae67e 100644 --- a/test/concrete/raindex/RaindexV6.withdraw.entask.t.sol +++ b/test/concrete/raindex/RaindexV6.withdraw.entask.t.sol @@ -28,7 +28,8 @@ contract RaindexV6WithdrawEvalTest is RaindexV6ExternalRealTest { function checkReentrancyRW(uint256 expectedReads, uint256 expectedWrites) internal view { (bytes32[] memory reads, bytes32[] memory writes) = vm.accesses(address(iRaindex)); // 3 reads for reentrancy guard. - // 2 reads for deposit. + // 2 reads for the vault balance Float. + // 2 reads for the sDustCredit Float that pushTokens loads. assertEq(reads.length, expectedReads, "reads length"); // ReentrancyGuard.REENTRANCY_GUARD_STORAGE bytes32 reentrancyGuardStorage = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00; @@ -36,7 +37,8 @@ contract RaindexV6WithdrawEvalTest is RaindexV6ExternalRealTest { assertEq(reads[1], reentrancyGuardStorage, "reads[1]"); assertEq(reads[reads.length - 1], reentrancyGuardStorage, "reads[reads.length - 1]"); // 2 writes for reentrancy guard. - // 1 write for deposit. + // 1 write for the vault balance. + // 1 write for the sDustCredit slot that pushTokens stores back. assertEq(writes.length, expectedWrites, "writes length"); assertEq(writes[0], reentrancyGuardStorage, "writes[0]"); assertEq(writes[writes.length - 1], reentrancyGuardStorage, "writes[writes.length - 1]"); @@ -117,7 +119,7 @@ contract RaindexV6WithdrawEvalTest is RaindexV6ExternalRealTest { } iRaindex.withdraw4(address(iToken0), vaultId, targetAmount, actions); if (err.length == 0) { - checkReentrancyRW(6, 3); + checkReentrancyRW(8, 4); (bytes32[] memory reads, bytes32[] memory writes) = vm.accesses(address(iStore)); assertEq(reads.length, expectedReads); assertEq(writes.length, expectedWrites); diff --git a/test/concrete/raindex/RaindexV6.withdraw.t.sol b/test/concrete/raindex/RaindexV6.withdraw.t.sol index c093e2ab8d..0762ccae99 100644 --- a/test/concrete/raindex/RaindexV6.withdraw.t.sol +++ b/test/concrete/raindex/RaindexV6.withdraw.t.sol @@ -56,8 +56,11 @@ contract RaindexV6WithdrawTest is RaindexV6ExternalMockTest { vm.record(); iRaindex.withdraw4(address(iToken0), vaultId, amount, new TaskV2[](0)); (bytes32[] memory reads, bytes32[] memory writes) = vm.accesses(address(iRaindex)); - assertEq(reads.length, 6, "reads"); - assertEq(writes.length, 3, "writes"); + // The noop withdraw still calls pushTokens, which reads sDustCredit (2 + // SLOADs of the Float slot) and unconditionally writes it back (1 SSTORE), + // adding 2 reads and 1 write over the pre-dust-credit 6 reads / 3 writes. + assertEq(reads.length, 8, "reads"); + assertEq(writes.length, 4, "writes"); } /// Withdrawing the full amount from a vault should delete the vault. From 17034721518b929438c7720ef521c8b63253f8ce Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Mon, 15 Jun 2026 20:25:15 +0000 Subject: [PATCH 5/8] build(raindex): regenerate pointers + pin 0.1.10 deploy constants The dust-credit ledger changes RaindexV6 bytecode, so its CREATE2 address moves; the three arb takers embed that address and re-emit in turn. BuildPointers run to a fixpoint (RaindexV6, GenericPoolArbOrderTaker, RouteProcessorArbOrderTaker, GenericPoolFlashBorrower all settle; SubParser and RouteProcessor4 unchanged). The next-version (0.1.10) deploy-constant suite is pre-pinned in LibRaindexDeploy so the publish lands without a red main. build.sh regenerated the test_fixtures RaindexV6 abi+bytecode. Co-Authored-By: Claude Opus 4.8 --- crates/test_fixtures/abis/RaindexV6.json | 2 +- ...ricPoolRaindexV6ArbOrderTaker.pointers.sol | 6 +- ...ricPoolRaindexV6FlashBorrower.pointers.sol | 6 +- src/generated/RaindexV6.pointers.sol | 8 +-- ...ocessorRaindexV6ArbOrderTaker.pointers.sol | 6 +- src/lib/deploy/LibRaindexDeploy.sol | 58 +++++++++++++++++++ 6 files changed, 72 insertions(+), 14 deletions(-) diff --git a/crates/test_fixtures/abis/RaindexV6.json b/crates/test_fixtures/abis/RaindexV6.json index 54621ad6fe..dc1e3cc85d 100644 --- a/crates/test_fixtures/abis/RaindexV6.json +++ b/crates/test_fixtures/abis/RaindexV6.json @@ -2352,7 +2352,7 @@ } ], "bytecode": { - "object": "0x6080604052348015600e575f80fd5b5060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055615eed806100405f395ff3fe608060405234801561000f575f80fd5b50600436106100f0575f3560e01c8063613255ab11610093578063ac9650d811610063578063ac9650d81461022b578063d7e442ec1461024b578063d9d98ce41461025e578063fa50118214610271575f80fd5b8063613255ab146101ad57806369c72856146101c0578063709fb8a5146101e85780639235084d146101fb575f80fd5b80632fbc4ba0116100ce5780632fbc4ba01461015157806341d1514f146101665780635cffe9de14610187578063607461191461019a575f80fd5b806301ffc9a7146100f45780631f69cb751461011c5780632cb77e9f1461012f575b5f80fd5b6101076101023660046148e8565b610284565b60405190151581526020015b60405180910390f35b61010761012a366004614950565b6102ba565b61010761013d3660046149bb565b5f9081526020819052604090205460011490565b61016461015f3660046149f1565b6103c2565b005b610179610174366004614a56565b610521565b604051908152602001610113565b610107610195366004614a94565b610535565b6101646101a83660046149f1565b610635565b6101796101bb366004614b2b565b6107c8565b6101d36101ce366004614b5c565b610830565b60408051928352602083019190915201610113565b6101076101f6366004614b8e565b610fc9565b61020e610209366004614bd8565b61130c565b604080519315158452602084019290925290820152606001610113565b61023e610239366004614c0f565b6113ce565b6040516101139190614c7c565b610164610259366004614c0f565b6114b4565b61017961026c366004614cde565b61150e565b61016461027f366004615150565b6115a8565b5f6001600160e01b0319821663e414309160e01b14806102b457506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f6102c3611a9a565b6102d06020850185614b2b565b6001600160a01b0316336001600160a01b03161461031f576102f56020850185614b2b565b6040516335252be360e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b5f61033161032c8661520a565b611ab5565b5f818152602081905260409020549091505f19016103a4575f818152602081905260408082209190915551600192507f09d18501db0080ca2d6cd7c17fa7255daff4b2d503ea93b76ff68b6752ea8e639061039190339084908990615360565b60405180910390a16103a4818585611ae4565b506103bb60015f80516020615ecd83398151915255565b9392505050565b6103ca611a9a565b3385856103d8838383611b1b565b6103e2865f611b4c565b610417576040516306dde9c360e41b81523360048201526001600160a01b038916602482015260448101889052606401610316565b5f80610424338b8a611b86565b604080513381526001600160a01b038e1660208201529081018c90526060810183905291935091507f7f9dfa19cf1cc2f806f2f860fbc9c056b601fb1afc0e9b843dfe5c63616268e69060800160405180910390a15f80610487338d8d8d611c06565b909250905087156104fd5760408051600581526001600160a01b038e1660208201528082018d9052606081018490526080810183905260ff851660a082015260c081019091526104fd906104ee905b60408051600181526020810192909252818101905290565b6104f88a8c615424565b611cf6565b5050505050505061051a60015f80516020615ecd83398151915255565b5050505050565b5f61052d848484611ec4565b949350505050565b5f61054a6001600160a01b038616878661204e565b6040516323e30c8b60e01b81525f906001600160a01b038816906323e30c8b906105829033908a908a9087908b908b906004016154e4565b6020604051808303815f875af115801561059e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105c29190615528565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9811461060757604051630b6c58a960e31b815260048101829052602401610316565b61062887306106165f89615553565b6001600160a01b038a16929190612083565b5060019695505050505050565b61063d611a9a565b33858561064b838383611b1b565b5f8080806106598a82611b4c565b61068d57604051623a3a4d60e21b81523360048201526001600160a01b038d166024820152604481018c9052606401610316565b5f610699338e8e611ec4565b90506106a58b826120bf565b94506106b3338e8e886120db565b90935091505f6106c4338f88612152565b80965081925050507f8045c25080b0868951141ed0a91720bcad09a8364a2b3109ee1fd49c1f0bc8b8338f8f8f8a86604051610736969594939291906001600160a01b03968716815294909516602085015260408401929092526060830152608082015260a081019190915260c00190565b60405180910390a1505060408051600681526001600160a01b038e1660208201528082018d9052606081018490526080810183905260a081018c905260ff851660c0820152600160e08201908152610100820182905261012082019092529089156107a9576107a9816104f88c8e615424565b50505050505050505061051a60015f80516020615ecd83398151915255565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa15801561080c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b49190615528565b5f8061083a611a9a565b6108476080840184615566565b90505f0361086857604051639c95219f60e01b815260040160405180910390fd5b610870614810565b61087861483c565b5f60405180606001604052808780608001906108949190615566565b5f8181106108a4576108a46155ac565b90506020028101906108b691906155c0565b6108c090806155de565b6108ce9060408101906155f2565b6108db60808b018b615566565b5f8181106108eb576108eb6155ac565b90506020028101906108fd91906155c0565b60200135818110610910576109106155ac565b6109269260206040909202019081019150614b2b565b6001600160a01b031681526020016109416080890189615566565b5f818110610951576109516155ac565b905060200281019061096391906155c0565b61096d90806155de565b61097b9060608101906155f2565b61098860808b018b615566565b5f818110610998576109986155ac565b90506020028101906109aa91906155c0565b604001358181106109bd576109bd6155ac565b6109d39260206040909202019081019150614b2b565b6001600160a01b03168152602088810135910152905060605f6109f96080890189615566565b604080516001909201602002820181528501519093505f9250610a1d915082611b4c565b610a3a5760405163315f9e2360e21b815260040160405180910390fd5b5f5b610a4960808a018a615566565b905081108015610a6357506040840151610a63905f611b4c565b15610e7157610a7560808a018a615566565b82818110610a8557610a856155ac565b9050602002810190610a9791906155c0565b610aa090615638565b9550855f01519450835f01516001600160a01b03168560400151876020015181518110610acf57610acf6155ac565b60200260200101515f01516001600160a01b0316141580610b2a575083602001516001600160a01b03168560600151876040015181518110610b1357610b136155ac565b60200260200101515f01516001600160a01b031614155b15610b485760405163936bb5ad60e01b815260040160405180910390fd5b610b5b85876020015188604001516121bb565b5f610b6586611ab5565b5f81815260208190526040902054909150610bca578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a1610e68565b5f610c278789602001518a60400151338c606001515f67ffffffffffffffff811115610bf857610bf8614d08565b604051908082528060200260200182016040528015610c21578160200160208202803683370190505b5061222d565b90505f610c458c604001358360600151611b4c90919063ffffffff16565b15610c9b578751604080513381526001600160a01b03909216602083015281018490527fe3151dc8cb7a54ffc4baabd28c1f241c94d510b5e5b502491ac3cad6c16316d5906060015b60405180910390a1610e5a565b6040820151610caa905f611b4c565b1580610cc257506060820151610cc0905f611b4c565b155b15610d0f578751604080513381526001600160a01b03909216602083015281018490527f500b713857325f9e6dcb52ae832eca9109d107ed1aae9cb4928b4c1e13f051aa90606001610c8e565b600190505f808d6060016020810190610d2891906156ce565b15610d6e576040808a015190850151610d40916120bf565b6060850151909250610d5290836126f2565b60408a0151909150610d64908361273f565b60408a0152610dd5565b5f610d8a856040015186606001516126f290919063ffffffff16565b9050610da38a60400151826120bf90919063ffffffff16565b9150610dbc85606001518361276f90919063ffffffff16565b60408b0151909350610dce908361273f565b60408b0152505b610ddf8c8261279f565b9b50610deb8d8361279f565b9c50610df782856127cf565b610e018185612890565b7f194f1feb3b4d7076a2c272e774e792e0c48bb8c7aa1a9a3671c1cd6da9e6b4c1338c8484604051610e3694939291906157f6565b60405180910390a187516001018089526020028801849052610e5784612a3c565b50505b8480610e635750805b945050505b50600101610a3c565b505f610e8360808a0160608b016156ce565b610e8d5786610e8f565b875b9050610e9c818a35612c7f565b15610ec45760405163573b6f4160e01b81528935600482015260248101829052604401610316565b50610ed433846020015189612152565b505f9050610ee560a08a018a6158e0565b9050118015610ef15750805b15610f635760208301518351339163691f9ed7918a8a610f1460a08f018f6158e0565b6040518763ffffffff1660e01b8152600401610f35969594939291906154e4565b5f604051808303815f87803b158015610f4c575f80fd5b505af1158015610f5e573d5f803e3d5ffd5b505050505b610f7133845f015188611b86565b50505f5b8251811015610fa857610fa0838281518110610f9357610f936155ac565b6020026020010151612cb9565b600101610f75565b505050505050610fc460015f80516020615ecd83398151915255565b915091565b5f610fd2611a9a565b5f61102f61102a610fe38780615923565b610ff19060408101906158e0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612dc392505050565b612e34565b90505f811161105157604051632cff108b60e21b815260040160405180910390fd5b6001811161107257604051633c8270bd60e21b815260040160405180910390fd5b61107f60208601866155f2565b90505f036110a057604051636c44ef8f60e01b815260040160405180910390fd5b6110ad60408601866155f2565b90505f036110ce5760405163540e5f0b60e01b815260040160405180910390fd5b6040805160a081019091523381525f90602081016110ec8880615923565b6110f590615937565b815260200187806020019061110a91906155f2565b808060200260200160405190810160405280939291908181526020015f905b828210156111555761114660408302860136819003810190615942565b81526020019060010190611129565b505050918352505060200161116d60408901896155f2565b808060200260200160405190810160405280939291908181526020015f905b828210156111b8576111a960408302860136819003810190615942565b8152602001906001019061118c565b50505050508152602001876060013581525090505f6111d682611ab5565b5f818152602081905260409020549091501580156112f1575f828152602081905260409081902060019055835190517f87491344dfbcf91f6cbbc610cbbeedc85313d37a02df0c93527f7ea5f8db717f91611234918590879061595c565b60405180910390a15f61124a60a08a018a6158e0565b905011156112e65761129b61126260a08a018a6158e0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612e4e92505050565b82517fd46c2c56b35c8210e9e712ec3f02242d5fc90187c0ac8ed80cc33626846ec36990836112cd60a08c018c6158e0565b6040516112dd9493929190615983565b60405180910390a15b6112f1828888611ae4565b93505050506103bb60015f80516020615ecd83398151915255565b5f80808061132661131d86806155de565b61032c9061520a565b5f8181526020819052604090205490915060011461134d57505f92508291508190506113c7565b61137261135a86806155de565b6113639061520a565b866020013587604001356121bb565b5f6113b061138087806155de565b6113899061520a565b60208801356040890135336113a160608c018c615566565b6113aa916159b5565b5f610bf8565b905060018160400151826060015194509450945050505b9193909250565b604080515f8152602081019091526060908267ffffffffffffffff8111156113f8576113f8614d08565b60405190808252806020026020018201604052801561142b57816020015b60608152602001906001900390816114165790505b5091505f5b838110156114ac576114873086868481811061144e5761144e6155ac565b905060200281019061146091906158e0565b85604051602001611473939291906159d4565b604051602081830303815290604052612e79565b838281518110611499576114996155ac565b6020908102919091010152600101611430565b505092915050565b6114bc611a9a565b604080515f808252602082019092526114f4916114e9565b60608152602001906001900390816114d45790505b506104f88385615424565b61150a60015f80516020615ecd83398151915255565b5050565b6040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611552573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115769190615528565b5f036115a057604051633c5bf76960e21b81526001600160a01b0384166004820152602401610316565b505f92915050565b6115b0611a9a565b835185516001600160a01b039182169116036115df57604051630a98f1f360e21b815260040160405180910390fd5b83604001518360400135815181106115f9576115f96155ac565b60200260200101515f01516001600160a01b03168560600151846020013581518110611627576116276155ac565b60200260200101515f01516001600160a01b03161415806116a0575060408501518051843590811061165b5761165b6155ac565b60200260200101515f01516001600160a01b03168460600151846060013581518110611689576116896155ac565b60200260200101515f01516001600160a01b031614155b156116be5760405163936bb5ad60e01b815260040160405180910390fd5b84606001518360200135815181106116d8576116d86155ac565b60200260200101515f01516001600160a01b03168560400151845f013581518110611705576117056155ac565b60200260200101515f01516001600160a01b03160361173757604051631cd2f1c760e21b815260040160405180910390fd5b5f61174186611ab5565b5f818152602081905260409020549091506117a7578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a150611a84565b5f6117b186611ab5565b5f81815260208190526040902054909150611818578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a15050611a84565b7f6fa7f4c28634b0a9d6831401c45ae468195fb63aed07308935c35374ff5d9e393388888860405161184d94939291906159f7565b60405180910390a1505083515f906118719087908635906020880135908686610bf8565b90505f6118a086866040013587606001358a5f0151885f67ffffffffffffffff811115610bf857610bf8614d08565b90505f6118ad8383612f19565b90506118bc815f0151846127cf565b6118ca8160200151836127cf565b6118d8816040015184612890565b6118e6816060015183612890565b6118ef83612cb9565b6118f882612cb9565b606081015181515f9161190b919061273f565b90505f6119298360400151846020015161273f90919063ffffffff16565b9050611935825f612c7f565b806119455750611945815f612c7f565b1561196357604051630d86822160e01b815260040160405180910390fd5b611997338b606001518a6020013581518110611981576119816155ac565b60200260200101515f01518a6080013585611c06565b50506119cd338a606001518a60600135815181106119b7576119b76155ac565b60200260200101515f01518a60a0013584611c06565b5050604080513381528451602080830191909152850151818301529084015160608083019190915284015160808201527fd9fa84dd790c969daa5c33d8050dc06b4a9b59d5b42e2be5f5e8ae20447f618d925060a001905060405180910390a1611a3683612a3c565b611a3f82612a3c565b80516001600160e01b0316158015611a62575060208101516001600160e01b0316155b15611a80576040516321badf1f60e01b815260040160405180910390fd5b5050505b61051a60015f80516020615ecd83398151915255565b611aa2612f67565b60025f80516020615ecd83398151915255565b5f81604051602001611ac79190615a73565b604051602081830303815290604052805190602001209050919050565b604080516002815260208101859052338183015260608101909152611b1690611b0c906104d6565b6104f88385615424565b505050565b80611b16576040516305dbdfd960e41b81526001600160a01b03808516600483015283166024820152604401610316565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d611b7a84848484612f98565b12979650505050505050565b5f805f611b928561306c565b9050611b9e845f612c7f565b15611bbc57604051632eaefac360e21b815260040160405180910390fd5b5f80611bc886846130d2565b9150915080611bdd57611bda82615a85565b91505b8115611bf857611bf86001600160a01b038816893085612083565b50925090505b935093915050565b5f80611c128382612c7f565b15611c335760405163793a8f5560e01b815260048101849052602401610316565b83611c5157611c43868685612152565b505f9250829150611ced9050565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611c8b828661279f565b9050611c97815f612c7f565b15611cb85760405163c5e12af560e01b815260048101829052602401610316565b6001600160a01b038089165f908152600160209081526040808320938b16835292815282822089835290522081905590925090505b94509492505050565b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b8651811015611eba57868181518110611d5d57611d5d6155ac565b602002602001015193505f845f015160400151511115611eb2575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001611dd58d8a602001516130ff565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401611e009190615af5565b5f60405180830381865afa158015611e1a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e419190810190615bed565b9150505f81511115611eb05784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490611e82908a908590600401615ca3565b5f604051808303815f87803b158015611e99575f80fd5b505af1158015611eab573d5f803e3d5ffd5b505050505b505b600101611d42565b5050505050505050565b5f8115611efe57506001600160a01b038084165f9081526001602090815260408083209386168352928152828220848352905220546103bb565b5f611f08846133e1565b6040516370a0823160e01b81526001600160a01b0387811660048301529192505f91611f8091908716906370a0823190602401602060405180830381865afa158015611f56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f7a9190615528565b836133ed565b50604051636eb1769f60e11b81526001600160a01b0388811660048301523060248301529192505f91611fff919088169063dd62ed3e90604401602060405180830381865afa158015611fd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ff99190615528565b846133ed565b506001600160a01b038089165f908152600160209081526040808320938b168352928152828220828052905220549091506120449061203e84846120bf565b9061279f565b93505050506103bb565b61205b838383600161342d565b611b1657604051635274afe760e01b81526001600160a01b0384166004820152602401610316565b61209184848484600161348f565b6120b957604051635274afe760e01b81526001600160a01b0385166004820152602401610316565b50505050565b5f6120ca8383612c7f565b6120d457816103bb565b5090919050565b5f806120e78382612c7f565b156121085760405163793a8f5560e01b815260048101849052602401610316565b8361211857611c43868685611b86565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611c8b828661273f565b5f805f61215e8561306c565b905061216a845f612c7f565b1561218857604051632d1671a360e11b815260040160405180910390fd5b5f61219385836130d2565b50905080156121b0576121b06001600160a01b038716888361204e565b969095509350505050565b826060015181815181106121d1576121d16155ac565b60200260200101515f01516001600160a01b0316836040015183815181106121fb576121fb6155ac565b60200260200101515f01516001600160a01b031603611b1657604051631cd2f1c760e21b815260040160405180910390fd5b6122356148a3565b60408051600480825260a082019092526060915f9190816020015b60608152602001906001900390816122505790505090506122a56122738a611ab5565b8a51604080516003815260208101939093526001600160a01b0391821683820152908916606083015260808201905290565b8160018003815181106122ba576122ba6155ac565b60200260200101819052505f6122ef8a604001518a815181106122df576122df6155ac565b60200260200101515f01516133e1565b90505f6123418b5f01518c604001518c8151811061230f5761230f6155ac565b60200260200101515f01518d604001518d81518110612330576123306155ac565b602002602001015160200151611ec4565b90506123d08b604001518b8151811061235c5761235c6155ac565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d604001518d8151811061238e5761238e6155ac565b602002602001015160200151845f801b60408051600581526020810196909652858101949094526060850192909252608084015260a083015260c08201905290565b836001600303815181106123e6576123e66155ac565b602002602001018190525050505f61240d8a6060015189815181106122df576122df6155ac565b90505f61244e8b5f01518c606001518b8151811061242d5761242d6155ac565b60200260200101515f01518d606001518c81518110612330576123306155ac565b905061249b8b606001518a81518110612469576124696155ac565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d606001518c8151811061238e5761238e6155ac565b836001600403815181106124b1576124b16155ac565b602002602001018190525050506124c881866130ff565b9150505f885f01516001600160a01b031690505f808a602001515f01516001600160a01b031663d04dfe236040518060e001604052808e60200151602001516001600160a01b0316815260200161252887305f9182526020526040902090565b81526020018e602001516040015181526020015f81526020018781526020015f67ffffffffffffffff81111561256057612560614d08565b604051908082528060200260200182016040528015612589578160200160208202803683370190505b508152602001898152506040518263ffffffff1660e01b81526004016125af9190615af5565b5f60405180830381865afa1580156125c9573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526125f09190810190615bed565b9150915060028251101561261c578151604051630fbb8e5560e21b815260040161031691815260200190565b602082015160408301518551612670908790600490811061263f5761263f6155ac565b6020026020010151600381518110612659576126596155ac565b6020026020010151826120bf90919063ffffffff16565b60408051600281526020810183905280820185905260608101909152909150866002815181106126a2576126a26155ac565b60200260200101819052506040518060e001604052808e81526020018c81526020018281526020018381526020018781526020018681526020018481525096505050505050509695505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d8480612722868686866134fc565b915091505f612731838361361b565b9a9950505050505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061272286868686613668565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061272286868686613692565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061272286868686613bcf565b8181608001516004815181106127e7576127e76155ac565b6020026020010151600481518110612801576128016155ac565b6020026020010181815250506120b9815f01515f0151826080015160048151811061282e5761282e6155ac565b60200260200101515f81518110612847576128476155ac565b60200260200101515f1c8360800151600481518110612868576128686155ac565b6020026020010151600281518110612882576128826155ac565b6020026020010151856120db565b8181608001516003815181106128a8576128a86155ac565b60200260200101516004815181106128c2576128c26155ac565b6020908102919091010152805151608082015180515f919060039081106128eb576128eb6155ac565b60200260200101515f81518110612904576129046155ac565b60200260200101515f1c90505f8360800151600381518110612928576129286155ac565b6020026020010151600281518110612942576129426155ac565b602002602001015190505f801b81036129e95761295f855f612c7f565b156129805760405163793a8f5560e01b815260048101869052602401610316565b6001600160a01b038084165f9081526001602090815260408083209386168352928152828220848352905220546129b7908661279f565b6001600160a01b038085165f9081526001602090815260408083209387168352928152828220858352905220556129f8565b6129f583838388611c06565b50505b7f4cb6e22a3e7e651d7cf0376cff48f20f5007a54147777865be7f5f6c38c50f4a338560800151604051612a2d929190615cbb565b60405180910390a15050505050565b60c08101515115612ab6578051602090810151015160a082015160c083015160405163012c676d60e21b81526001600160a01b03909316926304b19db492612a88929091600401615ca3565b5f604051808303815f87803b158015612a9f575f80fd5b505af1158015612ab1573d5f803e3d5ffd5b505050505b5f815f0151602001515f01516001600160a01b031663d04dfe236040518060e00160405280855f015160200151602001516001600160a01b03168152602001612b0c8660a00151305f9182526020526040902090565b8152602001855f01516020015160400151815260200160018152602001856080015181526020015f67ffffffffffffffff811115612b4c57612b4c614d08565b604051908082528060200260200182016040528015612b75578160200160208202803683370190505b5081526020015f604051908082528060200260200182016040528015612ba5578160200160208202803683370190505b508152506040518263ffffffff1660e01b8152600401612bc59190615af5565b5f60405180830381865afa158015612bdf573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612c069190810190615bed565b9150505f8151111561150a578151602090810151015160a083015160405163012c676d60e21b81526001600160a01b03909216916304b19db491612c4e918590600401615ca3565b5f604051808303815f87803b158015612c65575f80fd5b505af1158015612c77573d5f803e3d5ffd5b505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d612cad84848484612f98565b13979650505050505050565b5f8160800151600381518110612cd157612cd16155ac565b6020026020010151600281518110612ceb57612ceb6155ac565b602002602001015190505f801b810361150a57815151608083015180515f91906003908110612d1c57612d1c6155ac565b60200260200101515f81518110612d3557612d356155ac565b6020908102919091018101516001600160a01b038481165f9081526001845260408082209284168252918452818120878252909352909120549091506001600160e01b0381161561051a576001600160a01b038084165f9081526001602090815260408083209386168352928152828220878352905290812055612dba838383612152565b50505050505050565b6060604082511015612de257505060408051602081019091525f815290565b5f60208301519050602060408451612dfa91906159c1565b612e049190615cf0565b811115612e2057505060408051602081019091525f8152919050565b600181016020026020840101915050919050565b5f81515f03612e4457505f919050565b50602001515f1a90565b612e5781613ccd565b612e765780604051630c89984b60e31b81526004016103169190615d0f565b50565b60605f612e868484613cfb565b9050808015612ea757505f3d1180612ea757505f846001600160a01b03163b115b15612ebc57612eb4613d0e565b9150506102b4565b8015612ee657604051639996b31560e01b81526001600160a01b0385166004820152602401610316565b3d15612ef957612ef4613d27565b612f12565b60405163d6bda27560e01b815260040160405180910390fd5b5092915050565b604080516080810182525f808252602082018190529181018290526060810191909152612f468383613d32565b82526040820152612f578284613d32565b6020830152606082015292915050565b5f80516020615ecd83398151915254600203612f9657604051633ee5aeb560e01b815260040160405180910390fd5b565b5f8085158415178187128286121817858414178015612fbd5786859250925050611ced565b505f85841315612fd1575092949193919260015b8386035f8112604c8213178015613004578215612ff6575f8994509450505050611ced565b885f94509450505050611ced565b600a82900a8981028a82828161301c5761301c615cdc565b0514613048578415613038575f8b965096505050505050611ced565b8a5f965096505050505050611ced565b841561305d578896509450611ced9350505050565b9550879450611ced9350505050565b5f805f61307884613d9b565b9092509050600182600381111561309157613091615d21565b141580156130b057505f8260038111156130ad576130ad615d21565b14155b156103bb57838260405163ee07877f60e01b8152600401610316929190615d35565b5f806001600160e01b038416601b0b60e085901d6130f1828287613e28565b9350935050505b9250929050565b60605f825167ffffffffffffffff81111561311c5761311c614d08565b604051908082528060200260200182016040528015613145578160200160208202803683370190505b5090505f80845111613157575f61315d565b83516001015b85516001010190505f8167ffffffffffffffff81111561317f5761317f614d08565b6040519080825280602002602001820160405280156131b257816020015b606081526020019060019003908161319d5790505b5090505f6131d6604080516002815233602082015230818301526060810190915290565b8282815181106131e8576131e86155ac565b60200260200101819052505f5b8751811015613245578180600101925050878181518110613218576132186155ac565b6020026020010151838381518110613232576132326155ac565b60209081029190910101526001016131f5565b508551156133d757808060010191505083828281518110613268576132686155ac565b60200260200101819052505f5b86518110156133d557613324878281518110613293576132936155ac565b60200260200101515f01516133016132cf8a85815181106132b6576132b66155ac565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b898481518110613313576133136155ac565b602002602001015160400151613f8e565b61334457604051630a57f30960e31b815260048101829052602401610316565b868181518110613356576133566155ac565b60200260200101515f01516001600160a01b03165f1b85828151811061337e5761337e6155ac565b60200260200101818152505081806001019250508681815181106133a4576133a46155ac565b6020026020010151602001518383815181106133c2576133c26155ac565b6020908102919091010152600101613275565b505b5095945050505050565b5f805f61307884613ffe565b5f805f805f6133fc878761405d565b9250925092505f8061340e85856140a0565b915091508183801561341d5750815b9650965050505050509250929050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316613483578383151615613477573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f511483166134eb5783831516156134df573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f8085158415178015613514575f92505f9150613611565b61351e8487615d6e565b91505f61352a88614178565b90505f61353687614178565b90505f61354383836141a6565b5090505f6f0785ee10d5da46d900f436a000000000821115613578576f0785ee10d5da46d900f436a000000000820491506025015b670de0b6b3a764000082111561359957670de0b6b3a7640000820491506012015b633b9aca008211156135b257633b9aca00820491506009015b6127108211156135c757612710820491506004015b81156135db57600a820491506001016135c7565b6135e58187615d6e565b95506136078b8a61360187876135fc87600a615e6d565b6141c2565b8961428e565b9097509550505050505b5094509492505050565b5f805f61362885856140a0565b9150915080158015613638575081155b1561366057604051638eba4d0760e01b81526004810186905260248101859052604401610316565b509392505050565b5f80613674848461432e565b909450925061368586868686613bcf565b9150915094509492505050565b5f80835f036136be57604051637a97930f60e01b81526004810187905260248101869052604401610316565b855f036136cf57505f905080611ced565b5f805f806136dd8a8a614383565b919b50995091506136ee8888614383565b919950975090505f6136ff8b614178565b90505f61370b8a614178565b90507f161bcca7119915b50764b4abe86529797775a5f1719510000000000000000000604c81831015613ad057841561376257507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b9050604b613aa8565b6f4b3b4ca85a86c47a098a22400000000083101561388e57678ac7230489e800008310156137f2576402540be4008310156137c057620186a08310156137b05750620186a090506005613a69565b506402540be4009050600a613a69565b655af3107a40008310156137df5750655af3107a40009050600e613a69565b50678ac7230489e8000090506013613a69565b6b204fce5e3e250261100000008310156138445769152d02c7e14af680000083101561382d575069152d02c7e14af680000090506017613a69565b506b204fce5e3e250261100000009050601c613a69565b6d314dc6448d9338c15b0a0000000083101561387357506d314dc6448d9338c15b0a0000000090506021613a69565b506f4b3b4ca85a86c47a098a22400000000090506026613a69565b780197d4df19d605767337e9f14d3eec8920e4000000000000008310156139865773af298d050e4395d69670b12b7f41000000000000831015613921577172cb5bd86321e38cb6ce6682e8000000000083101561390257507172cb5bd86321e38cb6ce6682e800000000009050602b613a69565b5073af298d050e4395d69670b12b7f4100000000000090506030613a69565b76010b46c6cdd6e3e0828f4db456ff0c8ea0000000000000831015613962575076010b46c6cdd6e3e0828f4db456ff0c8ea000000000000090506035613a69565b50780197d4df19d605767337e9f14d3eec8920e4000000000000009050603a613a69565b7c03b58e88c75313ec9d329eaaa18fb92f75215b17100000000000000000831015613a1c577a026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000008310156139f457507a026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000009050603f613a69565b507c03b58e88c75313ec9d329eaaa18fb92f75215b1710000000000000000090506044613a69565b7e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000831015613a6957507e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000905060495b818311613a7e57600a820491505f1901613a69565b815f03613aa8576040516305e51ecb60e01b8152600481018d9052602481018c9052604401610316565b85613ad0576040516305e51ecb60e01b8152600481018f9052602481018e9052604401610316565b80600160ff1b018d12613ae757808d039c50613b25565b600160ff1b9c90038c015f811315613b2557806001600160ff1b03038b13613b1257998a0199613b25565b5f80995099505050505050505050611ced565b5f808e128015613b3457505f8c135b15613b5557600160ff1b8e01808d13613b4d575f613b51565b808d035b9150505b8b818f01039750613b728f8e613b6c8887896141c2565b8b61428e565b90995097505f811315613bbc57604c811315613b9c575f809a509a50505050505050505050611ced565b80600a0a8981613bae57613bae615cdc565b059850885f03613bbc575f97505b50969850949650611ced95505050505050565b5f8085158415178015613bfb57865f03613bef5784849250925050611ced565b86869250925050611ced565b613c0587876145dd565b9097509550613c1485856145dd565b909550935085841315613c28579395929492935b838603604c811115613c41578787935093505050611ced565b80600a0a8681613c5357613c53615cdc565b0595505086850180881860ff90811c151589881890911c15168015613cbc57876001600160ff1b0303613ca35760405163d556b11160e01b8152600481018a905260248101899052604401610316565b600a968790059690980586019760019790970196613cc0565b8198505b5096979596505050505050565b5f600882511015613cdf57505f919050565b506008015167ffffffffffffffff1667ff0a89c674ee78741490565b5f805f835160208501865af49392505050565b6040513d81523d5f602083013e3d602001810160405290565b6040513d5f823e3d81fd5b5f80613d4f846060015185604001516126f290919063ffffffff16565b915083604001519050613d6f836040015183611b4c90919063ffffffff16565b156130f85782604001519150613d9284606001518361276f90919063ffffffff16565b90509250929050565b5f80613da5614626565b60405163b7bad1b160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb93899063b7bad1b19060240160408051808303815f875af1158015613dfb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e1f9190615e78565b91509150915091565b5f805f851215613e5557604051634a7d166b60e01b81526004810186905260248101859052604401610316565b845f03613e6757505f90506001611bfe565b8460ff8416850185811215613e995760405163d556b11160e01b81526004810188905260248101879052604401610316565b5f805f831215613ee557604c19831215613ebc575f809550955050505050611bfe565b825f03600a0a9150818481613ed357613ed3615cdc565b0495505084029091149150611bfe9050565b5f831315613f7e57604d831315613f225760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b82600a0a9150815f1981613f3857613f38615cdc565b04841115613f6c5760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b5091909102925060019150611bfe9050565b8360019550955050505050611bfe565b5f836001600160a01b03163b5f03613fec575f80613fac85856146b1565b5090925090505f816003811115613fc557613fc5615d21565b148015613fe35750856001600160a01b0316826001600160a01b0316145b925050506103bb565b613ff78484846146f7565b90506103bb565b5f80614008614626565b604051630782d7e160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb938990630782d7e1906024016040805180830381865afa158015613dfb573d5f803e3d5ffd5b5f808060ff841681036001600160ff1b0386111561408f57600a860460018201600a88065f1493509350935050614099565b8593509150600190505b9250925092565b5f601b83900b8314838382614104577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e10000000000000000008605156140e457620186a0860595506005850194505b8586601b0b146140ff57600a860595508460010194506140e4565b61411a565b855f0361411a57505f9250600191506130f89050565b848560030b1461415d575f85121561413a57505f92508291506130f89050565b60405163d556b11160e01b81526004810183905260248101829052604401610316565b50506001600160e01b03841660e084901b1791509250929050565b5f8082121561419d57600160ff1b82036141975750600160ff1b919050565b505f0390565b5090565b919050565b5f805f1983850993909202808410938190039390930393915050565b5f805f6141cf86866141a6565b91509150815f036141f3578381816141e9576141e9615cdc565b04925050506103bb565b8382106142245760405163362ced0960e11b8152600481018790526024810186905260448101859052606401610316565b5f84868809600186198101871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103025f82900382900490920185841190960395909502919093039390930492909217029150509392505050565b5f805f858718121561430a576001600160ff1b038411156142f7576142bb6001600160ff1b036001615553565b84036142cf5750600160ff1b905081611ced565b6142da600a85615cf0565b6142e390615eb8565b6142ee846001615d6e565b91509150611ced565b61430084615eb8565b8391509150611ced565b6001600160ff1b03841115614324576142e3600a85615cf0565b5082905081611ced565b5f80600160ff1b8403614379576001600160ff1b03830361436c5760405163d556b11160e01b81526004810185905260248101849052604401610316565b600a840593508260010192505b50505f9190910391565b5f805f845f0361439b57505f91508190506001614099565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b85055f03614588576f4b3b4ca85a86c47a098a22400000000085051580156143fd57507f80000000000000000000000000000000000000000000000000000000000000268412155b1561441e576f4b3b4ca85a86c47a098a224000000000850294506026840393505b7728c87cb5c89a2571ebfdcb54864ada834a00000000000000850515801561446657507f80000000000000000000000000000000000000000000000000000000000000138412155b1561447f57678ac7230489e80000850294506013840393505b7b097edd871cfda3a5697758bf0e3cbb5ac5741c64000000000000000085051580156144cb57507f800000000000000000000000000000000000000000000000000000000000000a8412155b156144e1576402540be40085029450600a840393505b7e3899162693736ac531a5a58f1fbb4b746504382ca7e4000000000000000000850515801561453057507f80000000000000000000000000000000000000000000000000000000000000028412155b15614546576064850294506002840393506144e1565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b850515801561457657506001600160ff1b018412155b1561458857600a850294506001840393505b600a808602908105861480156145a557506001600160ff1b018512155b156145b4578095506001850394505b50939492935050507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b8305151590565b5f805f805f6145ec8787614383565b9250925092508061461a576040516305e51ecb60e01b81526004810188905260248101879052604401610316565b50909590945092505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b158061467d575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b15612f96576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610316565b5f805f83516041036146e8576020840151604085015160608601515f1a6146da88828585614748565b955095509550505050614099565b505081515f9150600290614099565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561478157505f91506003905082614806565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156147d2573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b0381166147fd57505f925060019150829050614806565b92505f91508190505b9450945094915050565b604051806080016040528061482361483c565b81526020015f81526020015f8152602001606081525090565b6040518060a001604052805f6001600160a01b0316815260200161488a60405180606001604052805f6001600160a01b031681526020015f6001600160a01b03168152602001606081525090565b8152606060208201819052604082018190525f91015290565b6040518060e001604052806148b661483c565b81526020015f81526020015f80191681526020015f8019168152602001606081526020015f8152602001606081525090565b5f602082840312156148f8575f80fd5b81356001600160e01b0319811681146103bb575f80fd5b5f8083601f84011261491f575f80fd5b50813567ffffffffffffffff811115614936575f80fd5b6020830191508360208260051b85010111156130f8575f80fd5b5f805f60408486031215614962575f80fd5b833567ffffffffffffffff80821115614979575f80fd5b9085019060a0828803121561498c575f80fd5b909350602085013590808211156149a1575f80fd5b506149ae8682870161490f565b9497909650939450505050565b5f602082840312156149cb575f80fd5b5035919050565b6001600160a01b0381168114612e76575f80fd5b80356141a1816149d2565b5f805f805f60808688031215614a05575f80fd5b8535614a10816149d2565b94506020860135935060408601359250606086013567ffffffffffffffff811115614a39575f80fd5b614a458882890161490f565b969995985093965092949392505050565b5f805f60608486031215614a68575f80fd5b8335614a73816149d2565b92506020840135614a83816149d2565b929592945050506040919091013590565b5f805f805f60808688031215614aa8575f80fd5b8535614ab3816149d2565b94506020860135614ac3816149d2565b935060408601359250606086013567ffffffffffffffff80821115614ae6575f80fd5b818801915088601f830112614af9575f80fd5b813581811115614b07575f80fd5b896020828501011115614b18575f80fd5b9699959850939650602001949392505050565b5f60208284031215614b3b575f80fd5b81356103bb816149d2565b5f60c08284031215614b56575f80fd5b50919050565b5f60208284031215614b6c575f80fd5b813567ffffffffffffffff811115614b82575f80fd5b61052d84828501614b46565b5f805f60408486031215614ba0575f80fd5b833567ffffffffffffffff80821115614bb7575f80fd5b614bc387838801614b46565b945060208601359150808211156149a1575f80fd5b5f60208284031215614be8575f80fd5b813567ffffffffffffffff811115614bfe575f80fd5b8201608081850312156103bb575f80fd5b5f8060208385031215614c20575f80fd5b823567ffffffffffffffff811115614c36575f80fd5b614c428582860161490f565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b82811015614cd157603f19888603018452614cbf858351614c4e565b94509285019290850190600101614ca3565b5092979650505050505050565b5f8060408385031215614cef575f80fd5b8235614cfa816149d2565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614d3f57614d3f614d08565b60405290565b6040805190810167ffffffffffffffff81118282101715614d3f57614d3f614d08565b60405160a0810167ffffffffffffffff81118282101715614d3f57614d3f614d08565b604051601f8201601f1916810167ffffffffffffffff81118282101715614db457614db4614d08565b604052919050565b5f82601f830112614dcb575f80fd5b813567ffffffffffffffff811115614de557614de5614d08565b614df8601f8201601f1916602001614d8b565b818152846020838601011115614e0c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60608284031215614e38575f80fd5b614e40614d1c565b90508135614e4d816149d2565b81526020820135614e5d816149d2565b6020820152604082013567ffffffffffffffff811115614e7b575f80fd5b614e8784828501614dbc565b60408301525092915050565b5f67ffffffffffffffff821115614eac57614eac614d08565b5060051b60200190565b5f60408284031215614ec6575f80fd5b614ece614d45565b90508135614edb816149d2565b808252506020820135602082015292915050565b5f82601f830112614efe575f80fd5b81356020614f13614f0e83614e93565b614d8b565b8083825260208201915060208460061b870101935086841115614f34575f80fd5b602086015b84811015614f5957614f4b8882614eb6565b835291830191604001614f39565b509695505050505050565b5f60a08284031215614f74575f80fd5b614f7c614d68565b9050614f87826149e6565b8152602082013567ffffffffffffffff80821115614fa3575f80fd5b614faf85838601614e28565b60208401526040840135915080821115614fc7575f80fd5b614fd385838601614eef565b60408401526060840135915080821115614feb575f80fd5b50614ff884828501614eef565b6060830152506080820135608082015292915050565b5f61501b614f0e84614e93565b8381529050602080820190600585811b850187811115615039575f80fd5b855b8181101561512657803567ffffffffffffffff8082111561505a575f80fd5b908801906060828c03121561506d575f80fd5b615075614d1c565b8235615080816149d2565b81528287013582811115615092575f80fd5b8301601f81018d136150a2575f80fd5b80356150b0614f0e82614e93565b81815290881b8201890190898101908f8311156150cb575f80fd5b928a01925b828410156150e95783358252928a0192908a01906150d0565b848b01525060409150508381013583811115615103575f80fd5b61510f8e828701614dbc565b91830191909152508752505093830193830161503b565b50505050509392505050565b5f82601f830112615141575f80fd5b6103bb8383356020850161500e565b5f805f805f6101408688031215615165575f80fd5b853567ffffffffffffffff8082111561517c575f80fd5b61518889838a01614f64565b9650602088013591508082111561519d575f80fd5b6151a989838a01614f64565b95506151b88960408a01614b46565b94506101008801359150808211156151ce575f80fd5b6151da89838a01615132565b93506101208801359150808211156151f0575f80fd5b506151fd88828901615132565b9150509295509295909350565b5f6102b43683614f64565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f8135615249816149d2565b6001600160a01b039081168452602083013590615265826149d2565b166020840152604082013536839003601e19018112615282575f80fd5b820160208101903567ffffffffffffffff81111561529e575f80fd5b8036038213156152ac575f80fd5b606060408601526152c1606086018284615215565b95945050505050565b5f808335601e198436030181126152df575f80fd5b830160208101925035905067ffffffffffffffff8111156152fe575f80fd5b8060061b36038213156130f8575f80fd5b8183525f60208085019450825f5b85811015615355578135615330816149d2565b6001600160a01b0316875281830135838801526040968701969091019060010161531d565b509495945050505050565b5f6001600160a01b038086168352846020840152606060408401528335615386816149d2565b166060830152602083013536849003605e190181126153a3575f80fd5b60a060808401526153ba610100840185830161523d565b90506153c960408501856152ca565b605f19808685030160a08701526153e184838561530f565b93506153f060608801886152ca565b93509150808685030160c08701525061540a83838361530f565b92505050608084013560e084015280915050949350505050565b5f615431614f0e84614e93565b80848252602080830192508560051b85013681111561544e575f80fd5b855b818110156154d857803567ffffffffffffffff8082111561546f575f80fd5b818901915060408236031215615483575f80fd5b61548b614d45565b823582811115615499575f80fd5b6154a536828601614e28565b82525085830135828111156154b8575f80fd5b6154c436828601615132565b828801525087525050938201938201615450565b50919695505050505050565b5f6001600160a01b03808916835280881660208401525085604083015284606083015260a0608083015261551c60a083018486615215565b98975050505050505050565b5f60208284031215615538575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156102b4576102b461553f565b5f808335601e1984360301811261557b575f80fd5b83018035915067ffffffffffffffff821115615595575f80fd5b6020019150600581901b36038213156130f8575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e198336030181126155d4575f80fd5b9190910192915050565b5f8235609e198336030181126155d4575f80fd5b5f808335601e19843603018112615607575f80fd5b83018035915067ffffffffffffffff821115615621575f80fd5b6020019150600681901b36038213156130f8575f80fd5b5f60808236031215615648575f80fd5b6040516080810167ffffffffffffffff828210818311171561566c5761566c614d08565b816040528435915080821115615680575f80fd5b61568c36838701614f64565b8352602085013560208401526040850135604084015260608501359150808211156156b5575f80fd5b506156c236828601615132565b60608301525092915050565b5f602082840312156156de575f80fd5b813580151581146103bb575f80fd5b5f815180845260208085019450602084015f5b8381101561535557815180516001600160a01b031688528301518388015260409096019590820190600101615700565b5f6001600160a01b03808351168452602083015160a060208601528181511660a08601528160208201511660c08601526040810151915050606060e085015261577d610100850182614c4e565b90506040830151848203604086015261579682826156ed565b915050606083015184820360608601526157b082826156ed565b915050608083015160808501528091505092915050565b5f815180845260208085019450602084015f5b83811015615355578151875295820195908201906001016157da565b5f6001600160a01b03808716835260206080818501528651608080860152615822610100860182615730565b90508188015160a086015260408089015160c08701526060808a0151607f198885030160e08901528381518086528686019150868160051b87010187840193505f5b828110156158be57601f1988830301845284518a815116835289810151878b850152615892888501826157c7565b91890151848303858b01529190506158aa8183614c4e565b968b0196958b019593505050600101615864565b5080995050505050505050505083604083015282606083015295945050505050565b5f808335601e198436030181126158f5575f80fd5b83018035915067ffffffffffffffff82111561590f575f80fd5b6020019150368190038213156130f8575f80fd5b5f8235605e198336030181126155d4575f80fd5b5f6102b43683614e28565b5f60408284031215615952575f80fd5b6103bb8383614eb6565b6001600160a01b0384168152826020820152606060408201525f6152c16060830184615730565b6001600160a01b0385168152836020820152606060408201525f6159ab606083018486615215565b9695505050505050565b5f6103bb36848461500e565b818103818111156102b4576102b461553f565b828482375f8382015f815283518060208601835e5f910190815295945050505050565b5f6101206001600160a01b0387168352806020840152615a1981840187615730565b90508281036040840152615a2d8186615730565b9150508235606083015260208301356080830152604083013560a0830152606083013560c0830152608083013560e083015260a083013561010083015295945050505050565b602081525f6103bb6020830184615730565b5f60018201615a9657615a9661553f565b5060010190565b5f8282518085526020808601955060208260051b840101602086015f5b84811015615ae857601f19868403018952615ad68383516157c7565b98840198925090830190600101615aba565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e06060840152615b2e610100840182614c4e565b9050606084015160808401526080840151601f19808584030160a0860152615b568383615a9d565b925060a08601519150808584030160c0860152615b7383836157c7565b925060c08601519150808584030160e0860152506152c182826157c7565b5f82601f830112615ba0575f80fd5b81516020615bb0614f0e83614e93565b8083825260208201915060208460051b870101935086841115615bd1575f80fd5b602086015b84811015614f595780518352918301918301615bd6565b5f8060408385031215615bfe575f80fd5b825167ffffffffffffffff80821115615c15575f80fd5b818501915085601f830112615c28575f80fd5b81516020615c38614f0e83614e93565b82815260059290921b84018101918181019089841115615c56575f80fd5b948201945b83861015615c7457855182529482019490820190615c5b565b91880151919650909350505080821115615c8c575f80fd5b50615c9985828601615b91565b9150509250929050565b828152604060208201525f61052d60408301846157c7565b6001600160a01b0383168152604060208201525f61052d6040830184615a9d565b634e487b7160e01b5f52601260045260245ffd5b5f82615d0a57634e487b7160e01b5f52601260045260245ffd5b500490565b602081525f6103bb6020830184614c4e565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b03831681526040810160048310615d6157634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b8082018281125f8312801582168215821617156114ac576114ac61553f565b600181815b80851115615dc757815f1904821115615dad57615dad61553f565b80851615615dba57918102915b93841c9390800290615d92565b509250929050565b5f82615ddd575060016102b4565b81615de957505f6102b4565b8160018114615dff5760028114615e0957615e25565b60019150506102b4565b60ff841115615e1a57615e1a61553f565b50506001821b6102b4565b5060208310610133831016604e8410600b8410161715615e48575081810a6102b4565b615e528383615d8d565b805f1904821115615e6557615e6561553f565b029392505050565b5f6103bb8383615dcf565b5f8060408385031215615e89575f80fd5b825160048110615e97575f80fd5b602084015190925060ff81168114615ead575f80fd5b809150509250929050565b5f600160ff1b82016141975761419761553f56fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00", + "object": "0x6080604052348015600e575f80fd5b5060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055616019806100405f395ff3fe608060405234801561000f575f80fd5b50600436106100f0575f3560e01c8063613255ab11610093578063ac9650d811610063578063ac9650d81461022b578063d7e442ec1461024b578063d9d98ce41461025e578063fa50118214610271575f80fd5b8063613255ab146101ad57806369c72856146101c0578063709fb8a5146101e85780639235084d146101fb575f80fd5b80632fbc4ba0116100ce5780632fbc4ba01461015157806341d1514f146101665780635cffe9de14610187578063607461191461019a575f80fd5b806301ffc9a7146100f45780631f69cb751461011c5780632cb77e9f1461012f575b5f80fd5b610107610102366004614a14565b610284565b60405190151581526020015b60405180910390f35b61010761012a366004614a7c565b6102ba565b61010761013d366004614ae7565b5f9081526020819052604090205460011490565b61016461015f366004614b1d565b6103c2565b005b610179610174366004614b82565b610521565b604051908152602001610113565b610107610195366004614bc0565b610535565b6101646101a8366004614b1d565b610635565b6101796101bb366004614c57565b6107c8565b6101d36101ce366004614c88565b610830565b60408051928352602083019190915201610113565b6101076101f6366004614cba565b610fc9565b61020e610209366004614d04565b61130c565b604080519315158452602084019290925290820152606001610113565b61023e610239366004614d3b565b6113ce565b6040516101139190614da8565b610164610259366004614d3b565b6114b4565b61017961026c366004614e0a565b61150e565b61016461027f36600461527c565b6115a8565b5f6001600160e01b0319821663e414309160e01b14806102b457506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f6102c3611a9a565b6102d06020850185614c57565b6001600160a01b0316336001600160a01b03161461031f576102f56020850185614c57565b6040516335252be360e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b5f61033161032c86615336565b611ab5565b5f818152602081905260409020549091505f19016103a4575f818152602081905260408082209190915551600192507f09d18501db0080ca2d6cd7c17fa7255daff4b2d503ea93b76ff68b6752ea8e63906103919033908490899061548c565b60405180910390a16103a4818585611ae4565b506103bb60015f80516020615ff983398151915255565b9392505050565b6103ca611a9a565b3385856103d8838383611b1b565b6103e2865f611b4c565b610417576040516306dde9c360e41b81523360048201526001600160a01b038916602482015260448101889052606401610316565b5f80610424338b8a611b86565b604080513381526001600160a01b038e1660208201529081018c90526060810183905291935091507f7f9dfa19cf1cc2f806f2f860fbc9c056b601fb1afc0e9b843dfe5c63616268e69060800160405180910390a15f80610487338d8d8d611cbe565b909250905087156104fd5760408051600581526001600160a01b038e1660208201528082018d9052606081018490526080810183905260ff851660a082015260c081019091526104fd906104ee905b60408051600181526020810192909252818101905290565b6104f88a8c615550565b611dae565b5050505050505061051a60015f80516020615ff983398151915255565b5050505050565b5f61052d848484611f7c565b949350505050565b5f61054a6001600160a01b0386168786612106565b6040516323e30c8b60e01b81525f906001600160a01b038816906323e30c8b906105829033908a908a9087908b908b90600401615610565b6020604051808303815f875af115801561059e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105c29190615654565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9811461060757604051630b6c58a960e31b815260048101829052602401610316565b61062887306106165f8961567f565b6001600160a01b038a1692919061213b565b5060019695505050505050565b61063d611a9a565b33858561064b838383611b1b565b5f8080806106598a82611b4c565b61068d57604051623a3a4d60e21b81523360048201526001600160a01b038d166024820152604481018c9052606401610316565b5f610699338e8e611f7c565b90506106a58b82612177565b94506106b3338e8e88612193565b90935091505f6106c4338f8861220a565b80965081925050507f8045c25080b0868951141ed0a91720bcad09a8364a2b3109ee1fd49c1f0bc8b8338f8f8f8a86604051610736969594939291906001600160a01b03968716815294909516602085015260408401929092526060830152608082015260a081019190915260c00190565b60405180910390a1505060408051600681526001600160a01b038e1660208201528082018d9052606081018490526080810183905260a081018c905260ff851660c0820152600160e08201908152610100820182905261012082019092529089156107a9576107a9816104f88c8e615550565b50505050505050505061051a60015f80516020615ff983398151915255565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa15801561080c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b49190615654565b5f8061083a611a9a565b6108476080840184615692565b90505f0361086857604051639c95219f60e01b815260040160405180910390fd5b61087061493c565b610878614968565b5f60405180606001604052808780608001906108949190615692565b5f8181106108a4576108a46156d8565b90506020028101906108b691906156ec565b6108c0908061570a565b6108ce90604081019061571e565b6108db60808b018b615692565b5f8181106108eb576108eb6156d8565b90506020028101906108fd91906156ec565b60200135818110610910576109106156d8565b6109269260206040909202019081019150614c57565b6001600160a01b031681526020016109416080890189615692565b5f818110610951576109516156d8565b905060200281019061096391906156ec565b61096d908061570a565b61097b90606081019061571e565b61098860808b018b615692565b5f818110610998576109986156d8565b90506020028101906109aa91906156ec565b604001358181106109bd576109bd6156d8565b6109d39260206040909202019081019150614c57565b6001600160a01b03168152602088810135910152905060605f6109f96080890189615692565b604080516001909201602002820181528501519093505f9250610a1d915082611b4c565b610a3a5760405163315f9e2360e21b815260040160405180910390fd5b5f5b610a4960808a018a615692565b905081108015610a6357506040840151610a63905f611b4c565b15610e7157610a7560808a018a615692565b82818110610a8557610a856156d8565b9050602002810190610a9791906156ec565b610aa090615764565b9550855f01519450835f01516001600160a01b03168560400151876020015181518110610acf57610acf6156d8565b60200260200101515f01516001600160a01b0316141580610b2a575083602001516001600160a01b03168560600151876040015181518110610b1357610b136156d8565b60200260200101515f01516001600160a01b031614155b15610b485760405163936bb5ad60e01b815260040160405180910390fd5b610b5b85876020015188604001516122e7565b5f610b6586611ab5565b5f81815260208190526040902054909150610bca578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a1610e68565b5f610c278789602001518a60400151338c606001515f67ffffffffffffffff811115610bf857610bf8614e34565b604051908082528060200260200182016040528015610c21578160200160208202803683370190505b50612359565b90505f610c458c604001358360600151611b4c90919063ffffffff16565b15610c9b578751604080513381526001600160a01b03909216602083015281018490527fe3151dc8cb7a54ffc4baabd28c1f241c94d510b5e5b502491ac3cad6c16316d5906060015b60405180910390a1610e5a565b6040820151610caa905f611b4c565b1580610cc257506060820151610cc0905f611b4c565b155b15610d0f578751604080513381526001600160a01b03909216602083015281018490527f500b713857325f9e6dcb52ae832eca9109d107ed1aae9cb4928b4c1e13f051aa90606001610c8e565b600190505f808d6060016020810190610d2891906157fa565b15610d6e576040808a015190850151610d4091612177565b6060850151909250610d52908361281e565b60408a0151909150610d64908361286b565b60408a0152610dd5565b5f610d8a8560400151866060015161281e90919063ffffffff16565b9050610da38a604001518261217790919063ffffffff16565b9150610dbc85606001518361289b90919063ffffffff16565b60408b0151909350610dce908361286b565b60408b0152505b610ddf8c826128cb565b9b50610deb8d836128cb565b9c50610df782856128fb565b610e0181856129bc565b7f194f1feb3b4d7076a2c272e774e792e0c48bb8c7aa1a9a3671c1cd6da9e6b4c1338c8484604051610e369493929190615922565b60405180910390a187516001018089526020028801849052610e5784612b68565b50505b8480610e635750805b945050505b50600101610a3c565b505f610e8360808a0160608b016157fa565b610e8d5786610e8f565b875b9050610e9c818a35612dab565b15610ec45760405163573b6f4160e01b81528935600482015260248101829052604401610316565b50610ed43384602001518961220a565b505f9050610ee560a08a018a615a0c565b9050118015610ef15750805b15610f635760208301518351339163691f9ed7918a8a610f1460a08f018f615a0c565b6040518763ffffffff1660e01b8152600401610f3596959493929190615610565b5f604051808303815f87803b158015610f4c575f80fd5b505af1158015610f5e573d5f803e3d5ffd5b505050505b610f7133845f015188611b86565b50505f5b8251811015610fa857610fa0838281518110610f9357610f936156d8565b6020026020010151612de5565b600101610f75565b505050505050610fc460015f80516020615ff983398151915255565b915091565b5f610fd2611a9a565b5f61102f61102a610fe38780615a4f565b610ff1906040810190615a0c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612eef92505050565b612f60565b90505f811161105157604051632cff108b60e21b815260040160405180910390fd5b6001811161107257604051633c8270bd60e21b815260040160405180910390fd5b61107f602086018661571e565b90505f036110a057604051636c44ef8f60e01b815260040160405180910390fd5b6110ad604086018661571e565b90505f036110ce5760405163540e5f0b60e01b815260040160405180910390fd5b6040805160a081019091523381525f90602081016110ec8880615a4f565b6110f590615a63565b815260200187806020019061110a919061571e565b808060200260200160405190810160405280939291908181526020015f905b828210156111555761114660408302860136819003810190615a6e565b81526020019060010190611129565b505050918352505060200161116d604089018961571e565b808060200260200160405190810160405280939291908181526020015f905b828210156111b8576111a960408302860136819003810190615a6e565b8152602001906001019061118c565b50505050508152602001876060013581525090505f6111d682611ab5565b5f818152602081905260409020549091501580156112f1575f828152602081905260409081902060019055835190517f87491344dfbcf91f6cbbc610cbbeedc85313d37a02df0c93527f7ea5f8db717f916112349185908790615a88565b60405180910390a15f61124a60a08a018a615a0c565b905011156112e65761129b61126260a08a018a615a0c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612f7a92505050565b82517fd46c2c56b35c8210e9e712ec3f02242d5fc90187c0ac8ed80cc33626846ec36990836112cd60a08c018c615a0c565b6040516112dd9493929190615aaf565b60405180910390a15b6112f1828888611ae4565b93505050506103bb60015f80516020615ff983398151915255565b5f80808061132661131d868061570a565b61032c90615336565b5f8181526020819052604090205490915060011461134d57505f92508291508190506113c7565b61137261135a868061570a565b61136390615336565b866020013587604001356122e7565b5f6113b0611380878061570a565b61138990615336565b60208801356040890135336113a160608c018c615692565b6113aa91615ae1565b5f610bf8565b905060018160400151826060015194509450945050505b9193909250565b604080515f8152602081019091526060908267ffffffffffffffff8111156113f8576113f8614e34565b60405190808252806020026020018201604052801561142b57816020015b60608152602001906001900390816114165790505b5091505f5b838110156114ac576114873086868481811061144e5761144e6156d8565b90506020028101906114609190615a0c565b8560405160200161147393929190615b00565b604051602081830303815290604052612fa5565b838281518110611499576114996156d8565b6020908102919091010152600101611430565b505092915050565b6114bc611a9a565b604080515f808252602082019092526114f4916114e9565b60608152602001906001900390816114d45790505b506104f88385615550565b61150a60015f80516020615ff983398151915255565b5050565b6040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611552573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115769190615654565b5f036115a057604051633c5bf76960e21b81526001600160a01b0384166004820152602401610316565b505f92915050565b6115b0611a9a565b835185516001600160a01b039182169116036115df57604051630a98f1f360e21b815260040160405180910390fd5b83604001518360400135815181106115f9576115f96156d8565b60200260200101515f01516001600160a01b03168560600151846020013581518110611627576116276156d8565b60200260200101515f01516001600160a01b03161415806116a0575060408501518051843590811061165b5761165b6156d8565b60200260200101515f01516001600160a01b03168460600151846060013581518110611689576116896156d8565b60200260200101515f01516001600160a01b031614155b156116be5760405163936bb5ad60e01b815260040160405180910390fd5b84606001518360200135815181106116d8576116d86156d8565b60200260200101515f01516001600160a01b03168560400151845f013581518110611705576117056156d8565b60200260200101515f01516001600160a01b03160361173757604051631cd2f1c760e21b815260040160405180910390fd5b5f61174186611ab5565b5f818152602081905260409020549091506117a7578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a150611a84565b5f6117b186611ab5565b5f81815260208190526040902054909150611818578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a15050611a84565b7f6fa7f4c28634b0a9d6831401c45ae468195fb63aed07308935c35374ff5d9e393388888860405161184d9493929190615b23565b60405180910390a1505083515f906118719087908635906020880135908686610bf8565b90505f6118a086866040013587606001358a5f0151885f67ffffffffffffffff811115610bf857610bf8614e34565b90505f6118ad8383613045565b90506118bc815f0151846128fb565b6118ca8160200151836128fb565b6118d88160400151846129bc565b6118e68160600151836129bc565b6118ef83612de5565b6118f882612de5565b606081015181515f9161190b919061286b565b90505f6119298360400151846020015161286b90919063ffffffff16565b9050611935825f612dab565b806119455750611945815f612dab565b1561196357604051630d86822160e01b815260040160405180910390fd5b611997338b606001518a6020013581518110611981576119816156d8565b60200260200101515f01518a6080013585611cbe565b50506119cd338a606001518a60600135815181106119b7576119b76156d8565b60200260200101515f01518a60a0013584611cbe565b5050604080513381528451602080830191909152850151818301529084015160608083019190915284015160808201527fd9fa84dd790c969daa5c33d8050dc06b4a9b59d5b42e2be5f5e8ae20447f618d925060a001905060405180910390a1611a3683612b68565b611a3f82612b68565b80516001600160e01b0316158015611a62575060208101516001600160e01b0316155b15611a80576040516321badf1f60e01b815260040160405180910390fd5b5050505b61051a60015f80516020615ff983398151915255565b611aa2613093565b60025f80516020615ff983398151915255565b5f81604051602001611ac79190615b9f565b604051602081830303815290604052805190602001209050919050565b604080516002815260208101859052338183015260608101909152611b1690611b0c906104d6565b6104f88385615550565b505050565b80611b16576040516305dbdfd960e41b81526001600160a01b03808516600483015283166024820152604401610316565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d611b7a848484846130c4565b12979650505050505050565b5f805f611b9285613198565b9050611b9e845f612dab565b15611bbc57604051632eaefac360e21b815260040160405180910390fd5b6001600160a01b038087165f90815260026020908152604080832093891683529290529081205490611bee868361286b565b90505f80611bfc8382611b4c565b15611c62575f611c0c84876131fe565b909350905080611c2257611c1f83615bb1565b92505b5f611c2d8a886131fe565b50905080611c3c85600161567f565b1015611c4a57809350600192505b611c5f6001600160a01b038c168d308761213b565b50505b5f611c6d838761322b565b50905081611c8457611c7f818561286b565b611c86565b845b6001600160a01b03808d165f908152600260209081526040808320938f1683529290522055509095509293505050505b935093915050565b5f80611cca8382612dab565b15611ceb5760405163793a8f5560e01b815260048101849052602401610316565b83611d0957611cfb86868561220a565b505f9250829150611da59050565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611d4382866128cb565b9050611d4f815f612dab565b15611d705760405163c5e12af560e01b815260048101829052602401610316565b6001600160a01b038089165f908152600160209081526040808320938b16835292815282822089835290522081905590925090505b94509492505050565b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b8651811015611f7257868181518110611e1557611e156156d8565b602002602001015193505f845f015160400151511115611f6a575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001611e8d8d8a6020015161326b565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401611eb89190615c21565b5f60405180830381865afa158015611ed2573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611ef99190810190615d19565b9150505f81511115611f685784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490611f3a908a908590600401615dcf565b5f604051808303815f87803b158015611f51575f80fd5b505af1158015611f63573d5f803e3d5ffd5b505050505b505b600101611dfa565b5050505050505050565b5f8115611fb657506001600160a01b038084165f9081526001602090815260408083209386168352928152828220848352905220546103bb565b5f611fc08461354d565b6040516370a0823160e01b81526001600160a01b0387811660048301529192505f9161203891908716906370a0823190602401602060405180830381865afa15801561200e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120329190615654565b8361322b565b50604051636eb1769f60e11b81526001600160a01b0388811660048301523060248301529192505f916120b7919088169063dd62ed3e90604401602060405180830381865afa15801561208d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120b19190615654565b8461322b565b506001600160a01b038089165f908152600160209081526040808320938b168352928152828220828052905220549091506120fc906120f68484612177565b906128cb565b93505050506103bb565b6121138383836001613559565b611b1657604051635274afe760e01b81526001600160a01b0384166004820152602401610316565b6121498484848460016135bb565b61217157604051635274afe760e01b81526001600160a01b0385166004820152602401610316565b50505050565b5f6121828383612dab565b61218c57816103bb565b5090919050565b5f8061219f8382612dab565b156121c05760405163793a8f5560e01b815260048101849052602401610316565b836121d057611cfb868685611b86565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611d43828661286b565b5f805f61221685613198565b9050612222845f612dab565b1561224057604051632d1671a360e11b815260040160405180910390fd5b6001600160a01b038087165f9081526002602090815260408083209389168352929052908120546122729086906128cb565b90505f61227f82846131fe565b5090505f61228d828561322b565b50905061229a838261286b565b6001600160a01b03808b165f908152600260209081526040808320938d168352929052205581156122d9576122d96001600160a01b0389168a84612106565b509791965090945050505050565b826060015181815181106122fd576122fd6156d8565b60200260200101515f01516001600160a01b031683604001518381518110612327576123276156d8565b60200260200101515f01516001600160a01b031603611b1657604051631cd2f1c760e21b815260040160405180910390fd5b6123616149cf565b60408051600480825260a082019092526060915f9190816020015b606081526020019060019003908161237c5790505090506123d161239f8a611ab5565b8a51604080516003815260208101939093526001600160a01b0391821683820152908916606083015260808201905290565b8160018003815181106123e6576123e66156d8565b60200260200101819052505f61241b8a604001518a8151811061240b5761240b6156d8565b60200260200101515f015161354d565b90505f61246d8b5f01518c604001518c8151811061243b5761243b6156d8565b60200260200101515f01518d604001518d8151811061245c5761245c6156d8565b602002602001015160200151611f7c565b90506124fc8b604001518b81518110612488576124886156d8565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d604001518d815181106124ba576124ba6156d8565b602002602001015160200151845f801b60408051600581526020810196909652858101949094526060850192909252608084015260a083015260c08201905290565b83600160030381518110612512576125126156d8565b602002602001018190525050505f6125398a60600151898151811061240b5761240b6156d8565b90505f61257a8b5f01518c606001518b81518110612559576125596156d8565b60200260200101515f01518d606001518c8151811061245c5761245c6156d8565b90506125c78b606001518a81518110612595576125956156d8565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d606001518c815181106124ba576124ba6156d8565b836001600403815181106125dd576125dd6156d8565b602002602001018190525050506125f4818661326b565b9150505f885f01516001600160a01b031690505f808a602001515f01516001600160a01b031663d04dfe236040518060e001604052808e60200151602001516001600160a01b0316815260200161265487305f9182526020526040902090565b81526020018e602001516040015181526020015f81526020018781526020015f67ffffffffffffffff81111561268c5761268c614e34565b6040519080825280602002602001820160405280156126b5578160200160208202803683370190505b508152602001898152506040518263ffffffff1660e01b81526004016126db9190615c21565b5f60405180830381865afa1580156126f5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261271c9190810190615d19565b91509150600282511015612748578151604051630fbb8e5560e21b815260040161031691815260200190565b60208201516040830151855161279c908790600490811061276b5761276b6156d8565b6020026020010151600381518110612785576127856156d8565b60200260200101518261217790919063ffffffff16565b60408051600281526020810183905280820185905260608101909152909150866002815181106127ce576127ce6156d8565b60200260200101819052506040518060e001604052808e81526020018c81526020018281526020018381526020018781526020018681526020018481525096505050505050509695505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e86868686613628565b915091505f61285d8383613747565b9a9950505050505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e86868686613794565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e868686866137be565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e86868686613cfb565b818160800151600481518110612913576129136156d8565b602002602001015160048151811061292d5761292d6156d8565b602002602001018181525050612171815f01515f0151826080015160048151811061295a5761295a6156d8565b60200260200101515f81518110612973576129736156d8565b60200260200101515f1c8360800151600481518110612994576129946156d8565b60200260200101516002815181106129ae576129ae6156d8565b602002602001015185612193565b8181608001516003815181106129d4576129d46156d8565b60200260200101516004815181106129ee576129ee6156d8565b6020908102919091010152805151608082015180515f91906003908110612a1757612a176156d8565b60200260200101515f81518110612a3057612a306156d8565b60200260200101515f1c90505f8360800151600381518110612a5457612a546156d8565b6020026020010151600281518110612a6e57612a6e6156d8565b602002602001015190505f801b8103612b1557612a8b855f612dab565b15612aac5760405163793a8f5560e01b815260048101869052602401610316565b6001600160a01b038084165f908152600160209081526040808320938616835292815282822084835290522054612ae390866128cb565b6001600160a01b038085165f908152600160209081526040808320938716835292815282822085835290522055612b24565b612b2183838388611cbe565b50505b7f4cb6e22a3e7e651d7cf0376cff48f20f5007a54147777865be7f5f6c38c50f4a338560800151604051612b59929190615de7565b60405180910390a15050505050565b60c08101515115612be2578051602090810151015160a082015160c083015160405163012c676d60e21b81526001600160a01b03909316926304b19db492612bb4929091600401615dcf565b5f604051808303815f87803b158015612bcb575f80fd5b505af1158015612bdd573d5f803e3d5ffd5b505050505b5f815f0151602001515f01516001600160a01b031663d04dfe236040518060e00160405280855f015160200151602001516001600160a01b03168152602001612c388660a00151305f9182526020526040902090565b8152602001855f01516020015160400151815260200160018152602001856080015181526020015f67ffffffffffffffff811115612c7857612c78614e34565b604051908082528060200260200182016040528015612ca1578160200160208202803683370190505b5081526020015f604051908082528060200260200182016040528015612cd1578160200160208202803683370190505b508152506040518263ffffffff1660e01b8152600401612cf19190615c21565b5f60405180830381865afa158015612d0b573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612d329190810190615d19565b9150505f8151111561150a578151602090810151015160a083015160405163012c676d60e21b81526001600160a01b03909216916304b19db491612d7a918590600401615dcf565b5f604051808303815f87803b158015612d91575f80fd5b505af1158015612da3573d5f803e3d5ffd5b505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d612dd9848484846130c4565b13979650505050505050565b5f8160800151600381518110612dfd57612dfd6156d8565b6020026020010151600281518110612e1757612e176156d8565b602002602001015190505f801b810361150a57815151608083015180515f91906003908110612e4857612e486156d8565b60200260200101515f81518110612e6157612e616156d8565b6020908102919091018101516001600160a01b038481165f9081526001845260408082209284168252918452818120878252909352909120549091506001600160e01b0381161561051a576001600160a01b038084165f9081526001602090815260408083209386168352928152828220878352905290812055612ee683838361220a565b50505050505050565b6060604082511015612f0e57505060408051602081019091525f815290565b5f60208301519050602060408451612f269190615aed565b612f309190615e1c565b811115612f4c57505060408051602081019091525f8152919050565b600181016020026020840101915050919050565b5f81515f03612f7057505f919050565b50602001515f1a90565b612f8381613df9565b612fa25780604051630c89984b60e31b81526004016103169190615e3b565b50565b60605f612fb28484613e27565b9050808015612fd357505f3d1180612fd357505f846001600160a01b03163b115b15612fe857612fe0613e3a565b9150506102b4565b801561301257604051639996b31560e01b81526001600160a01b0385166004820152602401610316565b3d1561302557613020613e53565b61303e565b60405163d6bda27560e01b815260040160405180910390fd5b5092915050565b604080516080810182525f8082526020820181905291810182905260608101919091526130728383613e5e565b825260408201526130838284613e5e565b6020830152606082015292915050565b5f80516020615ff9833981519152546002036130c257604051633ee5aeb560e01b815260040160405180910390fd5b565b5f80851584151781871282861218178584141780156130e95786859250925050611da5565b505f858413156130fd575092949193919260015b8386035f8112604c8213178015613130578215613122575f8994509450505050611da5565b885f94509450505050611da5565b600a82900a8981028a82828161314857613148615e08565b0514613174578415613164575f8b965096505050505050611da5565b8a5f965096505050505050611da5565b8415613189578896509450611da59350505050565b9550879450611da59350505050565b5f805f6131a484613ec7565b909250905060018260038111156131bd576131bd615e4d565b141580156131dc57505f8260038111156131d9576131d9615e4d565b14155b156103bb57838260405163ee07877f60e01b8152600401610316929190615e61565b5f806001600160e01b038416601b0b60e085901d61321d828287613f54565b9350935050505b9250929050565b5f805f805f61323a87876140ba565b9250925092505f8061324c85856140fd565b915091508183801561325b5750815b9650965050505050509250929050565b60605f825167ffffffffffffffff81111561328857613288614e34565b6040519080825280602002602001820160405280156132b1578160200160208202803683370190505b5090505f808451116132c3575f6132c9565b83516001015b85516001010190505f8167ffffffffffffffff8111156132eb576132eb614e34565b60405190808252806020026020018201604052801561331e57816020015b60608152602001906001900390816133095790505b5090505f613342604080516002815233602082015230818301526060810190915290565b828281518110613354576133546156d8565b60200260200101819052505f5b87518110156133b1578180600101925050878181518110613384576133846156d8565b602002602001015183838151811061339e5761339e6156d8565b6020908102919091010152600101613361565b50855115613543578080600101915050838282815181106133d4576133d46156d8565b60200260200101819052505f5b8651811015613541576134908782815181106133ff576133ff6156d8565b60200260200101515f015161346d61343b8a8581518110613422576134226156d8565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b89848151811061347f5761347f6156d8565b6020026020010151604001516141d5565b6134b057604051630a57f30960e31b815260048101829052602401610316565b8681815181106134c2576134c26156d8565b60200260200101515f01516001600160a01b03165f1b8582815181106134ea576134ea6156d8565b6020026020010181815250508180600101925050868181518110613510576135106156d8565b60200260200101516020015183838151811061352e5761352e6156d8565b60209081029190910101526001016133e1565b505b5095945050505050565b5f805f6131a484614245565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f511483166135af5783831516156135a3573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f5114831661361757838315161561360b573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f8085158415178015613640575f92505f915061373d565b61364a8487615e9a565b91505f613656886142a4565b90505f613662876142a4565b90505f61366f83836142d2565b5090505f6f0785ee10d5da46d900f436a0000000008211156136a4576f0785ee10d5da46d900f436a000000000820491506025015b670de0b6b3a76400008211156136c557670de0b6b3a7640000820491506012015b633b9aca008211156136de57633b9aca00820491506009015b6127108211156136f357612710820491506004015b811561370757600a820491506001016136f3565b6137118187615e9a565b95506137338b8a61372d878761372887600a615f99565b6142ee565b896143ba565b9097509550505050505b5094509492505050565b5f805f61375485856140fd565b9150915080158015613764575081155b1561378c57604051638eba4d0760e01b81526004810186905260248101859052604401610316565b509392505050565b5f806137a0848461445a565b90945092506137b186868686613cfb565b9150915094509492505050565b5f80835f036137ea57604051637a97930f60e01b81526004810187905260248101869052604401610316565b855f036137fb57505f905080611da5565b5f805f806138098a8a6144af565b919b509950915061381a88886144af565b919950975090505f61382b8b6142a4565b90505f6138378a6142a4565b90507f161bcca7119915b50764b4abe86529797775a5f1719510000000000000000000604c81831015613bfc57841561388e57507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b9050604b613bd4565b6f4b3b4ca85a86c47a098a2240000000008310156139ba57678ac7230489e8000083101561391e576402540be4008310156138ec57620186a08310156138dc5750620186a090506005613b95565b506402540be4009050600a613b95565b655af3107a400083101561390b5750655af3107a40009050600e613b95565b50678ac7230489e8000090506013613b95565b6b204fce5e3e250261100000008310156139705769152d02c7e14af6800000831015613959575069152d02c7e14af680000090506017613b95565b506b204fce5e3e250261100000009050601c613b95565b6d314dc6448d9338c15b0a0000000083101561399f57506d314dc6448d9338c15b0a0000000090506021613b95565b506f4b3b4ca85a86c47a098a22400000000090506026613b95565b780197d4df19d605767337e9f14d3eec8920e400000000000000831015613ab25773af298d050e4395d69670b12b7f41000000000000831015613a4d577172cb5bd86321e38cb6ce6682e80000000000831015613a2e57507172cb5bd86321e38cb6ce6682e800000000009050602b613b95565b5073af298d050e4395d69670b12b7f4100000000000090506030613b95565b76010b46c6cdd6e3e0828f4db456ff0c8ea0000000000000831015613a8e575076010b46c6cdd6e3e0828f4db456ff0c8ea000000000000090506035613b95565b50780197d4df19d605767337e9f14d3eec8920e4000000000000009050603a613b95565b7c03b58e88c75313ec9d329eaaa18fb92f75215b17100000000000000000831015613b48577a026e4d30eccc3215dd8f3157d27e23acbdcfe68000000000000000831015613b2057507a026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000009050603f613b95565b507c03b58e88c75313ec9d329eaaa18fb92f75215b1710000000000000000090506044613b95565b7e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000831015613b9557507e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000905060495b818311613baa57600a820491505f1901613b95565b815f03613bd4576040516305e51ecb60e01b8152600481018d9052602481018c9052604401610316565b85613bfc576040516305e51ecb60e01b8152600481018f9052602481018e9052604401610316565b80600160ff1b018d12613c1357808d039c50613c51565b600160ff1b9c90038c015f811315613c5157806001600160ff1b03038b13613c3e57998a0199613c51565b5f80995099505050505050505050611da5565b5f808e128015613c6057505f8c135b15613c8157600160ff1b8e01808d13613c79575f613c7d565b808d035b9150505b8b818f01039750613c9e8f8e613c988887896142ee565b8b6143ba565b90995097505f811315613ce857604c811315613cc8575f809a509a50505050505050505050611da5565b80600a0a8981613cda57613cda615e08565b059850885f03613ce8575f97505b50969850949650611da595505050505050565b5f8085158415178015613d2757865f03613d1b5784849250925050611da5565b86869250925050611da5565b613d318787614709565b9097509550613d408585614709565b909550935085841315613d54579395929492935b838603604c811115613d6d578787935093505050611da5565b80600a0a8681613d7f57613d7f615e08565b0595505086850180881860ff90811c151589881890911c15168015613de857876001600160ff1b0303613dcf5760405163d556b11160e01b8152600481018a905260248101899052604401610316565b600a968790059690980586019760019790970196613dec565b8198505b5096979596505050505050565b5f600882511015613e0b57505f919050565b506008015167ffffffffffffffff1667ff0a89c674ee78741490565b5f805f835160208501865af49392505050565b6040513d81523d5f602083013e3d602001810160405290565b6040513d5f823e3d81fd5b5f80613e7b8460600151856040015161281e90919063ffffffff16565b915083604001519050613e9b836040015183611b4c90919063ffffffff16565b156132245782604001519150613ebe84606001518361289b90919063ffffffff16565b90509250929050565b5f80613ed1614752565b60405163b7bad1b160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb93899063b7bad1b19060240160408051808303815f875af1158015613f27573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f4b9190615fa4565b91509150915091565b5f805f851215613f8157604051634a7d166b60e01b81526004810186905260248101859052604401610316565b845f03613f9357505f90506001611cb6565b8460ff8416850185811215613fc55760405163d556b11160e01b81526004810188905260248101879052604401610316565b5f805f83121561401157604c19831215613fe8575f809550955050505050611cb6565b825f03600a0a9150818481613fff57613fff615e08565b0495505084029091149150611cb69050565b5f8313156140aa57604d83131561404e5760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b82600a0a9150815f198161406457614064615e08565b048411156140985760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b5091909102925060019150611cb69050565b8360019550955050505050611cb6565b5f808060ff841681036001600160ff1b038611156140ec57600a860460018201600a88065f14935093509350506140f6565b8593509150600190505b9250925092565b5f601b83900b8314838382614161577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561414157620186a0860595506005850194505b8586601b0b1461415c57600a86059550846001019450614141565b614177565b855f0361417757505f9250600191506132249050565b848560030b146141ba575f85121561419757505f92508291506132249050565b60405163d556b11160e01b81526004810183905260248101829052604401610316565b50506001600160e01b03841660e084901b1791509250929050565b5f836001600160a01b03163b5f03614233575f806141f385856147dd565b5090925090505f81600381111561420c5761420c615e4d565b14801561422a5750856001600160a01b0316826001600160a01b0316145b925050506103bb565b61423e848484614823565b90506103bb565b5f8061424f614752565b604051630782d7e160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb938990630782d7e1906024016040805180830381865afa158015613f27573d5f803e3d5ffd5b5f808212156142c957600160ff1b82036142c35750600160ff1b919050565b505f0390565b5090565b919050565b5f805f1983850993909202808410938190039390930393915050565b5f805f6142fb86866142d2565b91509150815f0361431f5783818161431557614315615e08565b04925050506103bb565b8382106143505760405163362ced0960e11b8152600481018790526024810186905260448101859052606401610316565b5f84868809600186198101871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103025f82900382900490920185841190960395909502919093039390930492909217029150509392505050565b5f805f8587181215614436576001600160ff1b03841115614423576143e76001600160ff1b03600161567f565b84036143fb5750600160ff1b905081611da5565b614406600a85615e1c565b61440f90615fe4565b61441a846001615e9a565b91509150611da5565b61442c84615fe4565b8391509150611da5565b6001600160ff1b038411156144505761440f600a85615e1c565b5082905081611da5565b5f80600160ff1b84036144a5576001600160ff1b0383036144985760405163d556b11160e01b81526004810185905260248101849052604401610316565b600a840593508260010192505b50505f9190910391565b5f805f845f036144c757505f915081905060016140f6565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b85055f036146b4576f4b3b4ca85a86c47a098a224000000000850515801561452957507f80000000000000000000000000000000000000000000000000000000000000268412155b1561454a576f4b3b4ca85a86c47a098a224000000000850294506026840393505b7728c87cb5c89a2571ebfdcb54864ada834a00000000000000850515801561459257507f80000000000000000000000000000000000000000000000000000000000000138412155b156145ab57678ac7230489e80000850294506013840393505b7b097edd871cfda3a5697758bf0e3cbb5ac5741c64000000000000000085051580156145f757507f800000000000000000000000000000000000000000000000000000000000000a8412155b1561460d576402540be40085029450600a840393505b7e3899162693736ac531a5a58f1fbb4b746504382ca7e4000000000000000000850515801561465c57507f80000000000000000000000000000000000000000000000000000000000000028412155b156146725760648502945060028403935061460d565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b85051580156146a257506001600160ff1b018412155b156146b457600a850294506001840393505b600a808602908105861480156146d157506001600160ff1b018512155b156146e0578095506001850394505b50939492935050507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b8305151590565b5f805f805f61471887876144af565b92509250925080614746576040516305e51ecb60e01b81526004810188905260248101879052604401610316565b50909590945092505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b15806147a9575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b156130c2576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610316565b5f805f8351604103614814576020840151604085015160608601515f1a61480688828585614874565b9550955095505050506140f6565b505081515f91506002906140f6565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156148ad57505f91506003905082614932565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156148fe573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661492957505f925060019150829050614932565b92505f91508190505b9450945094915050565b604051806080016040528061494f614968565b81526020015f81526020015f8152602001606081525090565b6040518060a001604052805f6001600160a01b031681526020016149b660405180606001604052805f6001600160a01b031681526020015f6001600160a01b03168152602001606081525090565b8152606060208201819052604082018190525f91015290565b6040518060e001604052806149e2614968565b81526020015f81526020015f80191681526020015f8019168152602001606081526020015f8152602001606081525090565b5f60208284031215614a24575f80fd5b81356001600160e01b0319811681146103bb575f80fd5b5f8083601f840112614a4b575f80fd5b50813567ffffffffffffffff811115614a62575f80fd5b6020830191508360208260051b8501011115613224575f80fd5b5f805f60408486031215614a8e575f80fd5b833567ffffffffffffffff80821115614aa5575f80fd5b9085019060a08288031215614ab8575f80fd5b90935060208501359080821115614acd575f80fd5b50614ada86828701614a3b565b9497909650939450505050565b5f60208284031215614af7575f80fd5b5035919050565b6001600160a01b0381168114612fa2575f80fd5b80356142cd81614afe565b5f805f805f60808688031215614b31575f80fd5b8535614b3c81614afe565b94506020860135935060408601359250606086013567ffffffffffffffff811115614b65575f80fd5b614b7188828901614a3b565b969995985093965092949392505050565b5f805f60608486031215614b94575f80fd5b8335614b9f81614afe565b92506020840135614baf81614afe565b929592945050506040919091013590565b5f805f805f60808688031215614bd4575f80fd5b8535614bdf81614afe565b94506020860135614bef81614afe565b935060408601359250606086013567ffffffffffffffff80821115614c12575f80fd5b818801915088601f830112614c25575f80fd5b813581811115614c33575f80fd5b896020828501011115614c44575f80fd5b9699959850939650602001949392505050565b5f60208284031215614c67575f80fd5b81356103bb81614afe565b5f60c08284031215614c82575f80fd5b50919050565b5f60208284031215614c98575f80fd5b813567ffffffffffffffff811115614cae575f80fd5b61052d84828501614c72565b5f805f60408486031215614ccc575f80fd5b833567ffffffffffffffff80821115614ce3575f80fd5b614cef87838801614c72565b94506020860135915080821115614acd575f80fd5b5f60208284031215614d14575f80fd5b813567ffffffffffffffff811115614d2a575f80fd5b8201608081850312156103bb575f80fd5b5f8060208385031215614d4c575f80fd5b823567ffffffffffffffff811115614d62575f80fd5b614d6e85828601614a3b565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b82811015614dfd57603f19888603018452614deb858351614d7a565b94509285019290850190600101614dcf565b5092979650505050505050565b5f8060408385031215614e1b575f80fd5b8235614e2681614afe565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614e6b57614e6b614e34565b60405290565b6040805190810167ffffffffffffffff81118282101715614e6b57614e6b614e34565b60405160a0810167ffffffffffffffff81118282101715614e6b57614e6b614e34565b604051601f8201601f1916810167ffffffffffffffff81118282101715614ee057614ee0614e34565b604052919050565b5f82601f830112614ef7575f80fd5b813567ffffffffffffffff811115614f1157614f11614e34565b614f24601f8201601f1916602001614eb7565b818152846020838601011115614f38575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60608284031215614f64575f80fd5b614f6c614e48565b90508135614f7981614afe565b81526020820135614f8981614afe565b6020820152604082013567ffffffffffffffff811115614fa7575f80fd5b614fb384828501614ee8565b60408301525092915050565b5f67ffffffffffffffff821115614fd857614fd8614e34565b5060051b60200190565b5f60408284031215614ff2575f80fd5b614ffa614e71565b9050813561500781614afe565b808252506020820135602082015292915050565b5f82601f83011261502a575f80fd5b8135602061503f61503a83614fbf565b614eb7565b8083825260208201915060208460061b870101935086841115615060575f80fd5b602086015b84811015615085576150778882614fe2565b835291830191604001615065565b509695505050505050565b5f60a082840312156150a0575f80fd5b6150a8614e94565b90506150b382614b12565b8152602082013567ffffffffffffffff808211156150cf575f80fd5b6150db85838601614f54565b602084015260408401359150808211156150f3575f80fd5b6150ff8583860161501b565b60408401526060840135915080821115615117575f80fd5b506151248482850161501b565b6060830152506080820135608082015292915050565b5f61514761503a84614fbf565b8381529050602080820190600585811b850187811115615165575f80fd5b855b8181101561525257803567ffffffffffffffff80821115615186575f80fd5b908801906060828c031215615199575f80fd5b6151a1614e48565b82356151ac81614afe565b815282870135828111156151be575f80fd5b8301601f81018d136151ce575f80fd5b80356151dc61503a82614fbf565b81815290881b8201890190898101908f8311156151f7575f80fd5b928a01925b828410156152155783358252928a0192908a01906151fc565b848b0152506040915050838101358381111561522f575f80fd5b61523b8e828701614ee8565b918301919091525087525050938301938301615167565b50505050509392505050565b5f82601f83011261526d575f80fd5b6103bb8383356020850161513a565b5f805f805f6101408688031215615291575f80fd5b853567ffffffffffffffff808211156152a8575f80fd5b6152b489838a01615090565b965060208801359150808211156152c9575f80fd5b6152d589838a01615090565b95506152e48960408a01614c72565b94506101008801359150808211156152fa575f80fd5b61530689838a0161525e565b935061012088013591508082111561531c575f80fd5b506153298882890161525e565b9150509295509295909350565b5f6102b43683615090565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f813561537581614afe565b6001600160a01b03908116845260208301359061539182614afe565b166020840152604082013536839003601e190181126153ae575f80fd5b820160208101903567ffffffffffffffff8111156153ca575f80fd5b8036038213156153d8575f80fd5b606060408601526153ed606086018284615341565b95945050505050565b5f808335601e1984360301811261540b575f80fd5b830160208101925035905067ffffffffffffffff81111561542a575f80fd5b8060061b3603821315613224575f80fd5b8183525f60208085019450825f5b8581101561548157813561545c81614afe565b6001600160a01b03168752818301358388015260409687019690910190600101615449565b509495945050505050565b5f6001600160a01b0380861683528460208401526060604084015283356154b281614afe565b166060830152602083013536849003605e190181126154cf575f80fd5b60a060808401526154e66101008401858301615369565b90506154f560408501856153f6565b605f19808685030160a087015261550d84838561543b565b935061551c60608801886153f6565b93509150808685030160c08701525061553683838361543b565b92505050608084013560e084015280915050949350505050565b5f61555d61503a84614fbf565b80848252602080830192508560051b85013681111561557a575f80fd5b855b8181101561560457803567ffffffffffffffff8082111561559b575f80fd5b8189019150604082360312156155af575f80fd5b6155b7614e71565b8235828111156155c5575f80fd5b6155d136828601614f54565b82525085830135828111156155e4575f80fd5b6155f03682860161525e565b82880152508752505093820193820161557c565b50919695505050505050565b5f6001600160a01b03808916835280881660208401525085604083015284606083015260a0608083015261564860a083018486615341565b98975050505050505050565b5f60208284031215615664575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156102b4576102b461566b565b5f808335601e198436030181126156a7575f80fd5b83018035915067ffffffffffffffff8211156156c1575f80fd5b6020019150600581901b3603821315613224575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e19833603018112615700575f80fd5b9190910192915050565b5f8235609e19833603018112615700575f80fd5b5f808335601e19843603018112615733575f80fd5b83018035915067ffffffffffffffff82111561574d575f80fd5b6020019150600681901b3603821315613224575f80fd5b5f60808236031215615774575f80fd5b6040516080810167ffffffffffffffff828210818311171561579857615798614e34565b8160405284359150808211156157ac575f80fd5b6157b836838701615090565b8352602085013560208401526040850135604084015260608501359150808211156157e1575f80fd5b506157ee3682860161525e565b60608301525092915050565b5f6020828403121561580a575f80fd5b813580151581146103bb575f80fd5b5f815180845260208085019450602084015f5b8381101561548157815180516001600160a01b03168852830151838801526040909601959082019060010161582c565b5f6001600160a01b03808351168452602083015160a060208601528181511660a08601528160208201511660c08601526040810151915050606060e08501526158a9610100850182614d7a565b9050604083015184820360408601526158c28282615819565b915050606083015184820360608601526158dc8282615819565b915050608083015160808501528091505092915050565b5f815180845260208085019450602084015f5b8381101561548157815187529582019590820190600101615906565b5f6001600160a01b0380871683526020608081850152865160808086015261594e61010086018261585c565b90508188015160a086015260408089015160c08701526060808a0151607f198885030160e08901528381518086528686019150868160051b87010187840193505f5b828110156159ea57601f1988830301845284518a815116835289810151878b8501526159be888501826158f3565b91890151848303858b01529190506159d68183614d7a565b968b0196958b019593505050600101615990565b5080995050505050505050505083604083015282606083015295945050505050565b5f808335601e19843603018112615a21575f80fd5b83018035915067ffffffffffffffff821115615a3b575f80fd5b602001915036819003821315613224575f80fd5b5f8235605e19833603018112615700575f80fd5b5f6102b43683614f54565b5f60408284031215615a7e575f80fd5b6103bb8383614fe2565b6001600160a01b0384168152826020820152606060408201525f6153ed606083018461585c565b6001600160a01b0385168152836020820152606060408201525f615ad7606083018486615341565b9695505050505050565b5f6103bb36848461513a565b818103818111156102b4576102b461566b565b828482375f8382015f815283518060208601835e5f910190815295945050505050565b5f6101206001600160a01b0387168352806020840152615b458184018761585c565b90508281036040840152615b59818661585c565b9150508235606083015260208301356080830152604083013560a0830152606083013560c0830152608083013560e083015260a083013561010083015295945050505050565b602081525f6103bb602083018461585c565b5f60018201615bc257615bc261566b565b5060010190565b5f8282518085526020808601955060208260051b840101602086015f5b84811015615c1457601f19868403018952615c028383516158f3565b98840198925090830190600101615be6565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e06060840152615c5a610100840182614d7a565b9050606084015160808401526080840151601f19808584030160a0860152615c828383615bc9565b925060a08601519150808584030160c0860152615c9f83836158f3565b925060c08601519150808584030160e0860152506153ed82826158f3565b5f82601f830112615ccc575f80fd5b81516020615cdc61503a83614fbf565b8083825260208201915060208460051b870101935086841115615cfd575f80fd5b602086015b848110156150855780518352918301918301615d02565b5f8060408385031215615d2a575f80fd5b825167ffffffffffffffff80821115615d41575f80fd5b818501915085601f830112615d54575f80fd5b81516020615d6461503a83614fbf565b82815260059290921b84018101918181019089841115615d82575f80fd5b948201945b83861015615da057855182529482019490820190615d87565b91880151919650909350505080821115615db8575f80fd5b50615dc585828601615cbd565b9150509250929050565b828152604060208201525f61052d60408301846158f3565b6001600160a01b0383168152604060208201525f61052d6040830184615bc9565b634e487b7160e01b5f52601260045260245ffd5b5f82615e3657634e487b7160e01b5f52601260045260245ffd5b500490565b602081525f6103bb6020830184614d7a565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b03831681526040810160048310615e8d57634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b8082018281125f8312801582168215821617156114ac576114ac61566b565b600181815b80851115615ef357815f1904821115615ed957615ed961566b565b80851615615ee657918102915b93841c9390800290615ebe565b509250929050565b5f82615f09575060016102b4565b81615f1557505f6102b4565b8160018114615f2b5760028114615f3557615f51565b60019150506102b4565b60ff841115615f4657615f4661566b565b50506001821b6102b4565b5060208310610133831016604e8410600b8410161715615f74575081810a6102b4565b615f7e8383615eb9565b805f1904821115615f9157615f9161566b565b029392505050565b5f6103bb8383615efb565b5f8060408385031215615fb5575f80fd5b825160048110615fc3575f80fd5b602084015190925060ff81168114615fd9575f80fd5b809150509250929050565b5f600160ff1b82016142c3576142c361566b56fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00", "linkReferences": {} } } diff --git a/src/generated/GenericPoolRaindexV6ArbOrderTaker.pointers.sol b/src/generated/GenericPoolRaindexV6ArbOrderTaker.pointers.sol index 2fee2ffc2d..8874a508d1 100644 --- a/src/generated/GenericPoolRaindexV6ArbOrderTaker.pointers.sol +++ b/src/generated/GenericPoolRaindexV6ArbOrderTaker.pointers.sol @@ -10,12 +10,12 @@ pragma solidity ^0.8.25; // file needs the contract to exist so that it can be compiled. /// @dev Hash of the known bytecode. -bytes32 constant BYTECODE_HASH = bytes32(0xc4492cb22d918a3f0d41f13e533744ef03a2e7f744ec0a43b79d97a04c537544); +bytes32 constant BYTECODE_HASH = bytes32(0xd3453fd739378f1ccce8181a1ba3554db33e3fc13f6eeda83d2abc716c45d89b); /// @dev The deterministic deploy address of the contract when deployed via /// the Zoltu factory. -address constant DEPLOYED_ADDRESS = address(0xc0c17e58018C80A5420dF7756acd2B2dcf37e380); +address constant DEPLOYED_ADDRESS = address(0xe2a825c9C2b52F7c73f30080680DdB90f36ed9c3); /// @dev The runtime bytecode of the contract. bytes constant RUNTIME_CODE = - hex"608060405260043610610034575f3560e01c806301ffc9a71461003d578063691f9ed714610070578063b17c83c11461008f57005b3661003b57005b005b348015610048575f80fd5b5061005c610057366004611363565b6100a2565b604051901515815260200160405180910390f35b34801561007b575f80fd5b5061003b61008a36600461139e565b6100f3565b61003b61009d366004611440565b61013a565b5f6001600160e01b0319821663691f9ed760e01b14806100d257506001600160e01b0319821663b17c83c160e01b145b806100ed57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6101328683838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506103fc92505050565b505050505050565b6101426104ad565b61015161014e8261172f565b50565b61015e60808301836117eb565b90505f0361017f57604051639c95219f60e01b815260040160405180910390fd5b6001600160a01b0383167386594ac4319230870c6e587f4aca48fab575619e146101cc5760405163516e822d60e01b81526001600160a01b03841660048201526024015b60405180910390fd5b5f6101da60808401846117eb565b5f8181106101ea576101ea611831565b90506020028101906101fc9190611845565b6102069080611863565b610214906040810190611877565b61022160808601866117eb565b5f81811061023157610231611831565b90506020028101906102439190611845565b6020013581811061025657610256611831565b61026c92602060409092020190810191506118bd565b90505f61027c60808501856117eb565b5f81811061028c5761028c611831565b905060200281019061029e9190611845565b6102a89080611863565b6102b6906060810190611877565b6102c360808701876117eb565b5f8181106102d3576102d3611831565b90506020028101906102e59190611845565b604001358181106102f8576102f8611831565b61030e92602060409092020190810191506118bd565b90506103256001600160a01b038316865f196104db565b6040516334e3942b60e11b81526001600160a01b038616906369c7285690610351908790600401611b21565b60408051808303815f875af115801561036c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103909190611d21565b506103a790506001600160a01b038316865f6104db565b6103cc6103b38461172f565b836103bd85610555565b846103c786610555565b6105d9565b50506103f760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050565b5f805f838060200190518101906104139190611d43565b919450925090506001600160a01b038316610441576040516398521dc560e01b815260040160405180910390fd5b6001600160a01b0382166104685760405163456ac4c360e11b815260040160405180910390fd5b61047d6001600160a01b038616845f196104db565b6104916001600160a01b0383168247610878565b506104a66001600160a01b038616845f6104db565b5050505050565b6104b5610945565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6104e78383835f610989565b6103f7576104f883835f6001610989565b61052057604051635274afe760e01b81526001600160a01b03841660048201526024016101c3565b61052d8383836001610989565b6103f757604051635274afe760e01b81526001600160a01b03841660048201526024016101c3565b5f61055e6109eb565b6040516354636d2b60e01b81526001600160a01b038316600482015273200e12d10bb0c5e4a17e7018f0f1161919bb9389906354636d2b906024016020604051808303815f875af11580156105b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100ed9190611dde565b6040805160018082528183019092525f91816020015b60608152602001906001900390816105ef575050604080516003808252608082019092529192505f919060208201606080368337019050506040516370a0823160e01b81523060048201529091505f906001600160a01b038816906370a0823190602401602060405180830381865afa15801561066e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106929190611dfe565b905080156106ae576106ae6001600160a01b0388163383610a76565b5f6106b98288610a83565b50905080835f815181106106cf576106cf611831565b602090810291909101015250506040516370a0823160e01b81523060048201525f906001600160a01b038616906370a0823190602401602060405180830381865afa158015610720573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107449190611dfe565b90508015610760576107606001600160a01b0386163383610a76565b5f61076b8286610a83565b509050808360018151811061078257610782611831565b60209081029190910101525047905080156107a1576107a13382610ac4565b5f6107ad826012610a83565b50905080836002815181106107c4576107c4611831565b602002602001018181525050505080825f815181106107e5576107e5611831565b60209081029190910101526040805160018082528183019092525f91816020015b6040805160a0810182525f918101828152606080830193909352608082018390528152602081019190915281526020019060019003908161080657905050905087815f8151811061085957610859611831565b602002602001018190525061086e8382610b22565b5050505050505050565b6060814710156108a45760405163cf47918160e01b8152476004820152602481018390526044016101c3565b5f6108b0858486610ce6565b90508080156108d157505f3d11806108d157505f856001600160a01b03163b115b156108e6576108de610cfb565b91505061093e565b801561091057604051639996b31560e01b81526001600160a01b03861660048201526024016101c3565b3d156109235761091e610d14565b61093c565b60405163d6bda27560e01b815260040160405180910390fd5b505b9392505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005460020361098757604051633ee5aeb560e01b815260040160405180910390fd5b565b60405163095ea7b360e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f511483166109df5783831516156109d3573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b1580610a42575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b15610987576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb938960048201526024016101c3565b61052d8383836001610d1f565b5f805f805f610a928787610d69565b9250925092505f80610aa48585610dc5565b9150915081838015610ab35750815b9650965050505050505b9250929050565b80471015610aee5760405163cf47918160e01b8152476004820152602481018290526044016101c3565b610b07828260405180602001604052805f815250610ce6565b15610b10575050565b3d1561092357610b1e610d14565b5050565b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b865181101561086e57868181518110610b8957610b89611831565b602002602001015193505f845f015160400151511115610cde575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001610c018d8a60200151610eb2565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401610c2c9190611eca565b5f60405180830381865afa158015610c46573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610c6d9190810190611fcb565b9150505f81511115610cdc5784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490610cae908a908590600401612081565b5f604051808303815f87803b158015610cc5575f80fd5b505af1158015610cd7573d5f803e3d5ffd5b505050505b505b600101610b6e565b5f805f83516020850186885af1949350505050565b6040513d81523d5f602083013e3d602001810160405290565b6040513d5f823e3d81fd5b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f511483166109df5783831516156109d3573d5f823e3d81fd5b5f808060ff841681037f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff861115610db457600a860460018201600a88065f1493509350935050610dbe565b8593509150600190505b9250925092565b5f601b83900b8314838382610e29577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e1000000000000000000860515610e0957620186a0860595506005850194505b8586601b0b14610e2457600a86059550846001019450610e09565b610e3f565b855f03610e3f57505f925060019150610abd9050565b848560030b14610e82575f851215610e5f57505f9250829150610abd9050565b60405163d556b11160e01b815260048101839052602481018290526044016101c3565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791509250929050565b60605f825167ffffffffffffffff811115610ecf57610ecf6114be565b604051908082528060200260200182016040528015610ef8578160200160208202803683370190505b5090505f80845111610f0a575f610f10565b83516001015b85516001010190505f8167ffffffffffffffff811115610f3257610f326114be565b604051908082528060200260200182016040528015610f6557816020015b6060815260200190600190039081610f505790505b5090505f610f89604080516002815233602082015230818301526060810190915290565b828281518110610f9b57610f9b611831565b60200260200101819052505f5b8751811015610ff8578180600101925050878181518110610fcb57610fcb611831565b6020026020010151838381518110610fe557610fe5611831565b6020908102919091010152600101610fa8565b5085511561118a5780806001019150508382828151811061101b5761101b611831565b60200260200101819052505f5b8651811015611188576110d787828151811061104657611046611831565b60200260200101515f01516110b46110828a858151811061106957611069611831565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b8984815181106110c6576110c6611831565b602002602001015160400151611194565b6110f757604051630a57f30960e31b8152600481018290526024016101c3565b86818151811061110957611109611831565b60200260200101515f01516001600160a01b03165f1b85828151811061113157611131611831565b602002602001018181525050818060010192505086818151811061115757611157611831565b60200260200101516020015183838151811061117557611175611831565b6020908102919091010152600101611028565b505b5095945050505050565b5f836001600160a01b03163b5f036111f2575f806111b28585611204565b5090925090505f8160038111156111cb576111cb6120a1565b1480156111e95750856001600160a01b0316826001600160a01b0316145b9250505061093e565b6111fd84848461124a565b905061093e565b5f805f835160410361123b576020840151604085015160608601515f1a61122d8882858561129b565b955095509550505050610dbe565b505081515f9150600290610dbe565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156112d457505f91506003905082611359565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015611325573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661135057505f925060019150829050611359565b92505f91508190505b9450945094915050565b5f60208284031215611373575f80fd5b81356001600160e01b03198116811461093e575f80fd5b6001600160a01b038116811461014e575f80fd5b5f805f805f8060a087890312156113b3575f80fd5b86356113be8161138a565b955060208701356113ce8161138a565b94506040870135935060608701359250608087013567ffffffffffffffff808211156113f8575f80fd5b818901915089601f83011261140b575f80fd5b813581811115611419575f80fd5b8a602082850101111561142a575f80fd5b6020830194508093505050509295509295509295565b5f805f60608486031215611452575f80fd5b833561145d8161138a565b9250602084013567ffffffffffffffff80821115611479575f80fd5b9085019060c0828803121561148c575f80fd5b909250604085013590808211156114a1575f80fd5b508401604081870312156114b3575f80fd5b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156114f5576114f56114be565b60405290565b6040805190810167ffffffffffffffff811182821017156114f5576114f56114be565b604051601f8201601f1916810167ffffffffffffffff81118282101715611547576115476114be565b604052919050565b5f67ffffffffffffffff821115611568576115686114be565b50601f01601f191660200190565b5f82601f830112611585575f80fd5b81356115986115938261154f565b61151e565b8181528460208386010111156115ac575f80fd5b816020850160208301375f918101602001919091529392505050565b5f67ffffffffffffffff8211156115e1576115e16114be565b5060051b60200190565b5f82601f8301126115fa575f80fd5b8135602061160a611593836115c8565b82815260059290921b84018101918181019086841115611628575f80fd5b8286015b8481101561172457803567ffffffffffffffff8082111561164b575f80fd5b908801906060828b03601f19011215611662575f80fd5b61166a6114d2565b868301356116778161138a565b81526040838101358381111561168b575f80fd5b8401603f81018d1361169b575f80fd5b888101356116ab611593826115c8565b81815260059190911b82018301908a8101908f8311156116c9575f80fd5b928401925b828410156116e75783358252928b0192908b01906116ce565b858c01525050506060840135838111156116ff575f80fd5b61170d8d8a83880101611576565b91830191909152508552505091830191830161162c565b509695505050505050565b5f6040823603121561173f575f80fd5b6117476114fb565b823567ffffffffffffffff8082111561175e575f80fd5b818501915060608236031215611772575f80fd5b61177a6114d2565b82356117858161138a565b815260208301356117958161138a565b60208201526040830135828111156117ab575f80fd5b6117b736828601611576565b604083015250835260208501359150808211156117d2575f80fd5b506117df368286016115eb565b60208301525092915050565b5f808335601e19843603018112611800575f80fd5b83018035915067ffffffffffffffff82111561181a575f80fd5b6020019150600581901b3603821315610abd575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e19833603018112611859575f80fd5b9190910192915050565b5f8235609e19833603018112611859575f80fd5b5f808335601e1984360301811261188c575f80fd5b83018035915067ffffffffffffffff8211156118a6575f80fd5b6020019150600681901b3603821315610abd575f80fd5b5f602082840312156118cd575f80fd5b813561093e8161138a565b5f808335601e198436030181126118ed575f80fd5b830160208101925035905067ffffffffffffffff81111561190c575f80fd5b8060051b3603821315610abd575f80fd5b5f8235605e19833603018112611931575f80fd5b90910192915050565b5f808335601e1984360301811261194f575f80fd5b830160208101925035905067ffffffffffffffff81111561196e575f80fd5b803603821315610abd575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f808335601e198436030181126119b9575f80fd5b830160208101925035905067ffffffffffffffff8111156119d8575f80fd5b8060061b3603821315610abd575f80fd5b8183525f60208085019450825f5b85811015611a2f578135611a0a8161138a565b6001600160a01b031687528183013583880152604096870196909101906001016119f7565b509495945050505050565b8183526020808401935f91600585811b8301820185855b88811015611b1357858303601f19018a52611a6c828961191d565b60608135611a798161138a565b6001600160a01b03168552611a90828801836118d8565b82898801528083880152608092507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115611aca575f80fd5b871b808288850137860190506040611ae48482018561193a565b9450838884030182890152611afc848401868361197c565b9e8a019e9750505093870193505050600101611a51565b509098975050505050505050565b5f602080835260e08301843582850152604082860135818601526060818701358187015280870135801515808214611b57575f80fd5b8060808901525050611b6c60808801886118d8565b60c060a08901529384905261010093848801600582901b89018601835f5b84811015611ce8578b830360ff19018452813536879003607e19018112611baf575f80fd5b8601803536829003609e19018112611bc5575f80fd5b6080855281018035611bd68161138a565b6001600160a01b038082166080880152611bf28e84018461191d565b915060a0808801528135611c058161138a565b8116610120880152818e0135611c1a8161138a565b16610140870152611c2d818c018261193a565b91508a610160880152611c456101808801838361197c565b915050611c548b8301836119a4565b607f19808985030160c08a0152611c6c8483856119e9565b9350611c7a8d8601866119a4565b93509150808985030160e08a015250611c948383836119e9565b9250505060808201358c8701528c8301358d8701528a8301358b870152611cbd8a8401846118d8565b935091508581038a870152611cd3818484611a3a565b968d019695505050918a019150600101611b8a565b5050611cf760a08c018c61193a565b8b8303601f190160c08d015298509650611d1281898961197c565b9b9a5050505050505050505050565b5f8060408385031215611d32575f80fd5b505080516020909101519092909150565b5f805f60608486031215611d55575f80fd5b8351611d608161138a565b6020850151909350611d718161138a565b604085015190925067ffffffffffffffff811115611d8d575f80fd5b8401601f81018613611d9d575f80fd5b8051611dab6115938261154f565b818152876020838501011115611dbf575f80fd5b8160208401602083015e5f602083830101528093505050509250925092565b5f60208284031215611dee575f80fd5b815160ff8116811461093e575f80fd5b5f60208284031215611e0e575f80fd5b5051919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f815180845260208085019450602084015f5b83811015611a2f57815187529582019590820190600101611e56565b5f8282518085526020808601955060208260051b840101602086015f5b84811015611ebd57601f19868403018952611eab838351611e43565b98840198925090830190600101611e8f565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e06060840152611f03610100840182611e15565b9050606084015160808401526080840151601f19808584030160a0860152611f2b8383611e72565b925060a08601519150808584030160c0860152611f488383611e43565b925060c08601519150808584030160e086015250611f668282611e43565b95945050505050565b5f82601f830112611f7e575f80fd5b81516020611f8e611593836115c8565b8083825260208201915060208460051b870101935086841115611faf575f80fd5b602086015b848110156117245780518352918301918301611fb4565b5f8060408385031215611fdc575f80fd5b825167ffffffffffffffff80821115611ff3575f80fd5b818501915085601f830112612006575f80fd5b81516020612016611593836115c8565b82815260059290921b84018101918181019089841115612034575f80fd5b948201945b8386101561205257855182529482019490820190612039565b9188015191965090935050508082111561206a575f80fd5b5061207785828601611f6f565b9150509250929050565b828152604060208201525f6120996040830184611e43565b949350505050565b634e487b7160e01b5f52602160045260245ffd"; + hex"608060405260043610610034575f3560e01c806301ffc9a71461003d578063691f9ed714610070578063b17c83c11461008f57005b3661003b57005b005b348015610048575f80fd5b5061005c610057366004611363565b6100a2565b604051901515815260200160405180910390f35b34801561007b575f80fd5b5061003b61008a36600461139e565b6100f3565b61003b61009d366004611440565b61013a565b5f6001600160e01b0319821663691f9ed760e01b14806100d257506001600160e01b0319821663b17c83c160e01b145b806100ed57506301ffc9a760e01b6001600160e01b03198316145b92915050565b6101328683838080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152506103fc92505050565b505050505050565b6101426104ad565b61015161014e8261172f565b50565b61015e60808301836117eb565b90505f0361017f57604051639c95219f60e01b815260040160405180910390fd5b6001600160a01b0383167366f51a9c29480491c9282d99cf324e9f419a4e1d146101cc5760405163516e822d60e01b81526001600160a01b03841660048201526024015b60405180910390fd5b5f6101da60808401846117eb565b5f8181106101ea576101ea611831565b90506020028101906101fc9190611845565b6102069080611863565b610214906040810190611877565b61022160808601866117eb565b5f81811061023157610231611831565b90506020028101906102439190611845565b6020013581811061025657610256611831565b61026c92602060409092020190810191506118bd565b90505f61027c60808501856117eb565b5f81811061028c5761028c611831565b905060200281019061029e9190611845565b6102a89080611863565b6102b6906060810190611877565b6102c360808701876117eb565b5f8181106102d3576102d3611831565b90506020028101906102e59190611845565b604001358181106102f8576102f8611831565b61030e92602060409092020190810191506118bd565b90506103256001600160a01b038316865f196104db565b6040516334e3942b60e11b81526001600160a01b038616906369c7285690610351908790600401611b21565b60408051808303815f875af115801561036c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103909190611d21565b506103a790506001600160a01b038316865f6104db565b6103cc6103b38461172f565b836103bd85610555565b846103c786610555565b6105d9565b50506103f760017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050565b5f805f838060200190518101906104139190611d43565b919450925090506001600160a01b038316610441576040516398521dc560e01b815260040160405180910390fd5b6001600160a01b0382166104685760405163456ac4c360e11b815260040160405180910390fd5b61047d6001600160a01b038616845f196104db565b6104916001600160a01b0383168247610878565b506104a66001600160a01b038616845f6104db565b5050505050565b6104b5610945565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6104e78383835f610989565b6103f7576104f883835f6001610989565b61052057604051635274afe760e01b81526001600160a01b03841660048201526024016101c3565b61052d8383836001610989565b6103f757604051635274afe760e01b81526001600160a01b03841660048201526024016101c3565b5f61055e6109eb565b6040516354636d2b60e01b81526001600160a01b038316600482015273200e12d10bb0c5e4a17e7018f0f1161919bb9389906354636d2b906024016020604051808303815f875af11580156105b5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100ed9190611dde565b6040805160018082528183019092525f91816020015b60608152602001906001900390816105ef575050604080516003808252608082019092529192505f919060208201606080368337019050506040516370a0823160e01b81523060048201529091505f906001600160a01b038816906370a0823190602401602060405180830381865afa15801561066e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106929190611dfe565b905080156106ae576106ae6001600160a01b0388163383610a76565b5f6106b98288610a83565b50905080835f815181106106cf576106cf611831565b602090810291909101015250506040516370a0823160e01b81523060048201525f906001600160a01b038616906370a0823190602401602060405180830381865afa158015610720573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107449190611dfe565b90508015610760576107606001600160a01b0386163383610a76565b5f61076b8286610a83565b509050808360018151811061078257610782611831565b60209081029190910101525047905080156107a1576107a13382610ac4565b5f6107ad826012610a83565b50905080836002815181106107c4576107c4611831565b602002602001018181525050505080825f815181106107e5576107e5611831565b60209081029190910101526040805160018082528183019092525f91816020015b6040805160a0810182525f918101828152606080830193909352608082018390528152602081019190915281526020019060019003908161080657905050905087815f8151811061085957610859611831565b602002602001018190525061086e8382610b22565b5050505050505050565b6060814710156108a45760405163cf47918160e01b8152476004820152602481018390526044016101c3565b5f6108b0858486610ce6565b90508080156108d157505f3d11806108d157505f856001600160a01b03163b115b156108e6576108de610cfb565b91505061093e565b801561091057604051639996b31560e01b81526001600160a01b03861660048201526024016101c3565b3d156109235761091e610d14565b61093c565b60405163d6bda27560e01b815260040160405180910390fd5b505b9392505050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005460020361098757604051633ee5aeb560e01b815260040160405180910390fd5b565b60405163095ea7b360e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f511483166109df5783831516156109d3573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b1580610a42575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b15610987576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb938960048201526024016101c3565b61052d8383836001610d1f565b5f805f805f610a928787610d69565b9250925092505f80610aa48585610dc5565b9150915081838015610ab35750815b9650965050505050505b9250929050565b80471015610aee5760405163cf47918160e01b8152476004820152602481018290526044016101c3565b610b07828260405180602001604052805f815250610ce6565b15610b10575050565b3d1561092357610b1e610d14565b5050565b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b865181101561086e57868181518110610b8957610b89611831565b602002602001015193505f845f015160400151511115610cde575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001610c018d8a60200151610eb2565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401610c2c9190611eca565b5f60405180830381865afa158015610c46573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610c6d9190810190611fcb565b9150505f81511115610cdc5784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490610cae908a908590600401612081565b5f604051808303815f87803b158015610cc5575f80fd5b505af1158015610cd7573d5f803e3d5ffd5b505050505b505b600101610b6e565b5f805f83516020850186885af1949350505050565b6040513d81523d5f602083013e3d602001810160405290565b6040513d5f823e3d81fd5b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f511483166109df5783831516156109d3573d5f823e3d81fd5b5f808060ff841681037f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff861115610db457600a860460018201600a88065f1493509350935050610dbe565b8593509150600190505b9250925092565b5f601b83900b8314838382610e29577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e1000000000000000000860515610e0957620186a0860595506005850194505b8586601b0b14610e2457600a86059550846001019450610e09565b610e3f565b855f03610e3f57505f925060019150610abd9050565b848560030b14610e82575f851215610e5f57505f9250829150610abd9050565b60405163d556b11160e01b815260048101839052602481018290526044016101c3565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791509250929050565b60605f825167ffffffffffffffff811115610ecf57610ecf6114be565b604051908082528060200260200182016040528015610ef8578160200160208202803683370190505b5090505f80845111610f0a575f610f10565b83516001015b85516001010190505f8167ffffffffffffffff811115610f3257610f326114be565b604051908082528060200260200182016040528015610f6557816020015b6060815260200190600190039081610f505790505b5090505f610f89604080516002815233602082015230818301526060810190915290565b828281518110610f9b57610f9b611831565b60200260200101819052505f5b8751811015610ff8578180600101925050878181518110610fcb57610fcb611831565b6020026020010151838381518110610fe557610fe5611831565b6020908102919091010152600101610fa8565b5085511561118a5780806001019150508382828151811061101b5761101b611831565b60200260200101819052505f5b8651811015611188576110d787828151811061104657611046611831565b60200260200101515f01516110b46110828a858151811061106957611069611831565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b8984815181106110c6576110c6611831565b602002602001015160400151611194565b6110f757604051630a57f30960e31b8152600481018290526024016101c3565b86818151811061110957611109611831565b60200260200101515f01516001600160a01b03165f1b85828151811061113157611131611831565b602002602001018181525050818060010192505086818151811061115757611157611831565b60200260200101516020015183838151811061117557611175611831565b6020908102919091010152600101611028565b505b5095945050505050565b5f836001600160a01b03163b5f036111f2575f806111b28585611204565b5090925090505f8160038111156111cb576111cb6120a1565b1480156111e95750856001600160a01b0316826001600160a01b0316145b9250505061093e565b6111fd84848461124a565b905061093e565b5f805f835160410361123b576020840151604085015160608601515f1a61122d8882858561129b565b955095509550505050610dbe565b505081515f9150600290610dbe565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156112d457505f91506003905082611359565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015611325573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661135057505f925060019150829050611359565b92505f91508190505b9450945094915050565b5f60208284031215611373575f80fd5b81356001600160e01b03198116811461093e575f80fd5b6001600160a01b038116811461014e575f80fd5b5f805f805f8060a087890312156113b3575f80fd5b86356113be8161138a565b955060208701356113ce8161138a565b94506040870135935060608701359250608087013567ffffffffffffffff808211156113f8575f80fd5b818901915089601f83011261140b575f80fd5b813581811115611419575f80fd5b8a602082850101111561142a575f80fd5b6020830194508093505050509295509295509295565b5f805f60608486031215611452575f80fd5b833561145d8161138a565b9250602084013567ffffffffffffffff80821115611479575f80fd5b9085019060c0828803121561148c575f80fd5b909250604085013590808211156114a1575f80fd5b508401604081870312156114b3575f80fd5b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156114f5576114f56114be565b60405290565b6040805190810167ffffffffffffffff811182821017156114f5576114f56114be565b604051601f8201601f1916810167ffffffffffffffff81118282101715611547576115476114be565b604052919050565b5f67ffffffffffffffff821115611568576115686114be565b50601f01601f191660200190565b5f82601f830112611585575f80fd5b81356115986115938261154f565b61151e565b8181528460208386010111156115ac575f80fd5b816020850160208301375f918101602001919091529392505050565b5f67ffffffffffffffff8211156115e1576115e16114be565b5060051b60200190565b5f82601f8301126115fa575f80fd5b8135602061160a611593836115c8565b82815260059290921b84018101918181019086841115611628575f80fd5b8286015b8481101561172457803567ffffffffffffffff8082111561164b575f80fd5b908801906060828b03601f19011215611662575f80fd5b61166a6114d2565b868301356116778161138a565b81526040838101358381111561168b575f80fd5b8401603f81018d1361169b575f80fd5b888101356116ab611593826115c8565b81815260059190911b82018301908a8101908f8311156116c9575f80fd5b928401925b828410156116e75783358252928b0192908b01906116ce565b858c01525050506060840135838111156116ff575f80fd5b61170d8d8a83880101611576565b91830191909152508552505091830191830161162c565b509695505050505050565b5f6040823603121561173f575f80fd5b6117476114fb565b823567ffffffffffffffff8082111561175e575f80fd5b818501915060608236031215611772575f80fd5b61177a6114d2565b82356117858161138a565b815260208301356117958161138a565b60208201526040830135828111156117ab575f80fd5b6117b736828601611576565b604083015250835260208501359150808211156117d2575f80fd5b506117df368286016115eb565b60208301525092915050565b5f808335601e19843603018112611800575f80fd5b83018035915067ffffffffffffffff82111561181a575f80fd5b6020019150600581901b3603821315610abd575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e19833603018112611859575f80fd5b9190910192915050565b5f8235609e19833603018112611859575f80fd5b5f808335601e1984360301811261188c575f80fd5b83018035915067ffffffffffffffff8211156118a6575f80fd5b6020019150600681901b3603821315610abd575f80fd5b5f602082840312156118cd575f80fd5b813561093e8161138a565b5f808335601e198436030181126118ed575f80fd5b830160208101925035905067ffffffffffffffff81111561190c575f80fd5b8060051b3603821315610abd575f80fd5b5f8235605e19833603018112611931575f80fd5b90910192915050565b5f808335601e1984360301811261194f575f80fd5b830160208101925035905067ffffffffffffffff81111561196e575f80fd5b803603821315610abd575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f808335601e198436030181126119b9575f80fd5b830160208101925035905067ffffffffffffffff8111156119d8575f80fd5b8060061b3603821315610abd575f80fd5b8183525f60208085019450825f5b85811015611a2f578135611a0a8161138a565b6001600160a01b031687528183013583880152604096870196909101906001016119f7565b509495945050505050565b8183526020808401935f91600585811b8301820185855b88811015611b1357858303601f19018a52611a6c828961191d565b60608135611a798161138a565b6001600160a01b03168552611a90828801836118d8565b82898801528083880152608092507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115611aca575f80fd5b871b808288850137860190506040611ae48482018561193a565b9450838884030182890152611afc848401868361197c565b9e8a019e9750505093870193505050600101611a51565b509098975050505050505050565b5f602080835260e08301843582850152604082860135818601526060818701358187015280870135801515808214611b57575f80fd5b8060808901525050611b6c60808801886118d8565b60c060a08901529384905261010093848801600582901b89018601835f5b84811015611ce8578b830360ff19018452813536879003607e19018112611baf575f80fd5b8601803536829003609e19018112611bc5575f80fd5b6080855281018035611bd68161138a565b6001600160a01b038082166080880152611bf28e84018461191d565b915060a0808801528135611c058161138a565b8116610120880152818e0135611c1a8161138a565b16610140870152611c2d818c018261193a565b91508a610160880152611c456101808801838361197c565b915050611c548b8301836119a4565b607f19808985030160c08a0152611c6c8483856119e9565b9350611c7a8d8601866119a4565b93509150808985030160e08a015250611c948383836119e9565b9250505060808201358c8701528c8301358d8701528a8301358b870152611cbd8a8401846118d8565b935091508581038a870152611cd3818484611a3a565b968d019695505050918a019150600101611b8a565b5050611cf760a08c018c61193a565b8b8303601f190160c08d015298509650611d1281898961197c565b9b9a5050505050505050505050565b5f8060408385031215611d32575f80fd5b505080516020909101519092909150565b5f805f60608486031215611d55575f80fd5b8351611d608161138a565b6020850151909350611d718161138a565b604085015190925067ffffffffffffffff811115611d8d575f80fd5b8401601f81018613611d9d575f80fd5b8051611dab6115938261154f565b818152876020838501011115611dbf575f80fd5b8160208401602083015e5f602083830101528093505050509250925092565b5f60208284031215611dee575f80fd5b815160ff8116811461093e575f80fd5b5f60208284031215611e0e575f80fd5b5051919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f815180845260208085019450602084015f5b83811015611a2f57815187529582019590820190600101611e56565b5f8282518085526020808601955060208260051b840101602086015f5b84811015611ebd57601f19868403018952611eab838351611e43565b98840198925090830190600101611e8f565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e06060840152611f03610100840182611e15565b9050606084015160808401526080840151601f19808584030160a0860152611f2b8383611e72565b925060a08601519150808584030160c0860152611f488383611e43565b925060c08601519150808584030160e086015250611f668282611e43565b95945050505050565b5f82601f830112611f7e575f80fd5b81516020611f8e611593836115c8565b8083825260208201915060208460051b870101935086841115611faf575f80fd5b602086015b848110156117245780518352918301918301611fb4565b5f8060408385031215611fdc575f80fd5b825167ffffffffffffffff80821115611ff3575f80fd5b818501915085601f830112612006575f80fd5b81516020612016611593836115c8565b82815260059290921b84018101918181019089841115612034575f80fd5b948201945b8386101561205257855182529482019490820190612039565b9188015191965090935050508082111561206a575f80fd5b5061207785828601611f6f565b9150509250929050565b828152604060208201525f6120996040830184611e43565b949350505050565b634e487b7160e01b5f52602160045260245ffd"; diff --git a/src/generated/GenericPoolRaindexV6FlashBorrower.pointers.sol b/src/generated/GenericPoolRaindexV6FlashBorrower.pointers.sol index 8932d45c12..8627becb8b 100644 --- a/src/generated/GenericPoolRaindexV6FlashBorrower.pointers.sol +++ b/src/generated/GenericPoolRaindexV6FlashBorrower.pointers.sol @@ -10,12 +10,12 @@ pragma solidity ^0.8.25; // file needs the contract to exist so that it can be compiled. /// @dev Hash of the known bytecode. -bytes32 constant BYTECODE_HASH = bytes32(0xed618063fd6ffc7558e4588ea6357356e781d660fa22caa292a2f9aeaa21996f); +bytes32 constant BYTECODE_HASH = bytes32(0x3438f85dace78d284e0eb33f8a245750498a37dfde867325a0760cf022e8fdb7); /// @dev The deterministic deploy address of the contract when deployed via /// the Zoltu factory. -address constant DEPLOYED_ADDRESS = address(0xAd8af7f90a06659E9bBFD457c6C642fB60B1F46b); +address constant DEPLOYED_ADDRESS = address(0x94e275d0eAf27c28C4737b91f8CD9D1DD9132019); /// @dev The runtime bytecode of the contract. bytes constant RUNTIME_CODE = - hex"608060405260043610610034575f3560e01c806301ffc9a71461003d57806323e30c8b146100715780638c18e4ba1461009e57005b3661003b57005b005b348015610048575f80fd5b5061005c6100573660046116eb565b6100b1565b60405190151581526020015b60405180910390f35b34801561007c575f80fd5b5061009061008b366004611774565b6100e7565b604051908152602001610068565b61003b6100ac3660046117eb565b610204565b5f6001600160e01b031982166323e30c8b60e01b14806100e157506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f337386594ac4319230870c6e587f4aca48fab575619e1461012257604051625e1e6f60e51b81523360048201526024015b60405180910390fd5b6001600160a01b0387163014610156576040516322c7df1960e21b81526001600160a01b0388166004820152602401610119565b5f8061016484860186611def565b915091506101728282610534565b6040516334e3942b60e11b815233906369c7285690610195908590600401612008565b60408051808303815f875af11580156101b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101d49190612186565b507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd99a9950505050505050505050565b61020c6105a8565b61021b610218826121a8565b50565b6102286080850185612211565b90505f0361024957604051639c95219f60e01b815260040160405180910390fd5b6102596080850160608601612257565b61027657604051636d3a9fe560e01b815260040160405180910390fd5b5f84848460405160200161028c939291906124b0565b60408051601f1981840301815291905290505f6102ac6080870187612211565b5f8181106102bc576102bc6126c2565b90506020028101906102ce91906126d6565b6102d890806126f4565b6102e6906060810190612708565b6102f36080890189612211565b5f818110610303576103036126c2565b905060200281019061031591906126d6565b60400135818110610328576103286126c2565b61033e926020604090920201908101915061274e565b90505f61034e6080880188612211565b5f81811061035e5761035e6126c2565b905060200281019061037091906126d6565b61037a90806126f4565b610388906040810190612708565b61039560808a018a612211565b5f8181106103a5576103a56126c2565b90506020028101906103b791906126d6565b602001358181106103ca576103ca6126c2565b6103e0926020604090920201908101915061274e565b90505f6103ec826105d6565b90505f6103f8846105d6565b90505f6104068a358361065a565b905061041d6001600160a01b0385168c5f19610696565b6104326001600160a01b0386168c5f19610696565b604051632e7ff4ef60e11b81526001600160a01b038c1690635cffe9de90610464903090899086908c90600401612769565b6020604051808303815f875af1158015610480573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104a4919061279a565b6104c1576040516349088f5960e11b815260040160405180910390fd5b6104d56001600160a01b0386168c5f610696565b6104e96001600160a01b0385168c5f610696565b6104fe6104f5886121a8565b85858886610710565b50505050505061052d60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050505050565b5f82608001515f8151811061054b5761054b6126c2565b60200260200101515f01516060015183608001515f81518110610570576105706126c2565b6020026020010151604001518151811061058c5761058c6126c2565b60200260200101515f015190506105a381836109af565b505050565b6105b0610a59565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f6105df610a9d565b6040516354636d2b60e01b81526001600160a01b038316600482015273200e12d10bb0c5e4a17e7018f0f1161919bb9389906354636d2b906024016020604051808303815f875af1158015610636573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e191906127b5565b5f7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316601b0b60e084901d61068d828286610b28565b95945050505050565b6106a28383835f610b6c565b6105a3576106b383835f6001610b6c565b6106db57604051635274afe760e01b81526001600160a01b0384166004820152602401610119565b6106e88383836001610b6c565b6105a357604051635274afe760e01b81526001600160a01b0384166004820152602401610119565b6040805160018082528183019092525f91816020015b6060815260200190600190039081610726575050604080516003808252608082019092529192505f919060208201606080368337019050506040516370a0823160e01b81523060048201529091505f906001600160a01b038816906370a0823190602401602060405180830381865afa1580156107a5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107c991906127d5565b905080156107e5576107e56001600160a01b0388163383610bce565b5f6107f08288610bdb565b50905080835f81518110610806576108066126c2565b602090810291909101015250506040516370a0823160e01b81523060048201525f906001600160a01b038616906370a0823190602401602060405180830381865afa158015610857573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061087b91906127d5565b90508015610897576108976001600160a01b0386163383610bce565b5f6108a28286610bdb565b50905080836001815181106108b9576108b96126c2565b60209081029190910101525047905080156108d8576108d83382610c1c565b5f6108e4826012610bdb565b50905080836002815181106108fb576108fb6126c2565b602002602001018181525050505080825f8151811061091c5761091c6126c2565b60209081029190910101526040805160018082528183019092525f91816020015b6040805160a0810182525f918101828152606080830193909352608082018390528152602081019190915281526020019060019003908161093d57905050905087815f81518110610990576109906126c2565b60200260200101819052506109a58382610c93565b5050505050505050565b5f805f838060200190518101906109c691906127ec565b919450925090506001600160a01b0383166109f4576040516398521dc560e01b815260040160405180910390fd5b6001600160a01b038216610a1b5760405163456ac4c360e11b815260040160405180910390fd5b610a306001600160a01b038616845f19610696565b610a446001600160a01b0383168247610e57565b5061052d6001600160a01b038616845f610696565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0054600203610a9b57604051633ee5aeb560e01b815260040160405180910390fd5b565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b1580610af4575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b15610a9b576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610119565b5f805f610b36868686610f05565b9150915080610b615760405162bc8ecf60e31b81526004810187905260248101869052604401610119565b5090505b9392505050565b60405163095ea7b360e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316610bc2578383151615610bb6573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6106e8838383600161106e565b5f805f805f610bea87876110b8565b9250925092505f80610bfc8585611114565b9150915081838015610c0b5750815b9650965050505050505b9250929050565b80471015610c465760405163cf47918160e01b815247600482015260248101829052604401610119565b610c5f828260405180602001604052805f815250611201565b15610c68575050565b3d15610c7a57610c76611216565b5050565b60405163d6bda27560e01b815260040160405180910390fd5b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b86518110156109a557868181518110610cfa57610cfa6126c2565b602002602001015193505f845f015160400151511115610e4f575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001610d728d8a60200151611221565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401610d9d91906128d2565b5f60405180830381865afa158015610db7573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610dde91908101906129ca565b9150505f81511115610e4d5784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490610e1f908a908590600401612a76565b5f604051808303815f87803b158015610e36575f80fd5b505af1158015610e48573d5f803e3d5ffd5b505050505b505b600101610cdf565b606081471015610e835760405163cf47918160e01b815247600482015260248101839052604401610119565b5f610e8f858486611201565b9050808015610eb057505f3d1180610eb057505f856001600160a01b03163b115b15610ec557610ebd611503565b915050610b65565b8015610eef57604051639996b31560e01b81526001600160a01b0386166004820152602401610119565b3d15610c7a57610efd611216565b509392505050565b5f805f851215610f3257604051634a7d166b60e01b81526004810186905260248101859052604401610119565b845f03610f4457505f90506001611066565b8460ff8416850185811215610f765760405163d556b11160e01b81526004810188905260248101879052604401610119565b5f805f831215610fc257604c19831215610f99575f809550955050505050611066565b825f03600a0a9150818481610fb057610fb0612a96565b04955050840290911491506110669050565b5f83131561105b57604d831315610fff5760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610119565b82600a0a9150815f198161101557611015612a96565b048411156110495760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610119565b50919091029250600191506110669050565b509193506001925050505b935093915050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316610bc2578383151615610bb6573d5f823e3d81fd5b5f808060ff841681037f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86111561110357600a860460018201600a88065f149350935093505061110d565b8593509150600190505b9250925092565b5f601b83900b8314838382611178577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561115857620186a0860595506005850194505b8586601b0b1461117357600a86059550846001019450611158565b61118e565b855f0361118e57505f925060019150610c159050565b848560030b146111d1575f8512156111ae57505f9250829150610c159050565b60405163d556b11160e01b81526004810183905260248101829052604401610119565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791509250929050565b5f805f83516020850186885af1949350505050565b6040513d5f823e3d81fd5b60605f825167ffffffffffffffff81111561123e5761123e611892565b604051908082528060200260200182016040528015611267578160200160208202803683370190505b5090505f80845111611279575f61127f565b83516001015b85516001010190505f8167ffffffffffffffff8111156112a1576112a1611892565b6040519080825280602002602001820160405280156112d457816020015b60608152602001906001900390816112bf5790505b5090505f6112f8604080516002815233602082015230818301526060810190915290565b82828151811061130a5761130a6126c2565b60200260200101819052505f5b875181101561136757818060010192505087818151811061133a5761133a6126c2565b6020026020010151838381518110611354576113546126c2565b6020908102919091010152600101611317565b508551156114f95780806001019150508382828151811061138a5761138a6126c2565b60200260200101819052505f5b86518110156114f7576114468782815181106113b5576113b56126c2565b60200260200101515f01516114236113f18a85815181106113d8576113d86126c2565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b898481518110611435576114356126c2565b60200260200101516040015161151c565b61146657604051630a57f30960e31b815260048101829052602401610119565b868181518110611478576114786126c2565b60200260200101515f01516001600160a01b03165f1b8582815181106114a0576114a06126c2565b60200260200101818152505081806001019250508681815181106114c6576114c66126c2565b6020026020010151602001518383815181106114e4576114e46126c2565b6020908102919091010152600101611397565b505b5095945050505050565b6040513d81523d5f602083013e3d602001810160405290565b5f836001600160a01b03163b5f0361157a575f8061153a858561158c565b5090925090505f81600381111561155357611553612aaa565b1480156115715750856001600160a01b0316826001600160a01b0316145b92505050610b65565b6115858484846115d2565b9050610b65565b5f805f83516041036115c3576020840151604085015160608601515f1a6115b588828585611623565b95509550955050505061110d565b505081515f915060029061110d565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561165c57505f915060039050826116e1565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156116ad573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b0381166116d857505f9250600191508290506116e1565b92505f91508190505b9450945094915050565b5f602082840312156116fb575f80fd5b81356001600160e01b031981168114610b65575f80fd5b6001600160a01b0381168114610218575f80fd5b803561173181611712565b919050565b5f8083601f840112611746575f80fd5b50813567ffffffffffffffff81111561175d575f80fd5b602083019150836020828501011115610c15575f80fd5b5f805f805f8060a08789031215611789575f80fd5b863561179481611712565b955060208701356117a481611712565b94506040870135935060608701359250608087013567ffffffffffffffff8111156117cd575f80fd5b6117d989828a01611736565b979a9699509497509295939492505050565b5f805f805f608086880312156117ff575f80fd5b853561180a81611712565b9450602086013567ffffffffffffffff80821115611826575f80fd5b9087019060c0828a031215611839575f80fd5b9094506040870135908082111561184e575f80fd5b61185a89838a01611736565b90955093506060880135915080821115611872575f80fd5b50860160408189031215611884575f80fd5b809150509295509295909350565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156118c9576118c9611892565b60405290565b6040805190810167ffffffffffffffff811182821017156118c9576118c9611892565b6040516080810167ffffffffffffffff811182821017156118c9576118c9611892565b60405160a0810167ffffffffffffffff811182821017156118c9576118c9611892565b60405160c0810167ffffffffffffffff811182821017156118c9576118c9611892565b604051601f8201601f1916810167ffffffffffffffff8111828210171561198457611984611892565b604052919050565b8015158114610218575f80fd5b80356117318161198c565b5f67ffffffffffffffff8211156119bd576119bd611892565b5060051b60200190565b5f67ffffffffffffffff8211156119e0576119e0611892565b50601f01601f191660200190565b5f82601f8301126119fd575f80fd5b8135611a10611a0b826119c7565b61195b565b818152846020838601011115611a24575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60608284031215611a50575f80fd5b611a586118a6565b90508135611a6581611712565b81526020820135611a7581611712565b6020820152604082013567ffffffffffffffff811115611a93575f80fd5b611a9f848285016119ee565b60408301525092915050565b5f82601f830112611aba575f80fd5b81356020611aca611a0b836119a4565b82815260069290921b84018101918181019086841115611ae8575f80fd5b8286015b84811015611b2e5760408189031215611b03575f80fd5b611b0b6118cf565b8135611b1681611712565b81528185013585820152835291830191604001611aec565b509695505050505050565b5f82601f830112611b48575f80fd5b81356020611b58611a0b836119a4565b82815260059290921b84018101918181019086841115611b76575f80fd5b8286015b84811015611b2e57803567ffffffffffffffff80821115611b99575f80fd5b908801906060828b03601f19011215611bb0575f80fd5b611bb86118a6565b86830135611bc581611712565b815260408381013583811115611bd9575f80fd5b8401603f81018d13611be9575f80fd5b88810135611bf9611a0b826119a4565b81815260059190911b82018301908a8101908f831115611c17575f80fd5b928401925b82841015611c355783358252928b0192908b0190611c1c565b858c0152505050606084013583811115611c4d575f80fd5b611c5b8d8a838801016119ee565b918301919091525085525050918301918301611b7a565b5f82601f830112611c81575f80fd5b81356020611c91611a0b836119a4565b82815260059290921b84018101918181019086841115611caf575f80fd5b8286015b84811015611b2e57803567ffffffffffffffff80821115611cd2575f80fd5b90880190601f196080838c0382011215611cea575f80fd5b611cf26118f2565b8784013583811115611d02575f80fd5b840160a0818e0384011215611d15575f80fd5b611d1d611915565b9250611d2a898201611726565b8352604081013584811115611d3d575f80fd5b611d4b8e8b83850101611a40565b8a8501525060608082013585811115611d62575f80fd5b611d708f8c83860101611aab565b604086015250608082013585811115611d87575f80fd5b611d958f8c83860101611aab565b828601525060a0820135608085015283835260408601358a8401528086013560408401526080860135935084841115611dcc575f80fd5b611dda8e8b86890101611b39565b90830152508652505050918301918301611cb3565b5f8060408385031215611e00575f80fd5b823567ffffffffffffffff80821115611e17575f80fd5b9084019060c08287031215611e2a575f80fd5b611e32611938565b823581526020830135602082015260408301356040820152611e5660608401611999565b6060820152608083013582811115611e6c575f80fd5b611e7888828601611c72565b60808301525060a083013582811115611e8f575f80fd5b611e9b888286016119ee565b60a08301525093506020850135915080821115611eb6575f80fd5b50611ec3858286016119ee565b9150509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f815180845260208085019450602084015f5b83811015611f3e57815180516001600160a01b031688528301518388015260409096019590820190600101611f0e565b509495945050505050565b5f815180845260208085019450602084015f5b83811015611f3e57815187529582019590820190600101611f5c565b5f82825180855260208086019550808260051b8401018186015f5b84811015611ffb57601f19868403018952815160606001600160a01b038251168552858201518187870152611fca82870182611f49565b91505060408083015192508582038187015250611fe78183611ecd565b9a86019a9450505090830190600101611f93565b5090979650505050505050565b5f602080835260e08301845182850152818501516040818187015280870151915060608281880152808801519250608083151560808901526080890151935060a060c060a08a01528585518088526101009750878b019150878160051b8c010189880197505f5b82811015612157578c820360ff190184528851805187845280516001600160a01b03908116898601528d82015188860189905280518216610120870152808f01519091166101408601528a015161016085018a90526120d2610180860182611ecd565b90508a820151607f19808784030160c08801526120ef8383611efb565b92508b8401519150808784030160e08801525061210c8282611efb565b915050888201518d8601528d8301518e8601528a8301518b8601528983015192508481038a86015261213e8184611f78565b9b8e019b968e019694505050600191909101905061206f565b5060a08d01518c8203601f190160c08e01529950612175818b611ecd565b9d9c50505050505050505050505050565b5f8060408385031215612197575f80fd5b505080516020909101519092909150565b5f604082360312156121b8575f80fd5b6121c06118cf565b823567ffffffffffffffff808211156121d7575f80fd5b6121e336838701611a40565b835260208501359150808211156121f8575f80fd5b5061220536828601611b39565b60208301525092915050565b5f808335601e19843603018112612226575f80fd5b83018035915067ffffffffffffffff821115612240575f80fd5b6020019150600581901b3603821315610c15575f80fd5b5f60208284031215612267575f80fd5b8135610b658161198c565b5f808335601e19843603018112612287575f80fd5b830160208101925035905067ffffffffffffffff8111156122a6575f80fd5b8060051b3603821315610c15575f80fd5b5f8235605e198336030181126122cb575f80fd5b90910192915050565b5f808335601e198436030181126122e9575f80fd5b830160208101925035905067ffffffffffffffff811115612308575f80fd5b803603821315610c15575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f808335601e19843603018112612353575f80fd5b830160208101925035905067ffffffffffffffff811115612372575f80fd5b8060061b3603821315610c15575f80fd5b8183525f60208085019450825f5b85811015611f3e5781356123a481611712565b6001600160a01b03168752818301358388015260409687019690910190600101612391565b8183526020808401935f91600585811b8301820185855b888110156124a257858303601f19018a526123fb82896122b7565b6060813561240881611712565b6001600160a01b0316855261241f82880183612272565b82898801528083880152608092507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115612459575f80fd5b871b808288850137860190506040612473848201856122d4565b945083888403018289015261248b8484018683612316565b9e8a019e97505050938701935050506001016123e0565b509098975050505050505050565b5f604080835261010080840187358386015260206060818a013581880152848a01356080880152808a01356124e48161198c565b151560a08801526124f860808b018b612272565b60c0898101529384905261012093848901600582901b8a018601835f5b84811015612672578c830361011f19018452813536879003607e1901811261253b575f80fd5b8601803536829003609e19018112612551575f80fd5b608085528101803561256281611712565b6001600160a01b03808216608088015261257e8c8401846122b7565b915060a080880152813561259181611712565b8116878e0152818c01356125a481611712565b166101408701526125b7818f01826122d4565b91508a6101608801526125cf61018088018383612316565b9150506125de8e83018361233e565b607f19808985030160c08a01526125f6848385612383565b93506126048d86018661233e565b93509150808985030160e08a01525061261e838383612383565b9250505060808201358d8701528a8301358b8701528d8301358e8701526126478a840184612272565b935091508581038a87015261265d8184846123c9565b968b0196955050509188019150600101612515565b505061268160a08f018f6122d4565b8c8303603f190160e08e01529950975061269c818a8a612316565b98505050505050858403818701525050506126b8818587612316565b9695505050505050565b634e487b7160e01b5f52603260045260245ffd5b5f8235607e198336030181126126ea575f80fd5b9190910192915050565b5f8235609e198336030181126126ea575f80fd5b5f808335601e1984360301811261271d575f80fd5b83018035915067ffffffffffffffff821115612737575f80fd5b6020019150600681901b3603821315610c15575f80fd5b5f6020828403121561275e575f80fd5b8135610b6581611712565b5f6001600160a01b038087168352808616602084015250836040830152608060608301526126b86080830184611ecd565b5f602082840312156127aa575f80fd5b8151610b658161198c565b5f602082840312156127c5575f80fd5b815160ff81168114610b65575f80fd5b5f602082840312156127e5575f80fd5b5051919050565b5f805f606084860312156127fe575f80fd5b835161280981611712565b602085015190935061281a81611712565b604085015190925067ffffffffffffffff811115612836575f80fd5b8401601f81018613612846575f80fd5b8051612854611a0b826119c7565b818152876020838501011115612868575f80fd5b8160208401602083015e5f602083830101528093505050509250925092565b5f8282518085526020808601955060208260051b840101602086015f5b84811015611ffb57601f198684030189526128c0838351611f49565b988401989250908301906001016128a4565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e0606084015261290b610100840182611ecd565b9050606084015160808401526080840151601f19808584030160a08601526129338383612887565b925060a08601519150808584030160c08601526129508383611f49565b925060c08601519150808584030160e08601525061068d8282611f49565b5f82601f83011261297d575f80fd5b8151602061298d611a0b836119a4565b8083825260208201915060208460051b8701019350868411156129ae575f80fd5b602086015b84811015611b2e57805183529183019183016129b3565b5f80604083850312156129db575f80fd5b825167ffffffffffffffff808211156129f2575f80fd5b818501915085601f830112612a05575f80fd5b81516020612a15611a0b836119a4565b82815260059290921b84018101918181019089841115612a33575f80fd5b948201945b83861015612a5157855182529482019490820190612a38565b91880151919650909350505080821115612a69575f80fd5b50611ec38582860161296e565b828152604060208201525f612a8e6040830184611f49565b949350505050565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52602160045260245ffd"; + hex"608060405260043610610034575f3560e01c806301ffc9a71461003d57806323e30c8b146100715780638c18e4ba1461009e57005b3661003b57005b005b348015610048575f80fd5b5061005c6100573660046116eb565b6100b1565b60405190151581526020015b60405180910390f35b34801561007c575f80fd5b5061009061008b366004611774565b6100e7565b604051908152602001610068565b61003b6100ac3660046117eb565b610204565b5f6001600160e01b031982166323e30c8b60e01b14806100e157506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f337366f51a9c29480491c9282d99cf324e9f419a4e1d1461012257604051625e1e6f60e51b81523360048201526024015b60405180910390fd5b6001600160a01b0387163014610156576040516322c7df1960e21b81526001600160a01b0388166004820152602401610119565b5f8061016484860186611def565b915091506101728282610534565b6040516334e3942b60e11b815233906369c7285690610195908590600401612008565b60408051808303815f875af11580156101b0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101d49190612186565b507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd99a9950505050505050505050565b61020c6105a8565b61021b610218826121a8565b50565b6102286080850185612211565b90505f0361024957604051639c95219f60e01b815260040160405180910390fd5b6102596080850160608601612257565b61027657604051636d3a9fe560e01b815260040160405180910390fd5b5f84848460405160200161028c939291906124b0565b60408051601f1981840301815291905290505f6102ac6080870187612211565b5f8181106102bc576102bc6126c2565b90506020028101906102ce91906126d6565b6102d890806126f4565b6102e6906060810190612708565b6102f36080890189612211565b5f818110610303576103036126c2565b905060200281019061031591906126d6565b60400135818110610328576103286126c2565b61033e926020604090920201908101915061274e565b90505f61034e6080880188612211565b5f81811061035e5761035e6126c2565b905060200281019061037091906126d6565b61037a90806126f4565b610388906040810190612708565b61039560808a018a612211565b5f8181106103a5576103a56126c2565b90506020028101906103b791906126d6565b602001358181106103ca576103ca6126c2565b6103e0926020604090920201908101915061274e565b90505f6103ec826105d6565b90505f6103f8846105d6565b90505f6104068a358361065a565b905061041d6001600160a01b0385168c5f19610696565b6104326001600160a01b0386168c5f19610696565b604051632e7ff4ef60e11b81526001600160a01b038c1690635cffe9de90610464903090899086908c90600401612769565b6020604051808303815f875af1158015610480573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104a4919061279a565b6104c1576040516349088f5960e11b815260040160405180910390fd5b6104d56001600160a01b0386168c5f610696565b6104e96001600160a01b0385168c5f610696565b6104fe6104f5886121a8565b85858886610710565b50505050505061052d60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5050505050565b5f82608001515f8151811061054b5761054b6126c2565b60200260200101515f01516060015183608001515f81518110610570576105706126c2565b6020026020010151604001518151811061058c5761058c6126c2565b60200260200101515f015190506105a381836109af565b505050565b6105b0610a59565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b5f6105df610a9d565b6040516354636d2b60e01b81526001600160a01b038316600482015273200e12d10bb0c5e4a17e7018f0f1161919bb9389906354636d2b906024016020604051808303815f875af1158015610636573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100e191906127b5565b5f7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8316601b0b60e084901d61068d828286610b28565b95945050505050565b6106a28383835f610b6c565b6105a3576106b383835f6001610b6c565b6106db57604051635274afe760e01b81526001600160a01b0384166004820152602401610119565b6106e88383836001610b6c565b6105a357604051635274afe760e01b81526001600160a01b0384166004820152602401610119565b6040805160018082528183019092525f91816020015b6060815260200190600190039081610726575050604080516003808252608082019092529192505f919060208201606080368337019050506040516370a0823160e01b81523060048201529091505f906001600160a01b038816906370a0823190602401602060405180830381865afa1580156107a5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107c991906127d5565b905080156107e5576107e56001600160a01b0388163383610bce565b5f6107f08288610bdb565b50905080835f81518110610806576108066126c2565b602090810291909101015250506040516370a0823160e01b81523060048201525f906001600160a01b038616906370a0823190602401602060405180830381865afa158015610857573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061087b91906127d5565b90508015610897576108976001600160a01b0386163383610bce565b5f6108a28286610bdb565b50905080836001815181106108b9576108b96126c2565b60209081029190910101525047905080156108d8576108d83382610c1c565b5f6108e4826012610bdb565b50905080836002815181106108fb576108fb6126c2565b602002602001018181525050505080825f8151811061091c5761091c6126c2565b60209081029190910101526040805160018082528183019092525f91816020015b6040805160a0810182525f918101828152606080830193909352608082018390528152602081019190915281526020019060019003908161093d57905050905087815f81518110610990576109906126c2565b60200260200101819052506109a58382610c93565b5050505050505050565b5f805f838060200190518101906109c691906127ec565b919450925090506001600160a01b0383166109f4576040516398521dc560e01b815260040160405180910390fd5b6001600160a01b038216610a1b5760405163456ac4c360e11b815260040160405180910390fd5b610a306001600160a01b038616845f19610696565b610a446001600160a01b0383168247610e57565b5061052d6001600160a01b038616845f610696565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0054600203610a9b57604051633ee5aeb560e01b815260040160405180910390fd5b565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b1580610af4575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b15610a9b576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610119565b5f805f610b36868686610f05565b9150915080610b615760405162bc8ecf60e31b81526004810187905260248101869052604401610119565b5090505b9392505050565b60405163095ea7b360e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316610bc2578383151615610bb6573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6106e8838383600161106e565b5f805f805f610bea87876110b8565b9250925092505f80610bfc8585611114565b9150915081838015610c0b5750815b9650965050505050505b9250929050565b80471015610c465760405163cf47918160e01b815247600482015260248101829052604401610119565b610c5f828260405180602001604052805f815250611201565b15610c68575050565b3d15610c7a57610c76611216565b5050565b60405163d6bda27560e01b815260040160405180910390fd5b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b86518110156109a557868181518110610cfa57610cfa6126c2565b602002602001015193505f845f015160400151511115610e4f575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001610d728d8a60200151611221565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401610d9d91906128d2565b5f60405180830381865afa158015610db7573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610dde91908101906129ca565b9150505f81511115610e4d5784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490610e1f908a908590600401612a76565b5f604051808303815f87803b158015610e36575f80fd5b505af1158015610e48573d5f803e3d5ffd5b505050505b505b600101610cdf565b606081471015610e835760405163cf47918160e01b815247600482015260248101839052604401610119565b5f610e8f858486611201565b9050808015610eb057505f3d1180610eb057505f856001600160a01b03163b115b15610ec557610ebd611503565b915050610b65565b8015610eef57604051639996b31560e01b81526001600160a01b0386166004820152602401610119565b3d15610c7a57610efd611216565b509392505050565b5f805f851215610f3257604051634a7d166b60e01b81526004810186905260248101859052604401610119565b845f03610f4457505f90506001611066565b8460ff8416850185811215610f765760405163d556b11160e01b81526004810188905260248101879052604401610119565b5f805f831215610fc257604c19831215610f99575f809550955050505050611066565b825f03600a0a9150818481610fb057610fb0612a96565b04955050840290911491506110669050565b5f83131561105b57604d831315610fff5760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610119565b82600a0a9150815f198161101557611015612a96565b048411156110495760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610119565b50919091029250600191506110669050565b509193506001925050505b935093915050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316610bc2578383151615610bb6573d5f823e3d81fd5b5f808060ff841681037f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86111561110357600a860460018201600a88065f149350935093505061110d565b8593509150600190505b9250925092565b5f601b83900b8314838382611178577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561115857620186a0860595506005850194505b8586601b0b1461117357600a86059550846001019450611158565b61118e565b855f0361118e57505f925060019150610c159050565b848560030b146111d1575f8512156111ae57505f9250829150610c159050565b60405163d556b11160e01b81526004810183905260248101829052604401610119565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791509250929050565b5f805f83516020850186885af1949350505050565b6040513d5f823e3d81fd5b60605f825167ffffffffffffffff81111561123e5761123e611892565b604051908082528060200260200182016040528015611267578160200160208202803683370190505b5090505f80845111611279575f61127f565b83516001015b85516001010190505f8167ffffffffffffffff8111156112a1576112a1611892565b6040519080825280602002602001820160405280156112d457816020015b60608152602001906001900390816112bf5790505b5090505f6112f8604080516002815233602082015230818301526060810190915290565b82828151811061130a5761130a6126c2565b60200260200101819052505f5b875181101561136757818060010192505087818151811061133a5761133a6126c2565b6020026020010151838381518110611354576113546126c2565b6020908102919091010152600101611317565b508551156114f95780806001019150508382828151811061138a5761138a6126c2565b60200260200101819052505f5b86518110156114f7576114468782815181106113b5576113b56126c2565b60200260200101515f01516114236113f18a85815181106113d8576113d86126c2565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b898481518110611435576114356126c2565b60200260200101516040015161151c565b61146657604051630a57f30960e31b815260048101829052602401610119565b868181518110611478576114786126c2565b60200260200101515f01516001600160a01b03165f1b8582815181106114a0576114a06126c2565b60200260200101818152505081806001019250508681815181106114c6576114c66126c2565b6020026020010151602001518383815181106114e4576114e46126c2565b6020908102919091010152600101611397565b505b5095945050505050565b6040513d81523d5f602083013e3d602001810160405290565b5f836001600160a01b03163b5f0361157a575f8061153a858561158c565b5090925090505f81600381111561155357611553612aaa565b1480156115715750856001600160a01b0316826001600160a01b0316145b92505050610b65565b6115858484846115d2565b9050610b65565b5f805f83516041036115c3576020840151604085015160608601515f1a6115b588828585611623565b95509550955050505061110d565b505081515f915060029061110d565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561165c57505f915060039050826116e1565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156116ad573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b0381166116d857505f9250600191508290506116e1565b92505f91508190505b9450945094915050565b5f602082840312156116fb575f80fd5b81356001600160e01b031981168114610b65575f80fd5b6001600160a01b0381168114610218575f80fd5b803561173181611712565b919050565b5f8083601f840112611746575f80fd5b50813567ffffffffffffffff81111561175d575f80fd5b602083019150836020828501011115610c15575f80fd5b5f805f805f8060a08789031215611789575f80fd5b863561179481611712565b955060208701356117a481611712565b94506040870135935060608701359250608087013567ffffffffffffffff8111156117cd575f80fd5b6117d989828a01611736565b979a9699509497509295939492505050565b5f805f805f608086880312156117ff575f80fd5b853561180a81611712565b9450602086013567ffffffffffffffff80821115611826575f80fd5b9087019060c0828a031215611839575f80fd5b9094506040870135908082111561184e575f80fd5b61185a89838a01611736565b90955093506060880135915080821115611872575f80fd5b50860160408189031215611884575f80fd5b809150509295509295909350565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156118c9576118c9611892565b60405290565b6040805190810167ffffffffffffffff811182821017156118c9576118c9611892565b6040516080810167ffffffffffffffff811182821017156118c9576118c9611892565b60405160a0810167ffffffffffffffff811182821017156118c9576118c9611892565b60405160c0810167ffffffffffffffff811182821017156118c9576118c9611892565b604051601f8201601f1916810167ffffffffffffffff8111828210171561198457611984611892565b604052919050565b8015158114610218575f80fd5b80356117318161198c565b5f67ffffffffffffffff8211156119bd576119bd611892565b5060051b60200190565b5f67ffffffffffffffff8211156119e0576119e0611892565b50601f01601f191660200190565b5f82601f8301126119fd575f80fd5b8135611a10611a0b826119c7565b61195b565b818152846020838601011115611a24575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60608284031215611a50575f80fd5b611a586118a6565b90508135611a6581611712565b81526020820135611a7581611712565b6020820152604082013567ffffffffffffffff811115611a93575f80fd5b611a9f848285016119ee565b60408301525092915050565b5f82601f830112611aba575f80fd5b81356020611aca611a0b836119a4565b82815260069290921b84018101918181019086841115611ae8575f80fd5b8286015b84811015611b2e5760408189031215611b03575f80fd5b611b0b6118cf565b8135611b1681611712565b81528185013585820152835291830191604001611aec565b509695505050505050565b5f82601f830112611b48575f80fd5b81356020611b58611a0b836119a4565b82815260059290921b84018101918181019086841115611b76575f80fd5b8286015b84811015611b2e57803567ffffffffffffffff80821115611b99575f80fd5b908801906060828b03601f19011215611bb0575f80fd5b611bb86118a6565b86830135611bc581611712565b815260408381013583811115611bd9575f80fd5b8401603f81018d13611be9575f80fd5b88810135611bf9611a0b826119a4565b81815260059190911b82018301908a8101908f831115611c17575f80fd5b928401925b82841015611c355783358252928b0192908b0190611c1c565b858c0152505050606084013583811115611c4d575f80fd5b611c5b8d8a838801016119ee565b918301919091525085525050918301918301611b7a565b5f82601f830112611c81575f80fd5b81356020611c91611a0b836119a4565b82815260059290921b84018101918181019086841115611caf575f80fd5b8286015b84811015611b2e57803567ffffffffffffffff80821115611cd2575f80fd5b90880190601f196080838c0382011215611cea575f80fd5b611cf26118f2565b8784013583811115611d02575f80fd5b840160a0818e0384011215611d15575f80fd5b611d1d611915565b9250611d2a898201611726565b8352604081013584811115611d3d575f80fd5b611d4b8e8b83850101611a40565b8a8501525060608082013585811115611d62575f80fd5b611d708f8c83860101611aab565b604086015250608082013585811115611d87575f80fd5b611d958f8c83860101611aab565b828601525060a0820135608085015283835260408601358a8401528086013560408401526080860135935084841115611dcc575f80fd5b611dda8e8b86890101611b39565b90830152508652505050918301918301611cb3565b5f8060408385031215611e00575f80fd5b823567ffffffffffffffff80821115611e17575f80fd5b9084019060c08287031215611e2a575f80fd5b611e32611938565b823581526020830135602082015260408301356040820152611e5660608401611999565b6060820152608083013582811115611e6c575f80fd5b611e7888828601611c72565b60808301525060a083013582811115611e8f575f80fd5b611e9b888286016119ee565b60a08301525093506020850135915080821115611eb6575f80fd5b50611ec3858286016119ee565b9150509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f815180845260208085019450602084015f5b83811015611f3e57815180516001600160a01b031688528301518388015260409096019590820190600101611f0e565b509495945050505050565b5f815180845260208085019450602084015f5b83811015611f3e57815187529582019590820190600101611f5c565b5f82825180855260208086019550808260051b8401018186015f5b84811015611ffb57601f19868403018952815160606001600160a01b038251168552858201518187870152611fca82870182611f49565b91505060408083015192508582038187015250611fe78183611ecd565b9a86019a9450505090830190600101611f93565b5090979650505050505050565b5f602080835260e08301845182850152818501516040818187015280870151915060608281880152808801519250608083151560808901526080890151935060a060c060a08a01528585518088526101009750878b019150878160051b8c010189880197505f5b82811015612157578c820360ff190184528851805187845280516001600160a01b03908116898601528d82015188860189905280518216610120870152808f01519091166101408601528a015161016085018a90526120d2610180860182611ecd565b90508a820151607f19808784030160c08801526120ef8383611efb565b92508b8401519150808784030160e08801525061210c8282611efb565b915050888201518d8601528d8301518e8601528a8301518b8601528983015192508481038a86015261213e8184611f78565b9b8e019b968e019694505050600191909101905061206f565b5060a08d01518c8203601f190160c08e01529950612175818b611ecd565b9d9c50505050505050505050505050565b5f8060408385031215612197575f80fd5b505080516020909101519092909150565b5f604082360312156121b8575f80fd5b6121c06118cf565b823567ffffffffffffffff808211156121d7575f80fd5b6121e336838701611a40565b835260208501359150808211156121f8575f80fd5b5061220536828601611b39565b60208301525092915050565b5f808335601e19843603018112612226575f80fd5b83018035915067ffffffffffffffff821115612240575f80fd5b6020019150600581901b3603821315610c15575f80fd5b5f60208284031215612267575f80fd5b8135610b658161198c565b5f808335601e19843603018112612287575f80fd5b830160208101925035905067ffffffffffffffff8111156122a6575f80fd5b8060051b3603821315610c15575f80fd5b5f8235605e198336030181126122cb575f80fd5b90910192915050565b5f808335601e198436030181126122e9575f80fd5b830160208101925035905067ffffffffffffffff811115612308575f80fd5b803603821315610c15575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f808335601e19843603018112612353575f80fd5b830160208101925035905067ffffffffffffffff811115612372575f80fd5b8060061b3603821315610c15575f80fd5b8183525f60208085019450825f5b85811015611f3e5781356123a481611712565b6001600160a01b03168752818301358388015260409687019690910190600101612391565b8183526020808401935f91600585811b8301820185855b888110156124a257858303601f19018a526123fb82896122b7565b6060813561240881611712565b6001600160a01b0316855261241f82880183612272565b82898801528083880152608092507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115612459575f80fd5b871b808288850137860190506040612473848201856122d4565b945083888403018289015261248b8484018683612316565b9e8a019e97505050938701935050506001016123e0565b509098975050505050505050565b5f604080835261010080840187358386015260206060818a013581880152848a01356080880152808a01356124e48161198c565b151560a08801526124f860808b018b612272565b60c0898101529384905261012093848901600582901b8a018601835f5b84811015612672578c830361011f19018452813536879003607e1901811261253b575f80fd5b8601803536829003609e19018112612551575f80fd5b608085528101803561256281611712565b6001600160a01b03808216608088015261257e8c8401846122b7565b915060a080880152813561259181611712565b8116878e0152818c01356125a481611712565b166101408701526125b7818f01826122d4565b91508a6101608801526125cf61018088018383612316565b9150506125de8e83018361233e565b607f19808985030160c08a01526125f6848385612383565b93506126048d86018661233e565b93509150808985030160e08a01525061261e838383612383565b9250505060808201358d8701528a8301358b8701528d8301358e8701526126478a840184612272565b935091508581038a87015261265d8184846123c9565b968b0196955050509188019150600101612515565b505061268160a08f018f6122d4565b8c8303603f190160e08e01529950975061269c818a8a612316565b98505050505050858403818701525050506126b8818587612316565b9695505050505050565b634e487b7160e01b5f52603260045260245ffd5b5f8235607e198336030181126126ea575f80fd5b9190910192915050565b5f8235609e198336030181126126ea575f80fd5b5f808335601e1984360301811261271d575f80fd5b83018035915067ffffffffffffffff821115612737575f80fd5b6020019150600681901b3603821315610c15575f80fd5b5f6020828403121561275e575f80fd5b8135610b6581611712565b5f6001600160a01b038087168352808616602084015250836040830152608060608301526126b86080830184611ecd565b5f602082840312156127aa575f80fd5b8151610b658161198c565b5f602082840312156127c5575f80fd5b815160ff81168114610b65575f80fd5b5f602082840312156127e5575f80fd5b5051919050565b5f805f606084860312156127fe575f80fd5b835161280981611712565b602085015190935061281a81611712565b604085015190925067ffffffffffffffff811115612836575f80fd5b8401601f81018613612846575f80fd5b8051612854611a0b826119c7565b818152876020838501011115612868575f80fd5b8160208401602083015e5f602083830101528093505050509250925092565b5f8282518085526020808601955060208260051b840101602086015f5b84811015611ffb57601f198684030189526128c0838351611f49565b988401989250908301906001016128a4565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e0606084015261290b610100840182611ecd565b9050606084015160808401526080840151601f19808584030160a08601526129338383612887565b925060a08601519150808584030160c08601526129508383611f49565b925060c08601519150808584030160e08601525061068d8282611f49565b5f82601f83011261297d575f80fd5b8151602061298d611a0b836119a4565b8083825260208201915060208460051b8701019350868411156129ae575f80fd5b602086015b84811015611b2e57805183529183019183016129b3565b5f80604083850312156129db575f80fd5b825167ffffffffffffffff808211156129f2575f80fd5b818501915085601f830112612a05575f80fd5b81516020612a15611a0b836119a4565b82815260059290921b84018101918181019089841115612a33575f80fd5b948201945b83861015612a5157855182529482019490820190612a38565b91880151919650909350505080821115612a69575f80fd5b50611ec38582860161296e565b828152604060208201525f612a8e6040830184611f49565b949350505050565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52602160045260245ffd"; diff --git a/src/generated/RaindexV6.pointers.sol b/src/generated/RaindexV6.pointers.sol index 27e8991640..a5d70f0227 100644 --- a/src/generated/RaindexV6.pointers.sol +++ b/src/generated/RaindexV6.pointers.sol @@ -10,16 +10,16 @@ pragma solidity ^0.8.25; // file needs the contract to exist so that it can be compiled. /// @dev Hash of the known bytecode. -bytes32 constant BYTECODE_HASH = bytes32(0x774ca4c194abf0720bca6c033580762029a80291feefd0a4b7855b16bcbbf7a9); +bytes32 constant BYTECODE_HASH = bytes32(0x670aa891cb8fcb7166ecf8031238f6287ead1ac018d6353af04dfd720b146e75); /// @dev The deterministic deploy address of the contract when deployed via /// the Zoltu factory. -address constant DEPLOYED_ADDRESS = address(0x86594ac4319230870C6E587f4ACa48FAb575619e); +address constant DEPLOYED_ADDRESS = address(0x66F51a9C29480491C9282D99cf324e9f419A4e1d); /// @dev The creation bytecode of the contract. bytes constant CREATION_CODE = - hex"6080604052348015600e575f80fd5b5060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055615eed806100405f395ff3fe608060405234801561000f575f80fd5b50600436106100f0575f3560e01c8063613255ab11610093578063ac9650d811610063578063ac9650d81461022b578063d7e442ec1461024b578063d9d98ce41461025e578063fa50118214610271575f80fd5b8063613255ab146101ad57806369c72856146101c0578063709fb8a5146101e85780639235084d146101fb575f80fd5b80632fbc4ba0116100ce5780632fbc4ba01461015157806341d1514f146101665780635cffe9de14610187578063607461191461019a575f80fd5b806301ffc9a7146100f45780631f69cb751461011c5780632cb77e9f1461012f575b5f80fd5b6101076101023660046148e8565b610284565b60405190151581526020015b60405180910390f35b61010761012a366004614950565b6102ba565b61010761013d3660046149bb565b5f9081526020819052604090205460011490565b61016461015f3660046149f1565b6103c2565b005b610179610174366004614a56565b610521565b604051908152602001610113565b610107610195366004614a94565b610535565b6101646101a83660046149f1565b610635565b6101796101bb366004614b2b565b6107c8565b6101d36101ce366004614b5c565b610830565b60408051928352602083019190915201610113565b6101076101f6366004614b8e565b610fc9565b61020e610209366004614bd8565b61130c565b604080519315158452602084019290925290820152606001610113565b61023e610239366004614c0f565b6113ce565b6040516101139190614c7c565b610164610259366004614c0f565b6114b4565b61017961026c366004614cde565b61150e565b61016461027f366004615150565b6115a8565b5f6001600160e01b0319821663e414309160e01b14806102b457506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f6102c3611a9a565b6102d06020850185614b2b565b6001600160a01b0316336001600160a01b03161461031f576102f56020850185614b2b565b6040516335252be360e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b5f61033161032c8661520a565b611ab5565b5f818152602081905260409020549091505f19016103a4575f818152602081905260408082209190915551600192507f09d18501db0080ca2d6cd7c17fa7255daff4b2d503ea93b76ff68b6752ea8e639061039190339084908990615360565b60405180910390a16103a4818585611ae4565b506103bb60015f80516020615ecd83398151915255565b9392505050565b6103ca611a9a565b3385856103d8838383611b1b565b6103e2865f611b4c565b610417576040516306dde9c360e41b81523360048201526001600160a01b038916602482015260448101889052606401610316565b5f80610424338b8a611b86565b604080513381526001600160a01b038e1660208201529081018c90526060810183905291935091507f7f9dfa19cf1cc2f806f2f860fbc9c056b601fb1afc0e9b843dfe5c63616268e69060800160405180910390a15f80610487338d8d8d611c06565b909250905087156104fd5760408051600581526001600160a01b038e1660208201528082018d9052606081018490526080810183905260ff851660a082015260c081019091526104fd906104ee905b60408051600181526020810192909252818101905290565b6104f88a8c615424565b611cf6565b5050505050505061051a60015f80516020615ecd83398151915255565b5050505050565b5f61052d848484611ec4565b949350505050565b5f61054a6001600160a01b038616878661204e565b6040516323e30c8b60e01b81525f906001600160a01b038816906323e30c8b906105829033908a908a9087908b908b906004016154e4565b6020604051808303815f875af115801561059e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105c29190615528565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9811461060757604051630b6c58a960e31b815260048101829052602401610316565b61062887306106165f89615553565b6001600160a01b038a16929190612083565b5060019695505050505050565b61063d611a9a565b33858561064b838383611b1b565b5f8080806106598a82611b4c565b61068d57604051623a3a4d60e21b81523360048201526001600160a01b038d166024820152604481018c9052606401610316565b5f610699338e8e611ec4565b90506106a58b826120bf565b94506106b3338e8e886120db565b90935091505f6106c4338f88612152565b80965081925050507f8045c25080b0868951141ed0a91720bcad09a8364a2b3109ee1fd49c1f0bc8b8338f8f8f8a86604051610736969594939291906001600160a01b03968716815294909516602085015260408401929092526060830152608082015260a081019190915260c00190565b60405180910390a1505060408051600681526001600160a01b038e1660208201528082018d9052606081018490526080810183905260a081018c905260ff851660c0820152600160e08201908152610100820182905261012082019092529089156107a9576107a9816104f88c8e615424565b50505050505050505061051a60015f80516020615ecd83398151915255565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa15801561080c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b49190615528565b5f8061083a611a9a565b6108476080840184615566565b90505f0361086857604051639c95219f60e01b815260040160405180910390fd5b610870614810565b61087861483c565b5f60405180606001604052808780608001906108949190615566565b5f8181106108a4576108a46155ac565b90506020028101906108b691906155c0565b6108c090806155de565b6108ce9060408101906155f2565b6108db60808b018b615566565b5f8181106108eb576108eb6155ac565b90506020028101906108fd91906155c0565b60200135818110610910576109106155ac565b6109269260206040909202019081019150614b2b565b6001600160a01b031681526020016109416080890189615566565b5f818110610951576109516155ac565b905060200281019061096391906155c0565b61096d90806155de565b61097b9060608101906155f2565b61098860808b018b615566565b5f818110610998576109986155ac565b90506020028101906109aa91906155c0565b604001358181106109bd576109bd6155ac565b6109d39260206040909202019081019150614b2b565b6001600160a01b03168152602088810135910152905060605f6109f96080890189615566565b604080516001909201602002820181528501519093505f9250610a1d915082611b4c565b610a3a5760405163315f9e2360e21b815260040160405180910390fd5b5f5b610a4960808a018a615566565b905081108015610a6357506040840151610a63905f611b4c565b15610e7157610a7560808a018a615566565b82818110610a8557610a856155ac565b9050602002810190610a9791906155c0565b610aa090615638565b9550855f01519450835f01516001600160a01b03168560400151876020015181518110610acf57610acf6155ac565b60200260200101515f01516001600160a01b0316141580610b2a575083602001516001600160a01b03168560600151876040015181518110610b1357610b136155ac565b60200260200101515f01516001600160a01b031614155b15610b485760405163936bb5ad60e01b815260040160405180910390fd5b610b5b85876020015188604001516121bb565b5f610b6586611ab5565b5f81815260208190526040902054909150610bca578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a1610e68565b5f610c278789602001518a60400151338c606001515f67ffffffffffffffff811115610bf857610bf8614d08565b604051908082528060200260200182016040528015610c21578160200160208202803683370190505b5061222d565b90505f610c458c604001358360600151611b4c90919063ffffffff16565b15610c9b578751604080513381526001600160a01b03909216602083015281018490527fe3151dc8cb7a54ffc4baabd28c1f241c94d510b5e5b502491ac3cad6c16316d5906060015b60405180910390a1610e5a565b6040820151610caa905f611b4c565b1580610cc257506060820151610cc0905f611b4c565b155b15610d0f578751604080513381526001600160a01b03909216602083015281018490527f500b713857325f9e6dcb52ae832eca9109d107ed1aae9cb4928b4c1e13f051aa90606001610c8e565b600190505f808d6060016020810190610d2891906156ce565b15610d6e576040808a015190850151610d40916120bf565b6060850151909250610d5290836126f2565b60408a0151909150610d64908361273f565b60408a0152610dd5565b5f610d8a856040015186606001516126f290919063ffffffff16565b9050610da38a60400151826120bf90919063ffffffff16565b9150610dbc85606001518361276f90919063ffffffff16565b60408b0151909350610dce908361273f565b60408b0152505b610ddf8c8261279f565b9b50610deb8d8361279f565b9c50610df782856127cf565b610e018185612890565b7f194f1feb3b4d7076a2c272e774e792e0c48bb8c7aa1a9a3671c1cd6da9e6b4c1338c8484604051610e3694939291906157f6565b60405180910390a187516001018089526020028801849052610e5784612a3c565b50505b8480610e635750805b945050505b50600101610a3c565b505f610e8360808a0160608b016156ce565b610e8d5786610e8f565b875b9050610e9c818a35612c7f565b15610ec45760405163573b6f4160e01b81528935600482015260248101829052604401610316565b50610ed433846020015189612152565b505f9050610ee560a08a018a6158e0565b9050118015610ef15750805b15610f635760208301518351339163691f9ed7918a8a610f1460a08f018f6158e0565b6040518763ffffffff1660e01b8152600401610f35969594939291906154e4565b5f604051808303815f87803b158015610f4c575f80fd5b505af1158015610f5e573d5f803e3d5ffd5b505050505b610f7133845f015188611b86565b50505f5b8251811015610fa857610fa0838281518110610f9357610f936155ac565b6020026020010151612cb9565b600101610f75565b505050505050610fc460015f80516020615ecd83398151915255565b915091565b5f610fd2611a9a565b5f61102f61102a610fe38780615923565b610ff19060408101906158e0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612dc392505050565b612e34565b90505f811161105157604051632cff108b60e21b815260040160405180910390fd5b6001811161107257604051633c8270bd60e21b815260040160405180910390fd5b61107f60208601866155f2565b90505f036110a057604051636c44ef8f60e01b815260040160405180910390fd5b6110ad60408601866155f2565b90505f036110ce5760405163540e5f0b60e01b815260040160405180910390fd5b6040805160a081019091523381525f90602081016110ec8880615923565b6110f590615937565b815260200187806020019061110a91906155f2565b808060200260200160405190810160405280939291908181526020015f905b828210156111555761114660408302860136819003810190615942565b81526020019060010190611129565b505050918352505060200161116d60408901896155f2565b808060200260200160405190810160405280939291908181526020015f905b828210156111b8576111a960408302860136819003810190615942565b8152602001906001019061118c565b50505050508152602001876060013581525090505f6111d682611ab5565b5f818152602081905260409020549091501580156112f1575f828152602081905260409081902060019055835190517f87491344dfbcf91f6cbbc610cbbeedc85313d37a02df0c93527f7ea5f8db717f91611234918590879061595c565b60405180910390a15f61124a60a08a018a6158e0565b905011156112e65761129b61126260a08a018a6158e0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612e4e92505050565b82517fd46c2c56b35c8210e9e712ec3f02242d5fc90187c0ac8ed80cc33626846ec36990836112cd60a08c018c6158e0565b6040516112dd9493929190615983565b60405180910390a15b6112f1828888611ae4565b93505050506103bb60015f80516020615ecd83398151915255565b5f80808061132661131d86806155de565b61032c9061520a565b5f8181526020819052604090205490915060011461134d57505f92508291508190506113c7565b61137261135a86806155de565b6113639061520a565b866020013587604001356121bb565b5f6113b061138087806155de565b6113899061520a565b60208801356040890135336113a160608c018c615566565b6113aa916159b5565b5f610bf8565b905060018160400151826060015194509450945050505b9193909250565b604080515f8152602081019091526060908267ffffffffffffffff8111156113f8576113f8614d08565b60405190808252806020026020018201604052801561142b57816020015b60608152602001906001900390816114165790505b5091505f5b838110156114ac576114873086868481811061144e5761144e6155ac565b905060200281019061146091906158e0565b85604051602001611473939291906159d4565b604051602081830303815290604052612e79565b838281518110611499576114996155ac565b6020908102919091010152600101611430565b505092915050565b6114bc611a9a565b604080515f808252602082019092526114f4916114e9565b60608152602001906001900390816114d45790505b506104f88385615424565b61150a60015f80516020615ecd83398151915255565b5050565b6040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611552573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115769190615528565b5f036115a057604051633c5bf76960e21b81526001600160a01b0384166004820152602401610316565b505f92915050565b6115b0611a9a565b835185516001600160a01b039182169116036115df57604051630a98f1f360e21b815260040160405180910390fd5b83604001518360400135815181106115f9576115f96155ac565b60200260200101515f01516001600160a01b03168560600151846020013581518110611627576116276155ac565b60200260200101515f01516001600160a01b03161415806116a0575060408501518051843590811061165b5761165b6155ac565b60200260200101515f01516001600160a01b03168460600151846060013581518110611689576116896155ac565b60200260200101515f01516001600160a01b031614155b156116be5760405163936bb5ad60e01b815260040160405180910390fd5b84606001518360200135815181106116d8576116d86155ac565b60200260200101515f01516001600160a01b03168560400151845f013581518110611705576117056155ac565b60200260200101515f01516001600160a01b03160361173757604051631cd2f1c760e21b815260040160405180910390fd5b5f61174186611ab5565b5f818152602081905260409020549091506117a7578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a150611a84565b5f6117b186611ab5565b5f81815260208190526040902054909150611818578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a15050611a84565b7f6fa7f4c28634b0a9d6831401c45ae468195fb63aed07308935c35374ff5d9e393388888860405161184d94939291906159f7565b60405180910390a1505083515f906118719087908635906020880135908686610bf8565b90505f6118a086866040013587606001358a5f0151885f67ffffffffffffffff811115610bf857610bf8614d08565b90505f6118ad8383612f19565b90506118bc815f0151846127cf565b6118ca8160200151836127cf565b6118d8816040015184612890565b6118e6816060015183612890565b6118ef83612cb9565b6118f882612cb9565b606081015181515f9161190b919061273f565b90505f6119298360400151846020015161273f90919063ffffffff16565b9050611935825f612c7f565b806119455750611945815f612c7f565b1561196357604051630d86822160e01b815260040160405180910390fd5b611997338b606001518a6020013581518110611981576119816155ac565b60200260200101515f01518a6080013585611c06565b50506119cd338a606001518a60600135815181106119b7576119b76155ac565b60200260200101515f01518a60a0013584611c06565b5050604080513381528451602080830191909152850151818301529084015160608083019190915284015160808201527fd9fa84dd790c969daa5c33d8050dc06b4a9b59d5b42e2be5f5e8ae20447f618d925060a001905060405180910390a1611a3683612a3c565b611a3f82612a3c565b80516001600160e01b0316158015611a62575060208101516001600160e01b0316155b15611a80576040516321badf1f60e01b815260040160405180910390fd5b5050505b61051a60015f80516020615ecd83398151915255565b611aa2612f67565b60025f80516020615ecd83398151915255565b5f81604051602001611ac79190615a73565b604051602081830303815290604052805190602001209050919050565b604080516002815260208101859052338183015260608101909152611b1690611b0c906104d6565b6104f88385615424565b505050565b80611b16576040516305dbdfd960e41b81526001600160a01b03808516600483015283166024820152604401610316565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d611b7a84848484612f98565b12979650505050505050565b5f805f611b928561306c565b9050611b9e845f612c7f565b15611bbc57604051632eaefac360e21b815260040160405180910390fd5b5f80611bc886846130d2565b9150915080611bdd57611bda82615a85565b91505b8115611bf857611bf86001600160a01b038816893085612083565b50925090505b935093915050565b5f80611c128382612c7f565b15611c335760405163793a8f5560e01b815260048101849052602401610316565b83611c5157611c43868685612152565b505f9250829150611ced9050565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611c8b828661279f565b9050611c97815f612c7f565b15611cb85760405163c5e12af560e01b815260048101829052602401610316565b6001600160a01b038089165f908152600160209081526040808320938b16835292815282822089835290522081905590925090505b94509492505050565b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b8651811015611eba57868181518110611d5d57611d5d6155ac565b602002602001015193505f845f015160400151511115611eb2575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001611dd58d8a602001516130ff565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401611e009190615af5565b5f60405180830381865afa158015611e1a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e419190810190615bed565b9150505f81511115611eb05784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490611e82908a908590600401615ca3565b5f604051808303815f87803b158015611e99575f80fd5b505af1158015611eab573d5f803e3d5ffd5b505050505b505b600101611d42565b5050505050505050565b5f8115611efe57506001600160a01b038084165f9081526001602090815260408083209386168352928152828220848352905220546103bb565b5f611f08846133e1565b6040516370a0823160e01b81526001600160a01b0387811660048301529192505f91611f8091908716906370a0823190602401602060405180830381865afa158015611f56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f7a9190615528565b836133ed565b50604051636eb1769f60e11b81526001600160a01b0388811660048301523060248301529192505f91611fff919088169063dd62ed3e90604401602060405180830381865afa158015611fd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ff99190615528565b846133ed565b506001600160a01b038089165f908152600160209081526040808320938b168352928152828220828052905220549091506120449061203e84846120bf565b9061279f565b93505050506103bb565b61205b838383600161342d565b611b1657604051635274afe760e01b81526001600160a01b0384166004820152602401610316565b61209184848484600161348f565b6120b957604051635274afe760e01b81526001600160a01b0385166004820152602401610316565b50505050565b5f6120ca8383612c7f565b6120d457816103bb565b5090919050565b5f806120e78382612c7f565b156121085760405163793a8f5560e01b815260048101849052602401610316565b8361211857611c43868685611b86565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611c8b828661273f565b5f805f61215e8561306c565b905061216a845f612c7f565b1561218857604051632d1671a360e11b815260040160405180910390fd5b5f61219385836130d2565b50905080156121b0576121b06001600160a01b038716888361204e565b969095509350505050565b826060015181815181106121d1576121d16155ac565b60200260200101515f01516001600160a01b0316836040015183815181106121fb576121fb6155ac565b60200260200101515f01516001600160a01b031603611b1657604051631cd2f1c760e21b815260040160405180910390fd5b6122356148a3565b60408051600480825260a082019092526060915f9190816020015b60608152602001906001900390816122505790505090506122a56122738a611ab5565b8a51604080516003815260208101939093526001600160a01b0391821683820152908916606083015260808201905290565b8160018003815181106122ba576122ba6155ac565b60200260200101819052505f6122ef8a604001518a815181106122df576122df6155ac565b60200260200101515f01516133e1565b90505f6123418b5f01518c604001518c8151811061230f5761230f6155ac565b60200260200101515f01518d604001518d81518110612330576123306155ac565b602002602001015160200151611ec4565b90506123d08b604001518b8151811061235c5761235c6155ac565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d604001518d8151811061238e5761238e6155ac565b602002602001015160200151845f801b60408051600581526020810196909652858101949094526060850192909252608084015260a083015260c08201905290565b836001600303815181106123e6576123e66155ac565b602002602001018190525050505f61240d8a6060015189815181106122df576122df6155ac565b90505f61244e8b5f01518c606001518b8151811061242d5761242d6155ac565b60200260200101515f01518d606001518c81518110612330576123306155ac565b905061249b8b606001518a81518110612469576124696155ac565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d606001518c8151811061238e5761238e6155ac565b836001600403815181106124b1576124b16155ac565b602002602001018190525050506124c881866130ff565b9150505f885f01516001600160a01b031690505f808a602001515f01516001600160a01b031663d04dfe236040518060e001604052808e60200151602001516001600160a01b0316815260200161252887305f9182526020526040902090565b81526020018e602001516040015181526020015f81526020018781526020015f67ffffffffffffffff81111561256057612560614d08565b604051908082528060200260200182016040528015612589578160200160208202803683370190505b508152602001898152506040518263ffffffff1660e01b81526004016125af9190615af5565b5f60405180830381865afa1580156125c9573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526125f09190810190615bed565b9150915060028251101561261c578151604051630fbb8e5560e21b815260040161031691815260200190565b602082015160408301518551612670908790600490811061263f5761263f6155ac565b6020026020010151600381518110612659576126596155ac565b6020026020010151826120bf90919063ffffffff16565b60408051600281526020810183905280820185905260608101909152909150866002815181106126a2576126a26155ac565b60200260200101819052506040518060e001604052808e81526020018c81526020018281526020018381526020018781526020018681526020018481525096505050505050509695505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d8480612722868686866134fc565b915091505f612731838361361b565b9a9950505050505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061272286868686613668565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061272286868686613692565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061272286868686613bcf565b8181608001516004815181106127e7576127e76155ac565b6020026020010151600481518110612801576128016155ac565b6020026020010181815250506120b9815f01515f0151826080015160048151811061282e5761282e6155ac565b60200260200101515f81518110612847576128476155ac565b60200260200101515f1c8360800151600481518110612868576128686155ac565b6020026020010151600281518110612882576128826155ac565b6020026020010151856120db565b8181608001516003815181106128a8576128a86155ac565b60200260200101516004815181106128c2576128c26155ac565b6020908102919091010152805151608082015180515f919060039081106128eb576128eb6155ac565b60200260200101515f81518110612904576129046155ac565b60200260200101515f1c90505f8360800151600381518110612928576129286155ac565b6020026020010151600281518110612942576129426155ac565b602002602001015190505f801b81036129e95761295f855f612c7f565b156129805760405163793a8f5560e01b815260048101869052602401610316565b6001600160a01b038084165f9081526001602090815260408083209386168352928152828220848352905220546129b7908661279f565b6001600160a01b038085165f9081526001602090815260408083209387168352928152828220858352905220556129f8565b6129f583838388611c06565b50505b7f4cb6e22a3e7e651d7cf0376cff48f20f5007a54147777865be7f5f6c38c50f4a338560800151604051612a2d929190615cbb565b60405180910390a15050505050565b60c08101515115612ab6578051602090810151015160a082015160c083015160405163012c676d60e21b81526001600160a01b03909316926304b19db492612a88929091600401615ca3565b5f604051808303815f87803b158015612a9f575f80fd5b505af1158015612ab1573d5f803e3d5ffd5b505050505b5f815f0151602001515f01516001600160a01b031663d04dfe236040518060e00160405280855f015160200151602001516001600160a01b03168152602001612b0c8660a00151305f9182526020526040902090565b8152602001855f01516020015160400151815260200160018152602001856080015181526020015f67ffffffffffffffff811115612b4c57612b4c614d08565b604051908082528060200260200182016040528015612b75578160200160208202803683370190505b5081526020015f604051908082528060200260200182016040528015612ba5578160200160208202803683370190505b508152506040518263ffffffff1660e01b8152600401612bc59190615af5565b5f60405180830381865afa158015612bdf573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612c069190810190615bed565b9150505f8151111561150a578151602090810151015160a083015160405163012c676d60e21b81526001600160a01b03909216916304b19db491612c4e918590600401615ca3565b5f604051808303815f87803b158015612c65575f80fd5b505af1158015612c77573d5f803e3d5ffd5b505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d612cad84848484612f98565b13979650505050505050565b5f8160800151600381518110612cd157612cd16155ac565b6020026020010151600281518110612ceb57612ceb6155ac565b602002602001015190505f801b810361150a57815151608083015180515f91906003908110612d1c57612d1c6155ac565b60200260200101515f81518110612d3557612d356155ac565b6020908102919091018101516001600160a01b038481165f9081526001845260408082209284168252918452818120878252909352909120549091506001600160e01b0381161561051a576001600160a01b038084165f9081526001602090815260408083209386168352928152828220878352905290812055612dba838383612152565b50505050505050565b6060604082511015612de257505060408051602081019091525f815290565b5f60208301519050602060408451612dfa91906159c1565b612e049190615cf0565b811115612e2057505060408051602081019091525f8152919050565b600181016020026020840101915050919050565b5f81515f03612e4457505f919050565b50602001515f1a90565b612e5781613ccd565b612e765780604051630c89984b60e31b81526004016103169190615d0f565b50565b60605f612e868484613cfb565b9050808015612ea757505f3d1180612ea757505f846001600160a01b03163b115b15612ebc57612eb4613d0e565b9150506102b4565b8015612ee657604051639996b31560e01b81526001600160a01b0385166004820152602401610316565b3d15612ef957612ef4613d27565b612f12565b60405163d6bda27560e01b815260040160405180910390fd5b5092915050565b604080516080810182525f808252602082018190529181018290526060810191909152612f468383613d32565b82526040820152612f578284613d32565b6020830152606082015292915050565b5f80516020615ecd83398151915254600203612f9657604051633ee5aeb560e01b815260040160405180910390fd5b565b5f8085158415178187128286121817858414178015612fbd5786859250925050611ced565b505f85841315612fd1575092949193919260015b8386035f8112604c8213178015613004578215612ff6575f8994509450505050611ced565b885f94509450505050611ced565b600a82900a8981028a82828161301c5761301c615cdc565b0514613048578415613038575f8b965096505050505050611ced565b8a5f965096505050505050611ced565b841561305d578896509450611ced9350505050565b9550879450611ced9350505050565b5f805f61307884613d9b565b9092509050600182600381111561309157613091615d21565b141580156130b057505f8260038111156130ad576130ad615d21565b14155b156103bb57838260405163ee07877f60e01b8152600401610316929190615d35565b5f806001600160e01b038416601b0b60e085901d6130f1828287613e28565b9350935050505b9250929050565b60605f825167ffffffffffffffff81111561311c5761311c614d08565b604051908082528060200260200182016040528015613145578160200160208202803683370190505b5090505f80845111613157575f61315d565b83516001015b85516001010190505f8167ffffffffffffffff81111561317f5761317f614d08565b6040519080825280602002602001820160405280156131b257816020015b606081526020019060019003908161319d5790505b5090505f6131d6604080516002815233602082015230818301526060810190915290565b8282815181106131e8576131e86155ac565b60200260200101819052505f5b8751811015613245578180600101925050878181518110613218576132186155ac565b6020026020010151838381518110613232576132326155ac565b60209081029190910101526001016131f5565b508551156133d757808060010191505083828281518110613268576132686155ac565b60200260200101819052505f5b86518110156133d557613324878281518110613293576132936155ac565b60200260200101515f01516133016132cf8a85815181106132b6576132b66155ac565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b898481518110613313576133136155ac565b602002602001015160400151613f8e565b61334457604051630a57f30960e31b815260048101829052602401610316565b868181518110613356576133566155ac565b60200260200101515f01516001600160a01b03165f1b85828151811061337e5761337e6155ac565b60200260200101818152505081806001019250508681815181106133a4576133a46155ac565b6020026020010151602001518383815181106133c2576133c26155ac565b6020908102919091010152600101613275565b505b5095945050505050565b5f805f61307884613ffe565b5f805f805f6133fc878761405d565b9250925092505f8061340e85856140a0565b915091508183801561341d5750815b9650965050505050509250929050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316613483578383151615613477573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f511483166134eb5783831516156134df573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f8085158415178015613514575f92505f9150613611565b61351e8487615d6e565b91505f61352a88614178565b90505f61353687614178565b90505f61354383836141a6565b5090505f6f0785ee10d5da46d900f436a000000000821115613578576f0785ee10d5da46d900f436a000000000820491506025015b670de0b6b3a764000082111561359957670de0b6b3a7640000820491506012015b633b9aca008211156135b257633b9aca00820491506009015b6127108211156135c757612710820491506004015b81156135db57600a820491506001016135c7565b6135e58187615d6e565b95506136078b8a61360187876135fc87600a615e6d565b6141c2565b8961428e565b9097509550505050505b5094509492505050565b5f805f61362885856140a0565b9150915080158015613638575081155b1561366057604051638eba4d0760e01b81526004810186905260248101859052604401610316565b509392505050565b5f80613674848461432e565b909450925061368586868686613bcf565b9150915094509492505050565b5f80835f036136be57604051637a97930f60e01b81526004810187905260248101869052604401610316565b855f036136cf57505f905080611ced565b5f805f806136dd8a8a614383565b919b50995091506136ee8888614383565b919950975090505f6136ff8b614178565b90505f61370b8a614178565b90507f161bcca7119915b50764b4abe86529797775a5f1719510000000000000000000604c81831015613ad057841561376257507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b9050604b613aa8565b6f4b3b4ca85a86c47a098a22400000000083101561388e57678ac7230489e800008310156137f2576402540be4008310156137c057620186a08310156137b05750620186a090506005613a69565b506402540be4009050600a613a69565b655af3107a40008310156137df5750655af3107a40009050600e613a69565b50678ac7230489e8000090506013613a69565b6b204fce5e3e250261100000008310156138445769152d02c7e14af680000083101561382d575069152d02c7e14af680000090506017613a69565b506b204fce5e3e250261100000009050601c613a69565b6d314dc6448d9338c15b0a0000000083101561387357506d314dc6448d9338c15b0a0000000090506021613a69565b506f4b3b4ca85a86c47a098a22400000000090506026613a69565b780197d4df19d605767337e9f14d3eec8920e4000000000000008310156139865773af298d050e4395d69670b12b7f41000000000000831015613921577172cb5bd86321e38cb6ce6682e8000000000083101561390257507172cb5bd86321e38cb6ce6682e800000000009050602b613a69565b5073af298d050e4395d69670b12b7f4100000000000090506030613a69565b76010b46c6cdd6e3e0828f4db456ff0c8ea0000000000000831015613962575076010b46c6cdd6e3e0828f4db456ff0c8ea000000000000090506035613a69565b50780197d4df19d605767337e9f14d3eec8920e4000000000000009050603a613a69565b7c03b58e88c75313ec9d329eaaa18fb92f75215b17100000000000000000831015613a1c577a026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000008310156139f457507a026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000009050603f613a69565b507c03b58e88c75313ec9d329eaaa18fb92f75215b1710000000000000000090506044613a69565b7e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000831015613a6957507e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000905060495b818311613a7e57600a820491505f1901613a69565b815f03613aa8576040516305e51ecb60e01b8152600481018d9052602481018c9052604401610316565b85613ad0576040516305e51ecb60e01b8152600481018f9052602481018e9052604401610316565b80600160ff1b018d12613ae757808d039c50613b25565b600160ff1b9c90038c015f811315613b2557806001600160ff1b03038b13613b1257998a0199613b25565b5f80995099505050505050505050611ced565b5f808e128015613b3457505f8c135b15613b5557600160ff1b8e01808d13613b4d575f613b51565b808d035b9150505b8b818f01039750613b728f8e613b6c8887896141c2565b8b61428e565b90995097505f811315613bbc57604c811315613b9c575f809a509a50505050505050505050611ced565b80600a0a8981613bae57613bae615cdc565b059850885f03613bbc575f97505b50969850949650611ced95505050505050565b5f8085158415178015613bfb57865f03613bef5784849250925050611ced565b86869250925050611ced565b613c0587876145dd565b9097509550613c1485856145dd565b909550935085841315613c28579395929492935b838603604c811115613c41578787935093505050611ced565b80600a0a8681613c5357613c53615cdc565b0595505086850180881860ff90811c151589881890911c15168015613cbc57876001600160ff1b0303613ca35760405163d556b11160e01b8152600481018a905260248101899052604401610316565b600a968790059690980586019760019790970196613cc0565b8198505b5096979596505050505050565b5f600882511015613cdf57505f919050565b506008015167ffffffffffffffff1667ff0a89c674ee78741490565b5f805f835160208501865af49392505050565b6040513d81523d5f602083013e3d602001810160405290565b6040513d5f823e3d81fd5b5f80613d4f846060015185604001516126f290919063ffffffff16565b915083604001519050613d6f836040015183611b4c90919063ffffffff16565b156130f85782604001519150613d9284606001518361276f90919063ffffffff16565b90509250929050565b5f80613da5614626565b60405163b7bad1b160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb93899063b7bad1b19060240160408051808303815f875af1158015613dfb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e1f9190615e78565b91509150915091565b5f805f851215613e5557604051634a7d166b60e01b81526004810186905260248101859052604401610316565b845f03613e6757505f90506001611bfe565b8460ff8416850185811215613e995760405163d556b11160e01b81526004810188905260248101879052604401610316565b5f805f831215613ee557604c19831215613ebc575f809550955050505050611bfe565b825f03600a0a9150818481613ed357613ed3615cdc565b0495505084029091149150611bfe9050565b5f831315613f7e57604d831315613f225760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b82600a0a9150815f1981613f3857613f38615cdc565b04841115613f6c5760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b5091909102925060019150611bfe9050565b8360019550955050505050611bfe565b5f836001600160a01b03163b5f03613fec575f80613fac85856146b1565b5090925090505f816003811115613fc557613fc5615d21565b148015613fe35750856001600160a01b0316826001600160a01b0316145b925050506103bb565b613ff78484846146f7565b90506103bb565b5f80614008614626565b604051630782d7e160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb938990630782d7e1906024016040805180830381865afa158015613dfb573d5f803e3d5ffd5b5f808060ff841681036001600160ff1b0386111561408f57600a860460018201600a88065f1493509350935050614099565b8593509150600190505b9250925092565b5f601b83900b8314838382614104577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e10000000000000000008605156140e457620186a0860595506005850194505b8586601b0b146140ff57600a860595508460010194506140e4565b61411a565b855f0361411a57505f9250600191506130f89050565b848560030b1461415d575f85121561413a57505f92508291506130f89050565b60405163d556b11160e01b81526004810183905260248101829052604401610316565b50506001600160e01b03841660e084901b1791509250929050565b5f8082121561419d57600160ff1b82036141975750600160ff1b919050565b505f0390565b5090565b919050565b5f805f1983850993909202808410938190039390930393915050565b5f805f6141cf86866141a6565b91509150815f036141f3578381816141e9576141e9615cdc565b04925050506103bb565b8382106142245760405163362ced0960e11b8152600481018790526024810186905260448101859052606401610316565b5f84868809600186198101871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103025f82900382900490920185841190960395909502919093039390930492909217029150509392505050565b5f805f858718121561430a576001600160ff1b038411156142f7576142bb6001600160ff1b036001615553565b84036142cf5750600160ff1b905081611ced565b6142da600a85615cf0565b6142e390615eb8565b6142ee846001615d6e565b91509150611ced565b61430084615eb8565b8391509150611ced565b6001600160ff1b03841115614324576142e3600a85615cf0565b5082905081611ced565b5f80600160ff1b8403614379576001600160ff1b03830361436c5760405163d556b11160e01b81526004810185905260248101849052604401610316565b600a840593508260010192505b50505f9190910391565b5f805f845f0361439b57505f91508190506001614099565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b85055f03614588576f4b3b4ca85a86c47a098a22400000000085051580156143fd57507f80000000000000000000000000000000000000000000000000000000000000268412155b1561441e576f4b3b4ca85a86c47a098a224000000000850294506026840393505b7728c87cb5c89a2571ebfdcb54864ada834a00000000000000850515801561446657507f80000000000000000000000000000000000000000000000000000000000000138412155b1561447f57678ac7230489e80000850294506013840393505b7b097edd871cfda3a5697758bf0e3cbb5ac5741c64000000000000000085051580156144cb57507f800000000000000000000000000000000000000000000000000000000000000a8412155b156144e1576402540be40085029450600a840393505b7e3899162693736ac531a5a58f1fbb4b746504382ca7e4000000000000000000850515801561453057507f80000000000000000000000000000000000000000000000000000000000000028412155b15614546576064850294506002840393506144e1565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b850515801561457657506001600160ff1b018412155b1561458857600a850294506001840393505b600a808602908105861480156145a557506001600160ff1b018512155b156145b4578095506001850394505b50939492935050507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b8305151590565b5f805f805f6145ec8787614383565b9250925092508061461a576040516305e51ecb60e01b81526004810188905260248101879052604401610316565b50909590945092505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b158061467d575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b15612f96576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610316565b5f805f83516041036146e8576020840151604085015160608601515f1a6146da88828585614748565b955095509550505050614099565b505081515f9150600290614099565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561478157505f91506003905082614806565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156147d2573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b0381166147fd57505f925060019150829050614806565b92505f91508190505b9450945094915050565b604051806080016040528061482361483c565b81526020015f81526020015f8152602001606081525090565b6040518060a001604052805f6001600160a01b0316815260200161488a60405180606001604052805f6001600160a01b031681526020015f6001600160a01b03168152602001606081525090565b8152606060208201819052604082018190525f91015290565b6040518060e001604052806148b661483c565b81526020015f81526020015f80191681526020015f8019168152602001606081526020015f8152602001606081525090565b5f602082840312156148f8575f80fd5b81356001600160e01b0319811681146103bb575f80fd5b5f8083601f84011261491f575f80fd5b50813567ffffffffffffffff811115614936575f80fd5b6020830191508360208260051b85010111156130f8575f80fd5b5f805f60408486031215614962575f80fd5b833567ffffffffffffffff80821115614979575f80fd5b9085019060a0828803121561498c575f80fd5b909350602085013590808211156149a1575f80fd5b506149ae8682870161490f565b9497909650939450505050565b5f602082840312156149cb575f80fd5b5035919050565b6001600160a01b0381168114612e76575f80fd5b80356141a1816149d2565b5f805f805f60808688031215614a05575f80fd5b8535614a10816149d2565b94506020860135935060408601359250606086013567ffffffffffffffff811115614a39575f80fd5b614a458882890161490f565b969995985093965092949392505050565b5f805f60608486031215614a68575f80fd5b8335614a73816149d2565b92506020840135614a83816149d2565b929592945050506040919091013590565b5f805f805f60808688031215614aa8575f80fd5b8535614ab3816149d2565b94506020860135614ac3816149d2565b935060408601359250606086013567ffffffffffffffff80821115614ae6575f80fd5b818801915088601f830112614af9575f80fd5b813581811115614b07575f80fd5b896020828501011115614b18575f80fd5b9699959850939650602001949392505050565b5f60208284031215614b3b575f80fd5b81356103bb816149d2565b5f60c08284031215614b56575f80fd5b50919050565b5f60208284031215614b6c575f80fd5b813567ffffffffffffffff811115614b82575f80fd5b61052d84828501614b46565b5f805f60408486031215614ba0575f80fd5b833567ffffffffffffffff80821115614bb7575f80fd5b614bc387838801614b46565b945060208601359150808211156149a1575f80fd5b5f60208284031215614be8575f80fd5b813567ffffffffffffffff811115614bfe575f80fd5b8201608081850312156103bb575f80fd5b5f8060208385031215614c20575f80fd5b823567ffffffffffffffff811115614c36575f80fd5b614c428582860161490f565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b82811015614cd157603f19888603018452614cbf858351614c4e565b94509285019290850190600101614ca3565b5092979650505050505050565b5f8060408385031215614cef575f80fd5b8235614cfa816149d2565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614d3f57614d3f614d08565b60405290565b6040805190810167ffffffffffffffff81118282101715614d3f57614d3f614d08565b60405160a0810167ffffffffffffffff81118282101715614d3f57614d3f614d08565b604051601f8201601f1916810167ffffffffffffffff81118282101715614db457614db4614d08565b604052919050565b5f82601f830112614dcb575f80fd5b813567ffffffffffffffff811115614de557614de5614d08565b614df8601f8201601f1916602001614d8b565b818152846020838601011115614e0c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60608284031215614e38575f80fd5b614e40614d1c565b90508135614e4d816149d2565b81526020820135614e5d816149d2565b6020820152604082013567ffffffffffffffff811115614e7b575f80fd5b614e8784828501614dbc565b60408301525092915050565b5f67ffffffffffffffff821115614eac57614eac614d08565b5060051b60200190565b5f60408284031215614ec6575f80fd5b614ece614d45565b90508135614edb816149d2565b808252506020820135602082015292915050565b5f82601f830112614efe575f80fd5b81356020614f13614f0e83614e93565b614d8b565b8083825260208201915060208460061b870101935086841115614f34575f80fd5b602086015b84811015614f5957614f4b8882614eb6565b835291830191604001614f39565b509695505050505050565b5f60a08284031215614f74575f80fd5b614f7c614d68565b9050614f87826149e6565b8152602082013567ffffffffffffffff80821115614fa3575f80fd5b614faf85838601614e28565b60208401526040840135915080821115614fc7575f80fd5b614fd385838601614eef565b60408401526060840135915080821115614feb575f80fd5b50614ff884828501614eef565b6060830152506080820135608082015292915050565b5f61501b614f0e84614e93565b8381529050602080820190600585811b850187811115615039575f80fd5b855b8181101561512657803567ffffffffffffffff8082111561505a575f80fd5b908801906060828c03121561506d575f80fd5b615075614d1c565b8235615080816149d2565b81528287013582811115615092575f80fd5b8301601f81018d136150a2575f80fd5b80356150b0614f0e82614e93565b81815290881b8201890190898101908f8311156150cb575f80fd5b928a01925b828410156150e95783358252928a0192908a01906150d0565b848b01525060409150508381013583811115615103575f80fd5b61510f8e828701614dbc565b91830191909152508752505093830193830161503b565b50505050509392505050565b5f82601f830112615141575f80fd5b6103bb8383356020850161500e565b5f805f805f6101408688031215615165575f80fd5b853567ffffffffffffffff8082111561517c575f80fd5b61518889838a01614f64565b9650602088013591508082111561519d575f80fd5b6151a989838a01614f64565b95506151b88960408a01614b46565b94506101008801359150808211156151ce575f80fd5b6151da89838a01615132565b93506101208801359150808211156151f0575f80fd5b506151fd88828901615132565b9150509295509295909350565b5f6102b43683614f64565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f8135615249816149d2565b6001600160a01b039081168452602083013590615265826149d2565b166020840152604082013536839003601e19018112615282575f80fd5b820160208101903567ffffffffffffffff81111561529e575f80fd5b8036038213156152ac575f80fd5b606060408601526152c1606086018284615215565b95945050505050565b5f808335601e198436030181126152df575f80fd5b830160208101925035905067ffffffffffffffff8111156152fe575f80fd5b8060061b36038213156130f8575f80fd5b8183525f60208085019450825f5b85811015615355578135615330816149d2565b6001600160a01b0316875281830135838801526040968701969091019060010161531d565b509495945050505050565b5f6001600160a01b038086168352846020840152606060408401528335615386816149d2565b166060830152602083013536849003605e190181126153a3575f80fd5b60a060808401526153ba610100840185830161523d565b90506153c960408501856152ca565b605f19808685030160a08701526153e184838561530f565b93506153f060608801886152ca565b93509150808685030160c08701525061540a83838361530f565b92505050608084013560e084015280915050949350505050565b5f615431614f0e84614e93565b80848252602080830192508560051b85013681111561544e575f80fd5b855b818110156154d857803567ffffffffffffffff8082111561546f575f80fd5b818901915060408236031215615483575f80fd5b61548b614d45565b823582811115615499575f80fd5b6154a536828601614e28565b82525085830135828111156154b8575f80fd5b6154c436828601615132565b828801525087525050938201938201615450565b50919695505050505050565b5f6001600160a01b03808916835280881660208401525085604083015284606083015260a0608083015261551c60a083018486615215565b98975050505050505050565b5f60208284031215615538575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156102b4576102b461553f565b5f808335601e1984360301811261557b575f80fd5b83018035915067ffffffffffffffff821115615595575f80fd5b6020019150600581901b36038213156130f8575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e198336030181126155d4575f80fd5b9190910192915050565b5f8235609e198336030181126155d4575f80fd5b5f808335601e19843603018112615607575f80fd5b83018035915067ffffffffffffffff821115615621575f80fd5b6020019150600681901b36038213156130f8575f80fd5b5f60808236031215615648575f80fd5b6040516080810167ffffffffffffffff828210818311171561566c5761566c614d08565b816040528435915080821115615680575f80fd5b61568c36838701614f64565b8352602085013560208401526040850135604084015260608501359150808211156156b5575f80fd5b506156c236828601615132565b60608301525092915050565b5f602082840312156156de575f80fd5b813580151581146103bb575f80fd5b5f815180845260208085019450602084015f5b8381101561535557815180516001600160a01b031688528301518388015260409096019590820190600101615700565b5f6001600160a01b03808351168452602083015160a060208601528181511660a08601528160208201511660c08601526040810151915050606060e085015261577d610100850182614c4e565b90506040830151848203604086015261579682826156ed565b915050606083015184820360608601526157b082826156ed565b915050608083015160808501528091505092915050565b5f815180845260208085019450602084015f5b83811015615355578151875295820195908201906001016157da565b5f6001600160a01b03808716835260206080818501528651608080860152615822610100860182615730565b90508188015160a086015260408089015160c08701526060808a0151607f198885030160e08901528381518086528686019150868160051b87010187840193505f5b828110156158be57601f1988830301845284518a815116835289810151878b850152615892888501826157c7565b91890151848303858b01529190506158aa8183614c4e565b968b0196958b019593505050600101615864565b5080995050505050505050505083604083015282606083015295945050505050565b5f808335601e198436030181126158f5575f80fd5b83018035915067ffffffffffffffff82111561590f575f80fd5b6020019150368190038213156130f8575f80fd5b5f8235605e198336030181126155d4575f80fd5b5f6102b43683614e28565b5f60408284031215615952575f80fd5b6103bb8383614eb6565b6001600160a01b0384168152826020820152606060408201525f6152c16060830184615730565b6001600160a01b0385168152836020820152606060408201525f6159ab606083018486615215565b9695505050505050565b5f6103bb36848461500e565b818103818111156102b4576102b461553f565b828482375f8382015f815283518060208601835e5f910190815295945050505050565b5f6101206001600160a01b0387168352806020840152615a1981840187615730565b90508281036040840152615a2d8186615730565b9150508235606083015260208301356080830152604083013560a0830152606083013560c0830152608083013560e083015260a083013561010083015295945050505050565b602081525f6103bb6020830184615730565b5f60018201615a9657615a9661553f565b5060010190565b5f8282518085526020808601955060208260051b840101602086015f5b84811015615ae857601f19868403018952615ad68383516157c7565b98840198925090830190600101615aba565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e06060840152615b2e610100840182614c4e565b9050606084015160808401526080840151601f19808584030160a0860152615b568383615a9d565b925060a08601519150808584030160c0860152615b7383836157c7565b925060c08601519150808584030160e0860152506152c182826157c7565b5f82601f830112615ba0575f80fd5b81516020615bb0614f0e83614e93565b8083825260208201915060208460051b870101935086841115615bd1575f80fd5b602086015b84811015614f595780518352918301918301615bd6565b5f8060408385031215615bfe575f80fd5b825167ffffffffffffffff80821115615c15575f80fd5b818501915085601f830112615c28575f80fd5b81516020615c38614f0e83614e93565b82815260059290921b84018101918181019089841115615c56575f80fd5b948201945b83861015615c7457855182529482019490820190615c5b565b91880151919650909350505080821115615c8c575f80fd5b50615c9985828601615b91565b9150509250929050565b828152604060208201525f61052d60408301846157c7565b6001600160a01b0383168152604060208201525f61052d6040830184615a9d565b634e487b7160e01b5f52601260045260245ffd5b5f82615d0a57634e487b7160e01b5f52601260045260245ffd5b500490565b602081525f6103bb6020830184614c4e565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b03831681526040810160048310615d6157634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b8082018281125f8312801582168215821617156114ac576114ac61553f565b600181815b80851115615dc757815f1904821115615dad57615dad61553f565b80851615615dba57918102915b93841c9390800290615d92565b509250929050565b5f82615ddd575060016102b4565b81615de957505f6102b4565b8160018114615dff5760028114615e0957615e25565b60019150506102b4565b60ff841115615e1a57615e1a61553f565b50506001821b6102b4565b5060208310610133831016604e8410600b8410161715615e48575081810a6102b4565b615e528383615d8d565b805f1904821115615e6557615e6561553f565b029392505050565b5f6103bb8383615dcf565b5f8060408385031215615e89575f80fd5b825160048110615e97575f80fd5b602084015190925060ff81168114615ead575f80fd5b809150509250929050565b5f600160ff1b82016141975761419761553f56fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00"; + hex"6080604052348015600e575f80fd5b5060017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055616019806100405f395ff3fe608060405234801561000f575f80fd5b50600436106100f0575f3560e01c8063613255ab11610093578063ac9650d811610063578063ac9650d81461022b578063d7e442ec1461024b578063d9d98ce41461025e578063fa50118214610271575f80fd5b8063613255ab146101ad57806369c72856146101c0578063709fb8a5146101e85780639235084d146101fb575f80fd5b80632fbc4ba0116100ce5780632fbc4ba01461015157806341d1514f146101665780635cffe9de14610187578063607461191461019a575f80fd5b806301ffc9a7146100f45780631f69cb751461011c5780632cb77e9f1461012f575b5f80fd5b610107610102366004614a14565b610284565b60405190151581526020015b60405180910390f35b61010761012a366004614a7c565b6102ba565b61010761013d366004614ae7565b5f9081526020819052604090205460011490565b61016461015f366004614b1d565b6103c2565b005b610179610174366004614b82565b610521565b604051908152602001610113565b610107610195366004614bc0565b610535565b6101646101a8366004614b1d565b610635565b6101796101bb366004614c57565b6107c8565b6101d36101ce366004614c88565b610830565b60408051928352602083019190915201610113565b6101076101f6366004614cba565b610fc9565b61020e610209366004614d04565b61130c565b604080519315158452602084019290925290820152606001610113565b61023e610239366004614d3b565b6113ce565b6040516101139190614da8565b610164610259366004614d3b565b6114b4565b61017961026c366004614e0a565b61150e565b61016461027f36600461527c565b6115a8565b5f6001600160e01b0319821663e414309160e01b14806102b457506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f6102c3611a9a565b6102d06020850185614c57565b6001600160a01b0316336001600160a01b03161461031f576102f56020850185614c57565b6040516335252be360e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b5f61033161032c86615336565b611ab5565b5f818152602081905260409020549091505f19016103a4575f818152602081905260408082209190915551600192507f09d18501db0080ca2d6cd7c17fa7255daff4b2d503ea93b76ff68b6752ea8e63906103919033908490899061548c565b60405180910390a16103a4818585611ae4565b506103bb60015f80516020615ff983398151915255565b9392505050565b6103ca611a9a565b3385856103d8838383611b1b565b6103e2865f611b4c565b610417576040516306dde9c360e41b81523360048201526001600160a01b038916602482015260448101889052606401610316565b5f80610424338b8a611b86565b604080513381526001600160a01b038e1660208201529081018c90526060810183905291935091507f7f9dfa19cf1cc2f806f2f860fbc9c056b601fb1afc0e9b843dfe5c63616268e69060800160405180910390a15f80610487338d8d8d611cbe565b909250905087156104fd5760408051600581526001600160a01b038e1660208201528082018d9052606081018490526080810183905260ff851660a082015260c081019091526104fd906104ee905b60408051600181526020810192909252818101905290565b6104f88a8c615550565b611dae565b5050505050505061051a60015f80516020615ff983398151915255565b5050505050565b5f61052d848484611f7c565b949350505050565b5f61054a6001600160a01b0386168786612106565b6040516323e30c8b60e01b81525f906001600160a01b038816906323e30c8b906105829033908a908a9087908b908b90600401615610565b6020604051808303815f875af115801561059e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105c29190615654565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9811461060757604051630b6c58a960e31b815260048101829052602401610316565b61062887306106165f8961567f565b6001600160a01b038a1692919061213b565b5060019695505050505050565b61063d611a9a565b33858561064b838383611b1b565b5f8080806106598a82611b4c565b61068d57604051623a3a4d60e21b81523360048201526001600160a01b038d166024820152604481018c9052606401610316565b5f610699338e8e611f7c565b90506106a58b82612177565b94506106b3338e8e88612193565b90935091505f6106c4338f8861220a565b80965081925050507f8045c25080b0868951141ed0a91720bcad09a8364a2b3109ee1fd49c1f0bc8b8338f8f8f8a86604051610736969594939291906001600160a01b03968716815294909516602085015260408401929092526060830152608082015260a081019190915260c00190565b60405180910390a1505060408051600681526001600160a01b038e1660208201528082018d9052606081018490526080810183905260a081018c905260ff851660c0820152600160e08201908152610100820182905261012082019092529089156107a9576107a9816104f88c8e615550565b50505050505050505061051a60015f80516020615ff983398151915255565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa15801561080c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b49190615654565b5f8061083a611a9a565b6108476080840184615692565b90505f0361086857604051639c95219f60e01b815260040160405180910390fd5b61087061493c565b610878614968565b5f60405180606001604052808780608001906108949190615692565b5f8181106108a4576108a46156d8565b90506020028101906108b691906156ec565b6108c0908061570a565b6108ce90604081019061571e565b6108db60808b018b615692565b5f8181106108eb576108eb6156d8565b90506020028101906108fd91906156ec565b60200135818110610910576109106156d8565b6109269260206040909202019081019150614c57565b6001600160a01b031681526020016109416080890189615692565b5f818110610951576109516156d8565b905060200281019061096391906156ec565b61096d908061570a565b61097b90606081019061571e565b61098860808b018b615692565b5f818110610998576109986156d8565b90506020028101906109aa91906156ec565b604001358181106109bd576109bd6156d8565b6109d39260206040909202019081019150614c57565b6001600160a01b03168152602088810135910152905060605f6109f96080890189615692565b604080516001909201602002820181528501519093505f9250610a1d915082611b4c565b610a3a5760405163315f9e2360e21b815260040160405180910390fd5b5f5b610a4960808a018a615692565b905081108015610a6357506040840151610a63905f611b4c565b15610e7157610a7560808a018a615692565b82818110610a8557610a856156d8565b9050602002810190610a9791906156ec565b610aa090615764565b9550855f01519450835f01516001600160a01b03168560400151876020015181518110610acf57610acf6156d8565b60200260200101515f01516001600160a01b0316141580610b2a575083602001516001600160a01b03168560600151876040015181518110610b1357610b136156d8565b60200260200101515f01516001600160a01b031614155b15610b485760405163936bb5ad60e01b815260040160405180910390fd5b610b5b85876020015188604001516122e7565b5f610b6586611ab5565b5f81815260208190526040902054909150610bca578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a1610e68565b5f610c278789602001518a60400151338c606001515f67ffffffffffffffff811115610bf857610bf8614e34565b604051908082528060200260200182016040528015610c21578160200160208202803683370190505b50612359565b90505f610c458c604001358360600151611b4c90919063ffffffff16565b15610c9b578751604080513381526001600160a01b03909216602083015281018490527fe3151dc8cb7a54ffc4baabd28c1f241c94d510b5e5b502491ac3cad6c16316d5906060015b60405180910390a1610e5a565b6040820151610caa905f611b4c565b1580610cc257506060820151610cc0905f611b4c565b155b15610d0f578751604080513381526001600160a01b03909216602083015281018490527f500b713857325f9e6dcb52ae832eca9109d107ed1aae9cb4928b4c1e13f051aa90606001610c8e565b600190505f808d6060016020810190610d2891906157fa565b15610d6e576040808a015190850151610d4091612177565b6060850151909250610d52908361281e565b60408a0151909150610d64908361286b565b60408a0152610dd5565b5f610d8a8560400151866060015161281e90919063ffffffff16565b9050610da38a604001518261217790919063ffffffff16565b9150610dbc85606001518361289b90919063ffffffff16565b60408b0151909350610dce908361286b565b60408b0152505b610ddf8c826128cb565b9b50610deb8d836128cb565b9c50610df782856128fb565b610e0181856129bc565b7f194f1feb3b4d7076a2c272e774e792e0c48bb8c7aa1a9a3671c1cd6da9e6b4c1338c8484604051610e369493929190615922565b60405180910390a187516001018089526020028801849052610e5784612b68565b50505b8480610e635750805b945050505b50600101610a3c565b505f610e8360808a0160608b016157fa565b610e8d5786610e8f565b875b9050610e9c818a35612dab565b15610ec45760405163573b6f4160e01b81528935600482015260248101829052604401610316565b50610ed43384602001518961220a565b505f9050610ee560a08a018a615a0c565b9050118015610ef15750805b15610f635760208301518351339163691f9ed7918a8a610f1460a08f018f615a0c565b6040518763ffffffff1660e01b8152600401610f3596959493929190615610565b5f604051808303815f87803b158015610f4c575f80fd5b505af1158015610f5e573d5f803e3d5ffd5b505050505b610f7133845f015188611b86565b50505f5b8251811015610fa857610fa0838281518110610f9357610f936156d8565b6020026020010151612de5565b600101610f75565b505050505050610fc460015f80516020615ff983398151915255565b915091565b5f610fd2611a9a565b5f61102f61102a610fe38780615a4f565b610ff1906040810190615a0c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612eef92505050565b612f60565b90505f811161105157604051632cff108b60e21b815260040160405180910390fd5b6001811161107257604051633c8270bd60e21b815260040160405180910390fd5b61107f602086018661571e565b90505f036110a057604051636c44ef8f60e01b815260040160405180910390fd5b6110ad604086018661571e565b90505f036110ce5760405163540e5f0b60e01b815260040160405180910390fd5b6040805160a081019091523381525f90602081016110ec8880615a4f565b6110f590615a63565b815260200187806020019061110a919061571e565b808060200260200160405190810160405280939291908181526020015f905b828210156111555761114660408302860136819003810190615a6e565b81526020019060010190611129565b505050918352505060200161116d604089018961571e565b808060200260200160405190810160405280939291908181526020015f905b828210156111b8576111a960408302860136819003810190615a6e565b8152602001906001019061118c565b50505050508152602001876060013581525090505f6111d682611ab5565b5f818152602081905260409020549091501580156112f1575f828152602081905260409081902060019055835190517f87491344dfbcf91f6cbbc610cbbeedc85313d37a02df0c93527f7ea5f8db717f916112349185908790615a88565b60405180910390a15f61124a60a08a018a615a0c565b905011156112e65761129b61126260a08a018a615a0c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612f7a92505050565b82517fd46c2c56b35c8210e9e712ec3f02242d5fc90187c0ac8ed80cc33626846ec36990836112cd60a08c018c615a0c565b6040516112dd9493929190615aaf565b60405180910390a15b6112f1828888611ae4565b93505050506103bb60015f80516020615ff983398151915255565b5f80808061132661131d868061570a565b61032c90615336565b5f8181526020819052604090205490915060011461134d57505f92508291508190506113c7565b61137261135a868061570a565b61136390615336565b866020013587604001356122e7565b5f6113b0611380878061570a565b61138990615336565b60208801356040890135336113a160608c018c615692565b6113aa91615ae1565b5f610bf8565b905060018160400151826060015194509450945050505b9193909250565b604080515f8152602081019091526060908267ffffffffffffffff8111156113f8576113f8614e34565b60405190808252806020026020018201604052801561142b57816020015b60608152602001906001900390816114165790505b5091505f5b838110156114ac576114873086868481811061144e5761144e6156d8565b90506020028101906114609190615a0c565b8560405160200161147393929190615b00565b604051602081830303815290604052612fa5565b838281518110611499576114996156d8565b6020908102919091010152600101611430565b505092915050565b6114bc611a9a565b604080515f808252602082019092526114f4916114e9565b60608152602001906001900390816114d45790505b506104f88385615550565b61150a60015f80516020615ff983398151915255565b5050565b6040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611552573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115769190615654565b5f036115a057604051633c5bf76960e21b81526001600160a01b0384166004820152602401610316565b505f92915050565b6115b0611a9a565b835185516001600160a01b039182169116036115df57604051630a98f1f360e21b815260040160405180910390fd5b83604001518360400135815181106115f9576115f96156d8565b60200260200101515f01516001600160a01b03168560600151846020013581518110611627576116276156d8565b60200260200101515f01516001600160a01b03161415806116a0575060408501518051843590811061165b5761165b6156d8565b60200260200101515f01516001600160a01b03168460600151846060013581518110611689576116896156d8565b60200260200101515f01516001600160a01b031614155b156116be5760405163936bb5ad60e01b815260040160405180910390fd5b84606001518360200135815181106116d8576116d86156d8565b60200260200101515f01516001600160a01b03168560400151845f013581518110611705576117056156d8565b60200260200101515f01516001600160a01b03160361173757604051631cd2f1c760e21b815260040160405180910390fd5b5f61174186611ab5565b5f818152602081905260409020549091506117a7578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a150611a84565b5f6117b186611ab5565b5f81815260208190526040902054909150611818578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a15050611a84565b7f6fa7f4c28634b0a9d6831401c45ae468195fb63aed07308935c35374ff5d9e393388888860405161184d9493929190615b23565b60405180910390a1505083515f906118719087908635906020880135908686610bf8565b90505f6118a086866040013587606001358a5f0151885f67ffffffffffffffff811115610bf857610bf8614e34565b90505f6118ad8383613045565b90506118bc815f0151846128fb565b6118ca8160200151836128fb565b6118d88160400151846129bc565b6118e68160600151836129bc565b6118ef83612de5565b6118f882612de5565b606081015181515f9161190b919061286b565b90505f6119298360400151846020015161286b90919063ffffffff16565b9050611935825f612dab565b806119455750611945815f612dab565b1561196357604051630d86822160e01b815260040160405180910390fd5b611997338b606001518a6020013581518110611981576119816156d8565b60200260200101515f01518a6080013585611cbe565b50506119cd338a606001518a60600135815181106119b7576119b76156d8565b60200260200101515f01518a60a0013584611cbe565b5050604080513381528451602080830191909152850151818301529084015160608083019190915284015160808201527fd9fa84dd790c969daa5c33d8050dc06b4a9b59d5b42e2be5f5e8ae20447f618d925060a001905060405180910390a1611a3683612b68565b611a3f82612b68565b80516001600160e01b0316158015611a62575060208101516001600160e01b0316155b15611a80576040516321badf1f60e01b815260040160405180910390fd5b5050505b61051a60015f80516020615ff983398151915255565b611aa2613093565b60025f80516020615ff983398151915255565b5f81604051602001611ac79190615b9f565b604051602081830303815290604052805190602001209050919050565b604080516002815260208101859052338183015260608101909152611b1690611b0c906104d6565b6104f88385615550565b505050565b80611b16576040516305dbdfd960e41b81526001600160a01b03808516600483015283166024820152604401610316565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d611b7a848484846130c4565b12979650505050505050565b5f805f611b9285613198565b9050611b9e845f612dab565b15611bbc57604051632eaefac360e21b815260040160405180910390fd5b6001600160a01b038087165f90815260026020908152604080832093891683529290529081205490611bee868361286b565b90505f80611bfc8382611b4c565b15611c62575f611c0c84876131fe565b909350905080611c2257611c1f83615bb1565b92505b5f611c2d8a886131fe565b50905080611c3c85600161567f565b1015611c4a57809350600192505b611c5f6001600160a01b038c168d308761213b565b50505b5f611c6d838761322b565b50905081611c8457611c7f818561286b565b611c86565b845b6001600160a01b03808d165f908152600260209081526040808320938f1683529290522055509095509293505050505b935093915050565b5f80611cca8382612dab565b15611ceb5760405163793a8f5560e01b815260048101849052602401610316565b83611d0957611cfb86868561220a565b505f9250829150611da59050565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611d4382866128cb565b9050611d4f815f612dab565b15611d705760405163c5e12af560e01b815260048101829052602401610316565b6001600160a01b038089165f908152600160209081526040808320938b16835292815282822089835290522081905590925090505b94509492505050565b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b8651811015611f7257868181518110611e1557611e156156d8565b602002602001015193505f845f015160400151511115611f6a575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001611e8d8d8a6020015161326b565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401611eb89190615c21565b5f60405180830381865afa158015611ed2573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611ef99190810190615d19565b9150505f81511115611f685784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490611f3a908a908590600401615dcf565b5f604051808303815f87803b158015611f51575f80fd5b505af1158015611f63573d5f803e3d5ffd5b505050505b505b600101611dfa565b5050505050505050565b5f8115611fb657506001600160a01b038084165f9081526001602090815260408083209386168352928152828220848352905220546103bb565b5f611fc08461354d565b6040516370a0823160e01b81526001600160a01b0387811660048301529192505f9161203891908716906370a0823190602401602060405180830381865afa15801561200e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120329190615654565b8361322b565b50604051636eb1769f60e11b81526001600160a01b0388811660048301523060248301529192505f916120b7919088169063dd62ed3e90604401602060405180830381865afa15801561208d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120b19190615654565b8461322b565b506001600160a01b038089165f908152600160209081526040808320938b168352928152828220828052905220549091506120fc906120f68484612177565b906128cb565b93505050506103bb565b6121138383836001613559565b611b1657604051635274afe760e01b81526001600160a01b0384166004820152602401610316565b6121498484848460016135bb565b61217157604051635274afe760e01b81526001600160a01b0385166004820152602401610316565b50505050565b5f6121828383612dab565b61218c57816103bb565b5090919050565b5f8061219f8382612dab565b156121c05760405163793a8f5560e01b815260048101849052602401610316565b836121d057611cfb868685611b86565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611d43828661286b565b5f805f61221685613198565b9050612222845f612dab565b1561224057604051632d1671a360e11b815260040160405180910390fd5b6001600160a01b038087165f9081526002602090815260408083209389168352929052908120546122729086906128cb565b90505f61227f82846131fe565b5090505f61228d828561322b565b50905061229a838261286b565b6001600160a01b03808b165f908152600260209081526040808320938d168352929052205581156122d9576122d96001600160a01b0389168a84612106565b509791965090945050505050565b826060015181815181106122fd576122fd6156d8565b60200260200101515f01516001600160a01b031683604001518381518110612327576123276156d8565b60200260200101515f01516001600160a01b031603611b1657604051631cd2f1c760e21b815260040160405180910390fd5b6123616149cf565b60408051600480825260a082019092526060915f9190816020015b606081526020019060019003908161237c5790505090506123d161239f8a611ab5565b8a51604080516003815260208101939093526001600160a01b0391821683820152908916606083015260808201905290565b8160018003815181106123e6576123e66156d8565b60200260200101819052505f61241b8a604001518a8151811061240b5761240b6156d8565b60200260200101515f015161354d565b90505f61246d8b5f01518c604001518c8151811061243b5761243b6156d8565b60200260200101515f01518d604001518d8151811061245c5761245c6156d8565b602002602001015160200151611f7c565b90506124fc8b604001518b81518110612488576124886156d8565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d604001518d815181106124ba576124ba6156d8565b602002602001015160200151845f801b60408051600581526020810196909652858101949094526060850192909252608084015260a083015260c08201905290565b83600160030381518110612512576125126156d8565b602002602001018190525050505f6125398a60600151898151811061240b5761240b6156d8565b90505f61257a8b5f01518c606001518b81518110612559576125596156d8565b60200260200101515f01518d606001518c8151811061245c5761245c6156d8565b90506125c78b606001518a81518110612595576125956156d8565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d606001518c815181106124ba576124ba6156d8565b836001600403815181106125dd576125dd6156d8565b602002602001018190525050506125f4818661326b565b9150505f885f01516001600160a01b031690505f808a602001515f01516001600160a01b031663d04dfe236040518060e001604052808e60200151602001516001600160a01b0316815260200161265487305f9182526020526040902090565b81526020018e602001516040015181526020015f81526020018781526020015f67ffffffffffffffff81111561268c5761268c614e34565b6040519080825280602002602001820160405280156126b5578160200160208202803683370190505b508152602001898152506040518263ffffffff1660e01b81526004016126db9190615c21565b5f60405180830381865afa1580156126f5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261271c9190810190615d19565b91509150600282511015612748578151604051630fbb8e5560e21b815260040161031691815260200190565b60208201516040830151855161279c908790600490811061276b5761276b6156d8565b6020026020010151600381518110612785576127856156d8565b60200260200101518261217790919063ffffffff16565b60408051600281526020810183905280820185905260608101909152909150866002815181106127ce576127ce6156d8565b60200260200101819052506040518060e001604052808e81526020018c81526020018281526020018381526020018781526020018681526020018481525096505050505050509695505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e86868686613628565b915091505f61285d8383613747565b9a9950505050505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e86868686613794565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e868686866137be565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e86868686613cfb565b818160800151600481518110612913576129136156d8565b602002602001015160048151811061292d5761292d6156d8565b602002602001018181525050612171815f01515f0151826080015160048151811061295a5761295a6156d8565b60200260200101515f81518110612973576129736156d8565b60200260200101515f1c8360800151600481518110612994576129946156d8565b60200260200101516002815181106129ae576129ae6156d8565b602002602001015185612193565b8181608001516003815181106129d4576129d46156d8565b60200260200101516004815181106129ee576129ee6156d8565b6020908102919091010152805151608082015180515f91906003908110612a1757612a176156d8565b60200260200101515f81518110612a3057612a306156d8565b60200260200101515f1c90505f8360800151600381518110612a5457612a546156d8565b6020026020010151600281518110612a6e57612a6e6156d8565b602002602001015190505f801b8103612b1557612a8b855f612dab565b15612aac5760405163793a8f5560e01b815260048101869052602401610316565b6001600160a01b038084165f908152600160209081526040808320938616835292815282822084835290522054612ae390866128cb565b6001600160a01b038085165f908152600160209081526040808320938716835292815282822085835290522055612b24565b612b2183838388611cbe565b50505b7f4cb6e22a3e7e651d7cf0376cff48f20f5007a54147777865be7f5f6c38c50f4a338560800151604051612b59929190615de7565b60405180910390a15050505050565b60c08101515115612be2578051602090810151015160a082015160c083015160405163012c676d60e21b81526001600160a01b03909316926304b19db492612bb4929091600401615dcf565b5f604051808303815f87803b158015612bcb575f80fd5b505af1158015612bdd573d5f803e3d5ffd5b505050505b5f815f0151602001515f01516001600160a01b031663d04dfe236040518060e00160405280855f015160200151602001516001600160a01b03168152602001612c388660a00151305f9182526020526040902090565b8152602001855f01516020015160400151815260200160018152602001856080015181526020015f67ffffffffffffffff811115612c7857612c78614e34565b604051908082528060200260200182016040528015612ca1578160200160208202803683370190505b5081526020015f604051908082528060200260200182016040528015612cd1578160200160208202803683370190505b508152506040518263ffffffff1660e01b8152600401612cf19190615c21565b5f60405180830381865afa158015612d0b573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612d329190810190615d19565b9150505f8151111561150a578151602090810151015160a083015160405163012c676d60e21b81526001600160a01b03909216916304b19db491612d7a918590600401615dcf565b5f604051808303815f87803b158015612d91575f80fd5b505af1158015612da3573d5f803e3d5ffd5b505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d612dd9848484846130c4565b13979650505050505050565b5f8160800151600381518110612dfd57612dfd6156d8565b6020026020010151600281518110612e1757612e176156d8565b602002602001015190505f801b810361150a57815151608083015180515f91906003908110612e4857612e486156d8565b60200260200101515f81518110612e6157612e616156d8565b6020908102919091018101516001600160a01b038481165f9081526001845260408082209284168252918452818120878252909352909120549091506001600160e01b0381161561051a576001600160a01b038084165f9081526001602090815260408083209386168352928152828220878352905290812055612ee683838361220a565b50505050505050565b6060604082511015612f0e57505060408051602081019091525f815290565b5f60208301519050602060408451612f269190615aed565b612f309190615e1c565b811115612f4c57505060408051602081019091525f8152919050565b600181016020026020840101915050919050565b5f81515f03612f7057505f919050565b50602001515f1a90565b612f8381613df9565b612fa25780604051630c89984b60e31b81526004016103169190615e3b565b50565b60605f612fb28484613e27565b9050808015612fd357505f3d1180612fd357505f846001600160a01b03163b115b15612fe857612fe0613e3a565b9150506102b4565b801561301257604051639996b31560e01b81526001600160a01b0385166004820152602401610316565b3d1561302557613020613e53565b61303e565b60405163d6bda27560e01b815260040160405180910390fd5b5092915050565b604080516080810182525f8082526020820181905291810182905260608101919091526130728383613e5e565b825260408201526130838284613e5e565b6020830152606082015292915050565b5f80516020615ff9833981519152546002036130c257604051633ee5aeb560e01b815260040160405180910390fd5b565b5f80851584151781871282861218178584141780156130e95786859250925050611da5565b505f858413156130fd575092949193919260015b8386035f8112604c8213178015613130578215613122575f8994509450505050611da5565b885f94509450505050611da5565b600a82900a8981028a82828161314857613148615e08565b0514613174578415613164575f8b965096505050505050611da5565b8a5f965096505050505050611da5565b8415613189578896509450611da59350505050565b9550879450611da59350505050565b5f805f6131a484613ec7565b909250905060018260038111156131bd576131bd615e4d565b141580156131dc57505f8260038111156131d9576131d9615e4d565b14155b156103bb57838260405163ee07877f60e01b8152600401610316929190615e61565b5f806001600160e01b038416601b0b60e085901d61321d828287613f54565b9350935050505b9250929050565b5f805f805f61323a87876140ba565b9250925092505f8061324c85856140fd565b915091508183801561325b5750815b9650965050505050509250929050565b60605f825167ffffffffffffffff81111561328857613288614e34565b6040519080825280602002602001820160405280156132b1578160200160208202803683370190505b5090505f808451116132c3575f6132c9565b83516001015b85516001010190505f8167ffffffffffffffff8111156132eb576132eb614e34565b60405190808252806020026020018201604052801561331e57816020015b60608152602001906001900390816133095790505b5090505f613342604080516002815233602082015230818301526060810190915290565b828281518110613354576133546156d8565b60200260200101819052505f5b87518110156133b1578180600101925050878181518110613384576133846156d8565b602002602001015183838151811061339e5761339e6156d8565b6020908102919091010152600101613361565b50855115613543578080600101915050838282815181106133d4576133d46156d8565b60200260200101819052505f5b8651811015613541576134908782815181106133ff576133ff6156d8565b60200260200101515f015161346d61343b8a8581518110613422576134226156d8565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b89848151811061347f5761347f6156d8565b6020026020010151604001516141d5565b6134b057604051630a57f30960e31b815260048101829052602401610316565b8681815181106134c2576134c26156d8565b60200260200101515f01516001600160a01b03165f1b8582815181106134ea576134ea6156d8565b6020026020010181815250508180600101925050868181518110613510576135106156d8565b60200260200101516020015183838151811061352e5761352e6156d8565b60209081029190910101526001016133e1565b505b5095945050505050565b5f805f6131a484614245565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f511483166135af5783831516156135a3573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f5114831661361757838315161561360b573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f8085158415178015613640575f92505f915061373d565b61364a8487615e9a565b91505f613656886142a4565b90505f613662876142a4565b90505f61366f83836142d2565b5090505f6f0785ee10d5da46d900f436a0000000008211156136a4576f0785ee10d5da46d900f436a000000000820491506025015b670de0b6b3a76400008211156136c557670de0b6b3a7640000820491506012015b633b9aca008211156136de57633b9aca00820491506009015b6127108211156136f357612710820491506004015b811561370757600a820491506001016136f3565b6137118187615e9a565b95506137338b8a61372d878761372887600a615f99565b6142ee565b896143ba565b9097509550505050505b5094509492505050565b5f805f61375485856140fd565b9150915080158015613764575081155b1561378c57604051638eba4d0760e01b81526004810186905260248101859052604401610316565b509392505050565b5f806137a0848461445a565b90945092506137b186868686613cfb565b9150915094509492505050565b5f80835f036137ea57604051637a97930f60e01b81526004810187905260248101869052604401610316565b855f036137fb57505f905080611da5565b5f805f806138098a8a6144af565b919b509950915061381a88886144af565b919950975090505f61382b8b6142a4565b90505f6138378a6142a4565b90507f161bcca7119915b50764b4abe86529797775a5f1719510000000000000000000604c81831015613bfc57841561388e57507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b9050604b613bd4565b6f4b3b4ca85a86c47a098a2240000000008310156139ba57678ac7230489e8000083101561391e576402540be4008310156138ec57620186a08310156138dc5750620186a090506005613b95565b506402540be4009050600a613b95565b655af3107a400083101561390b5750655af3107a40009050600e613b95565b50678ac7230489e8000090506013613b95565b6b204fce5e3e250261100000008310156139705769152d02c7e14af6800000831015613959575069152d02c7e14af680000090506017613b95565b506b204fce5e3e250261100000009050601c613b95565b6d314dc6448d9338c15b0a0000000083101561399f57506d314dc6448d9338c15b0a0000000090506021613b95565b506f4b3b4ca85a86c47a098a22400000000090506026613b95565b780197d4df19d605767337e9f14d3eec8920e400000000000000831015613ab25773af298d050e4395d69670b12b7f41000000000000831015613a4d577172cb5bd86321e38cb6ce6682e80000000000831015613a2e57507172cb5bd86321e38cb6ce6682e800000000009050602b613b95565b5073af298d050e4395d69670b12b7f4100000000000090506030613b95565b76010b46c6cdd6e3e0828f4db456ff0c8ea0000000000000831015613a8e575076010b46c6cdd6e3e0828f4db456ff0c8ea000000000000090506035613b95565b50780197d4df19d605767337e9f14d3eec8920e4000000000000009050603a613b95565b7c03b58e88c75313ec9d329eaaa18fb92f75215b17100000000000000000831015613b48577a026e4d30eccc3215dd8f3157d27e23acbdcfe68000000000000000831015613b2057507a026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000009050603f613b95565b507c03b58e88c75313ec9d329eaaa18fb92f75215b1710000000000000000090506044613b95565b7e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000831015613b9557507e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000905060495b818311613baa57600a820491505f1901613b95565b815f03613bd4576040516305e51ecb60e01b8152600481018d9052602481018c9052604401610316565b85613bfc576040516305e51ecb60e01b8152600481018f9052602481018e9052604401610316565b80600160ff1b018d12613c1357808d039c50613c51565b600160ff1b9c90038c015f811315613c5157806001600160ff1b03038b13613c3e57998a0199613c51565b5f80995099505050505050505050611da5565b5f808e128015613c6057505f8c135b15613c8157600160ff1b8e01808d13613c79575f613c7d565b808d035b9150505b8b818f01039750613c9e8f8e613c988887896142ee565b8b6143ba565b90995097505f811315613ce857604c811315613cc8575f809a509a50505050505050505050611da5565b80600a0a8981613cda57613cda615e08565b059850885f03613ce8575f97505b50969850949650611da595505050505050565b5f8085158415178015613d2757865f03613d1b5784849250925050611da5565b86869250925050611da5565b613d318787614709565b9097509550613d408585614709565b909550935085841315613d54579395929492935b838603604c811115613d6d578787935093505050611da5565b80600a0a8681613d7f57613d7f615e08565b0595505086850180881860ff90811c151589881890911c15168015613de857876001600160ff1b0303613dcf5760405163d556b11160e01b8152600481018a905260248101899052604401610316565b600a968790059690980586019760019790970196613dec565b8198505b5096979596505050505050565b5f600882511015613e0b57505f919050565b506008015167ffffffffffffffff1667ff0a89c674ee78741490565b5f805f835160208501865af49392505050565b6040513d81523d5f602083013e3d602001810160405290565b6040513d5f823e3d81fd5b5f80613e7b8460600151856040015161281e90919063ffffffff16565b915083604001519050613e9b836040015183611b4c90919063ffffffff16565b156132245782604001519150613ebe84606001518361289b90919063ffffffff16565b90509250929050565b5f80613ed1614752565b60405163b7bad1b160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb93899063b7bad1b19060240160408051808303815f875af1158015613f27573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f4b9190615fa4565b91509150915091565b5f805f851215613f8157604051634a7d166b60e01b81526004810186905260248101859052604401610316565b845f03613f9357505f90506001611cb6565b8460ff8416850185811215613fc55760405163d556b11160e01b81526004810188905260248101879052604401610316565b5f805f83121561401157604c19831215613fe8575f809550955050505050611cb6565b825f03600a0a9150818481613fff57613fff615e08565b0495505084029091149150611cb69050565b5f8313156140aa57604d83131561404e5760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b82600a0a9150815f198161406457614064615e08565b048411156140985760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b5091909102925060019150611cb69050565b8360019550955050505050611cb6565b5f808060ff841681036001600160ff1b038611156140ec57600a860460018201600a88065f14935093509350506140f6565b8593509150600190505b9250925092565b5f601b83900b8314838382614161577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561414157620186a0860595506005850194505b8586601b0b1461415c57600a86059550846001019450614141565b614177565b855f0361417757505f9250600191506132249050565b848560030b146141ba575f85121561419757505f92508291506132249050565b60405163d556b11160e01b81526004810183905260248101829052604401610316565b50506001600160e01b03841660e084901b1791509250929050565b5f836001600160a01b03163b5f03614233575f806141f385856147dd565b5090925090505f81600381111561420c5761420c615e4d565b14801561422a5750856001600160a01b0316826001600160a01b0316145b925050506103bb565b61423e848484614823565b90506103bb565b5f8061424f614752565b604051630782d7e160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb938990630782d7e1906024016040805180830381865afa158015613f27573d5f803e3d5ffd5b5f808212156142c957600160ff1b82036142c35750600160ff1b919050565b505f0390565b5090565b919050565b5f805f1983850993909202808410938190039390930393915050565b5f805f6142fb86866142d2565b91509150815f0361431f5783818161431557614315615e08565b04925050506103bb565b8382106143505760405163362ced0960e11b8152600481018790526024810186905260448101859052606401610316565b5f84868809600186198101871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103025f82900382900490920185841190960395909502919093039390930492909217029150509392505050565b5f805f8587181215614436576001600160ff1b03841115614423576143e76001600160ff1b03600161567f565b84036143fb5750600160ff1b905081611da5565b614406600a85615e1c565b61440f90615fe4565b61441a846001615e9a565b91509150611da5565b61442c84615fe4565b8391509150611da5565b6001600160ff1b038411156144505761440f600a85615e1c565b5082905081611da5565b5f80600160ff1b84036144a5576001600160ff1b0383036144985760405163d556b11160e01b81526004810185905260248101849052604401610316565b600a840593508260010192505b50505f9190910391565b5f805f845f036144c757505f915081905060016140f6565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b85055f036146b4576f4b3b4ca85a86c47a098a224000000000850515801561452957507f80000000000000000000000000000000000000000000000000000000000000268412155b1561454a576f4b3b4ca85a86c47a098a224000000000850294506026840393505b7728c87cb5c89a2571ebfdcb54864ada834a00000000000000850515801561459257507f80000000000000000000000000000000000000000000000000000000000000138412155b156145ab57678ac7230489e80000850294506013840393505b7b097edd871cfda3a5697758bf0e3cbb5ac5741c64000000000000000085051580156145f757507f800000000000000000000000000000000000000000000000000000000000000a8412155b1561460d576402540be40085029450600a840393505b7e3899162693736ac531a5a58f1fbb4b746504382ca7e4000000000000000000850515801561465c57507f80000000000000000000000000000000000000000000000000000000000000028412155b156146725760648502945060028403935061460d565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b85051580156146a257506001600160ff1b018412155b156146b457600a850294506001840393505b600a808602908105861480156146d157506001600160ff1b018512155b156146e0578095506001850394505b50939492935050507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b8305151590565b5f805f805f61471887876144af565b92509250925080614746576040516305e51ecb60e01b81526004810188905260248101879052604401610316565b50909590945092505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b15806147a9575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b156130c2576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610316565b5f805f8351604103614814576020840151604085015160608601515f1a61480688828585614874565b9550955095505050506140f6565b505081515f91506002906140f6565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156148ad57505f91506003905082614932565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156148fe573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661492957505f925060019150829050614932565b92505f91508190505b9450945094915050565b604051806080016040528061494f614968565b81526020015f81526020015f8152602001606081525090565b6040518060a001604052805f6001600160a01b031681526020016149b660405180606001604052805f6001600160a01b031681526020015f6001600160a01b03168152602001606081525090565b8152606060208201819052604082018190525f91015290565b6040518060e001604052806149e2614968565b81526020015f81526020015f80191681526020015f8019168152602001606081526020015f8152602001606081525090565b5f60208284031215614a24575f80fd5b81356001600160e01b0319811681146103bb575f80fd5b5f8083601f840112614a4b575f80fd5b50813567ffffffffffffffff811115614a62575f80fd5b6020830191508360208260051b8501011115613224575f80fd5b5f805f60408486031215614a8e575f80fd5b833567ffffffffffffffff80821115614aa5575f80fd5b9085019060a08288031215614ab8575f80fd5b90935060208501359080821115614acd575f80fd5b50614ada86828701614a3b565b9497909650939450505050565b5f60208284031215614af7575f80fd5b5035919050565b6001600160a01b0381168114612fa2575f80fd5b80356142cd81614afe565b5f805f805f60808688031215614b31575f80fd5b8535614b3c81614afe565b94506020860135935060408601359250606086013567ffffffffffffffff811115614b65575f80fd5b614b7188828901614a3b565b969995985093965092949392505050565b5f805f60608486031215614b94575f80fd5b8335614b9f81614afe565b92506020840135614baf81614afe565b929592945050506040919091013590565b5f805f805f60808688031215614bd4575f80fd5b8535614bdf81614afe565b94506020860135614bef81614afe565b935060408601359250606086013567ffffffffffffffff80821115614c12575f80fd5b818801915088601f830112614c25575f80fd5b813581811115614c33575f80fd5b896020828501011115614c44575f80fd5b9699959850939650602001949392505050565b5f60208284031215614c67575f80fd5b81356103bb81614afe565b5f60c08284031215614c82575f80fd5b50919050565b5f60208284031215614c98575f80fd5b813567ffffffffffffffff811115614cae575f80fd5b61052d84828501614c72565b5f805f60408486031215614ccc575f80fd5b833567ffffffffffffffff80821115614ce3575f80fd5b614cef87838801614c72565b94506020860135915080821115614acd575f80fd5b5f60208284031215614d14575f80fd5b813567ffffffffffffffff811115614d2a575f80fd5b8201608081850312156103bb575f80fd5b5f8060208385031215614d4c575f80fd5b823567ffffffffffffffff811115614d62575f80fd5b614d6e85828601614a3b565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b82811015614dfd57603f19888603018452614deb858351614d7a565b94509285019290850190600101614dcf565b5092979650505050505050565b5f8060408385031215614e1b575f80fd5b8235614e2681614afe565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614e6b57614e6b614e34565b60405290565b6040805190810167ffffffffffffffff81118282101715614e6b57614e6b614e34565b60405160a0810167ffffffffffffffff81118282101715614e6b57614e6b614e34565b604051601f8201601f1916810167ffffffffffffffff81118282101715614ee057614ee0614e34565b604052919050565b5f82601f830112614ef7575f80fd5b813567ffffffffffffffff811115614f1157614f11614e34565b614f24601f8201601f1916602001614eb7565b818152846020838601011115614f38575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60608284031215614f64575f80fd5b614f6c614e48565b90508135614f7981614afe565b81526020820135614f8981614afe565b6020820152604082013567ffffffffffffffff811115614fa7575f80fd5b614fb384828501614ee8565b60408301525092915050565b5f67ffffffffffffffff821115614fd857614fd8614e34565b5060051b60200190565b5f60408284031215614ff2575f80fd5b614ffa614e71565b9050813561500781614afe565b808252506020820135602082015292915050565b5f82601f83011261502a575f80fd5b8135602061503f61503a83614fbf565b614eb7565b8083825260208201915060208460061b870101935086841115615060575f80fd5b602086015b84811015615085576150778882614fe2565b835291830191604001615065565b509695505050505050565b5f60a082840312156150a0575f80fd5b6150a8614e94565b90506150b382614b12565b8152602082013567ffffffffffffffff808211156150cf575f80fd5b6150db85838601614f54565b602084015260408401359150808211156150f3575f80fd5b6150ff8583860161501b565b60408401526060840135915080821115615117575f80fd5b506151248482850161501b565b6060830152506080820135608082015292915050565b5f61514761503a84614fbf565b8381529050602080820190600585811b850187811115615165575f80fd5b855b8181101561525257803567ffffffffffffffff80821115615186575f80fd5b908801906060828c031215615199575f80fd5b6151a1614e48565b82356151ac81614afe565b815282870135828111156151be575f80fd5b8301601f81018d136151ce575f80fd5b80356151dc61503a82614fbf565b81815290881b8201890190898101908f8311156151f7575f80fd5b928a01925b828410156152155783358252928a0192908a01906151fc565b848b0152506040915050838101358381111561522f575f80fd5b61523b8e828701614ee8565b918301919091525087525050938301938301615167565b50505050509392505050565b5f82601f83011261526d575f80fd5b6103bb8383356020850161513a565b5f805f805f6101408688031215615291575f80fd5b853567ffffffffffffffff808211156152a8575f80fd5b6152b489838a01615090565b965060208801359150808211156152c9575f80fd5b6152d589838a01615090565b95506152e48960408a01614c72565b94506101008801359150808211156152fa575f80fd5b61530689838a0161525e565b935061012088013591508082111561531c575f80fd5b506153298882890161525e565b9150509295509295909350565b5f6102b43683615090565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f813561537581614afe565b6001600160a01b03908116845260208301359061539182614afe565b166020840152604082013536839003601e190181126153ae575f80fd5b820160208101903567ffffffffffffffff8111156153ca575f80fd5b8036038213156153d8575f80fd5b606060408601526153ed606086018284615341565b95945050505050565b5f808335601e1984360301811261540b575f80fd5b830160208101925035905067ffffffffffffffff81111561542a575f80fd5b8060061b3603821315613224575f80fd5b8183525f60208085019450825f5b8581101561548157813561545c81614afe565b6001600160a01b03168752818301358388015260409687019690910190600101615449565b509495945050505050565b5f6001600160a01b0380861683528460208401526060604084015283356154b281614afe565b166060830152602083013536849003605e190181126154cf575f80fd5b60a060808401526154e66101008401858301615369565b90506154f560408501856153f6565b605f19808685030160a087015261550d84838561543b565b935061551c60608801886153f6565b93509150808685030160c08701525061553683838361543b565b92505050608084013560e084015280915050949350505050565b5f61555d61503a84614fbf565b80848252602080830192508560051b85013681111561557a575f80fd5b855b8181101561560457803567ffffffffffffffff8082111561559b575f80fd5b8189019150604082360312156155af575f80fd5b6155b7614e71565b8235828111156155c5575f80fd5b6155d136828601614f54565b82525085830135828111156155e4575f80fd5b6155f03682860161525e565b82880152508752505093820193820161557c565b50919695505050505050565b5f6001600160a01b03808916835280881660208401525085604083015284606083015260a0608083015261564860a083018486615341565b98975050505050505050565b5f60208284031215615664575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156102b4576102b461566b565b5f808335601e198436030181126156a7575f80fd5b83018035915067ffffffffffffffff8211156156c1575f80fd5b6020019150600581901b3603821315613224575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e19833603018112615700575f80fd5b9190910192915050565b5f8235609e19833603018112615700575f80fd5b5f808335601e19843603018112615733575f80fd5b83018035915067ffffffffffffffff82111561574d575f80fd5b6020019150600681901b3603821315613224575f80fd5b5f60808236031215615774575f80fd5b6040516080810167ffffffffffffffff828210818311171561579857615798614e34565b8160405284359150808211156157ac575f80fd5b6157b836838701615090565b8352602085013560208401526040850135604084015260608501359150808211156157e1575f80fd5b506157ee3682860161525e565b60608301525092915050565b5f6020828403121561580a575f80fd5b813580151581146103bb575f80fd5b5f815180845260208085019450602084015f5b8381101561548157815180516001600160a01b03168852830151838801526040909601959082019060010161582c565b5f6001600160a01b03808351168452602083015160a060208601528181511660a08601528160208201511660c08601526040810151915050606060e08501526158a9610100850182614d7a565b9050604083015184820360408601526158c28282615819565b915050606083015184820360608601526158dc8282615819565b915050608083015160808501528091505092915050565b5f815180845260208085019450602084015f5b8381101561548157815187529582019590820190600101615906565b5f6001600160a01b0380871683526020608081850152865160808086015261594e61010086018261585c565b90508188015160a086015260408089015160c08701526060808a0151607f198885030160e08901528381518086528686019150868160051b87010187840193505f5b828110156159ea57601f1988830301845284518a815116835289810151878b8501526159be888501826158f3565b91890151848303858b01529190506159d68183614d7a565b968b0196958b019593505050600101615990565b5080995050505050505050505083604083015282606083015295945050505050565b5f808335601e19843603018112615a21575f80fd5b83018035915067ffffffffffffffff821115615a3b575f80fd5b602001915036819003821315613224575f80fd5b5f8235605e19833603018112615700575f80fd5b5f6102b43683614f54565b5f60408284031215615a7e575f80fd5b6103bb8383614fe2565b6001600160a01b0384168152826020820152606060408201525f6153ed606083018461585c565b6001600160a01b0385168152836020820152606060408201525f615ad7606083018486615341565b9695505050505050565b5f6103bb36848461513a565b818103818111156102b4576102b461566b565b828482375f8382015f815283518060208601835e5f910190815295945050505050565b5f6101206001600160a01b0387168352806020840152615b458184018761585c565b90508281036040840152615b59818661585c565b9150508235606083015260208301356080830152604083013560a0830152606083013560c0830152608083013560e083015260a083013561010083015295945050505050565b602081525f6103bb602083018461585c565b5f60018201615bc257615bc261566b565b5060010190565b5f8282518085526020808601955060208260051b840101602086015f5b84811015615c1457601f19868403018952615c028383516158f3565b98840198925090830190600101615be6565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e06060840152615c5a610100840182614d7a565b9050606084015160808401526080840151601f19808584030160a0860152615c828383615bc9565b925060a08601519150808584030160c0860152615c9f83836158f3565b925060c08601519150808584030160e0860152506153ed82826158f3565b5f82601f830112615ccc575f80fd5b81516020615cdc61503a83614fbf565b8083825260208201915060208460051b870101935086841115615cfd575f80fd5b602086015b848110156150855780518352918301918301615d02565b5f8060408385031215615d2a575f80fd5b825167ffffffffffffffff80821115615d41575f80fd5b818501915085601f830112615d54575f80fd5b81516020615d6461503a83614fbf565b82815260059290921b84018101918181019089841115615d82575f80fd5b948201945b83861015615da057855182529482019490820190615d87565b91880151919650909350505080821115615db8575f80fd5b50615dc585828601615cbd565b9150509250929050565b828152604060208201525f61052d60408301846158f3565b6001600160a01b0383168152604060208201525f61052d6040830184615bc9565b634e487b7160e01b5f52601260045260245ffd5b5f82615e3657634e487b7160e01b5f52601260045260245ffd5b500490565b602081525f6103bb6020830184614d7a565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b03831681526040810160048310615e8d57634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b8082018281125f8312801582168215821617156114ac576114ac61566b565b600181815b80851115615ef357815f1904821115615ed957615ed961566b565b80851615615ee657918102915b93841c9390800290615ebe565b509250929050565b5f82615f09575060016102b4565b81615f1557505f6102b4565b8160018114615f2b5760028114615f3557615f51565b60019150506102b4565b60ff841115615f4657615f4661566b565b50506001821b6102b4565b5060208310610133831016604e8410600b8410161715615f74575081810a6102b4565b615f7e8383615eb9565b805f1904821115615f9157615f9161566b565b029392505050565b5f6103bb8383615efb565b5f8060408385031215615fb5575f80fd5b825160048110615fc3575f80fd5b602084015190925060ff81168114615fd9575f80fd5b809150509250929050565b5f600160ff1b82016142c3576142c361566b56fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00"; /// @dev The runtime bytecode of the contract. bytes constant RUNTIME_CODE = - hex"608060405234801561000f575f80fd5b50600436106100f0575f3560e01c8063613255ab11610093578063ac9650d811610063578063ac9650d81461022b578063d7e442ec1461024b578063d9d98ce41461025e578063fa50118214610271575f80fd5b8063613255ab146101ad57806369c72856146101c0578063709fb8a5146101e85780639235084d146101fb575f80fd5b80632fbc4ba0116100ce5780632fbc4ba01461015157806341d1514f146101665780635cffe9de14610187578063607461191461019a575f80fd5b806301ffc9a7146100f45780631f69cb751461011c5780632cb77e9f1461012f575b5f80fd5b6101076101023660046148e8565b610284565b60405190151581526020015b60405180910390f35b61010761012a366004614950565b6102ba565b61010761013d3660046149bb565b5f9081526020819052604090205460011490565b61016461015f3660046149f1565b6103c2565b005b610179610174366004614a56565b610521565b604051908152602001610113565b610107610195366004614a94565b610535565b6101646101a83660046149f1565b610635565b6101796101bb366004614b2b565b6107c8565b6101d36101ce366004614b5c565b610830565b60408051928352602083019190915201610113565b6101076101f6366004614b8e565b610fc9565b61020e610209366004614bd8565b61130c565b604080519315158452602084019290925290820152606001610113565b61023e610239366004614c0f565b6113ce565b6040516101139190614c7c565b610164610259366004614c0f565b6114b4565b61017961026c366004614cde565b61150e565b61016461027f366004615150565b6115a8565b5f6001600160e01b0319821663e414309160e01b14806102b457506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f6102c3611a9a565b6102d06020850185614b2b565b6001600160a01b0316336001600160a01b03161461031f576102f56020850185614b2b565b6040516335252be360e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b5f61033161032c8661520a565b611ab5565b5f818152602081905260409020549091505f19016103a4575f818152602081905260408082209190915551600192507f09d18501db0080ca2d6cd7c17fa7255daff4b2d503ea93b76ff68b6752ea8e639061039190339084908990615360565b60405180910390a16103a4818585611ae4565b506103bb60015f80516020615ecd83398151915255565b9392505050565b6103ca611a9a565b3385856103d8838383611b1b565b6103e2865f611b4c565b610417576040516306dde9c360e41b81523360048201526001600160a01b038916602482015260448101889052606401610316565b5f80610424338b8a611b86565b604080513381526001600160a01b038e1660208201529081018c90526060810183905291935091507f7f9dfa19cf1cc2f806f2f860fbc9c056b601fb1afc0e9b843dfe5c63616268e69060800160405180910390a15f80610487338d8d8d611c06565b909250905087156104fd5760408051600581526001600160a01b038e1660208201528082018d9052606081018490526080810183905260ff851660a082015260c081019091526104fd906104ee905b60408051600181526020810192909252818101905290565b6104f88a8c615424565b611cf6565b5050505050505061051a60015f80516020615ecd83398151915255565b5050505050565b5f61052d848484611ec4565b949350505050565b5f61054a6001600160a01b038616878661204e565b6040516323e30c8b60e01b81525f906001600160a01b038816906323e30c8b906105829033908a908a9087908b908b906004016154e4565b6020604051808303815f875af115801561059e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105c29190615528565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9811461060757604051630b6c58a960e31b815260048101829052602401610316565b61062887306106165f89615553565b6001600160a01b038a16929190612083565b5060019695505050505050565b61063d611a9a565b33858561064b838383611b1b565b5f8080806106598a82611b4c565b61068d57604051623a3a4d60e21b81523360048201526001600160a01b038d166024820152604481018c9052606401610316565b5f610699338e8e611ec4565b90506106a58b826120bf565b94506106b3338e8e886120db565b90935091505f6106c4338f88612152565b80965081925050507f8045c25080b0868951141ed0a91720bcad09a8364a2b3109ee1fd49c1f0bc8b8338f8f8f8a86604051610736969594939291906001600160a01b03968716815294909516602085015260408401929092526060830152608082015260a081019190915260c00190565b60405180910390a1505060408051600681526001600160a01b038e1660208201528082018d9052606081018490526080810183905260a081018c905260ff851660c0820152600160e08201908152610100820182905261012082019092529089156107a9576107a9816104f88c8e615424565b50505050505050505061051a60015f80516020615ecd83398151915255565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa15801561080c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b49190615528565b5f8061083a611a9a565b6108476080840184615566565b90505f0361086857604051639c95219f60e01b815260040160405180910390fd5b610870614810565b61087861483c565b5f60405180606001604052808780608001906108949190615566565b5f8181106108a4576108a46155ac565b90506020028101906108b691906155c0565b6108c090806155de565b6108ce9060408101906155f2565b6108db60808b018b615566565b5f8181106108eb576108eb6155ac565b90506020028101906108fd91906155c0565b60200135818110610910576109106155ac565b6109269260206040909202019081019150614b2b565b6001600160a01b031681526020016109416080890189615566565b5f818110610951576109516155ac565b905060200281019061096391906155c0565b61096d90806155de565b61097b9060608101906155f2565b61098860808b018b615566565b5f818110610998576109986155ac565b90506020028101906109aa91906155c0565b604001358181106109bd576109bd6155ac565b6109d39260206040909202019081019150614b2b565b6001600160a01b03168152602088810135910152905060605f6109f96080890189615566565b604080516001909201602002820181528501519093505f9250610a1d915082611b4c565b610a3a5760405163315f9e2360e21b815260040160405180910390fd5b5f5b610a4960808a018a615566565b905081108015610a6357506040840151610a63905f611b4c565b15610e7157610a7560808a018a615566565b82818110610a8557610a856155ac565b9050602002810190610a9791906155c0565b610aa090615638565b9550855f01519450835f01516001600160a01b03168560400151876020015181518110610acf57610acf6155ac565b60200260200101515f01516001600160a01b0316141580610b2a575083602001516001600160a01b03168560600151876040015181518110610b1357610b136155ac565b60200260200101515f01516001600160a01b031614155b15610b485760405163936bb5ad60e01b815260040160405180910390fd5b610b5b85876020015188604001516121bb565b5f610b6586611ab5565b5f81815260208190526040902054909150610bca578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a1610e68565b5f610c278789602001518a60400151338c606001515f67ffffffffffffffff811115610bf857610bf8614d08565b604051908082528060200260200182016040528015610c21578160200160208202803683370190505b5061222d565b90505f610c458c604001358360600151611b4c90919063ffffffff16565b15610c9b578751604080513381526001600160a01b03909216602083015281018490527fe3151dc8cb7a54ffc4baabd28c1f241c94d510b5e5b502491ac3cad6c16316d5906060015b60405180910390a1610e5a565b6040820151610caa905f611b4c565b1580610cc257506060820151610cc0905f611b4c565b155b15610d0f578751604080513381526001600160a01b03909216602083015281018490527f500b713857325f9e6dcb52ae832eca9109d107ed1aae9cb4928b4c1e13f051aa90606001610c8e565b600190505f808d6060016020810190610d2891906156ce565b15610d6e576040808a015190850151610d40916120bf565b6060850151909250610d5290836126f2565b60408a0151909150610d64908361273f565b60408a0152610dd5565b5f610d8a856040015186606001516126f290919063ffffffff16565b9050610da38a60400151826120bf90919063ffffffff16565b9150610dbc85606001518361276f90919063ffffffff16565b60408b0151909350610dce908361273f565b60408b0152505b610ddf8c8261279f565b9b50610deb8d8361279f565b9c50610df782856127cf565b610e018185612890565b7f194f1feb3b4d7076a2c272e774e792e0c48bb8c7aa1a9a3671c1cd6da9e6b4c1338c8484604051610e3694939291906157f6565b60405180910390a187516001018089526020028801849052610e5784612a3c565b50505b8480610e635750805b945050505b50600101610a3c565b505f610e8360808a0160608b016156ce565b610e8d5786610e8f565b875b9050610e9c818a35612c7f565b15610ec45760405163573b6f4160e01b81528935600482015260248101829052604401610316565b50610ed433846020015189612152565b505f9050610ee560a08a018a6158e0565b9050118015610ef15750805b15610f635760208301518351339163691f9ed7918a8a610f1460a08f018f6158e0565b6040518763ffffffff1660e01b8152600401610f35969594939291906154e4565b5f604051808303815f87803b158015610f4c575f80fd5b505af1158015610f5e573d5f803e3d5ffd5b505050505b610f7133845f015188611b86565b50505f5b8251811015610fa857610fa0838281518110610f9357610f936155ac565b6020026020010151612cb9565b600101610f75565b505050505050610fc460015f80516020615ecd83398151915255565b915091565b5f610fd2611a9a565b5f61102f61102a610fe38780615923565b610ff19060408101906158e0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612dc392505050565b612e34565b90505f811161105157604051632cff108b60e21b815260040160405180910390fd5b6001811161107257604051633c8270bd60e21b815260040160405180910390fd5b61107f60208601866155f2565b90505f036110a057604051636c44ef8f60e01b815260040160405180910390fd5b6110ad60408601866155f2565b90505f036110ce5760405163540e5f0b60e01b815260040160405180910390fd5b6040805160a081019091523381525f90602081016110ec8880615923565b6110f590615937565b815260200187806020019061110a91906155f2565b808060200260200160405190810160405280939291908181526020015f905b828210156111555761114660408302860136819003810190615942565b81526020019060010190611129565b505050918352505060200161116d60408901896155f2565b808060200260200160405190810160405280939291908181526020015f905b828210156111b8576111a960408302860136819003810190615942565b8152602001906001019061118c565b50505050508152602001876060013581525090505f6111d682611ab5565b5f818152602081905260409020549091501580156112f1575f828152602081905260409081902060019055835190517f87491344dfbcf91f6cbbc610cbbeedc85313d37a02df0c93527f7ea5f8db717f91611234918590879061595c565b60405180910390a15f61124a60a08a018a6158e0565b905011156112e65761129b61126260a08a018a6158e0565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612e4e92505050565b82517fd46c2c56b35c8210e9e712ec3f02242d5fc90187c0ac8ed80cc33626846ec36990836112cd60a08c018c6158e0565b6040516112dd9493929190615983565b60405180910390a15b6112f1828888611ae4565b93505050506103bb60015f80516020615ecd83398151915255565b5f80808061132661131d86806155de565b61032c9061520a565b5f8181526020819052604090205490915060011461134d57505f92508291508190506113c7565b61137261135a86806155de565b6113639061520a565b866020013587604001356121bb565b5f6113b061138087806155de565b6113899061520a565b60208801356040890135336113a160608c018c615566565b6113aa916159b5565b5f610bf8565b905060018160400151826060015194509450945050505b9193909250565b604080515f8152602081019091526060908267ffffffffffffffff8111156113f8576113f8614d08565b60405190808252806020026020018201604052801561142b57816020015b60608152602001906001900390816114165790505b5091505f5b838110156114ac576114873086868481811061144e5761144e6155ac565b905060200281019061146091906158e0565b85604051602001611473939291906159d4565b604051602081830303815290604052612e79565b838281518110611499576114996155ac565b6020908102919091010152600101611430565b505092915050565b6114bc611a9a565b604080515f808252602082019092526114f4916114e9565b60608152602001906001900390816114d45790505b506104f88385615424565b61150a60015f80516020615ecd83398151915255565b5050565b6040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611552573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115769190615528565b5f036115a057604051633c5bf76960e21b81526001600160a01b0384166004820152602401610316565b505f92915050565b6115b0611a9a565b835185516001600160a01b039182169116036115df57604051630a98f1f360e21b815260040160405180910390fd5b83604001518360400135815181106115f9576115f96155ac565b60200260200101515f01516001600160a01b03168560600151846020013581518110611627576116276155ac565b60200260200101515f01516001600160a01b03161415806116a0575060408501518051843590811061165b5761165b6155ac565b60200260200101515f01516001600160a01b03168460600151846060013581518110611689576116896155ac565b60200260200101515f01516001600160a01b031614155b156116be5760405163936bb5ad60e01b815260040160405180910390fd5b84606001518360200135815181106116d8576116d86155ac565b60200260200101515f01516001600160a01b03168560400151845f013581518110611705576117056155ac565b60200260200101515f01516001600160a01b03160361173757604051631cd2f1c760e21b815260040160405180910390fd5b5f61174186611ab5565b5f818152602081905260409020549091506117a7578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a150611a84565b5f6117b186611ab5565b5f81815260208190526040902054909150611818578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a15050611a84565b7f6fa7f4c28634b0a9d6831401c45ae468195fb63aed07308935c35374ff5d9e393388888860405161184d94939291906159f7565b60405180910390a1505083515f906118719087908635906020880135908686610bf8565b90505f6118a086866040013587606001358a5f0151885f67ffffffffffffffff811115610bf857610bf8614d08565b90505f6118ad8383612f19565b90506118bc815f0151846127cf565b6118ca8160200151836127cf565b6118d8816040015184612890565b6118e6816060015183612890565b6118ef83612cb9565b6118f882612cb9565b606081015181515f9161190b919061273f565b90505f6119298360400151846020015161273f90919063ffffffff16565b9050611935825f612c7f565b806119455750611945815f612c7f565b1561196357604051630d86822160e01b815260040160405180910390fd5b611997338b606001518a6020013581518110611981576119816155ac565b60200260200101515f01518a6080013585611c06565b50506119cd338a606001518a60600135815181106119b7576119b76155ac565b60200260200101515f01518a60a0013584611c06565b5050604080513381528451602080830191909152850151818301529084015160608083019190915284015160808201527fd9fa84dd790c969daa5c33d8050dc06b4a9b59d5b42e2be5f5e8ae20447f618d925060a001905060405180910390a1611a3683612a3c565b611a3f82612a3c565b80516001600160e01b0316158015611a62575060208101516001600160e01b0316155b15611a80576040516321badf1f60e01b815260040160405180910390fd5b5050505b61051a60015f80516020615ecd83398151915255565b611aa2612f67565b60025f80516020615ecd83398151915255565b5f81604051602001611ac79190615a73565b604051602081830303815290604052805190602001209050919050565b604080516002815260208101859052338183015260608101909152611b1690611b0c906104d6565b6104f88385615424565b505050565b80611b16576040516305dbdfd960e41b81526001600160a01b03808516600483015283166024820152604401610316565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d611b7a84848484612f98565b12979650505050505050565b5f805f611b928561306c565b9050611b9e845f612c7f565b15611bbc57604051632eaefac360e21b815260040160405180910390fd5b5f80611bc886846130d2565b9150915080611bdd57611bda82615a85565b91505b8115611bf857611bf86001600160a01b038816893085612083565b50925090505b935093915050565b5f80611c128382612c7f565b15611c335760405163793a8f5560e01b815260048101849052602401610316565b83611c5157611c43868685612152565b505f9250829150611ced9050565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611c8b828661279f565b9050611c97815f612c7f565b15611cb85760405163c5e12af560e01b815260048101829052602401610316565b6001600160a01b038089165f908152600160209081526040808320938b16835292815282822089835290522081905590925090505b94509492505050565b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b8651811015611eba57868181518110611d5d57611d5d6155ac565b602002602001015193505f845f015160400151511115611eb2575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001611dd58d8a602001516130ff565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401611e009190615af5565b5f60405180830381865afa158015611e1a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611e419190810190615bed565b9150505f81511115611eb05784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490611e82908a908590600401615ca3565b5f604051808303815f87803b158015611e99575f80fd5b505af1158015611eab573d5f803e3d5ffd5b505050505b505b600101611d42565b5050505050505050565b5f8115611efe57506001600160a01b038084165f9081526001602090815260408083209386168352928152828220848352905220546103bb565b5f611f08846133e1565b6040516370a0823160e01b81526001600160a01b0387811660048301529192505f91611f8091908716906370a0823190602401602060405180830381865afa158015611f56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611f7a9190615528565b836133ed565b50604051636eb1769f60e11b81526001600160a01b0388811660048301523060248301529192505f91611fff919088169063dd62ed3e90604401602060405180830381865afa158015611fd5573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ff99190615528565b846133ed565b506001600160a01b038089165f908152600160209081526040808320938b168352928152828220828052905220549091506120449061203e84846120bf565b9061279f565b93505050506103bb565b61205b838383600161342d565b611b1657604051635274afe760e01b81526001600160a01b0384166004820152602401610316565b61209184848484600161348f565b6120b957604051635274afe760e01b81526001600160a01b0385166004820152602401610316565b50505050565b5f6120ca8383612c7f565b6120d457816103bb565b5090919050565b5f806120e78382612c7f565b156121085760405163793a8f5560e01b815260048101849052602401610316565b8361211857611c43868685611b86565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611c8b828661273f565b5f805f61215e8561306c565b905061216a845f612c7f565b1561218857604051632d1671a360e11b815260040160405180910390fd5b5f61219385836130d2565b50905080156121b0576121b06001600160a01b038716888361204e565b969095509350505050565b826060015181815181106121d1576121d16155ac565b60200260200101515f01516001600160a01b0316836040015183815181106121fb576121fb6155ac565b60200260200101515f01516001600160a01b031603611b1657604051631cd2f1c760e21b815260040160405180910390fd5b6122356148a3565b60408051600480825260a082019092526060915f9190816020015b60608152602001906001900390816122505790505090506122a56122738a611ab5565b8a51604080516003815260208101939093526001600160a01b0391821683820152908916606083015260808201905290565b8160018003815181106122ba576122ba6155ac565b60200260200101819052505f6122ef8a604001518a815181106122df576122df6155ac565b60200260200101515f01516133e1565b90505f6123418b5f01518c604001518c8151811061230f5761230f6155ac565b60200260200101515f01518d604001518d81518110612330576123306155ac565b602002602001015160200151611ec4565b90506123d08b604001518b8151811061235c5761235c6155ac565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d604001518d8151811061238e5761238e6155ac565b602002602001015160200151845f801b60408051600581526020810196909652858101949094526060850192909252608084015260a083015260c08201905290565b836001600303815181106123e6576123e66155ac565b602002602001018190525050505f61240d8a6060015189815181106122df576122df6155ac565b90505f61244e8b5f01518c606001518b8151811061242d5761242d6155ac565b60200260200101515f01518d606001518c81518110612330576123306155ac565b905061249b8b606001518a81518110612469576124696155ac565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d606001518c8151811061238e5761238e6155ac565b836001600403815181106124b1576124b16155ac565b602002602001018190525050506124c881866130ff565b9150505f885f01516001600160a01b031690505f808a602001515f01516001600160a01b031663d04dfe236040518060e001604052808e60200151602001516001600160a01b0316815260200161252887305f9182526020526040902090565b81526020018e602001516040015181526020015f81526020018781526020015f67ffffffffffffffff81111561256057612560614d08565b604051908082528060200260200182016040528015612589578160200160208202803683370190505b508152602001898152506040518263ffffffff1660e01b81526004016125af9190615af5565b5f60405180830381865afa1580156125c9573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526125f09190810190615bed565b9150915060028251101561261c578151604051630fbb8e5560e21b815260040161031691815260200190565b602082015160408301518551612670908790600490811061263f5761263f6155ac565b6020026020010151600381518110612659576126596155ac565b6020026020010151826120bf90919063ffffffff16565b60408051600281526020810183905280820185905260608101909152909150866002815181106126a2576126a26155ac565b60200260200101819052506040518060e001604052808e81526020018c81526020018281526020018381526020018781526020018681526020018481525096505050505050509695505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d8480612722868686866134fc565b915091505f612731838361361b565b9a9950505050505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061272286868686613668565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061272286868686613692565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061272286868686613bcf565b8181608001516004815181106127e7576127e76155ac565b6020026020010151600481518110612801576128016155ac565b6020026020010181815250506120b9815f01515f0151826080015160048151811061282e5761282e6155ac565b60200260200101515f81518110612847576128476155ac565b60200260200101515f1c8360800151600481518110612868576128686155ac565b6020026020010151600281518110612882576128826155ac565b6020026020010151856120db565b8181608001516003815181106128a8576128a86155ac565b60200260200101516004815181106128c2576128c26155ac565b6020908102919091010152805151608082015180515f919060039081106128eb576128eb6155ac565b60200260200101515f81518110612904576129046155ac565b60200260200101515f1c90505f8360800151600381518110612928576129286155ac565b6020026020010151600281518110612942576129426155ac565b602002602001015190505f801b81036129e95761295f855f612c7f565b156129805760405163793a8f5560e01b815260048101869052602401610316565b6001600160a01b038084165f9081526001602090815260408083209386168352928152828220848352905220546129b7908661279f565b6001600160a01b038085165f9081526001602090815260408083209387168352928152828220858352905220556129f8565b6129f583838388611c06565b50505b7f4cb6e22a3e7e651d7cf0376cff48f20f5007a54147777865be7f5f6c38c50f4a338560800151604051612a2d929190615cbb565b60405180910390a15050505050565b60c08101515115612ab6578051602090810151015160a082015160c083015160405163012c676d60e21b81526001600160a01b03909316926304b19db492612a88929091600401615ca3565b5f604051808303815f87803b158015612a9f575f80fd5b505af1158015612ab1573d5f803e3d5ffd5b505050505b5f815f0151602001515f01516001600160a01b031663d04dfe236040518060e00160405280855f015160200151602001516001600160a01b03168152602001612b0c8660a00151305f9182526020526040902090565b8152602001855f01516020015160400151815260200160018152602001856080015181526020015f67ffffffffffffffff811115612b4c57612b4c614d08565b604051908082528060200260200182016040528015612b75578160200160208202803683370190505b5081526020015f604051908082528060200260200182016040528015612ba5578160200160208202803683370190505b508152506040518263ffffffff1660e01b8152600401612bc59190615af5565b5f60405180830381865afa158015612bdf573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612c069190810190615bed565b9150505f8151111561150a578151602090810151015160a083015160405163012c676d60e21b81526001600160a01b03909216916304b19db491612c4e918590600401615ca3565b5f604051808303815f87803b158015612c65575f80fd5b505af1158015612c77573d5f803e3d5ffd5b505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d612cad84848484612f98565b13979650505050505050565b5f8160800151600381518110612cd157612cd16155ac565b6020026020010151600281518110612ceb57612ceb6155ac565b602002602001015190505f801b810361150a57815151608083015180515f91906003908110612d1c57612d1c6155ac565b60200260200101515f81518110612d3557612d356155ac565b6020908102919091018101516001600160a01b038481165f9081526001845260408082209284168252918452818120878252909352909120549091506001600160e01b0381161561051a576001600160a01b038084165f9081526001602090815260408083209386168352928152828220878352905290812055612dba838383612152565b50505050505050565b6060604082511015612de257505060408051602081019091525f815290565b5f60208301519050602060408451612dfa91906159c1565b612e049190615cf0565b811115612e2057505060408051602081019091525f8152919050565b600181016020026020840101915050919050565b5f81515f03612e4457505f919050565b50602001515f1a90565b612e5781613ccd565b612e765780604051630c89984b60e31b81526004016103169190615d0f565b50565b60605f612e868484613cfb565b9050808015612ea757505f3d1180612ea757505f846001600160a01b03163b115b15612ebc57612eb4613d0e565b9150506102b4565b8015612ee657604051639996b31560e01b81526001600160a01b0385166004820152602401610316565b3d15612ef957612ef4613d27565b612f12565b60405163d6bda27560e01b815260040160405180910390fd5b5092915050565b604080516080810182525f808252602082018190529181018290526060810191909152612f468383613d32565b82526040820152612f578284613d32565b6020830152606082015292915050565b5f80516020615ecd83398151915254600203612f9657604051633ee5aeb560e01b815260040160405180910390fd5b565b5f8085158415178187128286121817858414178015612fbd5786859250925050611ced565b505f85841315612fd1575092949193919260015b8386035f8112604c8213178015613004578215612ff6575f8994509450505050611ced565b885f94509450505050611ced565b600a82900a8981028a82828161301c5761301c615cdc565b0514613048578415613038575f8b965096505050505050611ced565b8a5f965096505050505050611ced565b841561305d578896509450611ced9350505050565b9550879450611ced9350505050565b5f805f61307884613d9b565b9092509050600182600381111561309157613091615d21565b141580156130b057505f8260038111156130ad576130ad615d21565b14155b156103bb57838260405163ee07877f60e01b8152600401610316929190615d35565b5f806001600160e01b038416601b0b60e085901d6130f1828287613e28565b9350935050505b9250929050565b60605f825167ffffffffffffffff81111561311c5761311c614d08565b604051908082528060200260200182016040528015613145578160200160208202803683370190505b5090505f80845111613157575f61315d565b83516001015b85516001010190505f8167ffffffffffffffff81111561317f5761317f614d08565b6040519080825280602002602001820160405280156131b257816020015b606081526020019060019003908161319d5790505b5090505f6131d6604080516002815233602082015230818301526060810190915290565b8282815181106131e8576131e86155ac565b60200260200101819052505f5b8751811015613245578180600101925050878181518110613218576132186155ac565b6020026020010151838381518110613232576132326155ac565b60209081029190910101526001016131f5565b508551156133d757808060010191505083828281518110613268576132686155ac565b60200260200101819052505f5b86518110156133d557613324878281518110613293576132936155ac565b60200260200101515f01516133016132cf8a85815181106132b6576132b66155ac565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b898481518110613313576133136155ac565b602002602001015160400151613f8e565b61334457604051630a57f30960e31b815260048101829052602401610316565b868181518110613356576133566155ac565b60200260200101515f01516001600160a01b03165f1b85828151811061337e5761337e6155ac565b60200260200101818152505081806001019250508681815181106133a4576133a46155ac565b6020026020010151602001518383815181106133c2576133c26155ac565b6020908102919091010152600101613275565b505b5095945050505050565b5f805f61307884613ffe565b5f805f805f6133fc878761405d565b9250925092505f8061340e85856140a0565b915091508183801561341d5750815b9650965050505050509250929050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316613483578383151615613477573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f511483166134eb5783831516156134df573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f8085158415178015613514575f92505f9150613611565b61351e8487615d6e565b91505f61352a88614178565b90505f61353687614178565b90505f61354383836141a6565b5090505f6f0785ee10d5da46d900f436a000000000821115613578576f0785ee10d5da46d900f436a000000000820491506025015b670de0b6b3a764000082111561359957670de0b6b3a7640000820491506012015b633b9aca008211156135b257633b9aca00820491506009015b6127108211156135c757612710820491506004015b81156135db57600a820491506001016135c7565b6135e58187615d6e565b95506136078b8a61360187876135fc87600a615e6d565b6141c2565b8961428e565b9097509550505050505b5094509492505050565b5f805f61362885856140a0565b9150915080158015613638575081155b1561366057604051638eba4d0760e01b81526004810186905260248101859052604401610316565b509392505050565b5f80613674848461432e565b909450925061368586868686613bcf565b9150915094509492505050565b5f80835f036136be57604051637a97930f60e01b81526004810187905260248101869052604401610316565b855f036136cf57505f905080611ced565b5f805f806136dd8a8a614383565b919b50995091506136ee8888614383565b919950975090505f6136ff8b614178565b90505f61370b8a614178565b90507f161bcca7119915b50764b4abe86529797775a5f1719510000000000000000000604c81831015613ad057841561376257507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b9050604b613aa8565b6f4b3b4ca85a86c47a098a22400000000083101561388e57678ac7230489e800008310156137f2576402540be4008310156137c057620186a08310156137b05750620186a090506005613a69565b506402540be4009050600a613a69565b655af3107a40008310156137df5750655af3107a40009050600e613a69565b50678ac7230489e8000090506013613a69565b6b204fce5e3e250261100000008310156138445769152d02c7e14af680000083101561382d575069152d02c7e14af680000090506017613a69565b506b204fce5e3e250261100000009050601c613a69565b6d314dc6448d9338c15b0a0000000083101561387357506d314dc6448d9338c15b0a0000000090506021613a69565b506f4b3b4ca85a86c47a098a22400000000090506026613a69565b780197d4df19d605767337e9f14d3eec8920e4000000000000008310156139865773af298d050e4395d69670b12b7f41000000000000831015613921577172cb5bd86321e38cb6ce6682e8000000000083101561390257507172cb5bd86321e38cb6ce6682e800000000009050602b613a69565b5073af298d050e4395d69670b12b7f4100000000000090506030613a69565b76010b46c6cdd6e3e0828f4db456ff0c8ea0000000000000831015613962575076010b46c6cdd6e3e0828f4db456ff0c8ea000000000000090506035613a69565b50780197d4df19d605767337e9f14d3eec8920e4000000000000009050603a613a69565b7c03b58e88c75313ec9d329eaaa18fb92f75215b17100000000000000000831015613a1c577a026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000008310156139f457507a026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000009050603f613a69565b507c03b58e88c75313ec9d329eaaa18fb92f75215b1710000000000000000090506044613a69565b7e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000831015613a6957507e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000905060495b818311613a7e57600a820491505f1901613a69565b815f03613aa8576040516305e51ecb60e01b8152600481018d9052602481018c9052604401610316565b85613ad0576040516305e51ecb60e01b8152600481018f9052602481018e9052604401610316565b80600160ff1b018d12613ae757808d039c50613b25565b600160ff1b9c90038c015f811315613b2557806001600160ff1b03038b13613b1257998a0199613b25565b5f80995099505050505050505050611ced565b5f808e128015613b3457505f8c135b15613b5557600160ff1b8e01808d13613b4d575f613b51565b808d035b9150505b8b818f01039750613b728f8e613b6c8887896141c2565b8b61428e565b90995097505f811315613bbc57604c811315613b9c575f809a509a50505050505050505050611ced565b80600a0a8981613bae57613bae615cdc565b059850885f03613bbc575f97505b50969850949650611ced95505050505050565b5f8085158415178015613bfb57865f03613bef5784849250925050611ced565b86869250925050611ced565b613c0587876145dd565b9097509550613c1485856145dd565b909550935085841315613c28579395929492935b838603604c811115613c41578787935093505050611ced565b80600a0a8681613c5357613c53615cdc565b0595505086850180881860ff90811c151589881890911c15168015613cbc57876001600160ff1b0303613ca35760405163d556b11160e01b8152600481018a905260248101899052604401610316565b600a968790059690980586019760019790970196613cc0565b8198505b5096979596505050505050565b5f600882511015613cdf57505f919050565b506008015167ffffffffffffffff1667ff0a89c674ee78741490565b5f805f835160208501865af49392505050565b6040513d81523d5f602083013e3d602001810160405290565b6040513d5f823e3d81fd5b5f80613d4f846060015185604001516126f290919063ffffffff16565b915083604001519050613d6f836040015183611b4c90919063ffffffff16565b156130f85782604001519150613d9284606001518361276f90919063ffffffff16565b90509250929050565b5f80613da5614626565b60405163b7bad1b160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb93899063b7bad1b19060240160408051808303815f875af1158015613dfb573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e1f9190615e78565b91509150915091565b5f805f851215613e5557604051634a7d166b60e01b81526004810186905260248101859052604401610316565b845f03613e6757505f90506001611bfe565b8460ff8416850185811215613e995760405163d556b11160e01b81526004810188905260248101879052604401610316565b5f805f831215613ee557604c19831215613ebc575f809550955050505050611bfe565b825f03600a0a9150818481613ed357613ed3615cdc565b0495505084029091149150611bfe9050565b5f831315613f7e57604d831315613f225760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b82600a0a9150815f1981613f3857613f38615cdc565b04841115613f6c5760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b5091909102925060019150611bfe9050565b8360019550955050505050611bfe565b5f836001600160a01b03163b5f03613fec575f80613fac85856146b1565b5090925090505f816003811115613fc557613fc5615d21565b148015613fe35750856001600160a01b0316826001600160a01b0316145b925050506103bb565b613ff78484846146f7565b90506103bb565b5f80614008614626565b604051630782d7e160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb938990630782d7e1906024016040805180830381865afa158015613dfb573d5f803e3d5ffd5b5f808060ff841681036001600160ff1b0386111561408f57600a860460018201600a88065f1493509350935050614099565b8593509150600190505b9250925092565b5f601b83900b8314838382614104577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e10000000000000000008605156140e457620186a0860595506005850194505b8586601b0b146140ff57600a860595508460010194506140e4565b61411a565b855f0361411a57505f9250600191506130f89050565b848560030b1461415d575f85121561413a57505f92508291506130f89050565b60405163d556b11160e01b81526004810183905260248101829052604401610316565b50506001600160e01b03841660e084901b1791509250929050565b5f8082121561419d57600160ff1b82036141975750600160ff1b919050565b505f0390565b5090565b919050565b5f805f1983850993909202808410938190039390930393915050565b5f805f6141cf86866141a6565b91509150815f036141f3578381816141e9576141e9615cdc565b04925050506103bb565b8382106142245760405163362ced0960e11b8152600481018790526024810186905260448101859052606401610316565b5f84868809600186198101871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103025f82900382900490920185841190960395909502919093039390930492909217029150509392505050565b5f805f858718121561430a576001600160ff1b038411156142f7576142bb6001600160ff1b036001615553565b84036142cf5750600160ff1b905081611ced565b6142da600a85615cf0565b6142e390615eb8565b6142ee846001615d6e565b91509150611ced565b61430084615eb8565b8391509150611ced565b6001600160ff1b03841115614324576142e3600a85615cf0565b5082905081611ced565b5f80600160ff1b8403614379576001600160ff1b03830361436c5760405163d556b11160e01b81526004810185905260248101849052604401610316565b600a840593508260010192505b50505f9190910391565b5f805f845f0361439b57505f91508190506001614099565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b85055f03614588576f4b3b4ca85a86c47a098a22400000000085051580156143fd57507f80000000000000000000000000000000000000000000000000000000000000268412155b1561441e576f4b3b4ca85a86c47a098a224000000000850294506026840393505b7728c87cb5c89a2571ebfdcb54864ada834a00000000000000850515801561446657507f80000000000000000000000000000000000000000000000000000000000000138412155b1561447f57678ac7230489e80000850294506013840393505b7b097edd871cfda3a5697758bf0e3cbb5ac5741c64000000000000000085051580156144cb57507f800000000000000000000000000000000000000000000000000000000000000a8412155b156144e1576402540be40085029450600a840393505b7e3899162693736ac531a5a58f1fbb4b746504382ca7e4000000000000000000850515801561453057507f80000000000000000000000000000000000000000000000000000000000000028412155b15614546576064850294506002840393506144e1565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b850515801561457657506001600160ff1b018412155b1561458857600a850294506001840393505b600a808602908105861480156145a557506001600160ff1b018512155b156145b4578095506001850394505b50939492935050507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b8305151590565b5f805f805f6145ec8787614383565b9250925092508061461a576040516305e51ecb60e01b81526004810188905260248101879052604401610316565b50909590945092505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b158061467d575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b15612f96576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610316565b5f805f83516041036146e8576020840151604085015160608601515f1a6146da88828585614748565b955095509550505050614099565b505081515f9150600290614099565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084111561478157505f91506003905082614806565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156147d2573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b0381166147fd57505f925060019150829050614806565b92505f91508190505b9450945094915050565b604051806080016040528061482361483c565b81526020015f81526020015f8152602001606081525090565b6040518060a001604052805f6001600160a01b0316815260200161488a60405180606001604052805f6001600160a01b031681526020015f6001600160a01b03168152602001606081525090565b8152606060208201819052604082018190525f91015290565b6040518060e001604052806148b661483c565b81526020015f81526020015f80191681526020015f8019168152602001606081526020015f8152602001606081525090565b5f602082840312156148f8575f80fd5b81356001600160e01b0319811681146103bb575f80fd5b5f8083601f84011261491f575f80fd5b50813567ffffffffffffffff811115614936575f80fd5b6020830191508360208260051b85010111156130f8575f80fd5b5f805f60408486031215614962575f80fd5b833567ffffffffffffffff80821115614979575f80fd5b9085019060a0828803121561498c575f80fd5b909350602085013590808211156149a1575f80fd5b506149ae8682870161490f565b9497909650939450505050565b5f602082840312156149cb575f80fd5b5035919050565b6001600160a01b0381168114612e76575f80fd5b80356141a1816149d2565b5f805f805f60808688031215614a05575f80fd5b8535614a10816149d2565b94506020860135935060408601359250606086013567ffffffffffffffff811115614a39575f80fd5b614a458882890161490f565b969995985093965092949392505050565b5f805f60608486031215614a68575f80fd5b8335614a73816149d2565b92506020840135614a83816149d2565b929592945050506040919091013590565b5f805f805f60808688031215614aa8575f80fd5b8535614ab3816149d2565b94506020860135614ac3816149d2565b935060408601359250606086013567ffffffffffffffff80821115614ae6575f80fd5b818801915088601f830112614af9575f80fd5b813581811115614b07575f80fd5b896020828501011115614b18575f80fd5b9699959850939650602001949392505050565b5f60208284031215614b3b575f80fd5b81356103bb816149d2565b5f60c08284031215614b56575f80fd5b50919050565b5f60208284031215614b6c575f80fd5b813567ffffffffffffffff811115614b82575f80fd5b61052d84828501614b46565b5f805f60408486031215614ba0575f80fd5b833567ffffffffffffffff80821115614bb7575f80fd5b614bc387838801614b46565b945060208601359150808211156149a1575f80fd5b5f60208284031215614be8575f80fd5b813567ffffffffffffffff811115614bfe575f80fd5b8201608081850312156103bb575f80fd5b5f8060208385031215614c20575f80fd5b823567ffffffffffffffff811115614c36575f80fd5b614c428582860161490f565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b82811015614cd157603f19888603018452614cbf858351614c4e565b94509285019290850190600101614ca3565b5092979650505050505050565b5f8060408385031215614cef575f80fd5b8235614cfa816149d2565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614d3f57614d3f614d08565b60405290565b6040805190810167ffffffffffffffff81118282101715614d3f57614d3f614d08565b60405160a0810167ffffffffffffffff81118282101715614d3f57614d3f614d08565b604051601f8201601f1916810167ffffffffffffffff81118282101715614db457614db4614d08565b604052919050565b5f82601f830112614dcb575f80fd5b813567ffffffffffffffff811115614de557614de5614d08565b614df8601f8201601f1916602001614d8b565b818152846020838601011115614e0c575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60608284031215614e38575f80fd5b614e40614d1c565b90508135614e4d816149d2565b81526020820135614e5d816149d2565b6020820152604082013567ffffffffffffffff811115614e7b575f80fd5b614e8784828501614dbc565b60408301525092915050565b5f67ffffffffffffffff821115614eac57614eac614d08565b5060051b60200190565b5f60408284031215614ec6575f80fd5b614ece614d45565b90508135614edb816149d2565b808252506020820135602082015292915050565b5f82601f830112614efe575f80fd5b81356020614f13614f0e83614e93565b614d8b565b8083825260208201915060208460061b870101935086841115614f34575f80fd5b602086015b84811015614f5957614f4b8882614eb6565b835291830191604001614f39565b509695505050505050565b5f60a08284031215614f74575f80fd5b614f7c614d68565b9050614f87826149e6565b8152602082013567ffffffffffffffff80821115614fa3575f80fd5b614faf85838601614e28565b60208401526040840135915080821115614fc7575f80fd5b614fd385838601614eef565b60408401526060840135915080821115614feb575f80fd5b50614ff884828501614eef565b6060830152506080820135608082015292915050565b5f61501b614f0e84614e93565b8381529050602080820190600585811b850187811115615039575f80fd5b855b8181101561512657803567ffffffffffffffff8082111561505a575f80fd5b908801906060828c03121561506d575f80fd5b615075614d1c565b8235615080816149d2565b81528287013582811115615092575f80fd5b8301601f81018d136150a2575f80fd5b80356150b0614f0e82614e93565b81815290881b8201890190898101908f8311156150cb575f80fd5b928a01925b828410156150e95783358252928a0192908a01906150d0565b848b01525060409150508381013583811115615103575f80fd5b61510f8e828701614dbc565b91830191909152508752505093830193830161503b565b50505050509392505050565b5f82601f830112615141575f80fd5b6103bb8383356020850161500e565b5f805f805f6101408688031215615165575f80fd5b853567ffffffffffffffff8082111561517c575f80fd5b61518889838a01614f64565b9650602088013591508082111561519d575f80fd5b6151a989838a01614f64565b95506151b88960408a01614b46565b94506101008801359150808211156151ce575f80fd5b6151da89838a01615132565b93506101208801359150808211156151f0575f80fd5b506151fd88828901615132565b9150509295509295909350565b5f6102b43683614f64565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f8135615249816149d2565b6001600160a01b039081168452602083013590615265826149d2565b166020840152604082013536839003601e19018112615282575f80fd5b820160208101903567ffffffffffffffff81111561529e575f80fd5b8036038213156152ac575f80fd5b606060408601526152c1606086018284615215565b95945050505050565b5f808335601e198436030181126152df575f80fd5b830160208101925035905067ffffffffffffffff8111156152fe575f80fd5b8060061b36038213156130f8575f80fd5b8183525f60208085019450825f5b85811015615355578135615330816149d2565b6001600160a01b0316875281830135838801526040968701969091019060010161531d565b509495945050505050565b5f6001600160a01b038086168352846020840152606060408401528335615386816149d2565b166060830152602083013536849003605e190181126153a3575f80fd5b60a060808401526153ba610100840185830161523d565b90506153c960408501856152ca565b605f19808685030160a08701526153e184838561530f565b93506153f060608801886152ca565b93509150808685030160c08701525061540a83838361530f565b92505050608084013560e084015280915050949350505050565b5f615431614f0e84614e93565b80848252602080830192508560051b85013681111561544e575f80fd5b855b818110156154d857803567ffffffffffffffff8082111561546f575f80fd5b818901915060408236031215615483575f80fd5b61548b614d45565b823582811115615499575f80fd5b6154a536828601614e28565b82525085830135828111156154b8575f80fd5b6154c436828601615132565b828801525087525050938201938201615450565b50919695505050505050565b5f6001600160a01b03808916835280881660208401525085604083015284606083015260a0608083015261551c60a083018486615215565b98975050505050505050565b5f60208284031215615538575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156102b4576102b461553f565b5f808335601e1984360301811261557b575f80fd5b83018035915067ffffffffffffffff821115615595575f80fd5b6020019150600581901b36038213156130f8575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e198336030181126155d4575f80fd5b9190910192915050565b5f8235609e198336030181126155d4575f80fd5b5f808335601e19843603018112615607575f80fd5b83018035915067ffffffffffffffff821115615621575f80fd5b6020019150600681901b36038213156130f8575f80fd5b5f60808236031215615648575f80fd5b6040516080810167ffffffffffffffff828210818311171561566c5761566c614d08565b816040528435915080821115615680575f80fd5b61568c36838701614f64565b8352602085013560208401526040850135604084015260608501359150808211156156b5575f80fd5b506156c236828601615132565b60608301525092915050565b5f602082840312156156de575f80fd5b813580151581146103bb575f80fd5b5f815180845260208085019450602084015f5b8381101561535557815180516001600160a01b031688528301518388015260409096019590820190600101615700565b5f6001600160a01b03808351168452602083015160a060208601528181511660a08601528160208201511660c08601526040810151915050606060e085015261577d610100850182614c4e565b90506040830151848203604086015261579682826156ed565b915050606083015184820360608601526157b082826156ed565b915050608083015160808501528091505092915050565b5f815180845260208085019450602084015f5b83811015615355578151875295820195908201906001016157da565b5f6001600160a01b03808716835260206080818501528651608080860152615822610100860182615730565b90508188015160a086015260408089015160c08701526060808a0151607f198885030160e08901528381518086528686019150868160051b87010187840193505f5b828110156158be57601f1988830301845284518a815116835289810151878b850152615892888501826157c7565b91890151848303858b01529190506158aa8183614c4e565b968b0196958b019593505050600101615864565b5080995050505050505050505083604083015282606083015295945050505050565b5f808335601e198436030181126158f5575f80fd5b83018035915067ffffffffffffffff82111561590f575f80fd5b6020019150368190038213156130f8575f80fd5b5f8235605e198336030181126155d4575f80fd5b5f6102b43683614e28565b5f60408284031215615952575f80fd5b6103bb8383614eb6565b6001600160a01b0384168152826020820152606060408201525f6152c16060830184615730565b6001600160a01b0385168152836020820152606060408201525f6159ab606083018486615215565b9695505050505050565b5f6103bb36848461500e565b818103818111156102b4576102b461553f565b828482375f8382015f815283518060208601835e5f910190815295945050505050565b5f6101206001600160a01b0387168352806020840152615a1981840187615730565b90508281036040840152615a2d8186615730565b9150508235606083015260208301356080830152604083013560a0830152606083013560c0830152608083013560e083015260a083013561010083015295945050505050565b602081525f6103bb6020830184615730565b5f60018201615a9657615a9661553f565b5060010190565b5f8282518085526020808601955060208260051b840101602086015f5b84811015615ae857601f19868403018952615ad68383516157c7565b98840198925090830190600101615aba565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e06060840152615b2e610100840182614c4e565b9050606084015160808401526080840151601f19808584030160a0860152615b568383615a9d565b925060a08601519150808584030160c0860152615b7383836157c7565b925060c08601519150808584030160e0860152506152c182826157c7565b5f82601f830112615ba0575f80fd5b81516020615bb0614f0e83614e93565b8083825260208201915060208460051b870101935086841115615bd1575f80fd5b602086015b84811015614f595780518352918301918301615bd6565b5f8060408385031215615bfe575f80fd5b825167ffffffffffffffff80821115615c15575f80fd5b818501915085601f830112615c28575f80fd5b81516020615c38614f0e83614e93565b82815260059290921b84018101918181019089841115615c56575f80fd5b948201945b83861015615c7457855182529482019490820190615c5b565b91880151919650909350505080821115615c8c575f80fd5b50615c9985828601615b91565b9150509250929050565b828152604060208201525f61052d60408301846157c7565b6001600160a01b0383168152604060208201525f61052d6040830184615a9d565b634e487b7160e01b5f52601260045260245ffd5b5f82615d0a57634e487b7160e01b5f52601260045260245ffd5b500490565b602081525f6103bb6020830184614c4e565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b03831681526040810160048310615d6157634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b8082018281125f8312801582168215821617156114ac576114ac61553f565b600181815b80851115615dc757815f1904821115615dad57615dad61553f565b80851615615dba57918102915b93841c9390800290615d92565b509250929050565b5f82615ddd575060016102b4565b81615de957505f6102b4565b8160018114615dff5760028114615e0957615e25565b60019150506102b4565b60ff841115615e1a57615e1a61553f565b50506001821b6102b4565b5060208310610133831016604e8410600b8410161715615e48575081810a6102b4565b615e528383615d8d565b805f1904821115615e6557615e6561553f565b029392505050565b5f6103bb8383615dcf565b5f8060408385031215615e89575f80fd5b825160048110615e97575f80fd5b602084015190925060ff81168114615ead575f80fd5b809150509250929050565b5f600160ff1b82016141975761419761553f56fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00"; + hex"608060405234801561000f575f80fd5b50600436106100f0575f3560e01c8063613255ab11610093578063ac9650d811610063578063ac9650d81461022b578063d7e442ec1461024b578063d9d98ce41461025e578063fa50118214610271575f80fd5b8063613255ab146101ad57806369c72856146101c0578063709fb8a5146101e85780639235084d146101fb575f80fd5b80632fbc4ba0116100ce5780632fbc4ba01461015157806341d1514f146101665780635cffe9de14610187578063607461191461019a575f80fd5b806301ffc9a7146100f45780631f69cb751461011c5780632cb77e9f1461012f575b5f80fd5b610107610102366004614a14565b610284565b60405190151581526020015b60405180910390f35b61010761012a366004614a7c565b6102ba565b61010761013d366004614ae7565b5f9081526020819052604090205460011490565b61016461015f366004614b1d565b6103c2565b005b610179610174366004614b82565b610521565b604051908152602001610113565b610107610195366004614bc0565b610535565b6101646101a8366004614b1d565b610635565b6101796101bb366004614c57565b6107c8565b6101d36101ce366004614c88565b610830565b60408051928352602083019190915201610113565b6101076101f6366004614cba565b610fc9565b61020e610209366004614d04565b61130c565b604080519315158452602084019290925290820152606001610113565b61023e610239366004614d3b565b6113ce565b6040516101139190614da8565b610164610259366004614d3b565b6114b4565b61017961026c366004614e0a565b61150e565b61016461027f36600461527c565b6115a8565b5f6001600160e01b0319821663e414309160e01b14806102b457506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f6102c3611a9a565b6102d06020850185614c57565b6001600160a01b0316336001600160a01b03161461031f576102f56020850185614c57565b6040516335252be360e01b81526001600160a01b0390911660048201526024015b60405180910390fd5b5f61033161032c86615336565b611ab5565b5f818152602081905260409020549091505f19016103a4575f818152602081905260408082209190915551600192507f09d18501db0080ca2d6cd7c17fa7255daff4b2d503ea93b76ff68b6752ea8e63906103919033908490899061548c565b60405180910390a16103a4818585611ae4565b506103bb60015f80516020615ff983398151915255565b9392505050565b6103ca611a9a565b3385856103d8838383611b1b565b6103e2865f611b4c565b610417576040516306dde9c360e41b81523360048201526001600160a01b038916602482015260448101889052606401610316565b5f80610424338b8a611b86565b604080513381526001600160a01b038e1660208201529081018c90526060810183905291935091507f7f9dfa19cf1cc2f806f2f860fbc9c056b601fb1afc0e9b843dfe5c63616268e69060800160405180910390a15f80610487338d8d8d611cbe565b909250905087156104fd5760408051600581526001600160a01b038e1660208201528082018d9052606081018490526080810183905260ff851660a082015260c081019091526104fd906104ee905b60408051600181526020810192909252818101905290565b6104f88a8c615550565b611dae565b5050505050505061051a60015f80516020615ff983398151915255565b5050505050565b5f61052d848484611f7c565b949350505050565b5f61054a6001600160a01b0386168786612106565b6040516323e30c8b60e01b81525f906001600160a01b038816906323e30c8b906105829033908a908a9087908b908b90600401615610565b6020604051808303815f875af115801561059e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105c29190615654565b90507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9811461060757604051630b6c58a960e31b815260048101829052602401610316565b61062887306106165f8961567f565b6001600160a01b038a1692919061213b565b5060019695505050505050565b61063d611a9a565b33858561064b838383611b1b565b5f8080806106598a82611b4c565b61068d57604051623a3a4d60e21b81523360048201526001600160a01b038d166024820152604481018c9052606401610316565b5f610699338e8e611f7c565b90506106a58b82612177565b94506106b3338e8e88612193565b90935091505f6106c4338f8861220a565b80965081925050507f8045c25080b0868951141ed0a91720bcad09a8364a2b3109ee1fd49c1f0bc8b8338f8f8f8a86604051610736969594939291906001600160a01b03968716815294909516602085015260408401929092526060830152608082015260a081019190915260c00190565b60405180910390a1505060408051600681526001600160a01b038e1660208201528082018d9052606081018490526080810183905260a081018c905260ff851660c0820152600160e08201908152610100820182905261012082019092529089156107a9576107a9816104f88c8e615550565b50505050505050505061051a60015f80516020615ff983398151915255565b6040516370a0823160e01b81523060048201525f906001600160a01b038316906370a0823190602401602060405180830381865afa15801561080c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102b49190615654565b5f8061083a611a9a565b6108476080840184615692565b90505f0361086857604051639c95219f60e01b815260040160405180910390fd5b61087061493c565b610878614968565b5f60405180606001604052808780608001906108949190615692565b5f8181106108a4576108a46156d8565b90506020028101906108b691906156ec565b6108c0908061570a565b6108ce90604081019061571e565b6108db60808b018b615692565b5f8181106108eb576108eb6156d8565b90506020028101906108fd91906156ec565b60200135818110610910576109106156d8565b6109269260206040909202019081019150614c57565b6001600160a01b031681526020016109416080890189615692565b5f818110610951576109516156d8565b905060200281019061096391906156ec565b61096d908061570a565b61097b90606081019061571e565b61098860808b018b615692565b5f818110610998576109986156d8565b90506020028101906109aa91906156ec565b604001358181106109bd576109bd6156d8565b6109d39260206040909202019081019150614c57565b6001600160a01b03168152602088810135910152905060605f6109f96080890189615692565b604080516001909201602002820181528501519093505f9250610a1d915082611b4c565b610a3a5760405163315f9e2360e21b815260040160405180910390fd5b5f5b610a4960808a018a615692565b905081108015610a6357506040840151610a63905f611b4c565b15610e7157610a7560808a018a615692565b82818110610a8557610a856156d8565b9050602002810190610a9791906156ec565b610aa090615764565b9550855f01519450835f01516001600160a01b03168560400151876020015181518110610acf57610acf6156d8565b60200260200101515f01516001600160a01b0316141580610b2a575083602001516001600160a01b03168560600151876040015181518110610b1357610b136156d8565b60200260200101515f01516001600160a01b031614155b15610b485760405163936bb5ad60e01b815260040160405180910390fd5b610b5b85876020015188604001516122e7565b5f610b6586611ab5565b5f81815260208190526040902054909150610bca578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a1610e68565b5f610c278789602001518a60400151338c606001515f67ffffffffffffffff811115610bf857610bf8614e34565b604051908082528060200260200182016040528015610c21578160200160208202803683370190505b50612359565b90505f610c458c604001358360600151611b4c90919063ffffffff16565b15610c9b578751604080513381526001600160a01b03909216602083015281018490527fe3151dc8cb7a54ffc4baabd28c1f241c94d510b5e5b502491ac3cad6c16316d5906060015b60405180910390a1610e5a565b6040820151610caa905f611b4c565b1580610cc257506060820151610cc0905f611b4c565b155b15610d0f578751604080513381526001600160a01b03909216602083015281018490527f500b713857325f9e6dcb52ae832eca9109d107ed1aae9cb4928b4c1e13f051aa90606001610c8e565b600190505f808d6060016020810190610d2891906157fa565b15610d6e576040808a015190850151610d4091612177565b6060850151909250610d52908361281e565b60408a0151909150610d64908361286b565b60408a0152610dd5565b5f610d8a8560400151866060015161281e90919063ffffffff16565b9050610da38a604001518261217790919063ffffffff16565b9150610dbc85606001518361289b90919063ffffffff16565b60408b0151909350610dce908361286b565b60408b0152505b610ddf8c826128cb565b9b50610deb8d836128cb565b9c50610df782856128fb565b610e0181856129bc565b7f194f1feb3b4d7076a2c272e774e792e0c48bb8c7aa1a9a3671c1cd6da9e6b4c1338c8484604051610e369493929190615922565b60405180910390a187516001018089526020028801849052610e5784612b68565b50505b8480610e635750805b945050505b50600101610a3c565b505f610e8360808a0160608b016157fa565b610e8d5786610e8f565b875b9050610e9c818a35612dab565b15610ec45760405163573b6f4160e01b81528935600482015260248101829052604401610316565b50610ed43384602001518961220a565b505f9050610ee560a08a018a615a0c565b9050118015610ef15750805b15610f635760208301518351339163691f9ed7918a8a610f1460a08f018f615a0c565b6040518763ffffffff1660e01b8152600401610f3596959493929190615610565b5f604051808303815f87803b158015610f4c575f80fd5b505af1158015610f5e573d5f803e3d5ffd5b505050505b610f7133845f015188611b86565b50505f5b8251811015610fa857610fa0838281518110610f9357610f936156d8565b6020026020010151612de5565b600101610f75565b505050505050610fc460015f80516020615ff983398151915255565b915091565b5f610fd2611a9a565b5f61102f61102a610fe38780615a4f565b610ff1906040810190615a0c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612eef92505050565b612f60565b90505f811161105157604051632cff108b60e21b815260040160405180910390fd5b6001811161107257604051633c8270bd60e21b815260040160405180910390fd5b61107f602086018661571e565b90505f036110a057604051636c44ef8f60e01b815260040160405180910390fd5b6110ad604086018661571e565b90505f036110ce5760405163540e5f0b60e01b815260040160405180910390fd5b6040805160a081019091523381525f90602081016110ec8880615a4f565b6110f590615a63565b815260200187806020019061110a919061571e565b808060200260200160405190810160405280939291908181526020015f905b828210156111555761114660408302860136819003810190615a6e565b81526020019060010190611129565b505050918352505060200161116d604089018961571e565b808060200260200160405190810160405280939291908181526020015f905b828210156111b8576111a960408302860136819003810190615a6e565b8152602001906001019061118c565b50505050508152602001876060013581525090505f6111d682611ab5565b5f818152602081905260409020549091501580156112f1575f828152602081905260409081902060019055835190517f87491344dfbcf91f6cbbc610cbbeedc85313d37a02df0c93527f7ea5f8db717f916112349185908790615a88565b60405180910390a15f61124a60a08a018a615a0c565b905011156112e65761129b61126260a08a018a615a0c565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250612f7a92505050565b82517fd46c2c56b35c8210e9e712ec3f02242d5fc90187c0ac8ed80cc33626846ec36990836112cd60a08c018c615a0c565b6040516112dd9493929190615aaf565b60405180910390a15b6112f1828888611ae4565b93505050506103bb60015f80516020615ff983398151915255565b5f80808061132661131d868061570a565b61032c90615336565b5f8181526020819052604090205490915060011461134d57505f92508291508190506113c7565b61137261135a868061570a565b61136390615336565b866020013587604001356122e7565b5f6113b0611380878061570a565b61138990615336565b60208801356040890135336113a160608c018c615692565b6113aa91615ae1565b5f610bf8565b905060018160400151826060015194509450945050505b9193909250565b604080515f8152602081019091526060908267ffffffffffffffff8111156113f8576113f8614e34565b60405190808252806020026020018201604052801561142b57816020015b60608152602001906001900390816114165790505b5091505f5b838110156114ac576114873086868481811061144e5761144e6156d8565b90506020028101906114609190615a0c565b8560405160200161147393929190615b00565b604051602081830303815290604052612fa5565b838281518110611499576114996156d8565b6020908102919091010152600101611430565b505092915050565b6114bc611a9a565b604080515f808252602082019092526114f4916114e9565b60608152602001906001900390816114d45790505b506104f88385615550565b61150a60015f80516020615ff983398151915255565b5050565b6040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611552573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115769190615654565b5f036115a057604051633c5bf76960e21b81526001600160a01b0384166004820152602401610316565b505f92915050565b6115b0611a9a565b835185516001600160a01b039182169116036115df57604051630a98f1f360e21b815260040160405180910390fd5b83604001518360400135815181106115f9576115f96156d8565b60200260200101515f01516001600160a01b03168560600151846020013581518110611627576116276156d8565b60200260200101515f01516001600160a01b03161415806116a0575060408501518051843590811061165b5761165b6156d8565b60200260200101515f01516001600160a01b03168460600151846060013581518110611689576116896156d8565b60200260200101515f01516001600160a01b031614155b156116be5760405163936bb5ad60e01b815260040160405180910390fd5b84606001518360200135815181106116d8576116d86156d8565b60200260200101515f01516001600160a01b03168560400151845f013581518110611705576117056156d8565b60200260200101515f01516001600160a01b03160361173757604051631cd2f1c760e21b815260040160405180910390fd5b5f61174186611ab5565b5f818152602081905260409020549091506117a7578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a150611a84565b5f6117b186611ab5565b5f81815260208190526040902054909150611818578551604080513381526001600160a01b03909216602083015281018290527fb70c12fa453793fa6818ec07c91e74363a47aa6a6829dcd9533937fdf30314f39060600160405180910390a15050611a84565b7f6fa7f4c28634b0a9d6831401c45ae468195fb63aed07308935c35374ff5d9e393388888860405161184d9493929190615b23565b60405180910390a1505083515f906118719087908635906020880135908686610bf8565b90505f6118a086866040013587606001358a5f0151885f67ffffffffffffffff811115610bf857610bf8614e34565b90505f6118ad8383613045565b90506118bc815f0151846128fb565b6118ca8160200151836128fb565b6118d88160400151846129bc565b6118e68160600151836129bc565b6118ef83612de5565b6118f882612de5565b606081015181515f9161190b919061286b565b90505f6119298360400151846020015161286b90919063ffffffff16565b9050611935825f612dab565b806119455750611945815f612dab565b1561196357604051630d86822160e01b815260040160405180910390fd5b611997338b606001518a6020013581518110611981576119816156d8565b60200260200101515f01518a6080013585611cbe565b50506119cd338a606001518a60600135815181106119b7576119b76156d8565b60200260200101515f01518a60a0013584611cbe565b5050604080513381528451602080830191909152850151818301529084015160608083019190915284015160808201527fd9fa84dd790c969daa5c33d8050dc06b4a9b59d5b42e2be5f5e8ae20447f618d925060a001905060405180910390a1611a3683612b68565b611a3f82612b68565b80516001600160e01b0316158015611a62575060208101516001600160e01b0316155b15611a80576040516321badf1f60e01b815260040160405180910390fd5b5050505b61051a60015f80516020615ff983398151915255565b611aa2613093565b60025f80516020615ff983398151915255565b5f81604051602001611ac79190615b9f565b604051602081830303815290604052805190602001209050919050565b604080516002815260208101859052338183015260608101909152611b1690611b0c906104d6565b6104f88385615550565b505050565b80611b16576040516305dbdfd960e41b81526001600160a01b03808516600483015283166024820152604401610316565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d611b7a848484846130c4565b12979650505050505050565b5f805f611b9285613198565b9050611b9e845f612dab565b15611bbc57604051632eaefac360e21b815260040160405180910390fd5b6001600160a01b038087165f90815260026020908152604080832093891683529290529081205490611bee868361286b565b90505f80611bfc8382611b4c565b15611c62575f611c0c84876131fe565b909350905080611c2257611c1f83615bb1565b92505b5f611c2d8a886131fe565b50905080611c3c85600161567f565b1015611c4a57809350600192505b611c5f6001600160a01b038c168d308761213b565b50505b5f611c6d838761322b565b50905081611c8457611c7f818561286b565b611c86565b845b6001600160a01b03808d165f908152600260209081526040808320938f1683529290522055509095509293505050505b935093915050565b5f80611cca8382612dab565b15611ceb5760405163793a8f5560e01b815260048101849052602401610316565b83611d0957611cfb86868561220a565b505f9250829150611da59050565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611d4382866128cb565b9050611d4f815f612dab565b15611d705760405163c5e12af560e01b815260048101829052602401610316565b6001600160a01b038089165f908152600160209081526040808320938b16835292815282822089835290522081905590925090505b94509492505050565b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b8651811015611f7257868181518110611e1557611e156156d8565b602002602001015193505f845f015160400151511115611f6a575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001611e8d8d8a6020015161326b565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401611eb89190615c21565b5f60405180830381865afa158015611ed2573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611ef99190810190615d19565b9150505f81511115611f685784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490611f3a908a908590600401615dcf565b5f604051808303815f87803b158015611f51575f80fd5b505af1158015611f63573d5f803e3d5ffd5b505050505b505b600101611dfa565b5050505050505050565b5f8115611fb657506001600160a01b038084165f9081526001602090815260408083209386168352928152828220848352905220546103bb565b5f611fc08461354d565b6040516370a0823160e01b81526001600160a01b0387811660048301529192505f9161203891908716906370a0823190602401602060405180830381865afa15801561200e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120329190615654565b8361322b565b50604051636eb1769f60e11b81526001600160a01b0388811660048301523060248301529192505f916120b7919088169063dd62ed3e90604401602060405180830381865afa15801561208d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120b19190615654565b8461322b565b506001600160a01b038089165f908152600160209081526040808320938b168352928152828220828052905220549091506120fc906120f68484612177565b906128cb565b93505050506103bb565b6121138383836001613559565b611b1657604051635274afe760e01b81526001600160a01b0384166004820152602401610316565b6121498484848460016135bb565b61217157604051635274afe760e01b81526001600160a01b0385166004820152602401610316565b50505050565b5f6121828383612dab565b61218c57816103bb565b5090919050565b5f8061219f8382612dab565b156121c05760405163793a8f5560e01b815260048101849052602401610316565b836121d057611cfb868685611b86565b6001600160a01b038087165f908152600160209081526040808320938916835292815282822087835290529081205490611d43828661286b565b5f805f61221685613198565b9050612222845f612dab565b1561224057604051632d1671a360e11b815260040160405180910390fd5b6001600160a01b038087165f9081526002602090815260408083209389168352929052908120546122729086906128cb565b90505f61227f82846131fe565b5090505f61228d828561322b565b50905061229a838261286b565b6001600160a01b03808b165f908152600260209081526040808320938d168352929052205581156122d9576122d96001600160a01b0389168a84612106565b509791965090945050505050565b826060015181815181106122fd576122fd6156d8565b60200260200101515f01516001600160a01b031683604001518381518110612327576123276156d8565b60200260200101515f01516001600160a01b031603611b1657604051631cd2f1c760e21b815260040160405180910390fd5b6123616149cf565b60408051600480825260a082019092526060915f9190816020015b606081526020019060019003908161237c5790505090506123d161239f8a611ab5565b8a51604080516003815260208101939093526001600160a01b0391821683820152908916606083015260808201905290565b8160018003815181106123e6576123e66156d8565b60200260200101819052505f61241b8a604001518a8151811061240b5761240b6156d8565b60200260200101515f015161354d565b90505f61246d8b5f01518c604001518c8151811061243b5761243b6156d8565b60200260200101515f01518d604001518d8151811061245c5761245c6156d8565b602002602001015160200151611f7c565b90506124fc8b604001518b81518110612488576124886156d8565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d604001518d815181106124ba576124ba6156d8565b602002602001015160200151845f801b60408051600581526020810196909652858101949094526060850192909252608084015260a083015260c08201905290565b83600160030381518110612512576125126156d8565b602002602001018190525050505f6125398a60600151898151811061240b5761240b6156d8565b90505f61257a8b5f01518c606001518b81518110612559576125596156d8565b60200260200101515f01518d606001518c8151811061245c5761245c6156d8565b90506125c78b606001518a81518110612595576125956156d8565b60200260200101515f01516001600160a01b03165f1b8360ff165f1b8d606001518c815181106124ba576124ba6156d8565b836001600403815181106125dd576125dd6156d8565b602002602001018190525050506125f4818661326b565b9150505f885f01516001600160a01b031690505f808a602001515f01516001600160a01b031663d04dfe236040518060e001604052808e60200151602001516001600160a01b0316815260200161265487305f9182526020526040902090565b81526020018e602001516040015181526020015f81526020018781526020015f67ffffffffffffffff81111561268c5761268c614e34565b6040519080825280602002602001820160405280156126b5578160200160208202803683370190505b508152602001898152506040518263ffffffff1660e01b81526004016126db9190615c21565b5f60405180830381865afa1580156126f5573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261271c9190810190615d19565b91509150600282511015612748578151604051630fbb8e5560e21b815260040161031691815260200190565b60208201516040830151855161279c908790600490811061276b5761276b6156d8565b6020026020010151600381518110612785576127856156d8565b60200260200101518261217790919063ffffffff16565b60408051600281526020810183905280820185905260608101909152909150866002815181106127ce576127ce6156d8565b60200260200101819052506040518060e001604052808e81526020018c81526020018281526020018381526020018781526020018681526020018481525096505050505050509695505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e86868686613628565b915091505f61285d8383613747565b9a9950505050505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e86868686613794565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e868686866137be565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d848061284e86868686613cfb565b818160800151600481518110612913576129136156d8565b602002602001015160048151811061292d5761292d6156d8565b602002602001018181525050612171815f01515f0151826080015160048151811061295a5761295a6156d8565b60200260200101515f81518110612973576129736156d8565b60200260200101515f1c8360800151600481518110612994576129946156d8565b60200260200101516002815181106129ae576129ae6156d8565b602002602001015185612193565b8181608001516003815181106129d4576129d46156d8565b60200260200101516004815181106129ee576129ee6156d8565b6020908102919091010152805151608082015180515f91906003908110612a1757612a176156d8565b60200260200101515f81518110612a3057612a306156d8565b60200260200101515f1c90505f8360800151600381518110612a5457612a546156d8565b6020026020010151600281518110612a6e57612a6e6156d8565b602002602001015190505f801b8103612b1557612a8b855f612dab565b15612aac5760405163793a8f5560e01b815260048101869052602401610316565b6001600160a01b038084165f908152600160209081526040808320938616835292815282822084835290522054612ae390866128cb565b6001600160a01b038085165f908152600160209081526040808320938716835292815282822085835290522055612b24565b612b2183838388611cbe565b50505b7f4cb6e22a3e7e651d7cf0376cff48f20f5007a54147777865be7f5f6c38c50f4a338560800151604051612b59929190615de7565b60405180910390a15050505050565b60c08101515115612be2578051602090810151015160a082015160c083015160405163012c676d60e21b81526001600160a01b03909316926304b19db492612bb4929091600401615dcf565b5f604051808303815f87803b158015612bcb575f80fd5b505af1158015612bdd573d5f803e3d5ffd5b505050505b5f815f0151602001515f01516001600160a01b031663d04dfe236040518060e00160405280855f015160200151602001516001600160a01b03168152602001612c388660a00151305f9182526020526040902090565b8152602001855f01516020015160400151815260200160018152602001856080015181526020015f67ffffffffffffffff811115612c7857612c78614e34565b604051908082528060200260200182016040528015612ca1578160200160208202803683370190505b5081526020015f604051908082528060200260200182016040528015612cd1578160200160208202803683370190505b508152506040518263ffffffff1660e01b8152600401612cf19190615c21565b5f60405180830381865afa158015612d0b573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612d329190810190615d19565b9150505f8151111561150a578151602090810151015160a083015160405163012c676d60e21b81526001600160a01b03909216916304b19db491612d7a918590600401615dcf565b5f604051808303815f87803b158015612d91575f80fd5b505af1158015612da3573d5f803e3d5ffd5b505050505050565b5f6001600160e01b03838116601b90810b9160e086811d9291861690910b9085901d612dd9848484846130c4565b13979650505050505050565b5f8160800151600381518110612dfd57612dfd6156d8565b6020026020010151600281518110612e1757612e176156d8565b602002602001015190505f801b810361150a57815151608083015180515f91906003908110612e4857612e486156d8565b60200260200101515f81518110612e6157612e616156d8565b6020908102919091018101516001600160a01b038481165f9081526001845260408082209284168252918452818120878252909352909120549091506001600160e01b0381161561051a576001600160a01b038084165f9081526001602090815260408083209386168352928152828220878352905290812055612ee683838361220a565b50505050505050565b6060604082511015612f0e57505060408051602081019091525f815290565b5f60208301519050602060408451612f269190615aed565b612f309190615e1c565b811115612f4c57505060408051602081019091525f8152919050565b600181016020026020840101915050919050565b5f81515f03612f7057505f919050565b50602001515f1a90565b612f8381613df9565b612fa25780604051630c89984b60e31b81526004016103169190615e3b565b50565b60605f612fb28484613e27565b9050808015612fd357505f3d1180612fd357505f846001600160a01b03163b115b15612fe857612fe0613e3a565b9150506102b4565b801561301257604051639996b31560e01b81526001600160a01b0385166004820152602401610316565b3d1561302557613020613e53565b61303e565b60405163d6bda27560e01b815260040160405180910390fd5b5092915050565b604080516080810182525f8082526020820181905291810182905260608101919091526130728383613e5e565b825260408201526130838284613e5e565b6020830152606082015292915050565b5f80516020615ff9833981519152546002036130c257604051633ee5aeb560e01b815260040160405180910390fd5b565b5f80851584151781871282861218178584141780156130e95786859250925050611da5565b505f858413156130fd575092949193919260015b8386035f8112604c8213178015613130578215613122575f8994509450505050611da5565b885f94509450505050611da5565b600a82900a8981028a82828161314857613148615e08565b0514613174578415613164575f8b965096505050505050611da5565b8a5f965096505050505050611da5565b8415613189578896509450611da59350505050565b9550879450611da59350505050565b5f805f6131a484613ec7565b909250905060018260038111156131bd576131bd615e4d565b141580156131dc57505f8260038111156131d9576131d9615e4d565b14155b156103bb57838260405163ee07877f60e01b8152600401610316929190615e61565b5f806001600160e01b038416601b0b60e085901d61321d828287613f54565b9350935050505b9250929050565b5f805f805f61323a87876140ba565b9250925092505f8061324c85856140fd565b915091508183801561325b5750815b9650965050505050509250929050565b60605f825167ffffffffffffffff81111561328857613288614e34565b6040519080825280602002602001820160405280156132b1578160200160208202803683370190505b5090505f808451116132c3575f6132c9565b83516001015b85516001010190505f8167ffffffffffffffff8111156132eb576132eb614e34565b60405190808252806020026020018201604052801561331e57816020015b60608152602001906001900390816133095790505b5090505f613342604080516002815233602082015230818301526060810190915290565b828281518110613354576133546156d8565b60200260200101819052505f5b87518110156133b1578180600101925050878181518110613384576133846156d8565b602002602001015183838151811061339e5761339e6156d8565b6020908102919091010152600101613361565b50855115613543578080600101915050838282815181106133d4576133d46156d8565b60200260200101819052505f5b8651811015613541576134908782815181106133ff576133ff6156d8565b60200260200101515f015161346d61343b8a8581518110613422576134226156d8565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b89848151811061347f5761347f6156d8565b6020026020010151604001516141d5565b6134b057604051630a57f30960e31b815260048101829052602401610316565b8681815181106134c2576134c26156d8565b60200260200101515f01516001600160a01b03165f1b8582815181106134ea576134ea6156d8565b6020026020010181815250508180600101925050868181518110613510576135106156d8565b60200260200101516020015183838151811061352e5761352e6156d8565b60209081029190910101526001016133e1565b505b5095945050505050565b5f805f6131a484614245565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f511483166135af5783831516156135a3573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f5114831661361757838315161561360b573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b5f8085158415178015613640575f92505f915061373d565b61364a8487615e9a565b91505f613656886142a4565b90505f613662876142a4565b90505f61366f83836142d2565b5090505f6f0785ee10d5da46d900f436a0000000008211156136a4576f0785ee10d5da46d900f436a000000000820491506025015b670de0b6b3a76400008211156136c557670de0b6b3a7640000820491506012015b633b9aca008211156136de57633b9aca00820491506009015b6127108211156136f357612710820491506004015b811561370757600a820491506001016136f3565b6137118187615e9a565b95506137338b8a61372d878761372887600a615f99565b6142ee565b896143ba565b9097509550505050505b5094509492505050565b5f805f61375485856140fd565b9150915080158015613764575081155b1561378c57604051638eba4d0760e01b81526004810186905260248101859052604401610316565b509392505050565b5f806137a0848461445a565b90945092506137b186868686613cfb565b9150915094509492505050565b5f80835f036137ea57604051637a97930f60e01b81526004810187905260248101869052604401610316565b855f036137fb57505f905080611da5565b5f805f806138098a8a6144af565b919b509950915061381a88886144af565b919950975090505f61382b8b6142a4565b90505f6138378a6142a4565b90507f161bcca7119915b50764b4abe86529797775a5f1719510000000000000000000604c81831015613bfc57841561388e57507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b9050604b613bd4565b6f4b3b4ca85a86c47a098a2240000000008310156139ba57678ac7230489e8000083101561391e576402540be4008310156138ec57620186a08310156138dc5750620186a090506005613b95565b506402540be4009050600a613b95565b655af3107a400083101561390b5750655af3107a40009050600e613b95565b50678ac7230489e8000090506013613b95565b6b204fce5e3e250261100000008310156139705769152d02c7e14af6800000831015613959575069152d02c7e14af680000090506017613b95565b506b204fce5e3e250261100000009050601c613b95565b6d314dc6448d9338c15b0a0000000083101561399f57506d314dc6448d9338c15b0a0000000090506021613b95565b506f4b3b4ca85a86c47a098a22400000000090506026613b95565b780197d4df19d605767337e9f14d3eec8920e400000000000000831015613ab25773af298d050e4395d69670b12b7f41000000000000831015613a4d577172cb5bd86321e38cb6ce6682e80000000000831015613a2e57507172cb5bd86321e38cb6ce6682e800000000009050602b613b95565b5073af298d050e4395d69670b12b7f4100000000000090506030613b95565b76010b46c6cdd6e3e0828f4db456ff0c8ea0000000000000831015613a8e575076010b46c6cdd6e3e0828f4db456ff0c8ea000000000000090506035613b95565b50780197d4df19d605767337e9f14d3eec8920e4000000000000009050603a613b95565b7c03b58e88c75313ec9d329eaaa18fb92f75215b17100000000000000000831015613b48577a026e4d30eccc3215dd8f3157d27e23acbdcfe68000000000000000831015613b2057507a026e4d30eccc3215dd8f3157d27e23acbdcfe680000000000000009050603f613b95565b507c03b58e88c75313ec9d329eaaa18fb92f75215b1710000000000000000090506044613b95565b7e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000831015613b9557507e05a8e89d75252446eb5d5d5b1cc5edf20a1a059e10ca000000000000000000905060495b818311613baa57600a820491505f1901613b95565b815f03613bd4576040516305e51ecb60e01b8152600481018d9052602481018c9052604401610316565b85613bfc576040516305e51ecb60e01b8152600481018f9052602481018e9052604401610316565b80600160ff1b018d12613c1357808d039c50613c51565b600160ff1b9c90038c015f811315613c5157806001600160ff1b03038b13613c3e57998a0199613c51565b5f80995099505050505050505050611da5565b5f808e128015613c6057505f8c135b15613c8157600160ff1b8e01808d13613c79575f613c7d565b808d035b9150505b8b818f01039750613c9e8f8e613c988887896142ee565b8b6143ba565b90995097505f811315613ce857604c811315613cc8575f809a509a50505050505050505050611da5565b80600a0a8981613cda57613cda615e08565b059850885f03613ce8575f97505b50969850949650611da595505050505050565b5f8085158415178015613d2757865f03613d1b5784849250925050611da5565b86869250925050611da5565b613d318787614709565b9097509550613d408585614709565b909550935085841315613d54579395929492935b838603604c811115613d6d578787935093505050611da5565b80600a0a8681613d7f57613d7f615e08565b0595505086850180881860ff90811c151589881890911c15168015613de857876001600160ff1b0303613dcf5760405163d556b11160e01b8152600481018a905260248101899052604401610316565b600a968790059690980586019760019790970196613dec565b8198505b5096979596505050505050565b5f600882511015613e0b57505f919050565b506008015167ffffffffffffffff1667ff0a89c674ee78741490565b5f805f835160208501865af49392505050565b6040513d81523d5f602083013e3d602001810160405290565b6040513d5f823e3d81fd5b5f80613e7b8460600151856040015161281e90919063ffffffff16565b915083604001519050613e9b836040015183611b4c90919063ffffffff16565b156132245782604001519150613ebe84606001518361289b90919063ffffffff16565b90509250929050565b5f80613ed1614752565b60405163b7bad1b160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb93899063b7bad1b19060240160408051808303815f875af1158015613f27573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f4b9190615fa4565b91509150915091565b5f805f851215613f8157604051634a7d166b60e01b81526004810186905260248101859052604401610316565b845f03613f9357505f90506001611cb6565b8460ff8416850185811215613fc55760405163d556b11160e01b81526004810188905260248101879052604401610316565b5f805f83121561401157604c19831215613fe8575f809550955050505050611cb6565b825f03600a0a9150818481613fff57613fff615e08565b0495505084029091149150611cb69050565b5f8313156140aa57604d83131561404e5760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b82600a0a9150815f198161406457614064615e08565b048411156140985760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610316565b5091909102925060019150611cb69050565b8360019550955050505050611cb6565b5f808060ff841681036001600160ff1b038611156140ec57600a860460018201600a88065f14935093509350506140f6565b8593509150600190505b9250925092565b5f601b83900b8314838382614161577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e100000000000000000086051561414157620186a0860595506005850194505b8586601b0b1461415c57600a86059550846001019450614141565b614177565b855f0361417757505f9250600191506132249050565b848560030b146141ba575f85121561419757505f92508291506132249050565b60405163d556b11160e01b81526004810183905260248101829052604401610316565b50506001600160e01b03841660e084901b1791509250929050565b5f836001600160a01b03163b5f03614233575f806141f385856147dd565b5090925090505f81600381111561420c5761420c615e4d565b14801561422a5750856001600160a01b0316826001600160a01b0316145b925050506103bb565b61423e848484614823565b90506103bb565b5f8061424f614752565b604051630782d7e160e01b81526001600160a01b038416600482015273200e12d10bb0c5e4a17e7018f0f1161919bb938990630782d7e1906024016040805180830381865afa158015613f27573d5f803e3d5ffd5b5f808212156142c957600160ff1b82036142c35750600160ff1b919050565b505f0390565b5090565b919050565b5f805f1983850993909202808410938190039390930393915050565b5f805f6142fb86866142d2565b91509150815f0361431f5783818161431557614315615e08565b04925050506103bb565b8382106143505760405163362ced0960e11b8152600481018790526024810186905260448101859052606401610316565b5f84868809600186198101871696879004966002600389028118808a02820302808a02820302808a02820302808a02820302808a02820302808a02909103025f82900382900490920185841190960395909502919093039390930492909217029150509392505050565b5f805f8587181215614436576001600160ff1b03841115614423576143e76001600160ff1b03600161567f565b84036143fb5750600160ff1b905081611da5565b614406600a85615e1c565b61440f90615fe4565b61441a846001615e9a565b91509150611da5565b61442c84615fe4565b8391509150611da5565b6001600160ff1b038411156144505761440f600a85615e1c565b5082905081611da5565b5f80600160ff1b84036144a5576001600160ff1b0383036144985760405163d556b11160e01b81526004810185905260248101849052604401610316565b600a840593508260010192505b50505f9190910391565b5f805f845f036144c757505f915081905060016140f6565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b85055f036146b4576f4b3b4ca85a86c47a098a224000000000850515801561452957507f80000000000000000000000000000000000000000000000000000000000000268412155b1561454a576f4b3b4ca85a86c47a098a224000000000850294506026840393505b7728c87cb5c89a2571ebfdcb54864ada834a00000000000000850515801561459257507f80000000000000000000000000000000000000000000000000000000000000138412155b156145ab57678ac7230489e80000850294506013840393505b7b097edd871cfda3a5697758bf0e3cbb5ac5741c64000000000000000085051580156145f757507f800000000000000000000000000000000000000000000000000000000000000a8412155b1561460d576402540be40085029450600a840393505b7e3899162693736ac531a5a58f1fbb4b746504382ca7e4000000000000000000850515801561465c57507f80000000000000000000000000000000000000000000000000000000000000028412155b156146725760648502945060028403935061460d565b7546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b85051580156146a257506001600160ff1b018412155b156146b457600a850294506001840393505b600a808602908105861480156146d157506001600160ff1b018512155b156146e0578095506001850394505b50939492935050507546bf5bb0385045767e0f0ef2e7aa1e517e454637d1dd604b1b8305151590565b5f805f805f61471887876144af565b92509250925080614746576040516305e51ecb60e01b81526004810188905260248101879052604401610316565b50909590945092505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b15806147a9575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b156130c2576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610316565b5f805f8351604103614814576020840151604085015160608601515f1a61480688828585614874565b9550955095505050506140f6565b505081515f91506002906140f6565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156148ad57505f91506003905082614932565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa1580156148fe573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661492957505f925060019150829050614932565b92505f91508190505b9450945094915050565b604051806080016040528061494f614968565b81526020015f81526020015f8152602001606081525090565b6040518060a001604052805f6001600160a01b031681526020016149b660405180606001604052805f6001600160a01b031681526020015f6001600160a01b03168152602001606081525090565b8152606060208201819052604082018190525f91015290565b6040518060e001604052806149e2614968565b81526020015f81526020015f80191681526020015f8019168152602001606081526020015f8152602001606081525090565b5f60208284031215614a24575f80fd5b81356001600160e01b0319811681146103bb575f80fd5b5f8083601f840112614a4b575f80fd5b50813567ffffffffffffffff811115614a62575f80fd5b6020830191508360208260051b8501011115613224575f80fd5b5f805f60408486031215614a8e575f80fd5b833567ffffffffffffffff80821115614aa5575f80fd5b9085019060a08288031215614ab8575f80fd5b90935060208501359080821115614acd575f80fd5b50614ada86828701614a3b565b9497909650939450505050565b5f60208284031215614af7575f80fd5b5035919050565b6001600160a01b0381168114612fa2575f80fd5b80356142cd81614afe565b5f805f805f60808688031215614b31575f80fd5b8535614b3c81614afe565b94506020860135935060408601359250606086013567ffffffffffffffff811115614b65575f80fd5b614b7188828901614a3b565b969995985093965092949392505050565b5f805f60608486031215614b94575f80fd5b8335614b9f81614afe565b92506020840135614baf81614afe565b929592945050506040919091013590565b5f805f805f60808688031215614bd4575f80fd5b8535614bdf81614afe565b94506020860135614bef81614afe565b935060408601359250606086013567ffffffffffffffff80821115614c12575f80fd5b818801915088601f830112614c25575f80fd5b813581811115614c33575f80fd5b896020828501011115614c44575f80fd5b9699959850939650602001949392505050565b5f60208284031215614c67575f80fd5b81356103bb81614afe565b5f60c08284031215614c82575f80fd5b50919050565b5f60208284031215614c98575f80fd5b813567ffffffffffffffff811115614cae575f80fd5b61052d84828501614c72565b5f805f60408486031215614ccc575f80fd5b833567ffffffffffffffff80821115614ce3575f80fd5b614cef87838801614c72565b94506020860135915080821115614acd575f80fd5b5f60208284031215614d14575f80fd5b813567ffffffffffffffff811115614d2a575f80fd5b8201608081850312156103bb575f80fd5b5f8060208385031215614d4c575f80fd5b823567ffffffffffffffff811115614d62575f80fd5b614d6e85828601614a3b565b90969095509350505050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f60208083016020845280855180835260408601915060408160051b8701019250602087015f5b82811015614dfd57603f19888603018452614deb858351614d7a565b94509285019290850190600101614dcf565b5092979650505050505050565b5f8060408385031215614e1b575f80fd5b8235614e2681614afe565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff81118282101715614e6b57614e6b614e34565b60405290565b6040805190810167ffffffffffffffff81118282101715614e6b57614e6b614e34565b60405160a0810167ffffffffffffffff81118282101715614e6b57614e6b614e34565b604051601f8201601f1916810167ffffffffffffffff81118282101715614ee057614ee0614e34565b604052919050565b5f82601f830112614ef7575f80fd5b813567ffffffffffffffff811115614f1157614f11614e34565b614f24601f8201601f1916602001614eb7565b818152846020838601011115614f38575f80fd5b816020850160208301375f918101602001919091529392505050565b5f60608284031215614f64575f80fd5b614f6c614e48565b90508135614f7981614afe565b81526020820135614f8981614afe565b6020820152604082013567ffffffffffffffff811115614fa7575f80fd5b614fb384828501614ee8565b60408301525092915050565b5f67ffffffffffffffff821115614fd857614fd8614e34565b5060051b60200190565b5f60408284031215614ff2575f80fd5b614ffa614e71565b9050813561500781614afe565b808252506020820135602082015292915050565b5f82601f83011261502a575f80fd5b8135602061503f61503a83614fbf565b614eb7565b8083825260208201915060208460061b870101935086841115615060575f80fd5b602086015b84811015615085576150778882614fe2565b835291830191604001615065565b509695505050505050565b5f60a082840312156150a0575f80fd5b6150a8614e94565b90506150b382614b12565b8152602082013567ffffffffffffffff808211156150cf575f80fd5b6150db85838601614f54565b602084015260408401359150808211156150f3575f80fd5b6150ff8583860161501b565b60408401526060840135915080821115615117575f80fd5b506151248482850161501b565b6060830152506080820135608082015292915050565b5f61514761503a84614fbf565b8381529050602080820190600585811b850187811115615165575f80fd5b855b8181101561525257803567ffffffffffffffff80821115615186575f80fd5b908801906060828c031215615199575f80fd5b6151a1614e48565b82356151ac81614afe565b815282870135828111156151be575f80fd5b8301601f81018d136151ce575f80fd5b80356151dc61503a82614fbf565b81815290881b8201890190898101908f8311156151f7575f80fd5b928a01925b828410156152155783358252928a0192908a01906151fc565b848b0152506040915050838101358381111561522f575f80fd5b61523b8e828701614ee8565b918301919091525087525050938301938301615167565b50505050509392505050565b5f82601f83011261526d575f80fd5b6103bb8383356020850161513a565b5f805f805f6101408688031215615291575f80fd5b853567ffffffffffffffff808211156152a8575f80fd5b6152b489838a01615090565b965060208801359150808211156152c9575f80fd5b6152d589838a01615090565b95506152e48960408a01614c72565b94506101008801359150808211156152fa575f80fd5b61530689838a0161525e565b935061012088013591508082111561531c575f80fd5b506153298882890161525e565b9150509295509295909350565b5f6102b43683615090565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f813561537581614afe565b6001600160a01b03908116845260208301359061539182614afe565b166020840152604082013536839003601e190181126153ae575f80fd5b820160208101903567ffffffffffffffff8111156153ca575f80fd5b8036038213156153d8575f80fd5b606060408601526153ed606086018284615341565b95945050505050565b5f808335601e1984360301811261540b575f80fd5b830160208101925035905067ffffffffffffffff81111561542a575f80fd5b8060061b3603821315613224575f80fd5b8183525f60208085019450825f5b8581101561548157813561545c81614afe565b6001600160a01b03168752818301358388015260409687019690910190600101615449565b509495945050505050565b5f6001600160a01b0380861683528460208401526060604084015283356154b281614afe565b166060830152602083013536849003605e190181126154cf575f80fd5b60a060808401526154e66101008401858301615369565b90506154f560408501856153f6565b605f19808685030160a087015261550d84838561543b565b935061551c60608801886153f6565b93509150808685030160c08701525061553683838361543b565b92505050608084013560e084015280915050949350505050565b5f61555d61503a84614fbf565b80848252602080830192508560051b85013681111561557a575f80fd5b855b8181101561560457803567ffffffffffffffff8082111561559b575f80fd5b8189019150604082360312156155af575f80fd5b6155b7614e71565b8235828111156155c5575f80fd5b6155d136828601614f54565b82525085830135828111156155e4575f80fd5b6155f03682860161525e565b82880152508752505093820193820161557c565b50919695505050505050565b5f6001600160a01b03808916835280881660208401525085604083015284606083015260a0608083015261564860a083018486615341565b98975050505050505050565b5f60208284031215615664575f80fd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156102b4576102b461566b565b5f808335601e198436030181126156a7575f80fd5b83018035915067ffffffffffffffff8211156156c1575f80fd5b6020019150600581901b3603821315613224575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e19833603018112615700575f80fd5b9190910192915050565b5f8235609e19833603018112615700575f80fd5b5f808335601e19843603018112615733575f80fd5b83018035915067ffffffffffffffff82111561574d575f80fd5b6020019150600681901b3603821315613224575f80fd5b5f60808236031215615774575f80fd5b6040516080810167ffffffffffffffff828210818311171561579857615798614e34565b8160405284359150808211156157ac575f80fd5b6157b836838701615090565b8352602085013560208401526040850135604084015260608501359150808211156157e1575f80fd5b506157ee3682860161525e565b60608301525092915050565b5f6020828403121561580a575f80fd5b813580151581146103bb575f80fd5b5f815180845260208085019450602084015f5b8381101561548157815180516001600160a01b03168852830151838801526040909601959082019060010161582c565b5f6001600160a01b03808351168452602083015160a060208601528181511660a08601528160208201511660c08601526040810151915050606060e08501526158a9610100850182614d7a565b9050604083015184820360408601526158c28282615819565b915050606083015184820360608601526158dc8282615819565b915050608083015160808501528091505092915050565b5f815180845260208085019450602084015f5b8381101561548157815187529582019590820190600101615906565b5f6001600160a01b0380871683526020608081850152865160808086015261594e61010086018261585c565b90508188015160a086015260408089015160c08701526060808a0151607f198885030160e08901528381518086528686019150868160051b87010187840193505f5b828110156159ea57601f1988830301845284518a815116835289810151878b8501526159be888501826158f3565b91890151848303858b01529190506159d68183614d7a565b968b0196958b019593505050600101615990565b5080995050505050505050505083604083015282606083015295945050505050565b5f808335601e19843603018112615a21575f80fd5b83018035915067ffffffffffffffff821115615a3b575f80fd5b602001915036819003821315613224575f80fd5b5f8235605e19833603018112615700575f80fd5b5f6102b43683614f54565b5f60408284031215615a7e575f80fd5b6103bb8383614fe2565b6001600160a01b0384168152826020820152606060408201525f6153ed606083018461585c565b6001600160a01b0385168152836020820152606060408201525f615ad7606083018486615341565b9695505050505050565b5f6103bb36848461513a565b818103818111156102b4576102b461566b565b828482375f8382015f815283518060208601835e5f910190815295945050505050565b5f6101206001600160a01b0387168352806020840152615b458184018761585c565b90508281036040840152615b59818661585c565b9150508235606083015260208301356080830152604083013560a0830152606083013560c0830152608083013560e083015260a083013561010083015295945050505050565b602081525f6103bb602083018461585c565b5f60018201615bc257615bc261566b565b5060010190565b5f8282518085526020808601955060208260051b840101602086015f5b84811015615c1457601f19868403018952615c028383516158f3565b98840198925090830190600101615be6565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e06060840152615c5a610100840182614d7a565b9050606084015160808401526080840151601f19808584030160a0860152615c828383615bc9565b925060a08601519150808584030160c0860152615c9f83836158f3565b925060c08601519150808584030160e0860152506153ed82826158f3565b5f82601f830112615ccc575f80fd5b81516020615cdc61503a83614fbf565b8083825260208201915060208460051b870101935086841115615cfd575f80fd5b602086015b848110156150855780518352918301918301615d02565b5f8060408385031215615d2a575f80fd5b825167ffffffffffffffff80821115615d41575f80fd5b818501915085601f830112615d54575f80fd5b81516020615d6461503a83614fbf565b82815260059290921b84018101918181019089841115615d82575f80fd5b948201945b83861015615da057855182529482019490820190615d87565b91880151919650909350505080821115615db8575f80fd5b50615dc585828601615cbd565b9150509250929050565b828152604060208201525f61052d60408301846158f3565b6001600160a01b0383168152604060208201525f61052d6040830184615bc9565b634e487b7160e01b5f52601260045260245ffd5b5f82615e3657634e487b7160e01b5f52601260045260245ffd5b500490565b602081525f6103bb6020830184614d7a565b634e487b7160e01b5f52602160045260245ffd5b6001600160a01b03831681526040810160048310615e8d57634e487b7160e01b5f52602160045260245ffd5b8260208301529392505050565b8082018281125f8312801582168215821617156114ac576114ac61566b565b600181815b80851115615ef357815f1904821115615ed957615ed961566b565b80851615615ee657918102915b93841c9390800290615ebe565b509250929050565b5f82615f09575060016102b4565b81615f1557505f6102b4565b8160018114615f2b5760028114615f3557615f51565b60019150506102b4565b60ff841115615f4657615f4661566b565b50506001821b6102b4565b5060208310610133831016604e8410600b8410161715615f74575081810a6102b4565b615f7e8383615eb9565b805f1904821115615f9157615f9161566b565b029392505050565b5f6103bb8383615efb565b5f8060408385031215615fb5575f80fd5b825160048110615fc3575f80fd5b602084015190925060ff81168114615fd9575f80fd5b809150509250929050565b5f600160ff1b82016142c3576142c361566b56fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00"; diff --git a/src/generated/RouteProcessorRaindexV6ArbOrderTaker.pointers.sol b/src/generated/RouteProcessorRaindexV6ArbOrderTaker.pointers.sol index ff62d82305..2a49bd9c5e 100644 --- a/src/generated/RouteProcessorRaindexV6ArbOrderTaker.pointers.sol +++ b/src/generated/RouteProcessorRaindexV6ArbOrderTaker.pointers.sol @@ -10,12 +10,12 @@ pragma solidity ^0.8.25; // file needs the contract to exist so that it can be compiled. /// @dev Hash of the known bytecode. -bytes32 constant BYTECODE_HASH = bytes32(0xc3fb3bb0355fee22e54cade57f5ff828478d59f34fdd8057bc0bc6a11b3d48fc); +bytes32 constant BYTECODE_HASH = bytes32(0xebca76aecd91efeee0840b70028dda00c90b06266c1bea04d5367a58d5e7f751); /// @dev The deterministic deploy address of the contract when deployed via /// the Zoltu factory. -address constant DEPLOYED_ADDRESS = address(0x5Ec2625ee7c73c85fAb2bc4cf527E1434F0dcC5d); +address constant DEPLOYED_ADDRESS = address(0xDd436bd0e92389e1c45E6Af5F0C2D989c626d49e); /// @dev The runtime bytecode of the contract. bytes constant RUNTIME_CODE = - hex"608060405260043610610034575f3560e01c806301ffc9a71461003d578063691f9ed714610070578063b17c83c11461008f57005b3661003b57005b005b348015610048575f80fd5b5061005c610057366004611458565b6100a2565b604051901515815260200160405180910390f35b34801561007b575f80fd5b5061003b61008a366004611493565b6100f3565b61003b61009d366004611535565b610200565b5f6001600160e01b0319821663691f9ed760e01b14806100d257506001600160e01b0319821663b17c83c160e01b145b806100ed57506301ffc9a760e01b6001600160e01b03198316145b92915050565b736e2d0e71d900474b262e545bc4c98b71ab368d2161011d6001600160a01b038816825f196104c2565b5f61012a838501856116b0565b90505f61013f8761013a8b61053c565b6105c0565b5090505f806101518861013a8c61053c565b91509150806101685781610164816116ea565b9250505b604051632646478b60e01b81526001600160a01b03861690632646478b9061019e908e9087908f90889030908c9060040161173c565b6020604051808303815f875af11580156101ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101de9190611787565b506101f36001600160a01b038c16865f6104c2565b5050505050505050505050565b610208610602565b6102176102148261190a565b50565b61022460808301836119c6565b90505f0361024557604051639c95219f60e01b815260040160405180910390fd5b6001600160a01b0383167386594ac4319230870c6e587f4aca48fab575619e146102925760405163516e822d60e01b81526001600160a01b03841660048201526024015b60405180910390fd5b5f6102a060808401846119c6565b5f8181106102b0576102b0611a0c565b90506020028101906102c29190611a20565b6102cc9080611a3e565b6102da906040810190611a52565b6102e760808601866119c6565b5f8181106102f7576102f7611a0c565b90506020028101906103099190611a20565b6020013581811061031c5761031c611a0c565b6103329260206040909202019081019150611a98565b90505f61034260808501856119c6565b5f81811061035257610352611a0c565b90506020028101906103649190611a20565b61036e9080611a3e565b61037c906060810190611a52565b61038960808701876119c6565b5f81811061039957610399611a0c565b90506020028101906103ab9190611a20565b604001358181106103be576103be611a0c565b6103d49260206040909202019081019150611a98565b90506103eb6001600160a01b038316865f196104c2565b6040516334e3942b60e11b81526001600160a01b038616906369c7285690610417908790600401611cfc565b60408051808303815f875af1158015610432573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104569190611efc565b5061046d90506001600160a01b038316865f6104c2565b6104926104798461190a565b836104838561053c565b8461048d8661053c565b610630565b50506104bd60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050565b6104ce8383835f6108cf565b6104bd576104df83835f60016108cf565b61050757604051635274afe760e01b81526001600160a01b0384166004820152602401610289565b61051483838360016108cf565b6104bd57604051635274afe760e01b81526001600160a01b0384166004820152602401610289565b5f610545610931565b6040516354636d2b60e01b81526001600160a01b038316600482015273200e12d10bb0c5e4a17e7018f0f1161919bb9389906354636d2b906024016020604051808303815f875af115801561059c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100ed9190611f1e565b5f807bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8416601b0b60e085901d6105f48282876109be565b9350935050505b9250929050565b61060a610b27565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6040805160018082528183019092525f91816020015b6060815260200190600190039081610646575050604080516003808252608082019092529192505f919060208201606080368337019050506040516370a0823160e01b81523060048201529091505f906001600160a01b038816906370a0823190602401602060405180830381865afa1580156106c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106e99190611787565b90508015610705576107056001600160a01b0388163383610b69565b5f6107108288610b76565b50905080835f8151811061072657610726611a0c565b602090810291909101015250506040516370a0823160e01b81523060048201525f906001600160a01b038616906370a0823190602401602060405180830381865afa158015610777573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061079b9190611787565b905080156107b7576107b76001600160a01b0386163383610b69565b5f6107c28286610b76565b50905080836001815181106107d9576107d9611a0c565b60209081029190910101525047905080156107f8576107f83382610bb6565b5f610804826012610b76565b509050808360028151811061081b5761081b611a0c565b602002602001018181525050505080825f8151811061083c5761083c611a0c565b60209081029190910101526040805160018082528183019092525f91816020015b6040805160a0810182525f918101828152606080830193909352608082018390528152602081019190915281526020019060019003908161085d57905050905087815f815181106108b0576108b0611a0c565b60200260200101819052506108c58382610c2d565b5050505050505050565b60405163095ea7b360e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316610925578383151615610919573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b1580610988575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b156109bc576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610289565b565b5f805f8512156109eb57604051634a7d166b60e01b81526004810186905260248101859052604401610289565b845f036109fd57505f90506001610b1f565b8460ff8416850185811215610a2f5760405163d556b11160e01b81526004810188905260248101879052604401610289565b5f805f831215610a7b57604c19831215610a52575f809550955050505050610b1f565b825f03600a0a9150818481610a6957610a69611f3e565b0495505084029091149150610b1f9050565b5f831315610b1457604d831315610ab85760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610289565b82600a0a9150815f1981610ace57610ace611f3e565b04841115610b025760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610289565b5091909102925060019150610b1f9050565b509193506001925050505b935093915050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00546002036109bc57604051633ee5aeb560e01b815260040160405180910390fd5b6105148383836001610df1565b5f805f805f610b858787610e3b565b9250925092505f80610b978585610e97565b9150915081838015610ba65750815b9650965050505050509250929050565b80471015610be05760405163cf47918160e01b815247600482015260248101829052604401610289565b610bf9828260405180602001604052805f815250610f84565b15610c02575050565b3d15610c1457610c10610f99565b5050565b60405163d6bda27560e01b815260040160405180910390fd5b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b86518110156108c557868181518110610c9457610c94611a0c565b602002602001015193505f845f015160400151511115610de9575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001610d0c8d8a60200151610fa4565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401610d379190611fd9565b5f60405180830381865afa158015610d51573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610d7891908101906120da565b9150505f81511115610de75784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490610db9908a908590600401612190565b5f604051808303815f87803b158015610dd0575f80fd5b505af1158015610de2573d5f803e3d5ffd5b505050505b505b600101610c79565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316610925578383151615610919573d5f823e3d81fd5b5f808060ff841681037f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff861115610e8657600a860460018201600a88065f1493509350935050610e90565b8593509150600190505b9250925092565b5f601b83900b8314838382610efb577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e1000000000000000000860515610edb57620186a0860595506005850194505b8586601b0b14610ef657600a86059550846001019450610edb565b610f11565b855f03610f1157505f9250600191506105fb9050565b848560030b14610f54575f851215610f3157505f92508291506105fb9050565b60405163d556b11160e01b81526004810183905260248101829052604401610289565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791509250929050565b5f805f83516020850186885af1949350505050565b6040513d5f823e3d81fd5b60605f825167ffffffffffffffff811115610fc157610fc16115b3565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b5090505f80845111610ffc575f611002565b83516001015b85516001010190505f8167ffffffffffffffff811115611024576110246115b3565b60405190808252806020026020018201604052801561105757816020015b60608152602001906001900390816110425790505b5090505f61107b604080516002815233602082015230818301526060810190915290565b82828151811061108d5761108d611a0c565b60200260200101819052505f5b87518110156110ea5781806001019250508781815181106110bd576110bd611a0c565b60200260200101518383815181106110d7576110d7611a0c565b602090810291909101015260010161109a565b5085511561127c5780806001019150508382828151811061110d5761110d611a0c565b60200260200101819052505f5b865181101561127a576111c987828151811061113857611138611a0c565b60200260200101515f01516111a66111748a858151811061115b5761115b611a0c565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b8984815181106111b8576111b8611a0c565b602002602001015160400151611286565b6111e957604051630a57f30960e31b815260048101829052602401610289565b8681815181106111fb576111fb611a0c565b60200260200101515f01516001600160a01b03165f1b85828151811061122357611223611a0c565b602002602001018181525050818060010192505086818151811061124957611249611a0c565b60200260200101516020015183838151811061126757611267611a0c565b602090810291909101015260010161111a565b505b5095945050505050565b5f836001600160a01b03163b5f036112e4575f806112a485856112f9565b5090925090505f8160038111156112bd576112bd6121a8565b1480156112db5750856001600160a01b0316826001600160a01b0316145b925050506112f2565b6112ef84848461133f565b90505b9392505050565b5f805f8351604103611330576020840151604085015160608601515f1a61132288828585611390565b955095509550505050610e90565b505081515f9150600290610e90565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156113c957505f9150600390508261144e565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561141a573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661144557505f92506001915082905061144e565b92505f91508190505b9450945094915050565b5f60208284031215611468575f80fd5b81356001600160e01b0319811681146112f2575f80fd5b6001600160a01b0381168114610214575f80fd5b5f805f805f8060a087890312156114a8575f80fd5b86356114b38161147f565b955060208701356114c38161147f565b94506040870135935060608701359250608087013567ffffffffffffffff808211156114ed575f80fd5b818901915089601f830112611500575f80fd5b81358181111561150e575f80fd5b8a602082850101111561151f575f80fd5b6020830194508093505050509295509295509295565b5f805f60608486031215611547575f80fd5b83356115528161147f565b9250602084013567ffffffffffffffff8082111561156e575f80fd5b9085019060c08288031215611581575f80fd5b90925060408501359080821115611596575f80fd5b508401604081870312156115a8575f80fd5b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156115ea576115ea6115b3565b60405290565b6040805190810167ffffffffffffffff811182821017156115ea576115ea6115b3565b604051601f8201601f1916810167ffffffffffffffff8111828210171561163c5761163c6115b3565b604052919050565b5f82601f830112611653575f80fd5b813567ffffffffffffffff81111561166d5761166d6115b3565b611680601f8201601f1916602001611613565b818152846020838601011115611694575f80fd5b816020850160208301375f918101602001919091529392505050565b5f602082840312156116c0575f80fd5b813567ffffffffffffffff8111156116d6575f80fd5b6116e284828501611644565b949350505050565b5f6001820161170757634e487b7160e01b5f52601160045260245ffd5b5060010190565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f6001600160a01b038089168352876020840152808716604084015285606084015280851660808401525060c060a083015261177b60c083018461170e565b98975050505050505050565b5f60208284031215611797575f80fd5b5051919050565b5f67ffffffffffffffff8211156117b7576117b76115b3565b5060051b60200190565b5f82601f8301126117d0575f80fd5b813560206117e56117e08361179e565b611613565b82815260059290921b84018101918181019086841115611803575f80fd5b8286015b848110156118ff57803567ffffffffffffffff80821115611826575f80fd5b908801906060828b03601f1901121561183d575f80fd5b6118456115c7565b868301356118528161147f565b815260408381013583811115611866575f80fd5b8401603f81018d13611876575f80fd5b888101356118866117e08261179e565b81815260059190911b82018301908a8101908f8311156118a4575f80fd5b928401925b828410156118c25783358252928b0192908b01906118a9565b858c01525050506060840135838111156118da575f80fd5b6118e88d8a83880101611644565b918301919091525085525050918301918301611807565b509695505050505050565b5f6040823603121561191a575f80fd5b6119226115f0565b823567ffffffffffffffff80821115611939575f80fd5b81850191506060823603121561194d575f80fd5b6119556115c7565b82356119608161147f565b815260208301356119708161147f565b6020820152604083013582811115611986575f80fd5b61199236828601611644565b604083015250835260208501359150808211156119ad575f80fd5b506119ba368286016117c1565b60208301525092915050565b5f808335601e198436030181126119db575f80fd5b83018035915067ffffffffffffffff8211156119f5575f80fd5b6020019150600581901b36038213156105fb575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e19833603018112611a34575f80fd5b9190910192915050565b5f8235609e19833603018112611a34575f80fd5b5f808335601e19843603018112611a67575f80fd5b83018035915067ffffffffffffffff821115611a81575f80fd5b6020019150600681901b36038213156105fb575f80fd5b5f60208284031215611aa8575f80fd5b81356112f28161147f565b5f808335601e19843603018112611ac8575f80fd5b830160208101925035905067ffffffffffffffff811115611ae7575f80fd5b8060051b36038213156105fb575f80fd5b5f8235605e19833603018112611b0c575f80fd5b90910192915050565b5f808335601e19843603018112611b2a575f80fd5b830160208101925035905067ffffffffffffffff811115611b49575f80fd5b8036038213156105fb575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f808335601e19843603018112611b94575f80fd5b830160208101925035905067ffffffffffffffff811115611bb3575f80fd5b8060061b36038213156105fb575f80fd5b8183525f60208085019450825f5b85811015611c0a578135611be58161147f565b6001600160a01b03168752818301358388015260409687019690910190600101611bd2565b509495945050505050565b8183526020808401935f91600585811b8301820185855b88811015611cee57858303601f19018a52611c478289611af8565b60608135611c548161147f565b6001600160a01b03168552611c6b82880183611ab3565b82898801528083880152608092507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115611ca5575f80fd5b871b808288850137860190506040611cbf84820185611b15565b9450838884030182890152611cd78484018683611b57565b9e8a019e9750505093870193505050600101611c2c565b509098975050505050505050565b5f602080835260e08301843582850152604082860135818601526060818701358187015280870135801515808214611d32575f80fd5b8060808901525050611d476080880188611ab3565b60c060a08901529384905261010093848801600582901b89018601835f5b84811015611ec3578b830360ff19018452813536879003607e19018112611d8a575f80fd5b8601803536829003609e19018112611da0575f80fd5b6080855281018035611db18161147f565b6001600160a01b038082166080880152611dcd8e840184611af8565b915060a0808801528135611de08161147f565b8116610120880152818e0135611df58161147f565b16610140870152611e08818c0182611b15565b91508a610160880152611e2061018088018383611b57565b915050611e2f8b830183611b7f565b607f19808985030160c08a0152611e47848385611bc4565b9350611e558d860186611b7f565b93509150808985030160e08a015250611e6f838383611bc4565b9250505060808201358c8701528c8301358d8701528a8301358b870152611e988a840184611ab3565b935091508581038a870152611eae818484611c15565b968d019695505050918a019150600101611d65565b5050611ed260a08c018c611b15565b8b8303601f190160c08d015298509650611eed818989611b57565b9b9a5050505050505050505050565b5f8060408385031215611f0d575f80fd5b505080516020909101519092909150565b5f60208284031215611f2e575f80fd5b815160ff811681146112f2575f80fd5b634e487b7160e01b5f52601260045260245ffd5b5f815180845260208085019450602084015f5b83811015611c0a57815187529582019590820190600101611f65565b5f8282518085526020808601955060208260051b840101602086015f5b84811015611fcc57601f19868403018952611fba838351611f52565b98840198925090830190600101611f9e565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e0606084015261201261010084018261170e565b9050606084015160808401526080840151601f19808584030160a086015261203a8383611f81565b925060a08601519150808584030160c08601526120578383611f52565b925060c08601519150808584030160e0860152506120758282611f52565b95945050505050565b5f82601f83011261208d575f80fd5b8151602061209d6117e08361179e565b8083825260208201915060208460051b8701019350868411156120be575f80fd5b602086015b848110156118ff57805183529183019183016120c3565b5f80604083850312156120eb575f80fd5b825167ffffffffffffffff80821115612102575f80fd5b818501915085601f830112612115575f80fd5b815160206121256117e08361179e565b82815260059290921b84018101918181019089841115612143575f80fd5b948201945b8386101561216157855182529482019490820190612148565b91880151919650909350505080821115612179575f80fd5b506121868582860161207e565b9150509250929050565b828152604060208201525f6116e26040830184611f52565b634e487b7160e01b5f52602160045260245ffd"; + hex"608060405260043610610034575f3560e01c806301ffc9a71461003d578063691f9ed714610070578063b17c83c11461008f57005b3661003b57005b005b348015610048575f80fd5b5061005c610057366004611458565b6100a2565b604051901515815260200160405180910390f35b34801561007b575f80fd5b5061003b61008a366004611493565b6100f3565b61003b61009d366004611535565b610200565b5f6001600160e01b0319821663691f9ed760e01b14806100d257506001600160e01b0319821663b17c83c160e01b145b806100ed57506301ffc9a760e01b6001600160e01b03198316145b92915050565b736e2d0e71d900474b262e545bc4c98b71ab368d2161011d6001600160a01b038816825f196104c2565b5f61012a838501856116b0565b90505f61013f8761013a8b61053c565b6105c0565b5090505f806101518861013a8c61053c565b91509150806101685781610164816116ea565b9250505b604051632646478b60e01b81526001600160a01b03861690632646478b9061019e908e9087908f90889030908c9060040161173c565b6020604051808303815f875af11580156101ba573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101de9190611787565b506101f36001600160a01b038c16865f6104c2565b5050505050505050505050565b610208610602565b6102176102148261190a565b50565b61022460808301836119c6565b90505f0361024557604051639c95219f60e01b815260040160405180910390fd5b6001600160a01b0383167366f51a9c29480491c9282d99cf324e9f419a4e1d146102925760405163516e822d60e01b81526001600160a01b03841660048201526024015b60405180910390fd5b5f6102a060808401846119c6565b5f8181106102b0576102b0611a0c565b90506020028101906102c29190611a20565b6102cc9080611a3e565b6102da906040810190611a52565b6102e760808601866119c6565b5f8181106102f7576102f7611a0c565b90506020028101906103099190611a20565b6020013581811061031c5761031c611a0c565b6103329260206040909202019081019150611a98565b90505f61034260808501856119c6565b5f81811061035257610352611a0c565b90506020028101906103649190611a20565b61036e9080611a3e565b61037c906060810190611a52565b61038960808701876119c6565b5f81811061039957610399611a0c565b90506020028101906103ab9190611a20565b604001358181106103be576103be611a0c565b6103d49260206040909202019081019150611a98565b90506103eb6001600160a01b038316865f196104c2565b6040516334e3942b60e11b81526001600160a01b038616906369c7285690610417908790600401611cfc565b60408051808303815f875af1158015610432573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104569190611efc565b5061046d90506001600160a01b038316865f6104c2565b6104926104798461190a565b836104838561053c565b8461048d8661053c565b610630565b50506104bd60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b505050565b6104ce8383835f6108cf565b6104bd576104df83835f60016108cf565b61050757604051635274afe760e01b81526001600160a01b0384166004820152602401610289565b61051483838360016108cf565b6104bd57604051635274afe760e01b81526001600160a01b0384166004820152602401610289565b5f610545610931565b6040516354636d2b60e01b81526001600160a01b038316600482015273200e12d10bb0c5e4a17e7018f0f1161919bb9389906354636d2b906024016020604051808303815f875af115801561059c573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100ed9190611f1e565b5f807bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8416601b0b60e085901d6105f48282876109be565b9350935050505b9250929050565b61060a610b27565b60027f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f0055565b6040805160018082528183019092525f91816020015b6060815260200190600190039081610646575050604080516003808252608082019092529192505f919060208201606080368337019050506040516370a0823160e01b81523060048201529091505f906001600160a01b038816906370a0823190602401602060405180830381865afa1580156106c5573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106e99190611787565b90508015610705576107056001600160a01b0388163383610b69565b5f6107108288610b76565b50905080835f8151811061072657610726611a0c565b602090810291909101015250506040516370a0823160e01b81523060048201525f906001600160a01b038616906370a0823190602401602060405180830381865afa158015610777573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061079b9190611787565b905080156107b7576107b76001600160a01b0386163383610b69565b5f6107c28286610b76565b50905080836001815181106107d9576107d9611a0c565b60209081029190910101525047905080156107f8576107f83382610bb6565b5f610804826012610b76565b509050808360028151811061081b5761081b611a0c565b602002602001018181525050505080825f8151811061083c5761083c611a0c565b60209081029190910101526040805160018082528183019092525f91816020015b6040805160a0810182525f918101828152606080830193909352608082018390528152602081019190915281526020019060019003908161085d57905050905087815f815181106108b0576108b0611a0c565b60200260200101819052506108c58382610c2d565b5050505050505050565b60405163095ea7b360e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316610925578383151615610919573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b73200e12d10bb0c5e4a17e7018f0f1161919bb93893b1580610988575073200e12d10bb0c5e4a17e7018f0f1161919bb93893f7f1de7d717526cba131d684e312dedbf0852adef9cced9e36798ae4937f7145d4114155b156109bc576040516373e6d7b360e01b815273200e12d10bb0c5e4a17e7018f0f1161919bb93896004820152602401610289565b565b5f805f8512156109eb57604051634a7d166b60e01b81526004810186905260248101859052604401610289565b845f036109fd57505f90506001610b1f565b8460ff8416850185811215610a2f5760405163d556b11160e01b81526004810188905260248101879052604401610289565b5f805f831215610a7b57604c19831215610a52575f809550955050505050610b1f565b825f03600a0a9150818481610a6957610a69611f3e565b0495505084029091149150610b1f9050565b5f831315610b1457604d831315610ab85760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610289565b82600a0a9150815f1981610ace57610ace611f3e565b04841115610b025760405163c849483b60e01b8152600481018a90526024810189905260ff88166044820152606401610289565b5091909102925060019150610b1f9050565b509193506001925050505b935093915050565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00546002036109bc57604051633ee5aeb560e01b815260040160405180910390fd5b6105148383836001610df1565b5f805f805f610b858787610e3b565b9250925092505f80610b978585610e97565b9150915081838015610ba65750815b9650965050505050509250929050565b80471015610be05760405163cf47918160e01b815247600482015260248101829052604401610289565b610bf9828260405180602001604052805f815250610f84565b15610c02575050565b3d15610c1457610c10610f99565b5050565b60405163d6bda27560e01b815260040160405180910390fd5b335f8181523060209081526040808320815160a0810183528083018581526060808301879052608083018190529082528185015282518581529384018581528484019093529093909291905b86518110156108c557868181518110610c9457610c94611a0c565b602002602001015193505f845f015160400151511115610de9575f845f01515f01516001600160a01b031663d04dfe236040518060e00160405280885f0151602001516001600160a01b03168152602001898152602001885f01516040015181526020015f8152602001610d0c8d8a60200151610fa4565b8152602001878152602001868152506040518263ffffffff1660e01b8152600401610d379190611fd9565b5f60405180830381865afa158015610d51573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610d7891908101906120da565b9150505f81511115610de75784516020015160405163012c676d60e21b81526001600160a01b03909116906304b19db490610db9908a908590600401612190565b5f604051808303815f87803b158015610dd0575f80fd5b505af1158015610de2573d5f803e3d5ffd5b505050505b505b600101610c79565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316610925578383151615610919573d5f823e3d81fd5b5f808060ff841681037f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff861115610e8657600a860460018201600a88065f1493509350935050610e90565b8593509150600190505b9250925092565b5f601b83900b8314838382610efb577d90e40fbeea1d3a4abc8955e946fe31cdcf66f634e1000000000000000000860515610edb57620186a0860595506005850194505b8586601b0b14610ef657600a86059550846001019450610edb565b610f11565b855f03610f1157505f9250600191506105fb9050565b848560030b14610f54575f851215610f3157505f92508291506105fb9050565b60405163d556b11160e01b81526004810183905260248101829052604401610289565b50507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff841660e084901b1791509250929050565b5f805f83516020850186885af1949350505050565b6040513d5f823e3d81fd5b60605f825167ffffffffffffffff811115610fc157610fc16115b3565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b5090505f80845111610ffc575f611002565b83516001015b85516001010190505f8167ffffffffffffffff811115611024576110246115b3565b60405190808252806020026020018201604052801561105757816020015b60608152602001906001900390816110425790505b5090505f61107b604080516002815233602082015230818301526060810190915290565b82828151811061108d5761108d611a0c565b60200260200101819052505f5b87518110156110ea5781806001019250508781815181106110bd576110bd611a0c565b60200260200101518383815181106110d7576110d7611a0c565b602090810291909101015260010161109a565b5085511561127c5780806001019150508382828151811061110d5761110d611a0c565b60200260200101819052505f5b865181101561127a576111c987828151811061113857611138611a0c565b60200260200101515f01516111a66111748a858151811061115b5761115b611a0c565b6020026020010151602001518051602090810291012090565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000005f908152601c91909152603c902090565b8984815181106111b8576111b8611a0c565b602002602001015160400151611286565b6111e957604051630a57f30960e31b815260048101829052602401610289565b8681815181106111fb576111fb611a0c565b60200260200101515f01516001600160a01b03165f1b85828151811061122357611223611a0c565b602002602001018181525050818060010192505086818151811061124957611249611a0c565b60200260200101516020015183838151811061126757611267611a0c565b602090810291909101015260010161111a565b505b5095945050505050565b5f836001600160a01b03163b5f036112e4575f806112a485856112f9565b5090925090505f8160038111156112bd576112bd6121a8565b1480156112db5750856001600160a01b0316826001600160a01b0316145b925050506112f2565b6112ef84848461133f565b90505b9392505050565b5f805f8351604103611330576020840151604085015160608601515f1a61132288828585611390565b955095509550505050610e90565b505081515f9150600290610e90565b805160408051630b135d3f60e11b8082526004820186905260248201929092525f92906020820185604483015e60205f60648401838a5afa9050825f5114601f3d1116811693505050509392505050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411156113c957505f9150600390508261144e565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa15801561141a573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b03811661144557505f92506001915082905061144e565b92505f91508190505b9450945094915050565b5f60208284031215611468575f80fd5b81356001600160e01b0319811681146112f2575f80fd5b6001600160a01b0381168114610214575f80fd5b5f805f805f8060a087890312156114a8575f80fd5b86356114b38161147f565b955060208701356114c38161147f565b94506040870135935060608701359250608087013567ffffffffffffffff808211156114ed575f80fd5b818901915089601f830112611500575f80fd5b81358181111561150e575f80fd5b8a602082850101111561151f575f80fd5b6020830194508093505050509295509295509295565b5f805f60608486031215611547575f80fd5b83356115528161147f565b9250602084013567ffffffffffffffff8082111561156e575f80fd5b9085019060c08288031215611581575f80fd5b90925060408501359080821115611596575f80fd5b508401604081870312156115a8575f80fd5b809150509250925092565b634e487b7160e01b5f52604160045260245ffd5b6040516060810167ffffffffffffffff811182821017156115ea576115ea6115b3565b60405290565b6040805190810167ffffffffffffffff811182821017156115ea576115ea6115b3565b604051601f8201601f1916810167ffffffffffffffff8111828210171561163c5761163c6115b3565b604052919050565b5f82601f830112611653575f80fd5b813567ffffffffffffffff81111561166d5761166d6115b3565b611680601f8201601f1916602001611613565b818152846020838601011115611694575f80fd5b816020850160208301375f918101602001919091529392505050565b5f602082840312156116c0575f80fd5b813567ffffffffffffffff8111156116d6575f80fd5b6116e284828501611644565b949350505050565b5f6001820161170757634e487b7160e01b5f52601160045260245ffd5b5060010190565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b5f6001600160a01b038089168352876020840152808716604084015285606084015280851660808401525060c060a083015261177b60c083018461170e565b98975050505050505050565b5f60208284031215611797575f80fd5b5051919050565b5f67ffffffffffffffff8211156117b7576117b76115b3565b5060051b60200190565b5f82601f8301126117d0575f80fd5b813560206117e56117e08361179e565b611613565b82815260059290921b84018101918181019086841115611803575f80fd5b8286015b848110156118ff57803567ffffffffffffffff80821115611826575f80fd5b908801906060828b03601f1901121561183d575f80fd5b6118456115c7565b868301356118528161147f565b815260408381013583811115611866575f80fd5b8401603f81018d13611876575f80fd5b888101356118866117e08261179e565b81815260059190911b82018301908a8101908f8311156118a4575f80fd5b928401925b828410156118c25783358252928b0192908b01906118a9565b858c01525050506060840135838111156118da575f80fd5b6118e88d8a83880101611644565b918301919091525085525050918301918301611807565b509695505050505050565b5f6040823603121561191a575f80fd5b6119226115f0565b823567ffffffffffffffff80821115611939575f80fd5b81850191506060823603121561194d575f80fd5b6119556115c7565b82356119608161147f565b815260208301356119708161147f565b6020820152604083013582811115611986575f80fd5b61199236828601611644565b604083015250835260208501359150808211156119ad575f80fd5b506119ba368286016117c1565b60208301525092915050565b5f808335601e198436030181126119db575f80fd5b83018035915067ffffffffffffffff8211156119f5575f80fd5b6020019150600581901b36038213156105fb575f80fd5b634e487b7160e01b5f52603260045260245ffd5b5f8235607e19833603018112611a34575f80fd5b9190910192915050565b5f8235609e19833603018112611a34575f80fd5b5f808335601e19843603018112611a67575f80fd5b83018035915067ffffffffffffffff821115611a81575f80fd5b6020019150600681901b36038213156105fb575f80fd5b5f60208284031215611aa8575f80fd5b81356112f28161147f565b5f808335601e19843603018112611ac8575f80fd5b830160208101925035905067ffffffffffffffff811115611ae7575f80fd5b8060051b36038213156105fb575f80fd5b5f8235605e19833603018112611b0c575f80fd5b90910192915050565b5f808335601e19843603018112611b2a575f80fd5b830160208101925035905067ffffffffffffffff811115611b49575f80fd5b8036038213156105fb575f80fd5b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b5f808335601e19843603018112611b94575f80fd5b830160208101925035905067ffffffffffffffff811115611bb3575f80fd5b8060061b36038213156105fb575f80fd5b8183525f60208085019450825f5b85811015611c0a578135611be58161147f565b6001600160a01b03168752818301358388015260409687019690910190600101611bd2565b509495945050505050565b8183526020808401935f91600585811b8301820185855b88811015611cee57858303601f19018a52611c478289611af8565b60608135611c548161147f565b6001600160a01b03168552611c6b82880183611ab3565b82898801528083880152608092507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115611ca5575f80fd5b871b808288850137860190506040611cbf84820185611b15565b9450838884030182890152611cd78484018683611b57565b9e8a019e9750505093870193505050600101611c2c565b509098975050505050505050565b5f602080835260e08301843582850152604082860135818601526060818701358187015280870135801515808214611d32575f80fd5b8060808901525050611d476080880188611ab3565b60c060a08901529384905261010093848801600582901b89018601835f5b84811015611ec3578b830360ff19018452813536879003607e19018112611d8a575f80fd5b8601803536829003609e19018112611da0575f80fd5b6080855281018035611db18161147f565b6001600160a01b038082166080880152611dcd8e840184611af8565b915060a0808801528135611de08161147f565b8116610120880152818e0135611df58161147f565b16610140870152611e08818c0182611b15565b91508a610160880152611e2061018088018383611b57565b915050611e2f8b830183611b7f565b607f19808985030160c08a0152611e47848385611bc4565b9350611e558d860186611b7f565b93509150808985030160e08a015250611e6f838383611bc4565b9250505060808201358c8701528c8301358d8701528a8301358b870152611e988a840184611ab3565b935091508581038a870152611eae818484611c15565b968d019695505050918a019150600101611d65565b5050611ed260a08c018c611b15565b8b8303601f190160c08d015298509650611eed818989611b57565b9b9a5050505050505050505050565b5f8060408385031215611f0d575f80fd5b505080516020909101519092909150565b5f60208284031215611f2e575f80fd5b815160ff811681146112f2575f80fd5b634e487b7160e01b5f52601260045260245ffd5b5f815180845260208085019450602084015f5b83811015611c0a57815187529582019590820190600101611f65565b5f8282518085526020808601955060208260051b840101602086015f5b84811015611fcc57601f19868403018952611fba838351611f52565b98840198925090830190600101611f9e565b5090979650505050505050565b602081526001600160a01b038251166020820152602082015160408201525f604083015160e0606084015261201261010084018261170e565b9050606084015160808401526080840151601f19808584030160a086015261203a8383611f81565b925060a08601519150808584030160c08601526120578383611f52565b925060c08601519150808584030160e0860152506120758282611f52565b95945050505050565b5f82601f83011261208d575f80fd5b8151602061209d6117e08361179e565b8083825260208201915060208460051b8701019350868411156120be575f80fd5b602086015b848110156118ff57805183529183019183016120c3565b5f80604083850312156120eb575f80fd5b825167ffffffffffffffff80821115612102575f80fd5b818501915085601f830112612115575f80fd5b815160206121256117e08361179e565b82815260059290921b84018101918181019089841115612143575f80fd5b948201945b8386101561216157855182529482019490820190612148565b91880151919650909350505080821115612179575f80fd5b506121868582860161207e565b9150509250929050565b828152604060208201525f6116e26040830184611f52565b634e487b7160e01b5f52602160045260245ffd"; diff --git a/src/lib/deploy/LibRaindexDeploy.sol b/src/lib/deploy/LibRaindexDeploy.sol index 9371608cb0..aa3849f1fe 100644 --- a/src/lib/deploy/LibRaindexDeploy.sol +++ b/src/lib/deploy/LibRaindexDeploy.sol @@ -123,6 +123,15 @@ library LibRaindexDeploy { bytes32 constant RAINDEX_DEPLOYED_CODEHASH_0_1_9 = 0x774ca4c194abf0720bca6c033580762029a80291feefd0a4b7855b16bcbbf7a9; + /// The deployed address of the `RaindexV6` contract at the published `0.1.10` + /// tag. (Changed in 0.1.10 — per-(user,token) dust-credit ledger.) + address constant RAINDEX_DEPLOYED_ADDRESS_0_1_10 = 0x66F51a9C29480491C9282D99cf324e9f419A4e1d; + + /// The runtime code hash of the `RaindexV6` contract at the published `0.1.10` + /// tag. + bytes32 constant RAINDEX_DEPLOYED_CODEHASH_0_1_10 = + 0x670aa891cb8fcb7166ecf8031238f6287ead1ac018d6353af04dfd720b146e75; + /// The address of the `RaindexV6SubParser` contract when deployed with /// the rain standard zoltu deployer. address constant SUB_PARSER_DEPLOYED_ADDRESS = SUB_PARSER_ADDR; @@ -212,6 +221,15 @@ library LibRaindexDeploy { bytes32 constant SUB_PARSER_DEPLOYED_CODEHASH_0_1_9 = 0x704aadc1ed56f63ff918ab219e6681a5d2851d774e2ee136bbe7904ea3b2fdcd; + /// The deployed address of the `RaindexV6SubParser` contract at the + /// published `0.1.10` tag. (Unchanged from `0.1.2`.) + address constant SUB_PARSER_DEPLOYED_ADDRESS_0_1_10 = 0x09Bc7AF266012F44fb41D8Bd682da931666605e1; + + /// The runtime code hash of the `RaindexV6SubParser` contract at the + /// published `0.1.10` tag. + bytes32 constant SUB_PARSER_DEPLOYED_CODEHASH_0_1_10 = + 0x704aadc1ed56f63ff918ab219e6681a5d2851d774e2ee136bbe7904ea3b2fdcd; + /// The address of the `RouteProcessor4` contract when deployed with the /// rain standard zoltu deployer. address constant ROUTE_PROCESSOR_DEPLOYED_ADDRESS = ROUTE_PROCESSOR_ADDR; @@ -301,6 +319,15 @@ library LibRaindexDeploy { bytes32 constant ROUTE_PROCESSOR_DEPLOYED_CODEHASH_0_1_9 = 0xeb3745a79c6ba48e8767b9c355b8e7b79f9d6edeca004e4bb91be4de515a7eeb; + /// The deployed address of the `RouteProcessor4` contract at the published + /// `0.1.10` tag. (Unchanged from `0.1.0`.) + address constant ROUTE_PROCESSOR_DEPLOYED_ADDRESS_0_1_10 = 0x6E2d0e71d900474b262E545Bc4C98b71ab368d21; + + /// The runtime code hash of the `RouteProcessor4` contract at the published + /// `0.1.10` tag. + bytes32 constant ROUTE_PROCESSOR_DEPLOYED_CODEHASH_0_1_10 = + 0xeb3745a79c6ba48e8767b9c355b8e7b79f9d6edeca004e4bb91be4de515a7eeb; + /// The address of the `GenericPoolRaindexV6ArbOrderTaker` contract when /// deployed with the rain standard zoltu deployer. address constant GENERIC_POOL_ARB_ORDER_TAKER_DEPLOYED_ADDRESS = GENERIC_POOL_ARB_OT_ADDR; @@ -393,6 +420,16 @@ library LibRaindexDeploy { bytes32 constant GENERIC_POOL_ARB_ORDER_TAKER_DEPLOYED_CODEHASH_0_1_9 = 0xc4492cb22d918a3f0d41f13e533744ef03a2e7f744ec0a43b79d97a04c537544; + /// The deployed address of the `GenericPoolRaindexV6ArbOrderTaker` contract + /// at the published `0.1.10` tag. (Changed in 0.1.10 — embeds the new raindex + /// address.) + address constant GENERIC_POOL_ARB_ORDER_TAKER_DEPLOYED_ADDRESS_0_1_10 = 0xe2a825c9C2b52F7c73f30080680DdB90f36ed9c3; + + /// The runtime code hash of the `GenericPoolRaindexV6ArbOrderTaker` contract + /// at the published `0.1.10` tag. + bytes32 constant GENERIC_POOL_ARB_ORDER_TAKER_DEPLOYED_CODEHASH_0_1_10 = + 0xd3453fd739378f1ccce8181a1ba3554db33e3fc13f6eeda83d2abc716c45d89b; + /// The address of the `RouteProcessorRaindexV6ArbOrderTaker` contract /// when deployed with the rain standard zoltu deployer. address constant ROUTE_PROCESSOR_ARB_ORDER_TAKER_DEPLOYED_ADDRESS = RP_ARB_OT_ADDR; @@ -494,6 +531,17 @@ library LibRaindexDeploy { bytes32 constant ROUTE_PROCESSOR_ARB_ORDER_TAKER_DEPLOYED_CODEHASH_0_1_9 = 0xc3fb3bb0355fee22e54cade57f5ff828478d59f34fdd8057bc0bc6a11b3d48fc; + /// The deployed address of the `RouteProcessorRaindexV6ArbOrderTaker` + /// contract at the published `0.1.10` tag. (Changed in 0.1.10 — embeds the + /// new raindex address.) + address constant ROUTE_PROCESSOR_ARB_ORDER_TAKER_DEPLOYED_ADDRESS_0_1_10 = + 0xDd436bd0e92389e1c45E6Af5F0C2D989c626d49e; + + /// The runtime code hash of the `RouteProcessorRaindexV6ArbOrderTaker` + /// contract at the published `0.1.10` tag. + bytes32 constant ROUTE_PROCESSOR_ARB_ORDER_TAKER_DEPLOYED_CODEHASH_0_1_10 = + 0xebca76aecd91efeee0840b70028dda00c90b06266c1bea04d5367a58d5e7f751; + /// The address of the `GenericPoolRaindexV6FlashBorrower` contract when /// deployed with the rain standard zoltu deployer. address constant GENERIC_POOL_FLASH_BORROWER_DEPLOYED_ADDRESS = GENERIC_POOL_FB_ADDR; @@ -586,6 +634,16 @@ library LibRaindexDeploy { bytes32 constant GENERIC_POOL_FLASH_BORROWER_DEPLOYED_CODEHASH_0_1_9 = 0xed618063fd6ffc7558e4588ea6357356e781d660fa22caa292a2f9aeaa21996f; + /// The deployed address of the `GenericPoolRaindexV6FlashBorrower` contract + /// at the published `0.1.10` tag. (Changed in 0.1.10 — embeds the new raindex + /// address.) + address constant GENERIC_POOL_FLASH_BORROWER_DEPLOYED_ADDRESS_0_1_10 = 0x94e275d0eAf27c28C4737b91f8CD9D1DD9132019; + + /// The runtime code hash of the `GenericPoolRaindexV6FlashBorrower` contract + /// at the published `0.1.10` tag. + bytes32 constant GENERIC_POOL_FLASH_BORROWER_DEPLOYED_CODEHASH_0_1_10 = + 0x3438f85dace78d284e0eb33f8a245750498a37dfde867325a0760cf022e8fdb7; + uint256 constant RAINDEX_START_BLOCK_ARBITRUM = 473030678; uint256 constant RAINDEX_START_BLOCK_BASE = 47278140; uint256 constant RAINDEX_START_BLOCK_FLARE = 62835540; From efea6c7bb2fa40e35c5e559a792349b2680f7361 Mon Sep 17 00:00:00 2001 From: David Meister Date: Wed, 17 Jun 2026 21:26:51 +0000 Subject: [PATCH 6/8] fix(sol): explicit zero-init amount18 and clamped in pullTokens [3b-attempt] --- src/concrete/raindex/RaindexV6.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/concrete/raindex/RaindexV6.sol b/src/concrete/raindex/RaindexV6.sol index 766a11e0b1..09733ec655 100644 --- a/src/concrete/raindex/RaindexV6.sol +++ b/src/concrete/raindex/RaindexV6.sol @@ -1195,8 +1195,8 @@ contract RaindexV6 is IRaindexV6, IMetaV1_2, ReentrancyGuard, Multicall, Raindex Float credit = sDustCredit[account][token]; Float effective = amount.sub(credit); - uint256 amount18; - bool clamped; + uint256 amount18 = 0; + bool clamped = false; // A non-positive `effective` means the credit already covers the whole // pull, so no tokens move; `toFixedDecimalLossy` also rejects negatives. if (effective.gt(LibDecimalFloat.FLOAT_ZERO)) { From 1346fb55307713c290f7f7998fe07de23b23c0f7 Mon Sep 17 00:00:00 2001 From: David Meister Date: Thu, 18 Jun 2026 17:17:50 +0000 Subject: [PATCH 7/8] fix(ci): split dustCredit harnesses to one contract per file [3b-attempt] Each dustCredit test file had a Harness contract and a Test contract in the same file, violating the rainix-sol-single-contract static check. Extract each harness (and the PrecisionAttackMutableDecimalsToken helper) into its own .sol file and import it from the test file. Co-Authored-By: Claude --- .../PrecisionAttackMutableDecimalsToken.sol | 25 +++++++++++ ...ndexV6.dustCredit.conservationAttack.t.sol | 17 +------- ...RaindexV6.dustCredit.precisionAttack.t.sol | 42 ++----------------- .../RaindexV6.dustCredit.solvencyAttack.t.sol | 18 +------- .../raindex/RaindexV6.dustCredit.t.sol | 19 +-------- ...xV6DustCreditConservationAttackHarness.sol | 20 +++++++++ .../raindex/RaindexV6DustCreditHarness.sol | 20 +++++++++ ...ndexV6DustCreditPrecisionAttackHarness.sol | 20 +++++++++ ...indexV6DustCreditSolvencyAttackHarness.sol | 20 +++++++++ 9 files changed, 115 insertions(+), 86 deletions(-) create mode 100644 test/concrete/raindex/PrecisionAttackMutableDecimalsToken.sol create mode 100644 test/concrete/raindex/RaindexV6DustCreditConservationAttackHarness.sol create mode 100644 test/concrete/raindex/RaindexV6DustCreditHarness.sol create mode 100644 test/concrete/raindex/RaindexV6DustCreditPrecisionAttackHarness.sol create mode 100644 test/concrete/raindex/RaindexV6DustCreditSolvencyAttackHarness.sol diff --git a/test/concrete/raindex/PrecisionAttackMutableDecimalsToken.sol b/test/concrete/raindex/PrecisionAttackMutableDecimalsToken.sol new file mode 100644 index 0000000000..fe81c34761 --- /dev/null +++ b/test/concrete/raindex/PrecisionAttackMutableDecimalsToken.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {ERC20} from "@openzeppelin-contracts-5.6.1/token/ERC20/ERC20.sol"; + +contract PrecisionAttackMutableDecimalsToken is ERC20 { + uint8 public dec; + + constructor(uint8 d) ERC20("Mut", "MUT") { + dec = d; + } + + function setDecimals(uint8 d) external { + dec = d; + } + + function decimals() public view override returns (uint8) { + return dec; + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} diff --git a/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol index f4207e73fa..8121fcf3c1 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol @@ -3,25 +3,12 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.16.1/src/Test.sol"; -import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; import {MockToken} from "test/util/concrete/MockToken.sol"; import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; - -contract RaindexV6DustCreditConservationAttackHarness is RaindexV6 { - function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { - return pullTokens(account, token, amount); - } - - function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { - return pushTokens(account, token, amount); - } - - function exposedDustCredit(address user, address token) external view returns (Float) { - return sDustCredit[user][token]; - } -} +import {RaindexV6DustCreditConservationAttackHarness} from + "test/concrete/raindex/RaindexV6DustCreditConservationAttackHarness.sol"; /// @title Adversarial conservation attack on the dust-credit ledger. contract RaindexV6DustCreditConservationAttackTest is Test { diff --git a/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol index ef6bbfbcd1..3cea9f3d53 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol @@ -3,49 +3,15 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.16.1/src/Test.sol"; -import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; import {MockToken} from "test/util/concrete/MockToken.sol"; import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; import {ITOFUTokenDecimals, TOFUOutcome} from "rain-tofu-erc20-decimals-0.1.1/src/interface/ITOFUTokenDecimals.sol"; -import {ERC20} from "@openzeppelin-contracts-5.6.1/token/ERC20/ERC20.sol"; - -contract RaindexV6DustCreditPrecisionAttackHarness is RaindexV6 { - function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { - return pullTokens(account, token, amount); - } - - function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { - return pushTokens(account, token, amount); - } - - function exposedDustCredit(address user, address token) external view returns (Float) { - return sDustCredit[user][token]; - } -} - -/// @dev Token whose reported decimals can be flipped at runtime, to probe the -/// TOFU decimals-change behaviour. -contract PrecisionAttackMutableDecimalsToken is ERC20 { - uint8 public dec; - - constructor(uint8 d) ERC20("Mut", "MUT") { - dec = d; - } - - function setDecimals(uint8 d) external { - dec = d; - } - - function decimals() public view override returns (uint8) { - return dec; - } - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } -} +import {RaindexV6DustCreditPrecisionAttackHarness} from + "test/concrete/raindex/RaindexV6DustCreditPrecisionAttackHarness.sol"; +import {PrecisionAttackMutableDecimalsToken} from + "test/concrete/raindex/PrecisionAttackMutableDecimalsToken.sol"; contract RaindexV6DustCreditPrecisionAttackTest is Test { using LibDecimalFloat for Float; diff --git a/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol index 2deeb66f01..19459f3824 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol @@ -3,26 +3,12 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.16.1/src/Test.sol"; -import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; import {MockToken} from "test/util/concrete/MockToken.sol"; import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; - -/// @dev Same harness as the PR's test, exposing the internal helpers. -contract RaindexV6DustCreditSolvencyAttackHarness is RaindexV6 { - function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { - return pullTokens(account, token, amount); - } - - function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { - return pushTokens(account, token, amount); - } - - function exposedDustCredit(address user, address token) external view returns (Float) { - return sDustCredit[user][token]; - } -} +import {RaindexV6DustCreditSolvencyAttackHarness} from + "test/concrete/raindex/RaindexV6DustCreditSolvencyAttackHarness.sol"; /// @title Adversarial solvency attack on the dust-credit ledger. /// @notice Tries to construct a sequence where realizing a credit pays out diff --git a/test/concrete/raindex/RaindexV6.dustCredit.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.t.sol index bc5338b01e..71be1ca877 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.t.sol @@ -3,27 +3,12 @@ pragma solidity =0.8.25; import {Test} from "forge-std-1.16.1/src/Test.sol"; -import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; import {MockToken} from "test/util/concrete/MockToken.sol"; import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; - -/// @dev Exposes RaindexV6's internal token-move helpers and the dust-credit -/// ledger for testing. -contract RaindexV6DustCreditHarness is RaindexV6 { - function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { - return pullTokens(account, token, amount); - } - - function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { - return pushTokens(account, token, amount); - } - - function exposedDustCredit(address user, address token) external view returns (Float) { - return sDustCredit[user][token]; - } -} +import {RaindexV6DustCreditHarness} from + "test/concrete/raindex/RaindexV6DustCreditHarness.sol"; /// @title RaindexV6DustCreditTest /// @notice L01 follow-up (#2673): every lossy float->fixed-decimal token move diff --git a/test/concrete/raindex/RaindexV6DustCreditConservationAttackHarness.sol b/test/concrete/raindex/RaindexV6DustCreditConservationAttackHarness.sol new file mode 100644 index 0000000000..9cfac6ff66 --- /dev/null +++ b/test/concrete/raindex/RaindexV6DustCreditConservationAttackHarness.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; +import {Float} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; + +contract RaindexV6DustCreditConservationAttackHarness is RaindexV6 { + function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { + return pullTokens(account, token, amount); + } + + function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { + return pushTokens(account, token, amount); + } + + function exposedDustCredit(address user, address token) external view returns (Float) { + return sDustCredit[user][token]; + } +} diff --git a/test/concrete/raindex/RaindexV6DustCreditHarness.sol b/test/concrete/raindex/RaindexV6DustCreditHarness.sol new file mode 100644 index 0000000000..ff77c0ba26 --- /dev/null +++ b/test/concrete/raindex/RaindexV6DustCreditHarness.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; +import {Float} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; + +contract RaindexV6DustCreditHarness is RaindexV6 { + function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { + return pullTokens(account, token, amount); + } + + function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { + return pushTokens(account, token, amount); + } + + function exposedDustCredit(address user, address token) external view returns (Float) { + return sDustCredit[user][token]; + } +} diff --git a/test/concrete/raindex/RaindexV6DustCreditPrecisionAttackHarness.sol b/test/concrete/raindex/RaindexV6DustCreditPrecisionAttackHarness.sol new file mode 100644 index 0000000000..c727a2416e --- /dev/null +++ b/test/concrete/raindex/RaindexV6DustCreditPrecisionAttackHarness.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; +import {Float} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; + +contract RaindexV6DustCreditPrecisionAttackHarness is RaindexV6 { + function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { + return pullTokens(account, token, amount); + } + + function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { + return pushTokens(account, token, amount); + } + + function exposedDustCredit(address user, address token) external view returns (Float) { + return sDustCredit[user][token]; + } +} diff --git a/test/concrete/raindex/RaindexV6DustCreditSolvencyAttackHarness.sol b/test/concrete/raindex/RaindexV6DustCreditSolvencyAttackHarness.sol new file mode 100644 index 0000000000..2d5c7550e8 --- /dev/null +++ b/test/concrete/raindex/RaindexV6DustCreditSolvencyAttackHarness.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: LicenseRef-DCL-1.0 +// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd +pragma solidity =0.8.25; + +import {RaindexV6} from "src/concrete/raindex/RaindexV6.sol"; +import {Float} from "rain-math-float-0.1.1/src/lib/LibDecimalFloat.sol"; + +contract RaindexV6DustCreditSolvencyAttackHarness is RaindexV6 { + function exposedPull(address account, address token, Float amount) external returns (uint256, uint8) { + return pullTokens(account, token, amount); + } + + function exposedPush(address account, address token, Float amount) external returns (uint256, uint8) { + return pushTokens(account, token, amount); + } + + function exposedDustCredit(address user, address token) external view returns (Float) { + return sDustCredit[user][token]; + } +} From 8686b290a49f7eb4ac49248c7657113cbdf2e227 Mon Sep 17 00:00:00 2001 From: David Meister Date: Thu, 18 Jun 2026 17:44:23 +0000 Subject: [PATCH 8/8] fix(ci): copy-artifacts [3b-attempt] forge fmt reformats multi-line import statements to curly-brace style --- .../raindex/RaindexV6.dustCredit.conservationAttack.t.sol | 5 +++-- .../raindex/RaindexV6.dustCredit.precisionAttack.t.sol | 8 ++++---- .../raindex/RaindexV6.dustCredit.solvencyAttack.t.sol | 5 +++-- test/concrete/raindex/RaindexV6.dustCredit.t.sol | 3 +-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol index 8121fcf3c1..8c7a994fa5 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.conservationAttack.t.sol @@ -7,8 +7,9 @@ import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFl import {MockToken} from "test/util/concrete/MockToken.sol"; import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; -import {RaindexV6DustCreditConservationAttackHarness} from - "test/concrete/raindex/RaindexV6DustCreditConservationAttackHarness.sol"; +import { + RaindexV6DustCreditConservationAttackHarness +} from "test/concrete/raindex/RaindexV6DustCreditConservationAttackHarness.sol"; /// @title Adversarial conservation attack on the dust-credit ledger. contract RaindexV6DustCreditConservationAttackTest is Test { diff --git a/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol index 3cea9f3d53..6288294b17 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.precisionAttack.t.sol @@ -8,10 +8,10 @@ import {MockToken} from "test/util/concrete/MockToken.sol"; import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; import {ITOFUTokenDecimals, TOFUOutcome} from "rain-tofu-erc20-decimals-0.1.1/src/interface/ITOFUTokenDecimals.sol"; -import {RaindexV6DustCreditPrecisionAttackHarness} from - "test/concrete/raindex/RaindexV6DustCreditPrecisionAttackHarness.sol"; -import {PrecisionAttackMutableDecimalsToken} from - "test/concrete/raindex/PrecisionAttackMutableDecimalsToken.sol"; +import { + RaindexV6DustCreditPrecisionAttackHarness +} from "test/concrete/raindex/RaindexV6DustCreditPrecisionAttackHarness.sol"; +import {PrecisionAttackMutableDecimalsToken} from "test/concrete/raindex/PrecisionAttackMutableDecimalsToken.sol"; contract RaindexV6DustCreditPrecisionAttackTest is Test { using LibDecimalFloat for Float; diff --git a/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol index 19459f3824..892064e145 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.solvencyAttack.t.sol @@ -7,8 +7,9 @@ import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFl import {MockToken} from "test/util/concrete/MockToken.sol"; import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; -import {RaindexV6DustCreditSolvencyAttackHarness} from - "test/concrete/raindex/RaindexV6DustCreditSolvencyAttackHarness.sol"; +import { + RaindexV6DustCreditSolvencyAttackHarness +} from "test/concrete/raindex/RaindexV6DustCreditSolvencyAttackHarness.sol"; /// @title Adversarial solvency attack on the dust-credit ledger. /// @notice Tries to construct a sequence where realizing a credit pays out diff --git a/test/concrete/raindex/RaindexV6.dustCredit.t.sol b/test/concrete/raindex/RaindexV6.dustCredit.t.sol index 71be1ca877..d024bda536 100644 --- a/test/concrete/raindex/RaindexV6.dustCredit.t.sol +++ b/test/concrete/raindex/RaindexV6.dustCredit.t.sol @@ -7,8 +7,7 @@ import {Float, LibDecimalFloat} from "rain-math-float-0.1.1/src/lib/LibDecimalFl import {MockToken} from "test/util/concrete/MockToken.sol"; import {LibRainDeploy} from "rain-deploy-0.1.2/src/lib/LibRainDeploy.sol"; import {LibTOFUTokenDecimals} from "rain-tofu-erc20-decimals-0.1.1/src/lib/LibTOFUTokenDecimals.sol"; -import {RaindexV6DustCreditHarness} from - "test/concrete/raindex/RaindexV6DustCreditHarness.sol"; +import {RaindexV6DustCreditHarness} from "test/concrete/raindex/RaindexV6DustCreditHarness.sol"; /// @title RaindexV6DustCreditTest /// @notice L01 follow-up (#2673): every lossy float->fixed-decimal token move