Transactions
Token Transfers
Internal Transactions
Coin Balance History
Code
Read Contract
Write Contract
- Contract name:
- SwapRouter
- Optimization enabled
- true
- Compiler version
- v0.7.6+commit.7338295f
- Optimization runs
- 1000000
- Verified at
- 2023-12-14T15:31:09.438486Z
Constructor Arguments
000000000000000000000000da2f048c128506e720b0b0b32f20432157dde1c7000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f9
Arg [0] (address) : 0xda2f048c128506e720b0b0b32f20432157dde1c7
Arg [1] (address) : 0xae83571000af4499798d1e3b0fa0070eb3a3e3f9
contracts/SwapRouter.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity =0.7.6;pragma abicoder v2;import './core/libraries/SafeCast.sol';import './core/libraries/TickMath.sol';import './core/interfaces/ITangleswapPool.sol';import './core/interfaces/ITangleswapFactory.sol';import './interfaces/ISwapRouter.sol';import './base/PeripheryImmutableState.sol';import './base/PeripheryValidation.sol';import './base/PeripheryPaymentsWithFee.sol';import './base/Multicall.sol';import './base/SelfPermit.sol';import './libraries/Path.sol';import './libraries/PoolAddress.sol';import './libraries/CallbackValidation.sol';import './interfaces/external/IWETH9.sol';/// @title Tangleswap Swap Router/// @notice Router for stateless execution of swaps against Tangleswapcontract SwapRouter isISwapRouter,PeripheryImmutableState,PeripheryValidation,PeripheryPaymentsWithFee,Multicall,SelfPermit{using Path for bytes;using SafeCast for uint256;/// @dev Used as the placeholder value for amountInCached, because the computed amount in for an exact output swap/// can never actually be this valueuint256 private constant DEFAULT_AMOUNT_IN_CACHED = type(uint256).max;/// @dev Transient storage variable used for returning the computed amount in for an exact output swap.uint256 private amountInCached = DEFAULT_AMOUNT_IN_CACHED;constructor(address _factory, address _WETH9) PeripheryImmutableState(_factory, _WETH9) {}
contracts/base/PeripheryPaymentsWithFee.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.7.5;import '@openzeppelin/contracts/token/ERC20/IERC20.sol';import '../core/libraries/LowGasSafeMath.sol';import './PeripheryPayments.sol';import '../interfaces/IPeripheryPaymentsWithFee.sol';import '../interfaces/external/IWETH9.sol';import '../libraries/TransferHelper.sol';abstract contract PeripheryPaymentsWithFee is PeripheryPayments, IPeripheryPaymentsWithFee {using LowGasSafeMath for uint256;/// @inheritdoc IPeripheryPaymentsWithFeefunction unwrapWETH9WithFee(uint256 amountMinimum,address recipient,uint256 feeBips,address feeRecipient) public payable override {require(feeBips > 0 && feeBips <= 100);uint256 balanceWETH9 = IWETH9(WETH9).balanceOf(address(this));require(balanceWETH9 >= amountMinimum, 'Insufficient WETH9');if (balanceWETH9 > 0) {IWETH9(WETH9).withdraw(balanceWETH9);uint256 feeAmount = balanceWETH9.mul(feeBips) / 10_000;if (feeAmount > 0) TransferHelper.safeTransferETH(feeRecipient, feeAmount);TransferHelper.safeTransferETH(recipient, balanceWETH9 - feeAmount);}}/// @inheritdoc IPeripheryPaymentsWithFeefunction sweepTokenWithFee(address token,uint256 amountMinimum,address recipient,uint256 feeBips,
contracts/base/PeripheryValidation.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity =0.7.6;import './BlockTimestamp.sol';abstract contract PeripheryValidation is BlockTimestamp {modifier checkDeadline(uint256 deadline) {require(_blockTimestamp() <= deadline, 'Transaction too old');_;}}
contracts/base/SelfPermit.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.5.0;import '@openzeppelin/contracts/token/ERC20/IERC20.sol';import '@openzeppelin/contracts/drafts/IERC20Permit.sol';import '../interfaces/ISelfPermit.sol';import '../interfaces/external/IERC20PermitAllowed.sol';/// @title Self Permit/// @notice Functionality to call permit on any EIP-2612-compliant token for use in the route/// @dev These functions are expected to be embedded in multicalls to allow EOAs to approve a contract and call a function/// that requires an approval in a single transaction.abstract contract SelfPermit is ISelfPermit {/// @inheritdoc ISelfPermitfunction selfPermit(address token,uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) public payable override {IERC20Permit(token).permit(msg.sender, address(this), value, deadline, v, r, s);}/// @inheritdoc ISelfPermitfunction selfPermitIfNecessary(address token,uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) external payable override {if (IERC20(token).allowance(msg.sender, address(this)) < value) selfPermit(token, value, deadline, v, r, s);}/// @inheritdoc ISelfPermitfunction selfPermitAllowed(address token,
@openzeppelin/contracts/drafts/IERC20Permit.sol
// SPDX-License-Identifier: MITpragma solidity >=0.6.0 <0.8.0;/*** @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].** Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by* presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't* need to send a transaction, and thus is not required to hold Ether at all.*/interface IERC20Permit {/*** @dev Sets `value` as the allowance of `spender` over `owner`'s tokens,* given `owner`'s signed approval.** IMPORTANT: The same issues {IERC20-approve} has related to transaction* ordering also apply here.** Emits an {Approval} event.** Requirements:** - `spender` cannot be the zero address.* - `deadline` must be a timestamp in the future.* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`* over the EIP712-formatted function arguments.* - the signature must use ``owner``'s current nonce (see {nonces}).** For more information on the signature format, see the* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP* section].*/function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;/*** @dev Returns the current nonce for `owner`. This value must be* included whenever a signature is generated for {permit}.** Every successful call to {permit} increases ``owner``'s nonce by one. This
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MITpragma solidity ^0.7.0;/*** @dev Interface of the ERC20 standard as defined in the EIP.*/interface IERC20 {/*** @dev Returns the amount of tokens in existence.*/function totalSupply() external view returns (uint256);/*** @dev Returns the amount of tokens owned by `account`.*/function balanceOf(address account) external view returns (uint256);/*** @dev Moves `amount` tokens from the caller's account to `recipient`.** Returns a boolean value indicating whether the operation succeeded.** Emits a {Transfer} event.*/function transfer(address recipient, uint256 amount) external returns (bool);/*** @dev Returns the remaining number of tokens that `spender` will be* allowed to spend on behalf of `owner` through {transferFrom}. This is* zero by default.** This value changes when {approve} or {transferFrom} are called.*/function allowance(address owner, address spender) external view returns (uint256);/*** @dev Sets `amount` as the allowance of `spender` over the caller's tokens.** Returns a boolean value indicating whether the operation succeeded.*
contracts/base/BlockTimestamp.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity =0.7.6;/// @title Function for getting block timestamp/// @dev Base contract that is overridden for testsabstract contract BlockTimestamp {/// @dev Method that exists purely to be overridden for tests/// @return The current block timestampfunction _blockTimestamp() internal view virtual returns (uint256) {return block.timestamp;}}
contracts/base/Multicall.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity =0.7.6;pragma abicoder v2;import '../interfaces/IMulticall.sol';/// @title Multicall/// @notice Enables calling multiple methods in a single call to the contractabstract contract Multicall is IMulticall {/// @inheritdoc IMulticallfunction multicall(bytes[] calldata data) public payable override returns (bytes[] memory results) {results = new bytes[](data.length);for (uint256 i = 0; i < data.length; i++) {(bool success, bytes memory result) = address(this).delegatecall(data[i]);if (!success) {// Next 5 lines from https://ethereum.stackexchange.com/a/83577if (result.length < 68) revert();assembly {result := add(result, 0x04)}revert(abi.decode(result, (string)));}results[i] = result;}}}
contracts/base/PeripheryImmutableState.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity =0.7.6;import '../interfaces/IPeripheryImmutableState.sol';/// @title Immutable state/// @notice Immutable state used by periphery contractsabstract contract PeripheryImmutableState is IPeripheryImmutableState {/// @inheritdoc IPeripheryImmutableStateaddress public immutable override factory;/// @inheritdoc IPeripheryImmutableStateaddress public immutable override WETH9;constructor(address _factory, address _WETH9) {factory = _factory;WETH9 = _WETH9;}}
contracts/base/PeripheryPayments.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.7.5;import '@openzeppelin/contracts/token/ERC20/IERC20.sol';import '../interfaces/IPeripheryPayments.sol';import '../interfaces/external/IWETH9.sol';import '../libraries/TransferHelper.sol';import './PeripheryImmutableState.sol';abstract contract PeripheryPayments is IPeripheryPayments, PeripheryImmutableState {receive() external payable {require(msg.sender == WETH9, 'Not WETH9');}/// @inheritdoc IPeripheryPaymentsfunction unwrapWETH9(uint256 amountMinimum, address recipient) public payable override {uint256 balanceWETH9 = IWETH9(WETH9).balanceOf(address(this));require(balanceWETH9 >= amountMinimum, 'Insufficient WETH9');if (balanceWETH9 > 0) {IWETH9(WETH9).withdraw(balanceWETH9);TransferHelper.safeTransferETH(recipient, balanceWETH9);}}/// @inheritdoc IPeripheryPaymentsfunction sweepToken(address token,uint256 amountMinimum,address recipient) public payable override {uint256 balanceToken = IERC20(token).balanceOf(address(this));require(balanceToken >= amountMinimum, 'Insufficient token');if (balanceToken > 0) {TransferHelper.safeTransfer(token, recipient, balanceToken);}}
contracts/core/interfaces/ITangleswapFactory.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.5.0;/// @title The interface for the Tangleswap Factory/// @notice The Tangleswap Factory facilitates creation of Tangleswap pools and control over the protocol feesinterface ITangleswapFactory {/// @notice Emitted when the owner of the factory is changed/// @param oldOwner The owner before the owner was changed/// @param newOwner The owner after the owner was changedevent OwnerChanged(address indexed oldOwner, address indexed newOwner);/// @notice Emitted when a pool is created/// @param token0 The first token of the pool by address sort order/// @param token1 The second token of the pool by address sort order/// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip/// @param tickSpacing The minimum number of ticks between initialized ticks/// @param pool The address of the created poolevent PoolCreated(address indexed token0,address indexed token1,uint24 indexed fee,int24 tickSpacing,address pool);/// @notice Emitted when a new fee amount is enabled for pool creation via the factory/// @param fee The enabled fee, denominated in hundredths of a bip/// @param tickSpacing The minimum number of ticks between initialized ticks for pools created with the given feeevent FeeAmountEnabled(uint24 indexed fee, int24 indexed tickSpacing);/// @notice Returns the current owner of the factory/// @dev Can be changed by the current owner via setOwner/// @return The address of the factory ownerfunction owner() external view returns (address);/// @notice Returns the tick spacing for a given fee amount, if enabled, or 0 if not enabled/// @dev A fee amount can never be removed, so this value should be hard coded or cached in the calling context/// @param fee The enabled fee, denominated in hundredths of a bip. Returns 0 in case of unenabled fee/// @return The tick spacingfunction feeAmountTickSpacing(uint24 fee) external view returns (int24);
contracts/core/interfaces/ITangleswapPool.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.5.0;interface ITangleswapPool {/// @notice Sets the initial price for the pool/// @dev Price is represented as a sqrt(amountToken1/amountToken0) Q64.96 value/// @param sqrtPriceX96 the initial sqrt price of the pool as a Q64.96function initialize(uint160 sqrtPriceX96) external;/// @notice The 0th storage slot in the pool stores many values, and is exposed as a single method to save gas/// when accessed externally./// @return sqrtPriceX96 The current price of the pool as a sqrt(token1/token0) Q64.96 value/// tick The current tick of the pool, i.e. according to the last tick transition that was run./// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick/// boundary./// observationIndex The index of the last oracle observation that was written,/// observationCardinality The current maximum number of observations stored in the pool,/// observationCardinalityNext The next maximum number of observations, to be updated when the observation./// feeProtocol The protocol fee for both tokens of the pool./// Encoded as two 4 bit values, where the protocol fee of token1 is shifted 4 bits and the protocol fee of token0/// is the lower 4 bits. Used as the denominator of a fraction of the swap fee, e.g. 4 means 1/4th of the swap fee./// unlocked Whether the pool is currently locked to reentrancyfunction slot0()externalviewreturns (uint160 sqrtPriceX96,int24 tick,uint16 observationIndex,uint16 observationCardinality,uint16 observationCardinalityNext,uint8 feeProtocol,bool unlocked);/// @notice Collects tokens owed to a position/// @dev Does not recompute fees earned, which must be done either via mint or burn of any amount of liquidity./// Collect must be called by the position owner. To withdraw only token0 or only token1, amount0Requested or/// amount1Requested may be set to zero. To withdraw all tokens owed, caller may pass any value greater than the/// actual tokens owed, e.g. type(uint128).max. Tokens owed may be from accumulated swap fees or burned liquidity./// @param recipient The address which should receive the fees collected
contracts/core/interfaces/callback/ITangleswapSwapCallback.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.5.0;/// @title Callback for ITangleswapPoolActions#swap/// @notice Any contract that calls ITangleswapPoolActions#swap must implement this interfaceinterface ITangleswapSwapCallback {/// @notice Called to `msg.sender` after executing a swap via ITangleswapPool#swap./// @dev In the implementation you must pay the pool tokens owed for the swap./// The caller of this method must be checked to be a TangleswapPool deployed by the canonical TangleswapFactory./// amount0Delta and amount1Delta can both be 0 if no tokens were swapped./// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by/// the end of the swap. If positive, the callback must send that amount of token0 to the pool./// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by/// the end of the swap. If positive, the callback must send that amount of token1 to the pool./// @param data Any data passed through by the caller via the ITangleswapPoolActions#swap callfunction tangleswapSwapCallback(int256 amount0Delta,int256 amount1Delta,bytes calldata data) external;}
contracts/core/libraries/LowGasSafeMath.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.7.0;/// @title Optimized overflow and underflow safe math operations/// @notice Contains methods for doing math operations that revert on overflow or underflow for minimal gas costlibrary LowGasSafeMath {/// @notice Returns x + y, reverts if sum overflows uint256/// @param x The augend/// @param y The addend/// @return z The sum of x and yfunction add(uint256 x, uint256 y) internal pure returns (uint256 z) {require((z = x + y) >= x);}/// @notice Returns x - y, reverts if underflows/// @param x The minuend/// @param y The subtrahend/// @return z The difference of x and yfunction sub(uint256 x, uint256 y) internal pure returns (uint256 z) {require((z = x - y) <= x);}/// @notice Returns x * y, reverts if overflows/// @param x The multiplicand/// @param y The multiplier/// @return z The product of x and yfunction mul(uint256 x, uint256 y) internal pure returns (uint256 z) {require(x == 0 || (z = x * y) / x == y);}/// @notice Returns x + y, reverts if overflows or underflows/// @param x The augend/// @param y The addend/// @return z The sum of x and yfunction add(int256 x, int256 y) internal pure returns (int256 z) {require((z = x + y) >= x == (y >= 0));}/// @notice Returns x - y, reverts if overflows or underflows/// @param x The minuend/// @param y The subtrahend
contracts/core/libraries/SafeCast.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.5.0;/// @title Safe casting methods/// @notice Contains methods for safely casting between typeslibrary SafeCast {/// @notice Cast a uint256 to a uint160, revert on overflow/// @param y The uint256 to be downcasted/// @return z The downcasted integer, now type uint160function toUint160(uint256 y) internal pure returns (uint160 z) {require((z = uint160(y)) == y);}/// @notice Cast a int256 to a int128, revert on overflow or underflow/// @param y The int256 to be downcasted/// @return z The downcasted integer, now type int128function toInt128(int256 y) internal pure returns (int128 z) {require((z = int128(y)) == y);}/// @notice Cast a uint256 to a int256, revert on overflow/// @param y The uint256 to be casted/// @return z The casted integer, now type int256function toInt256(uint256 y) internal pure returns (int256 z) {require(y < 2**255);z = int256(y);}}
contracts/core/libraries/TickMath.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.5.0 <0.8.0;/// @title Math library for computing sqrt prices from ticks and vice versa/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports/// prices between 2**-128 and 2**128library TickMath {/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128int24 internal constant MIN_TICK = -887272;/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128int24 internal constant MAX_TICK = -MIN_TICK;/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)uint160 internal constant MIN_SQRT_RATIO = 4295128739;/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;/// @notice Calculates sqrt(1.0001^tick) * 2^96/// @dev Throws if |tick| > max tick/// @param tick The input tick for the above formula/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)/// at the given tickfunction getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));require(absTick <= uint256(MAX_TICK), 'T');uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
contracts/interfaces/IMulticall.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.7.5;pragma abicoder v2;/// @title Multicall interface/// @notice Enables calling multiple methods in a single call to the contractinterface IMulticall {/// @notice Call multiple functions in the current contract and return the data from all of them if they all succeed/// @dev The `msg.value` should not be trusted for any method callable from multicall./// @param data The encoded function data for each of the calls to make to this contract/// @return results The results from each of the calls passed in via datafunction multicall(bytes[] calldata data) external payable returns (bytes[] memory results);}
contracts/interfaces/IPeripheryImmutableState.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.5.0;/// @title Immutable state/// @notice Functions that return immutable state of the routerinterface IPeripheryImmutableState {/// @return Returns the address of the Tangleswap factoryfunction factory() external view returns (address);/// @return Returns the address of WETH9function WETH9() external view returns (address);}
contracts/interfaces/IPeripheryPayments.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.7.5;/// @title Periphery Payments/// @notice Functions to ease deposits and withdrawals of ETHinterface IPeripheryPayments {/// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH./// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users./// @param amountMinimum The minimum amount of WETH9 to unwrap/// @param recipient The address receiving ETHfunction unwrapWETH9(uint256 amountMinimum, address recipient) external payable;/// @notice Refunds any ETH balance held by this contract to the `msg.sender`/// @dev Useful for bundling with mint or increase liquidity that uses ether, or exact output swaps/// that use ether for the input amountfunction refundETH() external payable;/// @notice Transfers the full amount of a token held by this contract to recipient/// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from users/// @param token The contract address of the token which will be transferred to `recipient`/// @param amountMinimum The minimum amount of token required for a transfer/// @param recipient The destination address of the tokenfunction sweepToken(address token,uint256 amountMinimum,address recipient) external payable;}
contracts/interfaces/IPeripheryPaymentsWithFee.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.7.5;import './IPeripheryPayments.sol';/// @title Periphery Payments/// @notice Functions to ease deposits and withdrawals of ETHinterface IPeripheryPaymentsWithFee is IPeripheryPayments {/// @notice Unwraps the contract's WETH9 balance and sends it to recipient as ETH, with a percentage between/// 0 (exclusive), and 1 (inclusive) going to feeRecipient/// @dev The amountMinimum parameter prevents malicious contracts from stealing WETH9 from users.function unwrapWETH9WithFee(uint256 amountMinimum,address recipient,uint256 feeBips,address feeRecipient) external payable;/// @notice Transfers the full amount of a token held by this contract to recipient, with a percentage between/// 0 (exclusive) and 1 (inclusive) going to feeRecipient/// @dev The amountMinimum parameter prevents malicious contracts from stealing the token from usersfunction sweepTokenWithFee(address token,uint256 amountMinimum,address recipient,uint256 feeBips,address feeRecipient) external payable;}
contracts/interfaces/ISelfPermit.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.7.5;/// @title Self Permit/// @notice Functionality to call permit on any EIP-2612-compliant token for use in the routeinterface ISelfPermit {/// @notice Permits this contract to spend a given token from `msg.sender`/// @dev The `owner` is always msg.sender and the `spender` is always address(this)./// @param token The address of the token spent/// @param value The amount that can be spent of token/// @param deadline A timestamp, the current blocktime must be less than or equal to this timestamp/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s`/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s`/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v`function selfPermit(address token,uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) external payable;/// @notice Permits this contract to spend a given token from `msg.sender`/// @dev The `owner` is always msg.sender and the `spender` is always address(this)./// Can be used instead of #selfPermit to prevent calls from failing due to a frontrun of a call to #selfPermit/// @param token The address of the token spent/// @param value The amount that can be spent of token/// @param deadline A timestamp, the current blocktime must be less than or equal to this timestamp/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s`/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s`/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v`function selfPermitIfNecessary(address token,uint256 value,uint256 deadline,uint8 v,bytes32 r,bytes32 s) external payable;
contracts/interfaces/ISwapRouter.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.7.5;pragma abicoder v2;import '../core/interfaces/callback/ITangleswapSwapCallback.sol';/// @title Router token swapping functionality/// @notice Functions for swapping tokens via Tangleswapinterface ISwapRouter is ITangleswapSwapCallback {struct ExactInputSingleParams {address tokenIn;address tokenOut;uint24 fee;address recipient;uint256 deadline;uint256 amountIn;uint256 amountOutMinimum;uint160 sqrtPriceLimitX96;}/// @notice Swaps `amountIn` of one token for as much as possible of another token/// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata/// @return amountOut The amount of the received tokenfunction exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);struct ExactInputParams {bytes path;address recipient;uint256 deadline;uint256 amountIn;uint256 amountOutMinimum;}/// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path/// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata/// @return amountOut The amount of the received tokenfunction exactInput(ExactInputParams calldata params) external payable returns (uint256 amountOut);struct ExactOutputSingleParams {address tokenIn;address tokenOut;
contracts/interfaces/external/IERC20PermitAllowed.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.5.0;/// @title Interface for permit/// @notice Interface used by DAI/CHAI for permitinterface IERC20PermitAllowed {/// @notice Approve the spender to spend some tokens via the holder signature/// @dev This is the permit interface used by DAI and CHAI/// @param holder The address of the token holder, the token owner/// @param spender The address of the token spender/// @param nonce The holder's nonce, increases at each call to permit/// @param expiry The timestamp at which the permit is no longer valid/// @param allowed Boolean that sets approval amount, true for type(uint256).max and false for 0/// @param v Must produce valid secp256k1 signature from the holder along with `r` and `s`/// @param r Must produce valid secp256k1 signature from the holder along with `v` and `s`/// @param s Must produce valid secp256k1 signature from the holder along with `r` and `v`function permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed,uint8 v,bytes32 r,bytes32 s) external;}
contracts/interfaces/external/IWETH9.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity =0.7.6;import '@openzeppelin/contracts/token/ERC20/IERC20.sol';/// @title Interface for WETH9interface IWETH9 is IERC20 {/// @notice Deposit ether to get wrapped etherfunction deposit() external payable;/// @notice Withdraw wrapped ether to get etherfunction withdraw(uint256) external;}
contracts/libraries/BytesLib.sol
// SPDX-License-Identifier: GPL-2.0-or-later/** @title Solidity Bytes Arrays Utils* @author Gonçalo Sá <goncalo.sa@consensys.net>** @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.*/pragma solidity >=0.5.0 <0.8.0;library BytesLib {function slice(bytes memory _bytes,uint256 _start,uint256 _length) internal pure returns (bytes memory) {require(_length + 31 >= _length, 'slice_overflow');require(_start + _length >= _start, 'slice_overflow');require(_bytes.length >= _start + _length, 'slice_outOfBounds');bytes memory tempBytes;assembly {switch iszero(_length)case 0 {// Get a location of some free memory and store it in tempBytes as// Solidity does for memory variables.tempBytes := mload(0x40)// The first word of the slice result is potentially a partial// word read from the original array. To read it, we calculate// the length of that partial word and start copying that many// bytes into the array. The first word we copy will start with// data we don't care about, but the last `lengthmod` bytes will// land at the beginning of the contents of the new array. When// we're done copying, we overwrite the full first word with// the actual length of the slice.let lengthmod := and(_length, 31)// The multiplication in the next line is necessary// because when slicing multiples of 32 bytes (lengthmod == 0)
contracts/libraries/CallbackValidation.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity =0.7.6;import '../core/interfaces/ITangleswapPool.sol';import './PoolAddress.sol';/// @notice Provides validation for callbacks from Tangleswap Poolslibrary CallbackValidation {/// @notice Returns the address of a valid Tangleswap Pool/// @param factory The contract address of the Tangleswap factory/// @param tokenA The contract address of either token0 or token1/// @param tokenB The contract address of the other token/// @param fee The fee collected upon every swap in the pool, denominated in hundredths of a bip/// @return pool The pool contract addressfunction verifyCallback(address factory,address tokenA,address tokenB,uint24 fee) internal view returns (ITangleswapPool pool) {return verifyCallback(factory, PoolAddress.getPoolKey(tokenA, tokenB, fee));}/// @notice Returns the address of a valid Tangleswap Pool/// @param factory The contract address of the Tangleswap factory/// @param poolKey The identifying key of the pool/// @return pool The pool contract addressfunction verifyCallback(address factory, PoolAddress.PoolKey memory poolKey)internalviewreturns (ITangleswapPool pool){pool = ITangleswapPool(PoolAddress.computeAddress(factory, poolKey));require(msg.sender == address(pool));}}
contracts/libraries/Path.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.6.0;import './BytesLib.sol';/// @title Functions for manipulating path data for multihop swapslibrary Path {using BytesLib for bytes;/// @dev The length of the bytes encoded addressuint256 private constant ADDR_SIZE = 20;/// @dev The length of the bytes encoded feeuint256 private constant FEE_SIZE = 3;/// @dev The offset of a single token address and pool feeuint256 private constant NEXT_OFFSET = ADDR_SIZE + FEE_SIZE;/// @dev The offset of an encoded pool keyuint256 private constant POP_OFFSET = NEXT_OFFSET + ADDR_SIZE;/// @dev The minimum length of an encoding that contains 2 or more poolsuint256 private constant MULTIPLE_POOLS_MIN_LENGTH = POP_OFFSET + NEXT_OFFSET;/// @notice Returns true iff the path contains two or more pools/// @param path The encoded swap path/// @return True if path contains two or more pools, otherwise falsefunction hasMultiplePools(bytes memory path) internal pure returns (bool) {return path.length >= MULTIPLE_POOLS_MIN_LENGTH;}/// @notice Returns the number of pools in the path/// @param path The encoded swap path/// @return The number of pools in the pathfunction numPools(bytes memory path) internal pure returns (uint256) {// Ignore the first token address. From then on every fee and token offset indicates a pool.return ((path.length - ADDR_SIZE) / NEXT_OFFSET);}/// @notice Decodes the first pool in path/// @param path The bytes encoded swap path/// @return tokenA The first token of the given pool/// @return tokenB The second token of the given pool/// @return fee The fee level of the pool
contracts/libraries/PoolAddress.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.5.0;/// @title Provides functions for deriving a pool address from the factory, tokens, and the feelibrary PoolAddress {bytes32 internal constant POOL_INIT_CODE_HASH = 0xf007b71dfda986b254c5901f49fcbcd7f5a8297dab23b7bb32a5bb1a48d4ac4c;/// @notice The identifying key of the poolstruct PoolKey {address token0;address token1;uint24 fee;}/// @notice Returns PoolKey: the ordered tokens with the matched fee levels/// @param tokenA The first token of a pool, unsorted/// @param tokenB The second token of a pool, unsorted/// @param fee The fee level of the pool/// @return Poolkey The pool details with ordered token0 and token1 assignmentsfunction getPoolKey(address tokenA,address tokenB,uint24 fee) internal pure returns (PoolKey memory) {if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA);return PoolKey({token0: tokenA, token1: tokenB, fee: fee});}/// @notice Deterministically computes the pool address given the factory and PoolKey/// @param factory The Tangleswap factory contract address/// @param key The PoolKey/// @return pool The contract address of the poolfunction computeAddress(address factory, PoolKey memory key) internal pure returns (address pool) {require(key.token0 < key.token1);pool = address(uint256(keccak256(abi.encodePacked(hex'ff',factory,keccak256(abi.encode(key.token0, key.token1, key.fee)),
contracts/libraries/TransferHelper.sol
// SPDX-License-Identifier: GPL-2.0-or-laterpragma solidity >=0.6.0;import '@openzeppelin/contracts/token/ERC20/IERC20.sol';library TransferHelper {/// @notice Transfers tokens from the targeted address to the given destination/// @notice Errors with 'STF' if transfer fails/// @param token The contract address of the token to be transferred/// @param from The originating address from which the tokens will be transferred/// @param to The destination address of the transfer/// @param value The amount to be transferredfunction safeTransferFrom(address token,address from,address to,uint256 value) internal {(bool success, bytes memory data) =token.call(abi.encodeWithSelector(IERC20.transferFrom.selector, from, to, value));require(success && (data.length == 0 || abi.decode(data, (bool))), 'STF');}/// @notice Transfers tokens from msg.sender to a recipient/// @dev Errors with ST if transfer fails/// @param token The contract address of the token which will be transferred/// @param to The recipient of the transfer/// @param value The value of the transferfunction safeTransfer(address token,address to,uint256 value) internal {(bool success, bytes memory data) = token.call(abi.encodeWithSelector(IERC20.transfer.selector, to, value));require(success && (data.length == 0 || abi.decode(data, (bool))), 'ST');}/// @notice Approves the stipulated contract to spend the given allowance in the given token/// @dev Errors with 'SA' if transfer fails/// @param token The contract address of the token to be approved/// @param to The target of the approval
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_factory","internalType":"address"},{"type":"address","name":"_WETH9","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"WETH9","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"}],"name":"exactInput","inputs":[{"type":"tuple","name":"params","internalType":"struct ISwapRouter.ExactInputParams","components":[{"type":"bytes","name":"path","internalType":"bytes"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"uint256","name":"amountOutMinimum","internalType":"uint256"}]}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"amountOut","internalType":"uint256"}],"name":"exactInputSingle","inputs":[{"type":"tuple","name":"params","internalType":"struct ISwapRouter.ExactInputSingleParams","components":[{"type":"address","name":"tokenIn","internalType":"address"},{"type":"address","name":"tokenOut","internalType":"address"},{"type":"uint24","name":"fee","internalType":"uint24"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint256","name":"amountIn","internalType":"uint256"},{"type":"uint256","name":"amountOutMinimum","internalType":"uint256"},{"type":"uint160","name":"sqrtPriceLimitX96","internalType":"uint160"}]}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"}],"name":"exactOutput","inputs":[{"type":"tuple","name":"params","internalType":"struct ISwapRouter.ExactOutputParams","components":[{"type":"bytes","name":"path","internalType":"bytes"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint256","name":"amountOut","internalType":"uint256"},{"type":"uint256","name":"amountInMaximum","internalType":"uint256"}]}]},{"type":"function","stateMutability":"payable","outputs":[{"type":"uint256","name":"amountIn","internalType":"uint256"}],"name":"exactOutputSingle","inputs":[{"type":"tuple","name":"params","internalType":"struct ISwapRouter.ExactOutputSingleParams","components":[{"type":"address","name":"tokenIn","internalType":"address"},{"type":"address","name":"tokenOut","internalType":"address"},{"type":"uint24","name":"fee","internalType":"uint24"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint256","name":"amountOut","internalType":"uint256"},{"type":"uint256","name":"amountInMaximum","internalType":"uint256"},{"type":"uint160","name":"sqrtPriceLimitX96","internalType":"uint160"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"factory","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[{"type":"bytes[]","name":"results","internalType":"bytes[]"}],"name":"multicall","inputs":[{"type":"bytes[]","name":"data","internalType":"bytes[]"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"refundETH","inputs":[]},{"type":"function","stateMutability":"payable","outputs":[],"name":"selfPermit","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"selfPermitAllowed","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint256","name":"expiry","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"selfPermitAllowedIfNecessary","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"nonce","internalType":"uint256"},{"type":"uint256","name":"expiry","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"selfPermitIfNecessary","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"deadline","internalType":"uint256"},{"type":"uint8","name":"v","internalType":"uint8"},{"type":"bytes32","name":"r","internalType":"bytes32"},{"type":"bytes32","name":"s","internalType":"bytes32"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"sweepToken","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amountMinimum","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"sweepTokenWithFee","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"uint256","name":"amountMinimum","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"feeBips","internalType":"uint256"},{"type":"address","name":"feeRecipient","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"tangleswapSwapCallback","inputs":[{"type":"int256","name":"amount0Delta","internalType":"int256"},{"type":"int256","name":"amount1Delta","internalType":"int256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"unwrapWETH9","inputs":[{"type":"uint256","name":"amountMinimum","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"unwrapWETH9WithFee","inputs":[{"type":"uint256","name":"amountMinimum","internalType":"uint256"},{"type":"address","name":"recipient","internalType":"address"},{"type":"uint256","name":"feeBips","internalType":"uint256"},{"type":"address","name":"feeRecipient","internalType":"address"}]},{"type":"receive","stateMutability":"payable"}]
Deployed ByteCode
0x6080604052600436106101125760003560e01c8063ac9650d8116100a5578063db3e219811610074578063e0e189a011610059578063e0e189a014610302578063f28c049814610315578063f3995c6714610328576101bd565b8063db3e2198146102dc578063df2ab5bb146102ef576101bd565b8063ac9650d814610281578063c04b8d59146102a1578063c2e3140a146102b4578063c45a0155146102c7576101bd565b806349404b7c116100e157806349404b7c146102265780634aa4a4fc146102395780639b2c0a371461025b578063a4a78f0c1461026e576101bd565b806312210e8a146101c257806318e1bb27146101ca578063414bf389146101ea5780634659a49414610213576101bd565b366101bd573373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f916146101bb57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f742057455448390000000000000000000000000000000000000000000000604482015290519081900360640190fd5b005b600080fd5b6101bb61033b565b3480156101d657600080fd5b506101bb6101e5366004612a8a565b61034d565b6101fd6101f8366004612c1a565b6104a0565b60405161020a919061304a565b60405180910390f35b6101bb610221366004612998565b610612565b6101bb610234366004612d21565b6106c6565b34801561024557600080fd5b5061024e61088c565b60405161020a9190612e59565b6101bb610269366004612d50565b6108b0565b6101bb61027c366004612998565b610ac8565b61029461028f3660046129f8565b610b9d565b60405161020a9190612ecc565b6101fd6102af366004612b6f565b610cf7565b6101bb6102c2366004612998565b610e56565b3480156102d357600080fd5b5061024e610f0b565b6101fd6102ea366004612c1a565b610f2f565b6101bb6102fd3660046128f9565b6110bf565b6101bb61031036600461293a565b6111dc565b6101fd610323366004612c36565b611342565b6101bb610336366004612998565b611476565b471561034b5761034b334761150e565b565b600084138061035c5750600083135b61036557600080fd5b600061037382840184612c6e565b90506000806000610387846000015161165c565b9250925092506103b97f000000000000000000000000da2f048c128506e720b0b0b32f20432157dde1c784848461168d565b5060008060008a136103fa578473ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16108961042b565b8373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff16108a5b91509150811561044a5761044585876020015133846116ac565b610494565b85516104559061188a565b1561047a57855161046590611896565b865261047481336000896118d1565b50610494565b8060008190555083945061049485876020015133846116ac565b50505050505050505050565b60008160800135806104b0611b90565b111561051d57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b6105c360a084013561053560808601606087016128ba565b610546610100870160e088016128ba565b604080518082019091528061055e60208a018a6128ba565b61056e60608b0160408c01612cfe565b61057e60408c0160208d016128ba565b60405160200161059093929190612de3565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff16815250611b94565b91508260c0013582101561060c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060390612f94565b60405180910390fd5b50919050565b604080517f8fcbaf0c00000000000000000000000000000000000000000000000000000000815233600482015230602482015260448101879052606481018690526001608482015260ff851660a482015260c4810184905260e48101839052905173ffffffffffffffffffffffffffffffffffffffff881691638fcbaf0c9161010480830192600092919082900301818387803b1580156106b257600080fd5b505af1158015610494573d6000803e3d6000fd5b60007f000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f973ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561074f57600080fd5b505afa158015610763573d6000803e3d6000fd5b505050506040513d602081101561077957600080fd5b50519050828110156107ec57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e742057455448390000000000000000000000000000604482015290519081900360640190fd5b8015610887577f000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f973ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b15801561086557600080fd5b505af1158015610879573d6000803e3d6000fd5b50505050610887828261150e565b505050565b7f000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f981565b6000821180156108c1575060648211155b6108ca57600080fd5b60007f000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f973ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561095357600080fd5b505afa158015610967573d6000803e3d6000fd5b505050506040513d602081101561097d57600080fd5b50519050848110156109f057604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e742057455448390000000000000000000000000000604482015290519081900360640190fd5b8015610ac1577f000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f973ffffffffffffffffffffffffffffffffffffffff16632e1a7d4d826040518263ffffffff1660e01b815260040180828152602001915050600060405180830381600087803b158015610a6957600080fd5b505af1158015610a7d573d6000803e3d6000fd5b505050506000612710610a998584611e1d90919063ffffffff16565b81610aa057fe5b0490508015610ab357610ab3838261150e565b610abf8582840361150e565b505b5050505050565b604080517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015290517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b158015610b5d57600080fd5b505afa158015610b71573d6000803e3d6000fd5b505050506040513d6020811015610b8757600080fd5b50511015610abf57610abf868686868686610612565b60608167ffffffffffffffff81118015610bb657600080fd5b50604051908082528060200260200182016040528015610bea57816020015b6060815260200190600190039081610bd55790505b50905060005b82811015610cf05760008030868685818110610c0857fe5b9050602002810190610c1a9190613053565b604051610c28929190612e49565b600060405180830381855af49150503d8060008114610c63576040519150601f19603f3d011682016040523d82523d6000602084013e610c68565b606091505b509150915081610cce57604481511015610c8157600080fd5b60048101905080806020019051810190610c9b9190612b05565b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106039190612f4a565b80848481518110610cdb57fe5b60209081029190910101525050600101610bf0565b5092915050565b6000816040015180610d07611b90565b1115610d7457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b335b6000610d85856000015161188a565b9050610dde856060015182610d9e578660200151610da0565b305b60006040518060400160405280610dba8b60000151611e41565b81526020018773ffffffffffffffffffffffffffffffffffffffff16815250611b94565b60608601528015610dfe578451309250610df790611896565b8552610e0b565b8460600151935050610e11565b50610d76565b8360800151831015610e4f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060390612f94565b5050919050565b604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081523360048201523060248201529051869173ffffffffffffffffffffffffffffffffffffffff89169163dd62ed3e91604480820192602092909190829003018186803b158015610ecb57600080fd5b505afa158015610edf573d6000803e3d6000fd5b505050506040513d6020811015610ef557600080fd5b50511015610abf57610abf868686868686611476565b7f000000000000000000000000da2f048c128506e720b0b0b32f20432157dde1c781565b6000816080013580610f3f611b90565b1115610fac57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b61105560a0840135610fc460808601606087016128ba565b610fd5610100870160e088016128ba565b6040518060400160405280886020016020810190610ff391906128ba565b61100360608b0160408c01612cfe565b61101060208c018c6128ba565b60405160200161102293929190612de3565b60405160208183030381529060405281526020013373ffffffffffffffffffffffffffffffffffffffff168152506118d1565b91508260c00135821115611095576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060390612f5d565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600055919050565b60008373ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561112857600080fd5b505afa15801561113c573d6000803e3d6000fd5b505050506040513d602081101561115257600080fd5b50519050828110156111c557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e7420746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b80156111d6576111d6848383611e50565b50505050565b6000821180156111ed575060648211155b6111f657600080fd5b60008573ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b15801561125f57600080fd5b505afa158015611273573d6000803e3d6000fd5b505050506040513d602081101561128957600080fd5b50519050848110156112fc57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f496e73756666696369656e7420746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b8015610abf5760006127106113118386611e1d565b8161131857fe5b049050801561132c5761132c878483611e50565b6113398786838503611e50565b50505050505050565b6000816040013580611352611b90565b11156113bf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f5472616e73616374696f6e20746f6f206f6c6400000000000000000000000000604482015290519081900360640190fd5b61143260608401356113d760408601602087016128ba565b60408051808201909152600090806113ef8980613053565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250336020909101526118d1565b5060005491508260800135821115611095576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060390612f5d565b604080517fd505accf000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018790526064810186905260ff8516608482015260a4810184905260c48101839052905173ffffffffffffffffffffffffffffffffffffffff88169163d505accf9160e480830192600092919082900301818387803b1580156106b257600080fd5b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040518082805190602001908083835b6020831061158557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611548565b6001836020036101000a03801982511681845116808217855250505050505090500191505060006040518083038185875af1925050503d80600081146115e7576040519150601f19603f3d011682016040523d82523d6000602084013e6115ec565b606091505b505090508061088757604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354450000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b6000808061166a8482612025565b9250611677846014612125565b9050611684846017612025565b91509193909250565b60006116a38561169e868686612215565b612292565b95945050505050565b7f000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f973ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161480156117075750804710155b15611850577f000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f973ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b15801561177457600080fd5b505af1158015611788573d6000803e3d6000fd5b50505050507f000000000000000000000000ae83571000af4499798d1e3b0fa0070eb3a3e3f973ffffffffffffffffffffffffffffffffffffffff1663a9059cbb83836040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561181e57600080fd5b505af1158015611832573d6000803e3d6000fd5b505050506040513d602081101561184857600080fd5b506111d69050565b73ffffffffffffffffffffffffffffffffffffffff831630141561187e57611879848383611e50565b6111d6565b6111d6848484846122c2565b8051604211155b919050565b80516060906118cb9083906017907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe90161249f565b92915050565b60008073ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000da2f048c128506e720b0b0b32f20432157dde1c773ffffffffffffffffffffffffffffffffffffffff16635a9c63986040518163ffffffff1660e01b815260040160206040518083038186803b15801561195057600080fd5b505afa158015611964573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198891906128dd565b73ffffffffffffffffffffffffffffffffffffffff1614156119d6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060390612fcb565b73ffffffffffffffffffffffffffffffffffffffff84166119f5573093505b6000806000611a07856000015161165c565b9194509250905073ffffffffffffffffffffffffffffffffffffffff80841690831610600080611a38858786612686565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b85611a5e8f6126c4565b60000373ffffffffffffffffffffffffffffffffffffffff8e1615611a83578d611aa9565b87611aa25773fffd8963efd1fc6a506488495d951d5263988d25611aa9565b6401000276a45b8d604051602001611aba9190613002565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611ae9959493929190612e7a565b6040805180830381600087803b158015611b0257600080fd5b505af1158015611b16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b3a9190612a67565b91509150600083611b4f578183600003611b55565b82826000035b909850905073ffffffffffffffffffffffffffffffffffffffff8a16611b81578b8114611b8157600080fd5b50505050505050949350505050565b4290565b60008073ffffffffffffffffffffffffffffffffffffffff167f000000000000000000000000da2f048c128506e720b0b0b32f20432157dde1c773ffffffffffffffffffffffffffffffffffffffff16635a9c63986040518163ffffffff1660e01b815260040160206040518083038186803b158015611c1357600080fd5b505afa158015611c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4b91906128dd565b73ffffffffffffffffffffffffffffffffffffffff161415611c99576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161060390612fcb565b73ffffffffffffffffffffffffffffffffffffffff8416611cb8573093505b6000806000611cca856000015161165c565b9194509250905073ffffffffffffffffffffffffffffffffffffffff80831690841610600080611cfb868686612686565b73ffffffffffffffffffffffffffffffffffffffff1663128acb088b85611d218f6126c4565b73ffffffffffffffffffffffffffffffffffffffff8e1615611d43578d611d69565b87611d625773fffd8963efd1fc6a506488495d951d5263988d25611d69565b6401000276a45b8d604051602001611d7a9190613002565b6040516020818303038152906040526040518663ffffffff1660e01b8152600401611da9959493929190612e7a565b6040805180830381600087803b158015611dc257600080fd5b505af1158015611dd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dfa9190612a67565b9150915082611e095781611e0b565b805b6000039b9a5050505050505050505050565b6000821580611e3857505081810281838281611e3557fe5b04145b6118cb57600080fd5b60606118cb826000602b61249f565b6040805173ffffffffffffffffffffffffffffffffffffffff8481166024830152604480830185905283518084039091018152606490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb000000000000000000000000000000000000000000000000000000001781529251825160009485949389169392918291908083835b60208310611f2557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611ee8565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611f87576040519150601f19603f3d011682016040523d82523d6000602084013e611f8c565b606091505b5091509150818015611fba575080511580611fba5750808060200190516020811015611fb757600080fd5b50515b610ac157604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600260248201527f5354000000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60008182601401101561209957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601260248201527f746f416464726573735f6f766572666c6f770000000000000000000000000000604482015290519081900360640190fd5b816014018351101561210c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f746f416464726573735f6f75744f66426f756e64730000000000000000000000604482015290519081900360640190fd5b5001602001516c01000000000000000000000000900490565b60008182600301101561219957604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f746f55696e7432345f6f766572666c6f77000000000000000000000000000000604482015290519081900360640190fd5b816003018351101561220c57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f746f55696e7432345f6f75744f66426f756e6473000000000000000000000000604482015290519081900360640190fd5b50016003015190565b61221d61282c565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161115612255579192915b506040805160608101825273ffffffffffffffffffffffffffffffffffffffff948516815292909316602083015262ffffff169181019190915290565b600061229e83836126f6565b90503373ffffffffffffffffffffffffffffffffffffffff8216146118cb57600080fd5b6040805173ffffffffffffffffffffffffffffffffffffffff85811660248301528481166044830152606480830185905283518084039091018152608490920183526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f23b872dd00000000000000000000000000000000000000000000000000000000178152925182516000948594938a169392918291908083835b6020831061239f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101612362565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612401576040519150601f19603f3d011682016040523d82523d6000602084013e612406565b606091505b5091509150818015612434575080511580612434575080806020019051602081101561243157600080fd5b50515b610abf57604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600360248201527f5354460000000000000000000000000000000000000000000000000000000000604482015290519081900360640190fd5b60608182601f01101561251357604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b82828401101561258457604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f736c6963655f6f766572666c6f77000000000000000000000000000000000000604482015290519081900360640190fd5b818301845110156125f657604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f736c6963655f6f75744f66426f756e6473000000000000000000000000000000604482015290519081900360640190fd5b606082158015612615576040519150600082526020820160405261267d565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561264e578051835260209283019201612636565b5050858452601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016604052505b50949350505050565b60006126bc7f000000000000000000000000da2f048c128506e720b0b0b32f20432157dde1c76126b7868686612215565b6126f6565b949350505050565b60007f800000000000000000000000000000000000000000000000000000000000000082106126f257600080fd5b5090565b6000816020015173ffffffffffffffffffffffffffffffffffffffff16826000015173ffffffffffffffffffffffffffffffffffffffff161061273857600080fd5b508051602080830151604093840151845173ffffffffffffffffffffffffffffffffffffffff94851681850152939091168385015262ffffff166060808401919091528351808403820181526080840185528051908301207fff0000000000000000000000000000000000000000000000000000000000000060a085015294901b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001660a183015260b58201939093527ff007b71dfda986b254c5901f49fcbcd7f5a8297dab23b7bb32a5bb1a48d4ac4c60d5808301919091528251808303909101815260f5909101909152805191012090565b604080516060810182526000808252602082018190529181019190915290565b80356118918161314d565b600082601f830112612867578081fd5b813561287a612875826130e1565b6130bd565b81815284602083860101111561288e578283fd5b816020850160208301379081016020019190915292915050565b6000610100828403121561060c578081fd5b6000602082840312156128cb578081fd5b81356128d68161314d565b9392505050565b6000602082840312156128ee578081fd5b81516128d68161314d565b60008060006060848603121561290d578182fd5b83356129188161314d565b925060208401359150604084013561292f8161314d565b809150509250925092565b600080600080600060a08688031215612951578081fd5b853561295c8161314d565b94506020860135935060408601356129738161314d565b925060608601359150608086013561298a8161314d565b809150509295509295909350565b60008060008060008060c087890312156129b0578081fd5b86356129bb8161314d565b95506020870135945060408701359350606087013560ff811681146129de578182fd5b9598949750929560808101359460a0909101359350915050565b60008060208385031215612a0a578182fd5b823567ffffffffffffffff80821115612a21578384fd5b818501915085601f830112612a34578384fd5b813581811115612a42578485fd5b8660208083028501011115612a55578485fd5b60209290920196919550909350505050565b60008060408385031215612a79578182fd5b505080516020909101519092909150565b60008060008060608587031215612a9f578182fd5b8435935060208501359250604085013567ffffffffffffffff80821115612ac4578384fd5b818701915087601f830112612ad7578384fd5b813581811115612ae5578485fd5b886020828501011115612af6578485fd5b95989497505060200194505050565b600060208284031215612b16578081fd5b815167ffffffffffffffff811115612b2c578182fd5b8201601f81018413612b3c578182fd5b8051612b4a612875826130e1565b818152856020838501011115612b5e578384fd5b6116a3826020830160208601613121565b600060208284031215612b80578081fd5b813567ffffffffffffffff80821115612b97578283fd5b9083019060a08286031215612baa578283fd5b60405160a081018181108382111715612bbf57fe5b604052823582811115612bd0578485fd5b612bdc87828601612857565b825250612beb6020840161284c565b602082015260408301356040820152606083013560608201526080830135608082015280935050505092915050565b60006101008284031215612c2c578081fd5b6128d683836128a8565b600060208284031215612c47578081fd5b813567ffffffffffffffff811115612c5d578182fd5b820160a081850312156128d6578182fd5b600060208284031215612c7f578081fd5b813567ffffffffffffffff80821115612c96578283fd5b9083019060408286031215612ca9578283fd5b604051604081018181108382111715612cbe57fe5b604052823582811115612ccf578485fd5b612cdb87828601612857565b82525060208301359250612cee8361314d565b6020810192909252509392505050565b600060208284031215612d0f578081fd5b813562ffffff811681146128d6578182fd5b60008060408385031215612d33578182fd5b823591506020830135612d458161314d565b809150509250929050565b60008060008060808587031215612d65578182fd5b843593506020850135612d778161314d565b9250604085013591506060850135612d8e8161314d565b939692955090935050565b60008151808452612db1816020860160208601613121565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b606093841b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000908116825260e89390931b7fffffff0000000000000000000000000000000000000000000000000000000000166014820152921b166017820152602b0190565b6000828483379101908152919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff8088168352861515602084015285604084015280851660608401525060a06080830152612ec160a0830184612d99565b979650505050505050565b6000602080830181845280855180835260408601915060408482028701019250838701855b82811015612f3d577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0888603018452612f2b858351612d99565b94509285019290850190600101612ef1565b5092979650505050505050565b6000602082526128d66020830184612d99565b60208082526012908201527f546f6f206d756368207265717565737465640000000000000000000000000000604082015260600190565b60208082526013908201527f546f6f206c6974746c6520726563656976656400000000000000000000000000604082015260600190565b60208082526015908201527f74616e676c65537761704e4654206e6f74207365740000000000000000000000604082015260600190565b60006020825282516040602084015261301e6060840182612d99565b905073ffffffffffffffffffffffffffffffffffffffff60208501511660408401528091505092915050565b90815260200190565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613087578283fd5b83018035915067ffffffffffffffff8211156130a1578283fd5b6020019150368190038213156130b657600080fd5b9250929050565b60405181810167ffffffffffffffff811182821017156130d957fe5b604052919050565b600067ffffffffffffffff8211156130f557fe5b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b60005b8381101561313c578181015183820152602001613124565b838111156111d65750506000910152565b73ffffffffffffffffffffffffffffffffffffffff8116811461316f57600080fd5b5056fea164736f6c6343000706000a