Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 10 from a total of 10 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Swap By Axelar | 18076851 | 905 days ago | IN | 0.0302 ETH | 0.00431869 | ||||
| Swap By Axelar | 18075106 | 905 days ago | IN | 0.0301 ETH | 0.00290692 | ||||
| Swap By Axelar | 18074982 | 905 days ago | IN | 0.0001 ETH | 0.00349878 | ||||
| Swap By Axelar | 18074918 | 905 days ago | IN | 0.0001 ETH | 0.00044632 | ||||
| Swap By Axelar | 18074377 | 905 days ago | IN | 0.0001 ETH | 0.00348026 | ||||
| Swap By Axelar | 18074212 | 905 days ago | IN | 0.0201 ETH | 0.00071522 | ||||
| Swap By Axelar | 18026692 | 912 days ago | IN | 0.0201 ETH | 0.00477351 | ||||
| Swap By Axelar | 18026670 | 912 days ago | IN | 0.02 ETH | 0.00060783 | ||||
| Swap By Axelar | 18021176 | 912 days ago | IN | 0.0501 ETH | 0.02597564 | ||||
| Swap By Axelar | 18021148 | 912 days ago | IN | 0.05 ETH | 0.00362809 |
Latest 10 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Pay Native Gas F... | 18076851 | 905 days ago | 0.0002 ETH | ||||
| Transfer* | 18076851 | 905 days ago | 0.03 ETH | ||||
| Pay Native Gas F... | 18075106 | 905 days ago | 0.0001 ETH | ||||
| Transfer* | 18075106 | 905 days ago | 0.03 ETH | ||||
| Pay Native Gas F... | 18074982 | 905 days ago | 0.0001 ETH | ||||
| Pay Native Gas F... | 18074377 | 905 days ago | 0.0001 ETH | ||||
| Pay Native Gas F... | 18026692 | 912 days ago | 0.0001 ETH | ||||
| Transfer* | 18026692 | 912 days ago | 0.02 ETH | ||||
| Pay Native Gas F... | 18021176 | 912 days ago | 0.0001 ETH | ||||
| Transfer* | 18021176 | 912 days ago | 0.05 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SwitchAxelar
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "@axelar-network/axelar-gmp-sdk-solidity/contracts/executable/AxelarExecutable.sol";
import "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGateway.sol";
import "@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IAxelarGasService.sol";
import "../dexs/Switch.sol";
import "../lib/DataTypes.sol";
contract SwitchAxelar is Switch, AxelarExecutable {
using UniversalERC20 for IERC20;
using SafeERC20 for IERC20;
IAxelarGasService public immutable gasReceiver;
// Used when no swap required on dest chain
struct TransferArgsAxelar {
address srcToken;
address destToken;
address recipient;
address depositAddr;
address partner;
uint256 partnerFeeRate;
uint256 amount;
uint256 bridgeDstAmount;
uint64 nonce;
uint256[] srcDistribution;
bytes32 id;
bytes32 bridge;
bytes srcParaswapData;
DataTypes.SplitSwapInfo[] srcSplitSwapData;
DataTypes.ParaswapUsageStatus paraswapUsageStatus;
}
// Used when swap required on dest chain
struct SwapArgsAxelar {
DataTypes.SwapInfo srcSwap;
DataTypes.SwapInfo dstSwap;
string bridgeTokenSymbol;
address recipient;
string callTo; // The address of the destination app contract.
bool useNativeGas; // Indicate ETH or bridge token to pay axelar gas
uint256 gasAmount; // Gas amount for axelar gmp
address partner;
uint256 partnerFeeRate;
uint256 amount;
uint256 expectedReturn; // expected bridge token amount on sending chain
uint256 minReturn; // minimum amount of bridge token
uint256 bridgeDstAmount; // estimated token amount of bridgeToken
uint256 estimatedDstTokenAmount; // estimated dest token amount on receiving chain
uint256[] srcDistribution;
uint256[] dstDistribution;
string dstChain;
uint64 nonce;
bytes32 id;
bytes32 bridge;
bytes srcParaswapData;
bytes dstParaswapData;
DataTypes.SplitSwapInfo[] srcSplitSwapData;
DataTypes.SplitSwapInfo[] dstSplitSwapData;
DataTypes.ParaswapUsageStatus paraswapUsageStatus;
}
struct AxelarSwapRequest {
bytes32 id;
bytes32 bridge;
address recipient;
address bridgeToken;
address dstToken;
DataTypes.ParaswapUsageStatus paraswapUsageStatus;
bytes dstParaswapData;
DataTypes.SplitSwapInfo[] dstSplitSwapData;
uint256[] dstDistribution;
uint256 bridgeDstAmount;
}
constructor(
address _weth,
address _otherToken,
uint256[] memory _pathCountAndSplit,
address[] memory _factories,
address _switchViewAddress,
address _switchEventAddress,
address _paraswapProxy,
address _augustusSwapper,
address _gateway,
address _gasReceiver,
address _feeCollector
)
Switch(
_weth,
_otherToken,
_pathCountAndSplit[0],
_pathCountAndSplit[1],
_factories,
_switchViewAddress,
_switchEventAddress,
_paraswapProxy,
_augustusSwapper,
_feeCollector
)
AxelarExecutable(_gateway)
{
gasReceiver = IAxelarGasService(_gasReceiver);
}
receive() external payable {}
function transferByAxelar(TransferArgsAxelar calldata transferArgs)
external
payable
nonReentrant
returns (bytes32 transferId)
{
require(transferArgs.amount > 0, "The amount must be greater than zero");
IERC20(transferArgs.srcToken).universalTransferFrom(
msg.sender,
address(this),
transferArgs.amount
);
uint256 amountAfterFee = _getAmountAfterFee(
IERC20(transferArgs.srcToken),
transferArgs.amount,
transferArgs.partner,
transferArgs.partnerFeeRate
);
uint256 returnAmount = amountAfterFee;
if (
IERC20(transferArgs.srcToken).isETH() &&
transferArgs.destToken == address(weth)
) {
weth.deposit{ value: amountAfterFee }();
} else {
(returnAmount, ) = _swapInternal(
transferArgs.srcToken,
transferArgs.destToken,
amountAfterFee,
transferArgs.paraswapUsageStatus ==
DataTypes.ParaswapUsageStatus.Both ||
transferArgs.paraswapUsageStatus ==
DataTypes.ParaswapUsageStatus.OnSrcChain,
transferArgs.srcParaswapData,
transferArgs.srcSplitSwapData,
transferArgs.srcDistribution,
true
);
}
IERC20(transferArgs.destToken).universalTransfer(
transferArgs.depositAddr,
returnAmount
);
transferId = keccak256(
abi.encodePacked(
address(this),
transferArgs.recipient,
transferArgs.srcToken,
returnAmount,
transferArgs.depositAddr,
transferArgs.nonce,
uint64(block.chainid)
)
);
_emitCrossChainTransferRequest(
transferArgs,
transferId,
returnAmount,
msg.sender,
DataTypes.SwapStatus.Succeeded
);
}
function swapByAxelar(SwapArgsAxelar calldata _swapArgs)
external
payable
nonReentrant
returns (bytes32 transferId)
{
SwapArgsAxelar memory swapArgs = _swapArgs;
require(
swapArgs.expectedReturn >= swapArgs.minReturn,
"expectedReturn must be equal or larger than minReturn"
);
require(
!IERC20(swapArgs.srcSwap.dstToken).isETH(),
"src dest token must not be ETH"
);
if (IERC20(swapArgs.srcSwap.srcToken).isETH()) {
if (swapArgs.useNativeGas) {
require(
msg.value == swapArgs.gasAmount + swapArgs.amount,
"Incorrect Value"
);
} else {
require(msg.value == swapArgs.amount, "Incorrect Value");
}
} else if (swapArgs.useNativeGas) {
require(msg.value == swapArgs.gasAmount, "Incorrect Value");
}
IERC20(swapArgs.srcSwap.srcToken).universalTransferFrom(
msg.sender,
address(this),
swapArgs.amount
);
uint256 amountAfterFee = _getAmountAfterFee(
IERC20(swapArgs.srcSwap.srcToken),
swapArgs.amount,
swapArgs.partner,
swapArgs.partnerFeeRate
);
uint256 returnAmount = amountAfterFee;
if (
IERC20(swapArgs.srcSwap.srcToken).isETH() &&
swapArgs.srcSwap.dstToken == address(weth)
) {
weth.deposit{ value: amountAfterFee }();
} else {
(returnAmount, ) = _swapInternal(
swapArgs.srcSwap.srcToken,
swapArgs.srcSwap.dstToken,
amountAfterFee,
swapArgs.paraswapUsageStatus == DataTypes.ParaswapUsageStatus.Both ||
swapArgs.paraswapUsageStatus ==
DataTypes.ParaswapUsageStatus.OnSrcChain,
swapArgs.srcParaswapData,
swapArgs.srcSplitSwapData,
swapArgs.srcDistribution,
true
);
}
if (!swapArgs.useNativeGas) {
returnAmount -= swapArgs.gasAmount;
}
require(returnAmount > 0, "The amount too small");
require(
returnAmount >= swapArgs.expectedReturn,
"return amount is lower than expected"
);
transferId = keccak256(
abi.encodePacked(
address(this),
swapArgs.recipient,
swapArgs.srcSwap.srcToken,
returnAmount,
swapArgs.dstChain,
swapArgs.nonce,
uint64(block.chainid)
)
);
bytes memory payload = abi.encode(
AxelarSwapRequest({
id: swapArgs.id,
bridge: swapArgs.bridge,
recipient: swapArgs.recipient,
bridgeToken: swapArgs.dstSwap.srcToken,
dstToken: swapArgs.dstSwap.dstToken,
paraswapUsageStatus: swapArgs.paraswapUsageStatus,
dstParaswapData: swapArgs.dstParaswapData,
dstSplitSwapData: swapArgs.dstSplitSwapData,
dstDistribution: swapArgs.dstDistribution,
bridgeDstAmount: swapArgs.bridgeDstAmount
})
);
if (swapArgs.useNativeGas) {
gasReceiver.payNativeGasForContractCallWithToken{
value: swapArgs.gasAmount
}(
address(this),
swapArgs.dstChain,
swapArgs.callTo,
payload,
swapArgs.bridgeTokenSymbol,
amountAfterFee,
msg.sender
);
} else {
IERC20(swapArgs.srcSwap.dstToken).universalApprove(
address(gasReceiver),
swapArgs.gasAmount
);
gasReceiver.payGasForContractCallWithToken(
address(this),
swapArgs.dstChain,
swapArgs.callTo,
payload,
swapArgs.bridgeTokenSymbol,
returnAmount,
swapArgs.srcSwap.dstToken,
swapArgs.gasAmount,
msg.sender
);
}
IERC20(swapArgs.srcSwap.dstToken).universalApprove(
address(gateway),
amountAfterFee
);
gateway.callContractWithToken(
swapArgs.dstChain,
swapArgs.callTo,
payload,
swapArgs.bridgeTokenSymbol,
returnAmount
);
_emitCrossChainSwapRequest(
swapArgs,
transferId,
returnAmount,
msg.sender,
DataTypes.SwapStatus.Succeeded
);
}
function _emitCrossChainSwapRequest(
SwapArgsAxelar memory swapArgs,
bytes32 transferId,
uint256 returnAmount,
address sender,
DataTypes.SwapStatus status
) internal {
switchEvent.emitCrosschainSwapRequest(
swapArgs.id,
transferId,
swapArgs.bridge,
sender,
swapArgs.srcSwap.srcToken,
swapArgs.srcSwap.dstToken,
swapArgs.dstSwap.dstToken,
swapArgs.amount,
returnAmount,
swapArgs.estimatedDstTokenAmount,
status
);
}
function _emitCrossChainTransferRequest(
TransferArgsAxelar calldata transferArgs,
bytes32 transferId,
uint256 returnAmount,
address sender,
DataTypes.SwapStatus status
) internal {
switchEvent.emitCrosschainSwapRequest(
transferArgs.id,
transferId,
transferArgs.bridge,
sender,
transferArgs.srcToken,
transferArgs.destToken,
transferArgs.destToken,
transferArgs.amount,
returnAmount,
transferArgs.bridgeDstAmount,
status
);
}
function _emitCrosschainSwapDone(
AxelarSwapRequest memory swapRequest,
address bridgeToken,
uint256 srcAmount,
uint256 dstAmount,
DataTypes.SwapStatus status
) internal {
switchEvent.emitCrosschainSwapDone(
swapRequest.id,
swapRequest.bridge,
swapRequest.recipient,
bridgeToken,
swapRequest.dstToken,
srcAmount,
dstAmount,
status
);
}
function _executeWithToken(
string calldata,
string calldata,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) internal override {
address bridgeToken = gateway.tokenAddresses(tokenSymbol);
AxelarSwapRequest memory swapRequest = abi.decode(
payload,
(AxelarSwapRequest)
);
if (bridgeToken == address(0)) bridgeToken = swapRequest.bridgeToken;
bool useParaswap = swapRequest.paraswapUsageStatus ==
DataTypes.ParaswapUsageStatus.Both ||
swapRequest.paraswapUsageStatus ==
DataTypes.ParaswapUsageStatus.OnDestChain;
uint256 tokenBal = IERC20(bridgeToken).balanceOf(address(this));
uint256 returnAmount;
DataTypes.SwapStatus status;
if (bridgeToken == swapRequest.dstToken) {
returnAmount = amount;
} else {
if (amount >= swapRequest.bridgeDstAmount) {
(returnAmount, ) = _swapInternal(
bridgeToken,
swapRequest.dstToken,
amount,
useParaswap,
swapRequest.dstParaswapData,
swapRequest.dstSplitSwapData,
swapRequest.dstDistribution,
false
);
} else {
if (bridgeToken != swapRequest.dstToken) {
address dstToken = IERC20(swapRequest.dstToken).isETH()
? address(weth)
: swapRequest.dstToken;
(returnAmount, ) = _swapForSingleSwap(
bridgeToken,
dstToken,
amount,
swapRequest.dstDistribution
);
if (IERC20(swapRequest.dstToken).isETH() && returnAmount != 0) {
weth.deposit{ value: returnAmount }();
}
}
}
uint256 remainBal = IERC20(bridgeToken).balanceOf(address(this));
if (remainBal > tokenBal - amount) {
// Transfer rest bridge token to user
IERC20(bridgeToken).universalTransfer(
swapRequest.recipient,
remainBal + amount - tokenBal
);
}
}
if (returnAmount != 0) {
IERC20(swapRequest.dstToken).universalTransfer(
swapRequest.recipient,
returnAmount
);
}
_emitCrosschainSwapDone(
swapRequest,
bridgeToken,
amount,
returnAmount,
status
);
}
function _swapInternal(
address srcToken,
address destToken,
uint256 amount,
bool useParaswap,
bytes memory paraswapData,
DataTypes.SplitSwapInfo[] memory splitSwapData,
uint256[] memory distribution,
bool raiseError
) internal returns (uint256 returnAmount, uint256 srcAmountRemaining) {
if (srcToken == destToken) {
returnAmount = amount;
} else {
uint256 prevSrcTokenBal = IERC20(srcToken).universalBalanceOf(
address(this)
);
uint256 prevDstTokenBal = IERC20(destToken).universalBalanceOf(
address(this)
);
if (useParaswap) {
_swapInternalWithParaSwap(
IERC20(srcToken),
IERC20(destToken),
amount,
paraswapData
);
} else if (splitSwapData.length != 0) {
uint256 len = splitSwapData.length;
for (uint256 i; i < len; ) {
(bool success, , ) = _swapExternal(
srcToken,
destToken,
splitSwapData[i]
);
require(success || !raiseError, "Swap failed");
unchecked {
i++;
}
}
}
uint256 finalSrcTokenBal = IERC20(srcToken).universalBalanceOf(
address(this)
);
srcAmountRemaining = amount + finalSrcTokenBal - prevSrcTokenBal;
if (distribution.length != 0 && srcAmountRemaining != 0) {
(uint256 receivedAmount, ) = _swapForSingleSwap(
srcToken,
destToken,
srcAmountRemaining,
distribution
);
returnAmount += receivedAmount;
srcAmountRemaining = 0;
}
uint256 finalDstTokenBal = IERC20(destToken).universalBalanceOf(
address(this)
);
returnAmount = finalDstTokenBal - prevDstTokenBal;
}
}
function _swapForSingleSwap(
address srcToken,
address destToken,
uint256 amount,
uint256[] memory distribution
) private returns (uint256 returnAmount, uint256 parts) {
uint256 lastNonZeroIndex = 0;
uint256 len = distribution.length;
for (uint256 i; i < len; ) {
if (distribution[i] > 0) {
parts += distribution[i];
lastNonZeroIndex = i;
}
unchecked {
i++;
}
}
require(parts > 0, "invalid distribution param");
// break function to avoid stack too deep error
returnAmount = _swapInternalForSingleSwap(
distribution,
amount,
parts,
lastNonZeroIndex,
IERC20(srcToken),
IERC20(destToken)
);
require(returnAmount > 0, "Swap failed from dex");
switchEvent.emitSwapped(
msg.sender,
address(this),
IERC20(srcToken),
IERC20(destToken),
amount,
returnAmount,
0
);
}
function _swapExternal(
address srcToken,
address dstToken,
DataTypes.SplitSwapInfo memory splitSwapData
)
internal
returns (
bool success,
uint256 srcAmount,
uint256 returnAmount
)
{
uint256 currAmount = IERC20(dstToken).universalBalanceOf(address(this));
srcAmount = splitSwapData.amount;
IERC20(srcToken).universalApprove(
splitSwapData.spender,
splitSwapData.amount
);
(success, ) = splitSwapData.swapContract.call{
value: IERC20(srcToken).isETH() ? splitSwapData.amount : 0
}(splitSwapData.swapData);
if (success) {
returnAmount =
IERC20(dstToken).universalBalanceOf(address(this)) -
currAmount;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IAxelarGateway } from '../interfaces/IAxelarGateway.sol';
import { IAxelarExecutable } from '../interfaces/IAxelarExecutable.sol';
contract AxelarExecutable is IAxelarExecutable {
IAxelarGateway public immutable gateway;
constructor(address gateway_) {
if (gateway_ == address(0)) revert InvalidAddress();
gateway = IAxelarGateway(gateway_);
}
function execute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external {
bytes32 payloadHash = keccak256(payload);
if (!gateway.validateContractCall(commandId, sourceChain, sourceAddress, payloadHash))
revert NotApprovedByGateway();
_execute(sourceChain, sourceAddress, payload);
}
function executeWithToken(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) external {
bytes32 payloadHash = keccak256(payload);
if (
!gateway.validateContractCallAndMint(
commandId,
sourceChain,
sourceAddress,
payloadHash,
tokenSymbol,
amount
)
) revert NotApprovedByGateway();
_executeWithToken(sourceChain, sourceAddress, payload, tokenSymbol, amount);
}
function _execute(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) internal virtual {}
function _executeWithToken(
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) internal virtual {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { IAxelarGateway } from './IAxelarGateway.sol';
interface IAxelarExecutable {
error InvalidAddress();
error NotApprovedByGateway();
function gateway() external view returns (IAxelarGateway);
function execute(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload
) external;
function executeWithToken(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes calldata payload,
string calldata tokenSymbol,
uint256 amount
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// This should be owned by the microservice that is paying for gas.
interface IAxelarGasService {
error NothingReceived();
error InvalidAddress();
error NotCollector();
error InvalidAmounts();
event GasPaidForContractCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event GasPaidForContractCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForContractCall(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForContractCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
uint256 gasFeeAmount,
address refundAddress
);
event GasPaidForExpressCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasPaidForExpressCallWithToken(
address indexed sourceAddress,
string destinationChain,
string destinationAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
uint256 gasFeeAmount,
address refundAddress
);
event GasAdded(
bytes32 indexed txHash,
uint256 indexed logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeGasAdded(bytes32 indexed txHash, uint256 indexed logIndex, uint256 gasFeeAmount, address refundAddress);
event ExpressGasAdded(
bytes32 indexed txHash,
uint256 indexed logIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
);
event NativeExpressGasAdded(
bytes32 indexed txHash,
uint256 indexed logIndex,
uint256 gasFeeAmount,
address refundAddress
);
// This is called on the source chain before calling the gateway to execute a remote contract.
function payGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
// This is called on the source chain before calling the gateway to execute a remote contract.
function payGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
// This is called on the source chain before calling the gateway to execute a remote contract.
function payNativeGasForContractCall(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
address refundAddress
) external payable;
// This is called on the source chain before calling the gateway to execute a remote contract.
function payNativeGasForContractCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable;
// This is called on the source chain before calling the gateway to execute a remote contract.
function payGasForExpressCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
// This is called on the source chain before calling the gateway to execute a remote contract.
function payNativeGasForExpressCallWithToken(
address sender,
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount,
address refundAddress
) external payable;
function addGas(
bytes32 txHash,
uint256 txIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
function addNativeGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable;
function addExpressGas(
bytes32 txHash,
uint256 txIndex,
address gasToken,
uint256 gasFeeAmount,
address refundAddress
) external;
function addNativeExpressGas(
bytes32 txHash,
uint256 logIndex,
address refundAddress
) external payable;
function collectFees(
address payable receiver,
address[] calldata tokens,
uint256[] calldata amounts
) external;
function refund(
address payable receiver,
address token,
uint256 amount
) external;
function gasCollector() external returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IAxelarGateway {
/**********\
|* Errors *|
\**********/
error NotSelf();
error NotProxy();
error InvalidCodeHash();
error SetupFailed();
error InvalidAuthModule();
error InvalidTokenDeployer();
error InvalidAmount();
error InvalidChainId();
error InvalidCommands();
error TokenDoesNotExist(string symbol);
error TokenAlreadyExists(string symbol);
error TokenDeployFailed(string symbol);
error TokenContractDoesNotExist(address token);
error BurnFailed(string symbol);
error MintFailed(string symbol);
error InvalidSetMintLimitsParams();
error ExceedMintLimit(string symbol);
/**********\
|* Events *|
\**********/
event TokenSent(
address indexed sender,
string destinationChain,
string destinationAddress,
string symbol,
uint256 amount
);
event ContractCall(
address indexed sender,
string destinationChain,
string destinationContractAddress,
bytes32 indexed payloadHash,
bytes payload
);
event ContractCallWithToken(
address indexed sender,
string destinationChain,
string destinationContractAddress,
bytes32 indexed payloadHash,
bytes payload,
string symbol,
uint256 amount
);
event Executed(bytes32 indexed commandId);
event TokenDeployed(string symbol, address tokenAddresses);
event ContractCallApproved(
bytes32 indexed commandId,
string sourceChain,
string sourceAddress,
address indexed contractAddress,
bytes32 indexed payloadHash,
bytes32 sourceTxHash,
uint256 sourceEventIndex
);
event ContractCallApprovedWithMint(
bytes32 indexed commandId,
string sourceChain,
string sourceAddress,
address indexed contractAddress,
bytes32 indexed payloadHash,
string symbol,
uint256 amount,
bytes32 sourceTxHash,
uint256 sourceEventIndex
);
event TokenMintLimitUpdated(string symbol, uint256 limit);
event OperatorshipTransferred(bytes newOperatorsData);
event Upgraded(address indexed implementation);
/********************\
|* Public Functions *|
\********************/
function sendToken(
string calldata destinationChain,
string calldata destinationAddress,
string calldata symbol,
uint256 amount
) external;
function callContract(
string calldata destinationChain,
string calldata contractAddress,
bytes calldata payload
) external;
function callContractWithToken(
string calldata destinationChain,
string calldata contractAddress,
bytes calldata payload,
string calldata symbol,
uint256 amount
) external;
function isContractCallApproved(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
address contractAddress,
bytes32 payloadHash
) external view returns (bool);
function isContractCallAndMintApproved(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
address contractAddress,
bytes32 payloadHash,
string calldata symbol,
uint256 amount
) external view returns (bool);
function validateContractCall(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash
) external returns (bool);
function validateContractCallAndMint(
bytes32 commandId,
string calldata sourceChain,
string calldata sourceAddress,
bytes32 payloadHash,
string calldata symbol,
uint256 amount
) external returns (bool);
/***********\
|* Getters *|
\***********/
function authModule() external view returns (address);
function tokenDeployer() external view returns (address);
function tokenMintLimit(string memory symbol) external view returns (uint256);
function tokenMintAmount(string memory symbol) external view returns (uint256);
function allTokensFrozen() external view returns (bool);
function implementation() external view returns (address);
function tokenAddresses(string memory symbol) external view returns (address);
function tokenFrozen(string memory symbol) external view returns (bool);
function isCommandExecuted(bytes32 commandId) external view returns (bool);
function adminEpoch() external view returns (uint256);
function adminThreshold(uint256 epoch) external view returns (uint256);
function admins(uint256 epoch) external view returns (address[] memory);
/*******************\
|* Admin Functions *|
\*******************/
function setTokenMintLimits(string[] calldata symbols, uint256[] calldata limits) external;
function upgrade(
address newImplementation,
bytes32 newImplementationCodeHash,
bytes calldata setupParams
) external;
/**********************\
|* External Functions *|
\**********************/
function setup(bytes calldata params) external;
function execute(bytes calldata input) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^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
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "../interfaces/IUniswapFactory.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
abstract contract ISwitchView {
struct ReturnArgs {
IERC20 fromToken;
IERC20 destToken;
uint256 amount;
uint256 parts;
}
struct CalculateArgs {
IERC20 fromToken;
IERC20 destToken;
IUniswapFactory factory;
uint256 amount;
uint256 parts;
}
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts
)
public
virtual
view
returns (
uint256 returnAmount,
uint256[] memory distribution
);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
abstract contract IWETH is IERC20 {
function deposit() external virtual payable;
function withdraw(uint256 amount) virtual external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "./ISwitchView.sol";
import "./IWETH.sol";
import "../lib/DisableFlags.sol";
import "../lib/UniversalERC20.sol";
import "../interfaces/IUniswapFactory.sol";
import "../lib/UniswapExchangeLib.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
abstract contract SwitchRoot is Ownable, ISwitchView {
using DisableFlags for uint256;
using UniversalERC20 for IERC20;
using UniversalERC20 for IWETH;
using UniswapExchangeLib for IUniswapExchange;
address public ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
address public ZERO_ADDRESS = address(0);
uint256 public dexCount;
uint256 public pathCount;
uint256 public pathSplit;
IWETH public weth; // chain's native token
IWETH public otherToken; //could be weth on a non-eth chain or other mid token(like busd)
address[] public factories;
int256 internal constant VERY_NEGATIVE_VALUE = -1e72;
constructor(address _weth, address _otherToken, uint256 _pathCount, uint256 _pathSplit, address[] memory _factories) {
weth = IWETH(_weth);
otherToken = IWETH(_otherToken);
pathCount = _pathCount;
pathSplit = _pathSplit;
dexCount = _factories.length;
for (uint256 i = 0; i < _factories.length; i++) {
factories.push(_factories[i]);
}
}
event WETHSet(address _weth);
event OtherTokenSet(address _otherToken);
event PathCountSet(uint256 _pathCount);
event PathSplitSet(uint256 _pathSplit);
event FactoriesSet(address[] _factories);
function setWETH(address _weth) external onlyOwner {
weth = IWETH(_weth);
emit WETHSet(_weth);
}
function setOtherToken(address _otherToken) external onlyOwner {
otherToken = IWETH(_otherToken);
emit OtherTokenSet(_otherToken);
}
function setPathCount(uint256 _pathCount) external onlyOwner {
pathCount = _pathCount;
emit PathCountSet(_pathCount);
}
function setPathSplit(uint256 _pathSplit) external onlyOwner {
pathSplit = _pathSplit;
emit PathSplitSet(_pathSplit);
}
function setFactories(address[] memory _factories) external onlyOwner {
dexCount = _factories.length;
for (uint256 i = 0; i < _factories.length; i++) {
factories.push(_factories[i]);
}
emit FactoriesSet(_factories);
}
function _findBestDistribution(
uint256 s, // parts
int256[][] memory amounts // exchangesReturns
)
internal
view
returns (
int256 returnAmount,
uint256[] memory distribution
)
{
uint256 n = amounts.length;
int256[][] memory answer = new int256[][](n); // int[n][s+1]
uint256[][] memory parent = new uint256[][](n); // int[n][s+1]
for (uint i = 0; i < n; i++) {
answer[i] = new int256[](s + 1);
parent[i] = new uint256[](s + 1);
}
for (uint j = 0; j <= s; j++) {
answer[0][j] = amounts[0][j];
for (uint i = 1; i < n; i++) {
answer[i][j] = -1e72;
}
parent[0][j] = 0;
}
for (uint i = 1; i < n; i++) {
for (uint j = 0; j <= s; j++) {
answer[i][j] = answer[i - 1][j];
parent[i][j] = j;
for (uint k = 1; k <= j; k++) {
if (answer[i - 1][j - k] + amounts[i][k] > answer[i][j]) {
answer[i][j] = answer[i - 1][j - k] + amounts[i][k];
parent[i][j] = j - k;
}
}
}
}
distribution = new uint256[](dexCount*pathCount*pathSplit);
uint256 partsLeft = s;
unchecked {
for (uint curExchange = n - 1; partsLeft > 0; curExchange--) {
distribution[curExchange] = partsLeft - parent[curExchange][partsLeft];
partsLeft = parent[curExchange][partsLeft];
}
}
returnAmount = (answer[n - 1][s] == VERY_NEGATIVE_VALUE) ? int256(0) : answer[n - 1][s];
}
function _linearInterpolation(
uint256 value,
uint256 parts
)
internal
pure
returns (uint256[] memory rets)
{
rets = new uint256[](parts);
for (uint i = 0; i < parts; i++) {
rets[i] = value * (i + 1) / parts;
}
}
function _tokensEqual(
IERC20 tokenA,
IERC20 tokenB
)
internal
pure
returns (bool)
{
return ((tokenA.isETH() && tokenB.isETH()) || tokenA == tokenB);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "../core/ISwitchView.sol";
import "../core/SwitchRoot.sol";
import "../interfaces/ISwitchEvent.sol";
import "../interfaces/IFeeCollector.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Switch is Ownable, SwitchRoot, ReentrancyGuard {
using UniswapExchangeLib for IUniswapExchange;
using UniversalERC20 for IERC20;
using SafeERC20 for IERC20;
ISwitchView public switchView;
ISwitchEvent public switchEvent;
address public reward;
address public paraswapProxy;
address public augustusSwapper;
address public feeCollector;
uint256 public maxPartnerFeeRate = 1000; // max partner fee rate is 10%
uint256 public defaultSwingCut = 1500; // swing takes a cut of 15% from partner fee by default
uint256 public constant FEE_BASE = 10000;
struct SwapArgs {
IERC20 fromToken;
IERC20 destToken;
uint256 amount;
uint256 expectedReturn;
uint256 minReturn;
address partner;
uint256 partnerFeeRate;
address recipient;
uint256[] distribution;
}
event RewardSet(address reward);
event FeeCollectorSet(address feeCollector);
event MaxPartnerFeeRateSet(uint256 maxPartnerFeeRate);
event DefaultSwingCutSet(uint256 defaultSwingCut);
event SwitchEventSet(ISwitchEvent switchEvent);
event ParaswapProxySet(address paraswapProxy);
event AugustusSwapperSet(address augustusSwapper);
constructor(
address _weth,
address _otherToken,
uint256 _pathCount,
uint256 _pathSplit,
address[] memory _factories,
address _switchViewAddress,
address _switchEventAddress,
address _paraswapProxy,
address _augustusSwapper,
address _feeCollector
) SwitchRoot(_weth, _otherToken, _pathCount, _pathSplit, _factories)
public
{
switchView = ISwitchView(_switchViewAddress);
switchEvent = ISwitchEvent(_switchEventAddress);
paraswapProxy = _paraswapProxy;
augustusSwapper = _augustusSwapper;
feeCollector = _feeCollector;
reward = msg.sender;
}
fallback() external payable {
// solium-disable-next-line security/no-tx-origin
require(msg.sender != tx.origin);
}
function setReward(address _reward) external onlyOwner {
reward = _reward;
emit RewardSet(_reward);
}
function setFeeCollector(address _feeCollector) external onlyOwner {
feeCollector = _feeCollector;
emit FeeCollectorSet(_feeCollector);
}
function setMaxPartnerFeeRate(uint256 _maxPartnerFeeRate) external onlyOwner {
require(_maxPartnerFeeRate <= 5000, "too large");
maxPartnerFeeRate = _maxPartnerFeeRate;
emit MaxPartnerFeeRateSet(_maxPartnerFeeRate);
}
function setDefaultSwingCut(uint256 _defaultSwingCut) external onlyOwner {
defaultSwingCut = _defaultSwingCut;
emit DefaultSwingCutSet(_defaultSwingCut);
}
function setSwitchEvent(ISwitchEvent _switchEvent) external onlyOwner {
switchEvent = _switchEvent;
emit SwitchEventSet(_switchEvent);
}
function setParaswapProxy(address _paraswapProxy) external onlyOwner {
paraswapProxy = _paraswapProxy;
emit ParaswapProxySet(_paraswapProxy);
}
function setAugustusSwapper(address _augustusSwapper) external onlyOwner {
augustusSwapper = _augustusSwapper;
emit AugustusSwapperSet(_augustusSwapper);
}
function getTokenBalance(address token) external view onlyOwner returns(uint256 amount) {
amount = IERC20(token).universalBalanceOf(address(this));
}
function transferToken(address token, uint256 amount, address recipient) external onlyOwner {
IERC20(token).universalTransfer(recipient, amount);
}
function getExpectedReturn(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 parts
)
public
override
view
returns (
uint256 returnAmount,
uint256[] memory distribution
)
{
(returnAmount, distribution) = switchView.getExpectedReturn(fromToken, destToken, amount, parts);
}
function swap(
SwapArgs calldata swapArgs
)
public
payable
nonReentrant
returns (uint256 returnAmount)
{
require(swapArgs.expectedReturn >= swapArgs.minReturn, "expectedReturn must be equal or larger than minReturn");
if (swapArgs.fromToken == swapArgs.destToken) {
revert("it's not allowed to swap with same token");
}
uint256 parts = 0;
uint256 lastNonZeroIndex = 0;
for (uint i = 0; i < swapArgs.distribution.length; i++) {
if (swapArgs.distribution[i] > 0) {
parts += swapArgs.distribution[i];
lastNonZeroIndex = i;
}
}
if (parts == 0) {
if (swapArgs.fromToken.isETH()) {
payable(msg.sender).transfer(msg.value);
return msg.value;
}
return swapArgs.amount;
}
swapArgs.fromToken.universalTransferFrom(msg.sender, address(this), swapArgs.amount);
uint256 amountAfterFee = _getAmountAfterFee(swapArgs.fromToken, swapArgs.amount, swapArgs.partner, swapArgs.partnerFeeRate);
returnAmount = _swapInternalForSingleSwap(swapArgs.distribution, amountAfterFee, parts, lastNonZeroIndex, swapArgs.fromToken, swapArgs.destToken);
if (returnAmount > 0) {
require(returnAmount >= swapArgs.minReturn, "Switch: Return amount was not enough");
if (returnAmount > swapArgs.expectedReturn) {
swapArgs.destToken.universalTransfer(swapArgs.recipient, swapArgs.expectedReturn);
swapArgs.destToken.universalTransfer(reward, returnAmount - swapArgs.expectedReturn);
switchEvent.emitSwapped(msg.sender, swapArgs.recipient, swapArgs.fromToken, swapArgs.destToken, swapArgs.amount, swapArgs.expectedReturn, returnAmount - swapArgs.expectedReturn);
} else {
swapArgs.destToken.universalTransfer(swapArgs.recipient, returnAmount);
switchEvent.emitSwapped(msg.sender, swapArgs.recipient, swapArgs.fromToken, swapArgs.destToken, swapArgs.amount, returnAmount, 0);
}
} else {
if (swapArgs.fromToken.universalBalanceOf(address(this)) > swapArgs.amount) {
swapArgs.fromToken.universalTransfer(msg.sender, swapArgs.amount);
} else {
swapArgs.fromToken.universalTransfer(msg.sender, swapArgs.fromToken.universalBalanceOf(address(this)));
}
}
}
function swapWithParaswap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
uint256 destAmount,
address partner,
uint256 partnerFeeRate,
address recipient,
bytes memory callData
)
public
payable
nonReentrant
{
if (fromToken == destToken) {
revert("it's not allowed to swap with same token");
}
fromToken.universalTransferFrom(msg.sender, address(this), amount);
uint256 amountAfterFee = _getAmountAfterFee(IERC20(fromToken), amount, partner, partnerFeeRate);
_callParaswap(fromToken, amountAfterFee, callData);
switchEvent.emitSwapped(msg.sender, recipient, fromToken, destToken, amount, destAmount, 0);
}
function getFeeInfo(
uint256 amount,
address partner,
uint256 partnerFeeRate
)
public
view
returns (
uint256 partnerFee,
uint256 remainAmount
)
{
partnerFee = partnerFeeRate * amount / FEE_BASE;
remainAmount = amount - partnerFee;
}
function _swapInternalWithParaSwap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
bytes memory callData
)
internal
returns (
uint256 totalAmount
)
{
if (fromToken == destToken) {
revert("it's not allowed to swap with same token");
}
_callParaswap(fromToken, amount, callData);
totalAmount = destToken.universalBalanceOf(address(this));
switchEvent.emitSwapped(msg.sender, address(this), fromToken, destToken, amount, totalAmount, 0);
}
function _callParaswap(
IERC20 token,
uint256 amount,
bytes memory callData
)
internal
{
uint256 ethAmountToTransfert = 0;
if (token.isETH()) {
require(address(this).balance >= amount, "ETH balance is insufficient");
ethAmountToTransfert = amount;
} else {
token.universalApprove(paraswapProxy, amount);
}
(bool success,) = augustusSwapper.call{ value: ethAmountToTransfert }(callData);
require(success, "Paraswap execution failed");
}
function _swapInternalForSingleSwap(
uint256[] memory distribution,
uint256 amount,
uint256 parts,
uint256 lastNonZeroIndex,
IERC20 fromToken,
IERC20 destToken
)
internal
returns (
uint256 totalAmount
)
{
require(distribution.length <= dexCount*pathCount, "Switch: Distribution array should not exceed factories array size");
uint256 remainingAmount = amount;
uint256 swappedAmount = 0;
for (uint i = 0; i < distribution.length; i++) {
if (distribution[i] == 0) {
continue;
}
uint256 swapAmount = amount * distribution[i] / parts;
if (i == lastNonZeroIndex) {
swapAmount = remainingAmount;
}
remainingAmount -= swapAmount;
if (i % pathCount == 0) {
swappedAmount = _swap(fromToken, destToken, swapAmount, IUniswapFactory(factories[i/pathCount]));
} else if (i % pathCount == 1) {
swappedAmount = _swapETH(fromToken, destToken, swapAmount, IUniswapFactory(factories[i/pathCount]));
} else {
swappedAmount = _swapOtherToken(fromToken, destToken, swapAmount, IUniswapFactory(factories[i/pathCount]));
}
totalAmount += swappedAmount;
}
}
function _getAmountAfterFee(
IERC20 token,
uint256 amount,
address partner,
uint256 partnerFeeRate
)
internal
returns (
uint256 amountAfterFee
)
{
require(partnerFeeRate <= maxPartnerFeeRate, "partnerFeeRate too large");
amountAfterFee = amount;
if (partnerFeeRate > 0) {
uint256 swingCut = IFeeCollector(feeCollector).getPartnerSwingCut(partner) == 0 ? defaultSwingCut : IFeeCollector(feeCollector).getPartnerSwingCut(partner);
uint256 swingFee = partnerFeeRate * amount * defaultSwingCut / (FEE_BASE * FEE_BASE);
uint256 partnerFee = partnerFeeRate * amount / FEE_BASE - swingFee;
if (IERC20(token).isETH()) {
IFeeCollector(feeCollector).collectTokenFees{ value: partnerFee + swingFee }(address(token), partnerFee, swingFee, partner);
} else {
IERC20(token).safeApprove(feeCollector, 0);
IERC20(token).safeApprove(feeCollector, partnerFee + swingFee);
IFeeCollector(feeCollector).collectTokenFees(address(token), partnerFee, swingFee, partner);
}
amountAfterFee = amount - partnerFeeRate * amount / FEE_BASE;
}
}
// Swap helpers
function _swapInternal(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
IUniswapFactory factory
)
internal
returns (
uint256 returnAmount
)
{
if (fromToken.isETH()) {
weth.deposit{value: amount}();
}
IERC20 fromTokenReal = fromToken.isETH() ? weth : fromToken;
IERC20 toTokenReal = destToken.isETH() ? weth : destToken;
IUniswapExchange exchange = factory.getPair(fromTokenReal, toTokenReal);
bool needSync;
bool needSkim;
(returnAmount, needSync, needSkim) = exchange.getReturn(fromTokenReal, toTokenReal, amount);
if (needSync) {
exchange.sync();
} else if (needSkim) {
exchange.skim(0x46Fd07da395799F113a7584563b8cB886F33c2bc);
}
fromTokenReal.universalTransfer(address(exchange), amount);
if (uint160(address(fromTokenReal)) < uint160(address(toTokenReal))) {
exchange.swap(0, returnAmount, address(this), "");
} else {
exchange.swap(returnAmount, 0, address(this), "");
}
if (destToken.isETH()) {
weth.withdraw(weth.balanceOf(address(this)));
}
}
function _swapOverMid(
IERC20 fromToken,
IERC20 midToken,
IERC20 destToken,
uint256 amount,
IUniswapFactory factory
)
internal
returns (
uint256 returnAmount
)
{
returnAmount = _swapInternal(
midToken,
destToken,
_swapInternal(
fromToken,
midToken,
amount,
factory
),
factory
);
}
function _swap(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
IUniswapFactory factory
)
internal
returns (
uint256 returnAmount
)
{
returnAmount = _swapInternal(
fromToken,
destToken,
amount,
factory
);
}
function _swapETH(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
IUniswapFactory factory
)
internal
returns (
uint256 returnAmount
)
{
returnAmount = _swapOverMid(
fromToken,
weth,
destToken,
amount,
factory
);
}
function _swapOtherToken(
IERC20 fromToken,
IERC20 destToken,
uint256 amount,
IUniswapFactory factory
)
internal
returns (
uint256 returnAmount
)
{
returnAmount = _swapOverMid(
fromToken,
otherToken,
destToken,
amount,
factory
);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
interface IFeeCollector {
function collectTokenFees(
address tokenAddress,
uint256 partnerFee,
uint256 swingFee,
address partnerAddress
) payable external;
function getPartnerSwingCut(address partnerAddress) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../lib/DataTypes.sol";
interface ISwitchEvent {
function emitSwapped(
address from,
address recipient,
IERC20 fromToken,
IERC20 destToken,
uint256 fromAmount,
uint256 destAmount,
uint256 reward
) external;
function emitParaswapSwapped(
address from,
IERC20 fromToken,
uint256 fromAmount
) external;
function emitCrosschainSwapRequest(
bytes32 id,
bytes32 bridgeTransferId,
bytes32 bridge, // bridge slug
address from, // user address
address fromToken, // source token on sending chain
address bridgeToken, // bridge token on sending chain
address destToken, // dest token on receiving chain
uint256 fromAmount, // source token amount on sending chain
uint256 bridgeAmount, // swapped amount on sending chain
uint256 dstAmount, // estimated amount of dest token on receiving chain
DataTypes.SwapStatus status
) external;
function emitCrosschainContractCallRequest(
bytes32 id,
bytes32 bridgeTransferId,
bytes32 bridge, // bridge slug
address from, // user address
address toContractAddress, // The address of the contract to interact with
address toApprovalAddress, // the approval address for contract call
address fromToken, // source token on sending chain
address callToken, // contract call token on receiving chain
uint256 fromAmount, // source token amount on sending chain
uint256 estimatedCallAmount, // estimated amount of contract call token on receiving chain
DataTypes.ContractCallStatus status
) external;
function emitCrosschainSwapDone(
bytes32 id,
bytes32 bridge,
address from, // user address
address bridgeToken, // source token on receiving chain
address destToken, // dest token on receiving chain
uint256 bridgeAmount, // bridge token amount on receiving chain
uint256 destAmount, //dest token amount on receiving chain
DataTypes.SwapStatus status
) external;
function emitCrosschainContractCallDone(
bytes32 id,
bytes32 bridge,
address from, // user address
address toContractAddress, // The address of the contract to interact with
address toApprovalAddress, // the approval address for contract call
address bridgeToken, // source token on receiving chain
address callToken, // call token on receiving chain
uint256 bridgeAmount, // bridge token amount on receiving chain
uint256 estimatedCallAmount, //dest token amount on receiving chain
DataTypes.ContractCallStatus status
) external;
function emitSingleChainContractCallDone(
address from, // user address
address toContractAddress, // The address of the contract to interact with
address toApprovalAddress, // the approval address for contract call
address fromToken, // source token on receiving chain
address callToken, // call token on receiving chain
uint256 fromAmount, // from token amount on receiving chain
uint256 callAmount, //dest token amount on receiving chain
DataTypes.ContractCallStatus status
) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
interface IUniswapExchange {
function getReserves() external view returns(uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IUniswapExchange.sol";
interface IUniswapFactory {
function getPair(IERC20 tokenA, IERC20 tokenB) external view returns (IUniswapExchange pair);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
/**
* @title DataTypes
* @dev Definition of shared types
*/
library DataTypes {
/// @notice Type for representing a swapping status type
enum SwapStatus {
Null,
Succeeded,
Failed,
Fallback
}
enum ContractCallStatus {
Null,
Succeeded,
Failed,
Fallback
}
/// @notice Type for representing a paraswap usage status
enum ParaswapUsageStatus {
None,
OnSrcChain,
OnDestChain,
Both
}
/// @notice Split Swap params
struct SplitSwapInfo {
uint256 amount;
address swapContract;
address spender;
bytes swapData;
}
/// @notice Swap params
struct SwapInfo {
address srcToken;
address dstToken;
}
struct ContractCallInfo {
address toContractAddress; // The address of the contract to interact with.
address toApprovalAddress; // the approval address for contract call
address contractOutputsToken; // Some contract interactions will output a token (e.g. staking)
uint32 toContractGasLimit; // The estimated gas used by the destination call.
bytes toContractCallData; // The callData to be sent to the contract for the interaction on the destination chain.
}
struct ContractCallRequest {
bytes32 id;
bytes32 bridge;
address srcToken;
address bridgeToken;
address callToken;
address recipient;
uint256 srcAmount;
uint256 bridgeDstAmount;
uint256 estimatedCallAmount;
uint256[] dstDistribution;
bytes dstParaswapData;
ContractCallInfo callInfo;
ParaswapUsageStatus paraswapUsageStatus;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
library DisableFlags {
function check(
uint256 flags,
uint256 flag
)
internal
pure
returns (bool)
{
return (flags & flag) != 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
library Math {
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow, so we distribute
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "../interfaces/IUniswapExchange.sol";
import "./Math.sol";
import "./UniversalERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
library UniswapExchangeLib {
using Math for uint256;
using UniversalERC20 for IERC20;
function getReturn(
IUniswapExchange exchange,
IERC20 fromToken,
IERC20 destToken,
uint amountIn
)
internal
view
returns (uint256 result, bool needSync, bool needSkim)
{
uint256 reserveIn = fromToken.universalBalanceOf(address(exchange));
uint256 reserveOut = destToken.universalBalanceOf(address(exchange));
(uint112 reserve0, uint112 reserve1,) = exchange.getReserves();
if (fromToken > destToken) {
(reserve0, reserve1) = (reserve1, reserve0);
}
needSync = (reserveIn < reserve0 || reserveOut < reserve1);
needSkim = !needSync && (reserveIn > reserve0 || reserveOut > reserve1);
uint256 amountInWithFee = amountIn * 997;
uint256 numerator = amountInWithFee * Math.min(reserveOut, reserve1);
uint256 denominator = Math.min(reserveIn, reserve0) * 1000 + amountInWithFee;
result = (denominator == 0) ? 0 : numerator / denominator;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
library UniversalERC20 {
using SafeERC20 for IERC20;
address private constant ZERO_ADDRESS = address(0x0000000000000000000000000000000000000000);
address private constant ETH_ADDRESS = address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);
function universalTransfer(
IERC20 token,
address to,
uint256 amount
)
internal
returns (bool)
{
if (amount == 0) {
return true;
}
if (isETH(token)) {
payable(to).transfer(amount);
return true;
} else {
token.safeTransfer(to, amount);
return true;
}
}
function universalTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
)
internal
{
if (amount == 0) {
return;
}
if (isETH(token)) {
require(from == msg.sender && msg.value >= amount, "Wrong useage of ETH.universalTransferFrom()");
if (to != address(this)) {
payable(to).transfer(amount);
}
// commented following lines for passing celer fee properly.
// if (msg.value > amount) {
// payable(msg.sender).transfer(msg.value - amount);
// }
} else {
token.safeTransferFrom(from, to, amount);
}
}
function universalTransferFromSenderToThis(
IERC20 token,
uint256 amount
)
internal
{
if (amount == 0) {
return;
}
if (isETH(token)) {
if (msg.value > amount) {
// Return remainder if exist
payable(msg.sender).transfer(msg.value - amount);
}
} else {
token.safeTransferFrom(msg.sender, address(this), amount);
}
}
function universalApprove(
IERC20 token,
address to,
uint256 amount
)
internal
{
if (!isETH(token)) {
if (amount == 0) {
token.safeApprove(to, 0);
return;
}
uint256 approvedAmount = token.allowance(address(this), to);
if (approvedAmount > 0) {
token.safeApprove(to, 0);
}
token.safeApprove(to, amount);
}
}
function universalBalanceOf(IERC20 token, address who) internal view returns (uint256) {
if (isETH(token)) {
return who.balance;
} else {
return token.balanceOf(who);
}
}
function isETH(IERC20 token) internal pure returns(bool) {
return (address(token) == address(ZERO_ADDRESS) || address(token) == address(ETH_ADDRESS));
}
// function notExist(IERC20 token) internal pure returns(bool) {
// return (address(token) == address(-1));
// }
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_otherToken","type":"address"},{"internalType":"uint256[]","name":"_pathCountAndSplit","type":"uint256[]"},{"internalType":"address[]","name":"_factories","type":"address[]"},{"internalType":"address","name":"_switchViewAddress","type":"address"},{"internalType":"address","name":"_switchEventAddress","type":"address"},{"internalType":"address","name":"_paraswapProxy","type":"address"},{"internalType":"address","name":"_augustusSwapper","type":"address"},{"internalType":"address","name":"_gateway","type":"address"},{"internalType":"address","name":"_gasReceiver","type":"address"},{"internalType":"address","name":"_feeCollector","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"NotApprovedByGateway","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"augustusSwapper","type":"address"}],"name":"AugustusSwapperSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"defaultSwingCut","type":"uint256"}],"name":"DefaultSwingCutSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"_factories","type":"address[]"}],"name":"FactoriesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeCollector","type":"address"}],"name":"FeeCollectorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"maxPartnerFeeRate","type":"uint256"}],"name":"MaxPartnerFeeRateSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_otherToken","type":"address"}],"name":"OtherTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"paraswapProxy","type":"address"}],"name":"ParaswapProxySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_pathCount","type":"uint256"}],"name":"PathCountSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_pathSplit","type":"uint256"}],"name":"PathSplitSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"reward","type":"address"}],"name":"RewardSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract ISwitchEvent","name":"switchEvent","type":"address"}],"name":"SwitchEventSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_weth","type":"address"}],"name":"WETHSet","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"ETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_BASE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ZERO_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"augustusSwapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultSwingCut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dexCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"commandId","type":"bytes32"},{"internalType":"string","name":"sourceChain","type":"string"},{"internalType":"string","name":"sourceAddress","type":"string"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"executeWithToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"factories","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasReceiver","outputs":[{"internalType":"contract IAxelarGasService","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gateway","outputs":[{"internalType":"contract IAxelarGateway","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"parts","type":"uint256"}],"name":"getExpectedReturn","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"partner","type":"address"},{"internalType":"uint256","name":"partnerFeeRate","type":"uint256"}],"name":"getFeeInfo","outputs":[{"internalType":"uint256","name":"partnerFee","type":"uint256"},{"internalType":"uint256","name":"remainAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getTokenBalance","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPartnerFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"otherToken","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paraswapProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pathCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pathSplit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reward","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_augustusSwapper","type":"address"}],"name":"setAugustusSwapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_defaultSwingCut","type":"uint256"}],"name":"setDefaultSwingCut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_factories","type":"address[]"}],"name":"setFactories","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeCollector","type":"address"}],"name":"setFeeCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxPartnerFeeRate","type":"uint256"}],"name":"setMaxPartnerFeeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_otherToken","type":"address"}],"name":"setOtherToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_paraswapProxy","type":"address"}],"name":"setParaswapProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pathCount","type":"uint256"}],"name":"setPathCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pathSplit","type":"uint256"}],"name":"setPathSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_reward","type":"address"}],"name":"setReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISwitchEvent","name":"_switchEvent","type":"address"}],"name":"setSwitchEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_weth","type":"address"}],"name":"setWETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expectedReturn","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"address","name":"partner","type":"address"},{"internalType":"uint256","name":"partnerFeeRate","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"distribution","type":"uint256[]"}],"internalType":"struct Switch.SwapArgs","name":"swapArgs","type":"tuple"}],"name":"swap","outputs":[{"internalType":"uint256","name":"returnAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"}],"internalType":"struct DataTypes.SwapInfo","name":"srcSwap","type":"tuple"},{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"dstToken","type":"address"}],"internalType":"struct DataTypes.SwapInfo","name":"dstSwap","type":"tuple"},{"internalType":"string","name":"bridgeTokenSymbol","type":"string"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"string","name":"callTo","type":"string"},{"internalType":"bool","name":"useNativeGas","type":"bool"},{"internalType":"uint256","name":"gasAmount","type":"uint256"},{"internalType":"address","name":"partner","type":"address"},{"internalType":"uint256","name":"partnerFeeRate","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"expectedReturn","type":"uint256"},{"internalType":"uint256","name":"minReturn","type":"uint256"},{"internalType":"uint256","name":"bridgeDstAmount","type":"uint256"},{"internalType":"uint256","name":"estimatedDstTokenAmount","type":"uint256"},{"internalType":"uint256[]","name":"srcDistribution","type":"uint256[]"},{"internalType":"uint256[]","name":"dstDistribution","type":"uint256[]"},{"internalType":"string","name":"dstChain","type":"string"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"bytes32","name":"bridge","type":"bytes32"},{"internalType":"bytes","name":"srcParaswapData","type":"bytes"},{"internalType":"bytes","name":"dstParaswapData","type":"bytes"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"swapContract","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"}],"internalType":"struct DataTypes.SplitSwapInfo[]","name":"srcSplitSwapData","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"swapContract","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"}],"internalType":"struct DataTypes.SplitSwapInfo[]","name":"dstSplitSwapData","type":"tuple[]"},{"internalType":"enum DataTypes.ParaswapUsageStatus","name":"paraswapUsageStatus","type":"uint8"}],"internalType":"struct SwitchAxelar.SwapArgsAxelar","name":"_swapArgs","type":"tuple"}],"name":"swapByAxelar","outputs":[{"internalType":"bytes32","name":"transferId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"fromToken","type":"address"},{"internalType":"contract IERC20","name":"destToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"destAmount","type":"uint256"},{"internalType":"address","name":"partner","type":"address"},{"internalType":"uint256","name":"partnerFeeRate","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"swapWithParaswap","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"switchEvent","outputs":[{"internalType":"contract ISwitchEvent","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"switchView","outputs":[{"internalType":"contract ISwitchView","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"srcToken","type":"address"},{"internalType":"address","name":"destToken","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"depositAddr","type":"address"},{"internalType":"address","name":"partner","type":"address"},{"internalType":"uint256","name":"partnerFeeRate","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"bridgeDstAmount","type":"uint256"},{"internalType":"uint64","name":"nonce","type":"uint64"},{"internalType":"uint256[]","name":"srcDistribution","type":"uint256[]"},{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"bytes32","name":"bridge","type":"bytes32"},{"internalType":"bytes","name":"srcParaswapData","type":"bytes"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"swapContract","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"bytes","name":"swapData","type":"bytes"}],"internalType":"struct DataTypes.SplitSwapInfo[]","name":"srcSplitSwapData","type":"tuple[]"},{"internalType":"enum DataTypes.ParaswapUsageStatus","name":"paraswapUsageStatus","type":"uint8"}],"internalType":"struct SwitchAxelar.TransferArgsAxelar","name":"transferArgs","type":"tuple"}],"name":"transferByAxelar","outputs":[{"internalType":"bytes32","name":"transferId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"transferToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60c0604052600180546001600160a01b031990811673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee179091556002805490911690556103e86010556105dc6011553480156200004f57600080fd5b5060405162005c2538038062005c2583398101604081905262000072916200040b565b828b8b8b6000815181106200008b576200008b62000527565b60200260200101518c600181518110620000a957620000a962000527565b60200260200101518c8c8c8c8c8a8989898989620000d6620000d06200024d60201b60201c565b62000251565b600680546001600160a01b038088166001600160a01b031992831617909255600780549287169290911691909117905560048390556005829055805160035560005b81518110156200018957600882828151811062000139576200013962000527565b60209081029190910181015182546001810184556000938452919092200180546001600160a01b0319166001600160a01b039092169190911790558062000180816200053d565b91505062000118565b505060016009555050600a80546001600160a01b03199081166001600160a01b03998a1617909155600b80548216978916979097179096555050600d8054851693861693909317909255600e80548416918516919091179055600f80548316918416919091179055600c80543392169190911790558616151594506200022793505050505760405163e6c4247b60e01b815260040160405180910390fd5b6001600160a01b039081166080529190911660a052506200056798505050505050505050565b3390565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620002b957600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715620002ff57620002ff620002be565b604052919050565b60006001600160401b03821115620003235762000323620002be565b5060051b60200190565b600082601f8301126200033f57600080fd5b8151602062000358620003528362000307565b620002d4565b82815260059290921b840181019181810190868411156200037857600080fd5b8286015b848110156200039557805183529183019183016200037c565b509695505050505050565b600082601f830112620003b257600080fd5b81516020620003c5620003528362000307565b82815260059290921b84018101918181019086841115620003e557600080fd5b8286015b848110156200039557620003fd81620002a1565b8352918301918301620003e9565b60008060008060008060008060008060006101608c8e0312156200042e57600080fd5b620004398c620002a1565b9a506200044960208d01620002a1565b60408d0151909a506001600160401b038111156200046657600080fd5b620004748e828f016200032d565b60608e0151909a5090506001600160401b038111156200049357600080fd5b620004a18e828f01620003a0565b985050620004b260808d01620002a1565b9650620004c260a08d01620002a1565b9550620004d260c08d01620002a1565b9450620004e260e08d01620002a1565b9350620004f36101008d01620002a1565b9250620005046101208d01620002a1565b9150620005156101408d01620002a1565b90509295989b509295989b9093969950565b634e487b7160e01b600052603260045260246000fd5b60006000198214156200056057634e487b7160e01b600052601160045260246000fd5b5060010190565b60805160a051615660620005c560003960008181610571015281816115080152818161159a01526115f10152600081816102930152818161082b01528181610dc90152818161167b015281816116a2015261205201526156606000f3fe60806040526004361061026b5760003560e01c806380d14b4a11610144578063b9d52d3c116100b6578063e5932c401161007a578063e5932c4014610744578063e8984c5f14610764578063ea15afc314610784578063ecefc705146107a4578063f2fde38b146107ba578063f640d508146107da57610272565b8063b9d52d3c146106a6578063c415b95c146106c6578063c93d732d146106e6578063d6821ed8146106f9578063e37c42501461072e57610272565b8063a42dce8011610108578063a42dce80146105f0578063a734f06e14610610578063a85f329814610630578063ab30469514610650578063ae551c6614610666578063b4c76fe01461068657610272565b806380d14b4a1461055f5780638928a29f146105935780638c821e90146105a65780638da5cb5b146105bc57806390f3f208146105da57610272565b806349160658116101dd5780635b769f3c116101a15780635b769f3c146104a95780635c3d258f146104c95780636076a0b4146104e9578063672383c414610517578063715018a6146105375780637184e28d1461054c57610272565b8063491606581461041357806352b721f814610433578063538ba4f91461044957806353fd7bf1146104695780635b18075e1461048957610272565b806331428a871161022f57806331428a87146103535780633aecd0e3146103735780633fc8cef314610393578063433b3c05146103b35780634399fa56146103d357806348c4d781146103f357610272565b8063116191b6146102815780631a98b2e0146102d2578063228cb733146102f257806323a9495e14610312578063245ab19e1461033257610272565b3661027257005b3332141561027f57600080fd5b005b34801561028d57600080fd5b506102b57f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102de57600080fd5b5061027f6102ed366004614045565b6107fa565b3480156102fe57600080fd5b50600c546102b5906001600160a01b031681565b34801561031e57600080fd5b5061027f61032d36600461411e565b6108fd565b610345610340366004614137565b610941565b6040519081526020016102c9565b34801561035f57600080fd5b50600a546102b5906001600160a01b031681565b34801561037f57600080fd5b5061034561038e366004614192565b610cfa565b34801561039f57600080fd5b506006546102b5906001600160a01b031681565b3480156103bf57600080fd5b506007546102b5906001600160a01b031681565b3480156103df57600080fd5b50600b546102b5906001600160a01b031681565b3480156103ff57600080fd5b5061027f61040e36600461411e565b610d1d565b34801561041f57600080fd5b5061027f61042e3660046141af565b610d98565b34801561043f57600080fd5b5061034560115481565b34801561045557600080fd5b506002546102b5906001600160a01b031681565b34801561047557600080fd5b5061027f610484366004614192565b610e81565b34801561049557600080fd5b50600d546102b5906001600160a01b031681565b3480156104b557600080fd5b5061027f6104c4366004614192565b610ed7565b3480156104d557600080fd5b5061027f6104e436600461411e565b610f2d565b3480156104f557600080fd5b50610509610504366004614252565b610f6a565b6040516102c9929190614298565b34801561052357600080fd5b506102b561053236600461411e565b611013565b34801561054357600080fd5b5061027f61103d565b61034561055a3660046142e6565b611051565b34801561056b57600080fd5b506102b57f000000000000000000000000000000000000000000000000000000000000000081565b61027f6105a1366004614444565b61174f565b3480156105b257600080fd5b5061034560045481565b3480156105c857600080fd5b506000546001600160a01b03166102b5565b3480156105e657600080fd5b5061034560055481565b3480156105fc57600080fd5b5061027f61060b366004614192565b611833565b34801561061c57600080fd5b506001546102b5906001600160a01b031681565b34801561063c57600080fd5b5061027f61064b36600461411e565b611889565b34801561065c57600080fd5b5061034560035481565b34801561067257600080fd5b50600e546102b5906001600160a01b031681565b34801561069257600080fd5b5061027f6106a1366004614192565b6118c6565b3480156106b257600080fd5b5061027f6106c1366004614192565b61191c565b3480156106d257600080fd5b50600f546102b5906001600160a01b031681565b6103456106f43660046144e8565b611972565b34801561070557600080fd5b50610719610714366004614523565b611e17565b604080519283526020830191909152016102c9565b34801561073a57600080fd5b5061034560105481565b34801561075057600080fd5b5061027f61075f366004614192565b611e47565b34801561077057600080fd5b5061027f61077f366004614192565b611e9d565b34801561079057600080fd5b5061027f61079f36600461457e565b611ef3565b3480156107b057600080fd5b5061034561271081565b3480156107c657600080fd5b5061027f6107d5366004614192565b611f9d565b3480156107e657600080fd5b5061027f6107f5366004614611565b612016565b6000858560405161080c929190614653565b604051908190038120631876eed960e01b825291506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631876eed990610870908e908e908e908e908e9089908d908d908d9060040161468c565b602060405180830381600087803b15801561088a57600080fd5b505af115801561089e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c291906146f9565b6108df57604051631403112d60e21b815260040160405180910390fd5b6108f08a8a8a8a8a8a8a8a8a612038565b5050505050505050505050565b610905612420565b60058190556040518181527f11e8ee12d79dc7314b845f4e82465af5bd3d2214081526061af36de8364eaa2e906020015b60405180910390a150565b600061094b61247a565b60008260c00135116109b05760405162461bcd60e51b8152602060048201526024808201527f54686520616d6f756e74206d7573742062652067726561746572207468616e206044820152637a65726f60e01b60648201526084015b60405180910390fd5b6109d8333060c08501356109c76020870187614192565b6001600160a01b03169291906124d4565b6000610a096109ea6020850185614192565b60c08501356109ff60a0870160808801614192565b8660a001356125c6565b905080610a2a610a1c6020860186614192565b6001600160a01b0316612914565b8015610a5857506006546001600160a01b0316610a4d6040860160208701614192565b6001600160a01b0316145b15610acb57600660009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610aad57600080fd5b505af1158015610ac1573d6000803e3d6000fd5b5050505050610be5565b610be1610adb6020860186614192565b610aeb6040870160208801614192565b846003610b006101e08a016101c08b0161473b565b6003811115610b1157610b11614716565b1480610b3f57506001610b2c6101e08a016101c08b0161473b565b6003811115610b3d57610b3d614716565b145b610b4d6101808a018a614756565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610b90925050506101a08b018b61479c565b610b99916148bb565b610ba76101208c018c61479c565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506001925061294d915050565b5090505b610c19610bf86080860160608701614192565b82610c096040880160208901614192565b6001600160a01b03169190612ae2565b5030610c2b6060860160408701614192565b610c386020870187614192565b83610c496080890160608a01614192565b610c5b6101208a016101008b016148df565b6040516bffffffffffffffffffffffff19606097881b8116602083015295871b8616603482015293861b85166048850152605c84019290925290931b909116607c8201526001600160c01b031960c092831b811660908301524690921b909116609882015260a001604051602081830303815290604052805190602001209250610ce9848483336001612b5e565b5050610cf56001600955565b919050565b6000610d04612420565b610d176001600160a01b03831630612c15565b92915050565b610d25612420565b611388811115610d635760405162461bcd60e51b8152602060048201526009602482015268746f6f206c6172676560b81b60448201526064016109a7565b60108190556040518181527fa28aac6f4ba79029a647ee085b0ae88419c6aa87bae5dcf77d303dba45b3681b90602001610936565b60008282604051610daa929190614653565b604051908190038120635f6970c360e01b825291506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635f6970c390610e08908b908b908b908b908b9089906004016148fa565b602060405180830381600087803b158015610e2257600080fd5b505af1158015610e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5a91906146f9565b610e7757604051631403112d60e21b815260040160405180910390fd5b5050505050505050565b610e89612420565b600b80546001600160a01b0319166001600160a01b0383169081179091556040519081527f35e63b7fefc2b1fb2ed78adeed6688b187514d96c2d7d56222e52f3e41c2fb2f90602001610936565b610edf612420565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527f41408be49f75701fe4bb8484ce88d68f1d82e03cb4eb44263b6682ce2dbd32f090602001610936565b610f35612420565b60118190556040518181527f8f817f25bf47abe304b519d80d1a633064758c57d280731736fe82ad20816c5590602001610936565b600a5460405163181da82d60e21b81526001600160a01b03868116600483015285811660248301526044820185905260648201849052600092606092911690636076a0b49060840160006040518083038186803b158015610fca57600080fd5b505afa158015610fde573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611006919081019061493b565b9097909650945050505050565b6008818154811061102357600080fd5b6000918252602090912001546001600160a01b0316905081565b611045612420565b61104f6000612caf565b565b600061105b61247a565b600061106683614aca565b905080610160015181610140015110156110925760405162461bcd60e51b81526004016109a790614d35565b8051602001516110aa906001600160a01b0316612914565b156110f75760405162461bcd60e51b815260206004820152601e60248201527f737263206465737420746f6b656e206d757374206e6f7420626520455448000060448201526064016109a7565b80515161110c906001600160a01b0316612914565b15611177578060a0015115611153578061012001518160c001516111309190614da0565b341461114e5760405162461bcd60e51b81526004016109a790614db8565b6111a4565b806101200151341461114e5760405162461bcd60e51b81526004016109a790614db8565b8060a00151156111a4578060c0015134146111a45760405162461bcd60e51b81526004016109a790614db8565b6101208101518151516111c6916001600160a01b0390911690339030906124d4565b60006111ea8260000151600001518361012001518460e001518561010001516125c6565b8251519091508190611204906001600160a01b0316612914565b801561122357506006548351602001516001600160a01b039081169116145b1561129657600660009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b15801561127857600080fd5b505af115801561128c573d6000803e3d6000fd5b50505050506112fe565b825180516020909101516112fa919084600387610300015160038111156112bf576112bf614716565b14806112e15750600187610300015160038111156112df576112df614716565b145b876102800151886102c00151896101c00151600161294d565b5090505b8260a001516113195760c08301516113169082614de1565b90505b600081116113605760405162461bcd60e51b8152602060048201526014602482015273151a1948185b5bdd5b9d081d1bdbc81cdb585b1b60621b60448201526064016109a7565b8261014001518110156113c15760405162461bcd60e51b8152602060048201526024808201527f72657475726e20616d6f756e74206973206c6f776572207468616e206578706560448201526318dd195960e21b60648201526084016109a7565b60608301518351516102008501516102208601516040516113ee9430949093909287924690602001614e24565b60405160208183030381529060405280519060200120935060006040518061014001604052808561024001518152602001856102600151815260200185606001516001600160a01b031681526020018560200151600001516001600160a01b031681526020018560200151602001516001600160a01b03168152602001856103000151600381111561148257611482614716565b8152602001856102a001518152602001856102e001518152602001856101e0015181526020018561018001518152506040516020016114c19190614fbe565b60405160208183030381529060405290508360a001511561157d5760c084015161020085015160808601516040808801519051636316100160e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169463c62c20029490936115469330938991908c90339060040161509c565b6000604051808303818588803b15801561155f57600080fd5b505af1158015611573573d6000803e3d6000fd5b5050505050611666565b60c08401518451602001516115bf916001600160a01b03909116907f000000000000000000000000000000000000000000000000000000000000000090612cff565b610200840151608085015160408087015187516020015160c0890151925163edb6b3a560e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169563edb6b3a595611633953095929491938a93928c9290913390600401615115565b600060405180830381600087803b15801561164d57600080fd5b505af1158015611661573d6000803e3d6000fd5b505050505b8351602001516116a0906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000085612cff565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b54170848561020001518660800151848860400151876040518663ffffffff1660e01b81526004016117019594939291906151a4565b600060405180830381600087803b15801561171b57600080fd5b505af115801561172f573d6000803e3d6000fd5b50505050611741848684336001612ddf565b50505050610cf56001600955565b61175761247a565b866001600160a01b0316886001600160a01b031614156117895760405162461bcd60e51b81526004016109a790615204565b61179e6001600160a01b0389163330896124d4565b60006117ac898887876125c6565b90506117b9898284612e4a565b600b54604051630e47f70960e21b81526001600160a01b039091169063391fdc24906117f690339087908e908e908e908e9060009060040161524c565b600060405180830381600087803b15801561181057600080fd5b505af1158015611824573d6000803e3d6000fd5b5050505050610e776001600955565b61183b612420565b600f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f12e1d17016b94668449f97876f4a8d5cc2c19f314db337418894734037cc19d490602001610936565b611891612420565b60048190556040518181527f70f24e12a9db25e0d80cbcde19ffef47d6a7c52c1089db4c71e53ce1856577fc90602001610936565b6118ce612420565b600780546001600160a01b0319166001600160a01b0383169081179091556040519081527f17780f3919f73af11f29e4157534858a06c91294d64b679fe4e49340122cd32290602001610936565b611924612420565b600e80546001600160a01b0319166001600160a01b0383169081179091556040519081527fe0209b1ff5892dc27d9ffb30000e308317645f928d78a0a018dd2e9289ecc29290602001610936565b600061197c61247a565b8160800135826060013510156119a45760405162461bcd60e51b81526004016109a790614d35565b6119b46040830160208401614192565b6001600160a01b03166119ca6020840184614192565b6001600160a01b031614156119f15760405162461bcd60e51b81526004016109a790615204565b60008060005b611a0561010086018661479c565b9050811015611a83576000611a1e61010087018761479c565b83818110611a2e57611a2e615290565b905060200201351115611a7157611a4961010086018661479c565b82818110611a5957611a59615290565b9050602002013583611a6b9190614da0565b92508091505b80611a7b816152a6565b9150506119f7565b5081611ae257611a99610a1c6020860186614192565b15611ad55760405133903480156108fc02916000818181858888f19350505050158015611aca573d6000803e3d6000fd5b503492505050611e0d565b5050506040810135611e0d565b611af9333060408701356109c76020890189614192565b6000611b2a611b0b6020870187614192565b6040870135611b2060c0890160a08a01614192565b8860c001356125c6565b9050611b96611b3d61010087018761479c565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250859250879150869050611b8160208b018b614192565b611b9160408c0160208d01614192565b612f8e565b93508315611da0578460800135841015611bfe5760405162461bcd60e51b8152602060048201526024808201527f5377697463683a2052657475726e20616d6f756e7420776173206e6f7420656e6044820152630deeaced60e31b60648201526084016109a7565b8460600135841115611d1057611c33611c1e610100870160e08801614192565b6060870135610c096040890160208a01614192565b50600c54611c62906001600160a01b0316611c52606088013587614de1565b610c096040890160208a01614192565b50600b546001600160a01b031663391fdc2433611c86610100890160e08a01614192565b611c9360208a018a614192565b611ca360408b0160208c01614192565b60408b013560608c0135611cb7818d614de1565b6040518863ffffffff1660e01b8152600401611cd9979695949392919061524c565b600060405180830381600087803b158015611cf357600080fd5b505af1158015611d07573d6000803e3d6000fd5b50505050611e09565b611d35611d24610100870160e08801614192565b85610c096040890160208a01614192565b50600b546001600160a01b031663391fdc2433611d59610100890160e08a01614192565b611d6660208a018a614192565b611d7660408b0160208c01614192565b8a604001358a60006040518863ffffffff1660e01b8152600401611cd9979695949392919061524c565b6040850135611dc530611db66020890189614192565b6001600160a01b031690612c15565b1115611de757611de1336040870135610c096020890189614192565b50611e09565b61174133611dfc30611db660208a018a614192565b610c096020890189614192565b5050505b610cf56001600955565b600080612710611e2786856152c1565b611e3191906152f6565b9150611e3d8286614de1565b9050935093915050565b611e4f612420565b600c80546001600160a01b0319166001600160a01b0383169081179091556040519081527f53a596d7be747a5a4f4d39a6a36476d2eed407c93f6f2ba8a96c8b971240d5cd90602001610936565b611ea5612420565b600d80546001600160a01b0319166001600160a01b0383169081179091556040519081527f4528d04696417deba6006cd6c7e5bbb56b9874ac9d954a956e14b8d74f08d72b90602001610936565b611efb612420565b805160035560005b8151811015611f6d576008828281518110611f2057611f20615290565b60209081029190910181015182546001810184556000938452919092200180546001600160a01b0319166001600160a01b0390921691909117905580611f65816152a6565b915050611f03565b507fbbc63a7f378af7e269ef19f3fe0d08f044c91ee72930c0d045a58be58580f3d381604051610936919061530a565b611fa5612420565b6001600160a01b03811661200a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016109a7565b61201381612caf565b50565b61201e612420565b6120326001600160a01b0384168284612ae2565b50505050565b6040516349ad89fb60e11b81526000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063935b13f6906120899087908790600401615357565b60206040518083038186803b1580156120a157600080fd5b505afa1580156120b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d9919061536b565b905060006120e986880188615388565b90506001600160a01b03821661210157806060015191505b600060038260a00151600381111561211b5761211b614716565b148061213c575060028260a00151600381111561213a5761213a614716565b145b6040516370a0823160e01b81523060048201529091506000906001600160a01b038516906370a082319060240160206040518083038186803b15801561218157600080fd5b505afa158015612195573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b991906154a6565b905060008084608001516001600160a01b0316866001600160a01b031614156121e4578691506123d4565b846101200151871061221a5761221286866080015189878960c001518a60e001518b6101000151600061294d565b509150612314565b84608001516001600160a01b0316866001600160a01b03161461231457600061224f86608001516001600160a01b0316612914565b61225d57856080015161226a565b6006546001600160a01b03165b905061227d87828a8961010001516131be565b508093505061229886608001516001600160a01b0316612914565b80156122a357508215155b1561231257600660009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156122f857600080fd5b505af115801561230c573d6000803e3d6000fd5b50505050505b505b6040516370a0823160e01b81523060048201526000906001600160a01b038816906370a082319060240160206040518083038186803b15801561235657600080fd5b505afa15801561236a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238e91906154a6565b905061239a8885614de1565b8111156123d25760408601516123d090856123b58b85614da0565b6123bf9190614de1565b6001600160a01b038a169190612ae2565b505b505b81156124025761240085604001518387608001516001600160a01b0316612ae29092919063ffffffff16565b505b61240f858789858561334a565b505050505050505050505050505050565b6000546001600160a01b0316331461104f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109a7565b600260095414156124cd5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109a7565b6002600955565b806124de57612032565b6124e784612914565b156125b1576001600160a01b038316331480156125045750803410155b6125645760405162461bcd60e51b815260206004820152602b60248201527f57726f6e6720757365616765206f66204554482e756e6976657273616c54726160448201526a6e7366657246726f6d282960a81b60648201526084016109a7565b6001600160a01b03821630146125ac576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156125aa573d6000803e3d6000fd5b505b612032565b6120326001600160a01b038516848484613397565b600060105482111561261a5760405162461bcd60e51b815260206004820152601860248201527f706172746e65724665655261746520746f6f206c61726765000000000000000060448201526064016109a7565b5082811561290c57600f54604051637b8c4cdf60e01b81526001600160a01b0385811660048301526000921690637b8c4cdf9060240160206040518083038186803b15801561266857600080fd5b505afa15801561267c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126a091906154a6565b1561272757600f54604051637b8c4cdf60e01b81526001600160a01b03868116600483015290911690637b8c4cdf9060240160206040518083038186803b1580156126ea57600080fd5b505afa1580156126fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272291906154a6565b61272b565b6011545b9050600061273b612710806152c1565b60115461274888876152c1565b61275291906152c1565b61275c91906152f6565b905060008161271061276e89886152c1565b61277891906152f6565b6127829190614de1565b9050612796886001600160a01b0316612914565b1561282957600f546001600160a01b031663eedd56e16127b68484614da0565b6040516001600160e01b031960e084901b1681526001600160a01b03808d16600483015260248201869052604482018790528a1660648201526084016000604051808303818588803b15801561280b57600080fd5b505af115801561281f573d6000803e3d6000fd5b50505050506128e5565b600f54612844906001600160a01b038a811691166000613402565b600f5461286f906001600160a01b031661285e8484614da0565b6001600160a01b038b169190613402565b600f5460405163eedd56e160e01b81526001600160a01b038a81166004830152602482018490526044820185905288811660648301529091169063eedd56e190608401600060405180830381600087803b1580156128cc57600080fd5b505af11580156128e0573d6000803e3d6000fd5b505050505b6127106128f288876152c1565b6128fc91906152f6565b6129069088614de1565b93505050505b949350505050565b60006001600160a01b0382161580610d1757506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600080886001600160a01b03168a6001600160a01b0316141561297257879150612ad5565b60006129876001600160a01b038c1630612c15565b9050600061299e6001600160a01b038c1630612c15565b905088156129b8576129b28c8c8c8b613526565b50612a46565b865115612a4657865160005b81811015612a435760006129f28f8f8c85815181106129e5576129e5615290565b60200260200101516135f0565b505090508080612a00575087155b612a3a5760405162461bcd60e51b815260206004820152600b60248201526a14ddd85c0819985a5b195960aa1b60448201526064016109a7565b506001016129c4565b50505b6000612a5b6001600160a01b038e1630612c15565b905082612a68828d614da0565b612a729190614de1565b93508651600014158015612a8557508315155b15612aad576000612a988e8e878b6131be565b509050612aa58187614da0565b955060009450505b6000612ac26001600160a01b038e1630612c15565b9050612ace8382614de1565b9550505050505b9850989650505050505050565b600081612af157506001612b57565b612afa84612914565b15612b3f576040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015612b35573d6000803e3d6000fd5b5060019050612b57565b612b536001600160a01b03851684846136e2565b5060015b9392505050565b600b546001600160a01b0316630aea28c76101408701358661016089013586612b8a60208c018c614192565b612b9a60408d0160208e01614192565b612baa60408e0160208f01614192565b8d60c001358c8f60e001358c6040518c63ffffffff1660e01b8152600401612bdc9b9a999897969594939291906154bf565b600060405180830381600087803b158015612bf657600080fd5b505af1158015612c0a573d6000803e3d6000fd5b505050505050505050565b6000612c2083612914565b15612c3657506001600160a01b03811631610d17565b6040516370a0823160e01b81526001600160a01b0383811660048301528416906370a082319060240160206040518083038186803b158015612c7757600080fd5b505afa158015612c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b5791906154a6565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612d0883612914565b612d265780612d2b57612d266001600160a01b038416836000613402565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e9060440160206040518083038186803b158015612d7657600080fd5b505afa158015612d8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dae91906154a6565b90508015612dcb57612dcb6001600160a01b038516846000613402565b6120326001600160a01b0385168484613402565b600b5461024086015161026087015187518051602091820151828b0151909201516101208b01516101a08c0151604051630aea28c760e01b81526001600160a01b0390981697630aea28c797612bdc9790968e9691958d95929491939092918f918e906004016154bf565b6000612e5e846001600160a01b0316612914565b15612eba5782471015612eb35760405162461bcd60e51b815260206004820152601b60248201527f4554482062616c616e636520697320696e73756666696369656e74000000000060448201526064016109a7565b5081612ed4565b600d54612ed4906001600160a01b03868116911685612cff565b600e546040516000916001600160a01b0316908390612ef4908690615533565b60006040518083038185875af1925050503d8060008114612f31576040519150601f19603f3d011682016040523d82523d6000602084013e612f36565b606091505b5050905080612f875760405162461bcd60e51b815260206004820152601960248201527f506172617377617020657865637574696f6e206661696c65640000000000000060448201526064016109a7565b5050505050565b6000600454600354612fa091906152c1565b875111156130205760405162461bcd60e51b815260206004820152604160248201527f5377697463683a20446973747269627574696f6e2061727261792073686f756c60448201527f64206e6f742065786365656420666163746f726965732061727261792073697a6064820152606560f81b608482015260a4016109a7565b856000805b89518110156131b15789818151811061304057613040615290565b6020026020010151600014156130555761319f565b6000888b838151811061306a5761306a615290565b60200260200101518b61307d91906152c1565b61308791906152f6565b9050878214156130945750825b61309e8185614de1565b9350600454826130ae919061554f565b6130f9576130f28787836008600454876130c891906152f6565b815481106130d8576130d8615290565b6000918252602090912001546001600160a01b0316613712565b9250613191565b600454613106908361554f565b6001141561314e576130f287878360086004548761312491906152f6565b8154811061313457613134615290565b6000918252602090912001546001600160a01b0316613729565b61318e87878360086004548761316491906152f6565b8154811061317457613174615290565b6000918252602090912001546001600160a01b0316613746565b92505b61319b8386614da0565b9450505b806131a9816152a6565b915050613025565b5050509695505050505050565b6000806000808451905060005b818110156132285760008682815181106131e7576131e7615290565b602002602001015111156132205785818151811061320757613207615290565b60200260200101518461321a9190614da0565b93508092505b6001016131cb565b50600083116132795760405162461bcd60e51b815260206004820152601a60248201527f696e76616c696420646973747269627574696f6e20706172616d00000000000060448201526064016109a7565b613287858785858c8c612f8e565b9350600084116132d05760405162461bcd60e51b81526020600482015260146024820152730a6eec2e040ccc2d2d8cac840cce4deda40c8caf60631b60448201526064016109a7565b600b54604051630e47f70960e21b81526001600160a01b039091169063391fdc249061330d90339030908d908d908d908c9060009060040161524c565b600060405180830381600087803b15801561332757600080fd5b505af115801561333b573d6000803e3d6000fd5b50505050505094509492505050565b600b548551602087015160408089015160808a0151915163424971a960e11b81526001600160a01b0390951694638492e35294612bdc9490939092918b91908b908b908b90600401615563565b6040516001600160a01b03808516602483015283166044820152606481018290526120329085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613763565b80158061348b5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561345157600080fd5b505afa158015613465573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348991906154a6565b155b6134f65760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016109a7565b6040516001600160a01b038316602482015260448101829052612d2690849063095ea7b360e01b906064016133cb565b6000836001600160a01b0316856001600160a01b0316141561355a5760405162461bcd60e51b81526004016109a790615204565b613565858484612e4a565b6135786001600160a01b03851630612c15565b600b54604051630e47f70960e21b81529192506001600160a01b03169063391fdc24906135b690339030908a908a908a90899060009060040161524c565b600060405180830381600087803b1580156135d057600080fd5b505af11580156135e4573d6000803e3d6000fd5b50505050949350505050565b60008080806136086001600160a01b03871630612c15565b8551604087015190945090915061362a906001600160a01b0389169085612cff565b84602001516001600160a01b031661364a886001600160a01b0316612914565b613655576000613658565b85515b866060015160405161366a9190615533565b60006040518083038185875af1925050503d80600081146136a7576040519150601f19603f3d011682016040523d82523d6000602084013e6136ac565b606091505b509094505083156136d857806136cb6001600160a01b03881630612c15565b6136d59190614de1565b91505b5093509350939050565b6040516001600160a01b038316602482015260448101829052612d2690849063a9059cbb60e01b906064016133cb565b600061372085858585613838565b95945050505050565b6006546000906137209086906001600160a01b0316868686613ca4565b6007546000906137209086906001600160a01b0316868686613ca4565b60006137b8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613cc79092919063ffffffff16565b90508051600014806137d95750808060200190518101906137d991906146f9565b612d265760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109a7565b600061384c856001600160a01b0316612914565b156138bb57600660009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156138a157600080fd5b505af11580156138b5573d6000803e3d6000fd5b50505050505b60006138cf866001600160a01b0316612914565b6138d957856138e6565b6006546001600160a01b03165b905060006138fc866001600160a01b0316612914565b6139065785613913565b6006546001600160a01b03165b60405163e6a4390560e01b81526001600160a01b038481166004830152808316602483015291925060009186169063e6a439059060440160206040518083038186803b15801561396257600080fd5b505afa158015613976573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399a919061536b565b90506000806139b46001600160a01b03841686868b613cd6565b919750925090508115613a1957826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156139fc57600080fd5b505af1158015613a10573d6000803e3d6000fd5b50505050613a8d565b8015613a8d5760405163bc25cf7760e01b81527346fd07da395799f113a7584563b8cb886f33c2bc60048201526001600160a01b0384169063bc25cf7790602401600060405180830381600087803b158015613a7457600080fd5b505af1158015613a88573d6000803e3d6000fd5b505050505b613aa16001600160a01b038616848a612ae2565b50836001600160a01b0316856001600160a01b03161015613b365760405163022c0d9f60e01b8152600060048201819052602482018890523060448301526080606483015260848201526001600160a01b0384169063022c0d9f9060a401600060405180830381600087803b158015613b1957600080fd5b505af1158015613b2d573d6000803e3d6000fd5b50505050613bac565b60405163022c0d9f60e01b8152600481018790526000602482018190523060448301526080606483015260848201526001600160a01b0384169063022c0d9f9060a401600060405180830381600087803b158015613b9357600080fd5b505af1158015613ba7573d6000803e3d6000fd5b505050505b613bbe896001600160a01b0316612914565b15613c97576006546040516370a0823160e01b81523060048201526001600160a01b0390911690632e1a7d4d9082906370a082319060240160206040518083038186803b158015613c0e57600080fd5b505afa158015613c22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4691906154a6565b6040518263ffffffff1660e01b8152600401613c6491815260200190565b600060405180830381600087803b158015613c7e57600080fd5b505af1158015613c92573d6000803e3d6000fd5b505050505b5050505050949350505050565b6000613cbd8585613cb789898888613838565b85613838565b9695505050505050565b606061290c8484600085613e71565b6000808080613cee6001600160a01b03881689612c15565b90506000613d056001600160a01b0388168a612c15565b90506000808a6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015613d4357600080fd5b505afa158015613d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d7b91906155d2565b5091509150886001600160a01b03168a6001600160a01b03161115613d9c57905b816001600160701b0316841080613dbb5750806001600160701b031683105b955085158015613de55750816001600160701b0316841180613de55750806001600160701b031683115b94506000613df5896103e56152c1565b90506000613e0c85846001600160701b0316613f4c565b613e1690836152c1565b9050600082613e2e88876001600160701b0316613f4c565b613e3a906103e86152c1565b613e449190614da0565b90508015613e5b57613e5681836152f6565b613e5e565b60005b9950505050505050509450945094915050565b606082471015613ed25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016109a7565b600080866001600160a01b03168587604051613eee9190615533565b60006040518083038185875af1925050503d8060008114613f2b576040519150601f19603f3d011682016040523d82523d6000602084013e613f30565b606091505b5091509150613f4187838387613f62565b979650505050505050565b6000818310613f5b5781612b57565b5090919050565b60608315613fce578251613fc7576001600160a01b0385163b613fc75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109a7565b508161290c565b61290c8383815115613fe35781518083602001fd5b8060405162461bcd60e51b81526004016109a79190615617565b60008083601f84011261400f57600080fd5b5081356001600160401b0381111561402657600080fd5b60208301915083602082850101111561403e57600080fd5b9250929050565b60008060008060008060008060008060c08b8d03121561406457600080fd5b8a35995060208b01356001600160401b038082111561408257600080fd5b61408e8e838f01613ffd565b909b50995060408d01359150808211156140a757600080fd5b6140b38e838f01613ffd565b909950975060608d01359150808211156140cc57600080fd5b6140d88e838f01613ffd565b909750955060808d01359150808211156140f157600080fd5b506140fe8d828e01613ffd565b9150809450508092505060a08b013590509295989b9194979a5092959850565b60006020828403121561413057600080fd5b5035919050565b60006020828403121561414957600080fd5b81356001600160401b0381111561415f57600080fd5b82016101e08185031215612b5757600080fd5b6001600160a01b038116811461201357600080fd5b8035610cf581614172565b6000602082840312156141a457600080fd5b8135612b5781614172565b60008060008060008060006080888a0312156141ca57600080fd5b8735965060208801356001600160401b03808211156141e857600080fd5b6141f48b838c01613ffd565b909850965060408a013591508082111561420d57600080fd5b6142198b838c01613ffd565b909650945060608a013591508082111561423257600080fd5b5061423f8a828b01613ffd565b989b979a50959850939692959293505050565b6000806000806080858703121561426857600080fd5b843561427381614172565b9350602085013561428381614172565b93969395505050506040820135916060013590565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156142d9578451835293830193918301916001016142bd565b5090979650505050505050565b6000602082840312156142f857600080fd5b81356001600160401b0381111561430e57600080fd5b82016103608185031215612b5757600080fd5b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b038111828210171561435957614359614321565b60405290565b60405161032081016001600160401b038111828210171561435957614359614321565b60405161014081016001600160401b038111828210171561435957614359614321565b604051601f8201601f191681016001600160401b03811182821017156143cd576143cd614321565b604052919050565b600082601f8301126143e657600080fd5b81356001600160401b038111156143ff576143ff614321565b614412601f8201601f19166020016143a5565b81815284602083860101111561442757600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600080600080610100898b03121561446157600080fd5b883561446c81614172565b9750602089013561447c81614172565b96506040890135955060608901359450608089013561449a81614172565b935060a0890135925060c08901356144b181614172565b915060e08901356001600160401b038111156144cc57600080fd5b6144d88b828c016143d5565b9150509295985092959890939650565b6000602082840312156144fa57600080fd5b81356001600160401b0381111561451057600080fd5b82016101208185031215612b5757600080fd5b60008060006060848603121561453857600080fd5b83359250602084013561454a81614172565b929592945050506040919091013590565b60006001600160401b0382111561457457614574614321565b5060051b60200190565b6000602080838503121561459157600080fd5b82356001600160401b038111156145a757600080fd5b8301601f810185136145b857600080fd5b80356145cb6145c68261455b565b6143a5565b81815260059190911b820183019083810190878311156145ea57600080fd5b928401925b82841015613f4157833561460281614172565b825292840192908401906145ef565b60008060006060848603121561462657600080fd5b833561463181614172565b925060208401359150604084013561464881614172565b809150509250925092565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b89815260c0602082015260006146a660c083018a8c614663565b82810360408401526146b981898b614663565b905086606084015282810360808401526146d4818688614663565b9150508260a08301529a9950505050505050505050565b801515811461201357600080fd5b60006020828403121561470b57600080fd5b8151612b57816146eb565b634e487b7160e01b600052602160045260246000fd5b803560048110610cf557600080fd5b60006020828403121561474d57600080fd5b612b578261472c565b6000808335601e1984360301811261476d57600080fd5b8301803591506001600160401b0382111561478757600080fd5b60200191503681900382131561403e57600080fd5b6000808335601e198436030181126147b357600080fd5b8301803591506001600160401b038211156147cd57600080fd5b6020019150600581901b360382131561403e57600080fd5b60006147f36145c68461455b565b8381529050602080820190600585901b84018681111561481257600080fd5b845b818110156148b05780356001600160401b03808211156148345760008081fd5b908701906080828b0312156148495760008081fd5b614851614337565b823581528583013561486281614172565b8187015260408381013561487581614172565b908201526060838101358381111561488d5760008081fd5b6148998d8287016143d5565b918301919091525086525050928201928201614814565b505050509392505050565b6000612b573684846147e5565b80356001600160401b0381168114610cf557600080fd5b6000602082840312156148f157600080fd5b612b57826148c8565b868152608060208201526000614914608083018789614663565b8281036040840152614927818688614663565b915050826060830152979650505050505050565b6000806040838503121561494e57600080fd5b825191506020808401516001600160401b0381111561496c57600080fd5b8401601f8101861361497d57600080fd5b805161498b6145c68261455b565b81815260059190911b820183019083810190888311156149aa57600080fd5b928401925b828410156149c8578351825292840192908401906149af565b80955050505050509250929050565b6000604082840312156149e957600080fd5b604051604081018181106001600160401b0382111715614a0b57614a0b614321565b6040529050808235614a1c81614172565b81526020830135614a2c81614172565b6020919091015292915050565b8035610cf5816146eb565b600082601f830112614a5557600080fd5b81356020614a656145c68361455b565b82815260059290921b84018101918181019086841115614a8457600080fd5b8286015b84811015614a9f5780358352918301918301614a88565b509695505050505050565b600082601f830112614abb57600080fd5b612b57838335602085016147e5565b60006103608236031215614add57600080fd5b614ae561435f565b614aef36846149d7565b8152614afe36604085016149d7565b602082015260808301356001600160401b0380821115614b1d57600080fd5b614b29368387016143d5565b6040840152614b3a60a08601614187565b606084015260c0850135915080821115614b5357600080fd5b614b5f368387016143d5565b6080840152614b7060e08601614a39565b60a084015261010091508185013560c0840152610120614b91818701614187565b60e085015261014080870135848601526101609350838701358286015261018091508187013581860152506101a080870135848601526101c0935083870135828601526101e091508187013581860152506102008087013583811115614bf657600080fd5b614c0236828a01614a44565b858701525061022093508387013583811115614c1d57600080fd5b614c2936828a01614a44565b838701525061024091508187013583811115614c4457600080fd5b614c5036828a016143d5565b828701525050610260614c648188016148c8565b84860152610280935083870135828601526102a091508187013581860152506102c08087013583811115614c9757600080fd5b614ca336828a016143d5565b85870152506102e093508387013583811115614cbe57600080fd5b614cca36828a016143d5565b838701525061030091508187013583811115614ce557600080fd5b614cf136828a01614aaa565b82870152505061032086013582811115614d0a57600080fd5b614d1636828901614aaa565b8486015250614d28610340870161472c565b9084015250909392505050565b60208082526035908201527f657870656374656452657475726e206d75737420626520657175616c206f72206040820152743630b933b2b9103a3430b71036b4b72932ba3ab93760591b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b60008219821115614db357614db3614d8a565b500190565b6020808252600f908201526e496e636f72726563742056616c756560881b604082015260600190565b600082821015614df357614df3614d8a565b500390565b60005b83811015614e13578181015183820152602001614dfb565b838111156120325750506000910152565b60006bffffffffffffffffffffffff19808a60601b168352808960601b166014840152808860601b1660288401525085603c8301528451614e6c81605c850160208901614df8565b6001600160c01b031960c095861b811691909301605c8101919091529290931b166064820152606c019695505050505050565b6004811061201357634e487b7160e01b600052602160045260246000fd5b614ec681614e9f565b9052565b60008151808452614ee2816020860160208601614df8565b601f01601f19169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015614f76578284038952815180518552858101516001600160a01b039081168787015260408083015190911690860152606090810151608091860182905290614f6281870183614eca565b9a87019a9550505090840190600101614f14565b5091979650505050505050565b600081518084526020808501945080840160005b83811015614fb357815187529582019590820190600101614f97565b509495945050505050565b60208152815160208201526020820151604082015260006040830151614fef60608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a083015161502c60c0840182614ebd565b5060c08301516101408060e0850152615049610160850183614eca565b915060e0850151601f196101008187860301818801526150698584614ef6565b9450808801519250506101208187860301818801526150888584614f83565b970151959092019490945250929392505050565b600060018060a01b03808a16835260e060208401526150be60e084018a614eca565b83810360408501526150d0818a614eca565b905083810360608501526150e48189614eca565b905083810360808501526150f88188614eca565b60a0850196909652509290921660c0909101525095945050505050565b6001600160a01b038a811682526101206020830181905260009161513b8483018d614eca565b9150838203604085015261514f828c614eca565b91508382036060850152615163828b614eca565b91508382036080850152615177828a614eca565b60a085019890985295861660c0840152505060e08101929092529091166101009091015295945050505050565b60a0815260006151b760a0830188614eca565b82810360208401526151c98188614eca565b905082810360408401526151dd8187614eca565b905082810360608401526151f18186614eca565b9150508260808301529695505050505050565b60208082526028908201527f69742773206e6f7420616c6c6f77656420746f2073776170207769746820736160408201526736b2903a37b5b2b760c11b606082015260800190565b6001600160a01b03978816815295871660208701529386166040860152919094166060840152608083019390935260a082019290925260c081019190915260e00190565b634e487b7160e01b600052603260045260246000fd5b60006000198214156152ba576152ba614d8a565b5060010190565b60008160001904831182151516156152db576152db614d8a565b500290565b634e487b7160e01b600052601260045260246000fd5b600082615305576153056152e0565b500490565b6020808252825182820181905260009190848201906040850190845b8181101561534b5783516001600160a01b031683529284019291840191600101615326565b50909695505050505050565b60208152600061290c602083018486614663565b60006020828403121561537d57600080fd5b8151612b5781614172565b60006020828403121561539a57600080fd5b81356001600160401b03808211156153b157600080fd5b9083019061014082860312156153c657600080fd5b6153ce614382565b82358152602083013560208201526153e860408401614187565b60408201526153f960608401614187565b606082015261540a60808401614187565b608082015261541b60a0840161472c565b60a082015260c08301358281111561543257600080fd5b61543e878286016143d5565b60c08301525060e08301358281111561545657600080fd5b61546287828601614aaa565b60e083015250610100808401358381111561547c57600080fd5b61548888828701614a44565b91830191909152506101209283013592810192909252509392505050565b6000602082840312156154b857600080fd5b5051919050565b8b8152602081018b9052604081018a90526001600160a01b038981166060830152888116608083015287811660a0830152861660c082015260e0810185905261010081018490526101208101839052610160810161551c83614e9f565b826101408301529c9b505050505050505050505050565b60008251615545818460208701614df8565b9190910192915050565b60008261555e5761555e6152e0565b500690565b888152602081018890526001600160a01b03878116604083015286811660608301528516608082015260a0810184905260c0810183905261010081016155a883614e9f565b8260e08301529998505050505050505050565b80516001600160701b0381168114610cf557600080fd5b6000806000606084860312156155e757600080fd5b6155f0846155bb565b92506155fe602085016155bb565b9150604084015163ffffffff8116811461464857600080fd5b602081526000612b576020830184614eca56fea2646970667358221220a41f6d5f08985013aaba30bac52cbd51b13a929c0c9a85488e57ded14bfc570764736f6c63430008090033000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000006b4aafe0a2c03b223b73a681b544b1617a976ccb000000000000000000000000410f724847c92bc3cdacbcd4922f1d7833ec280a000000000000000000000000216b4b4ba9f3e719726886d34a177484278bfcae000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee570000000000000000000000004f4495243837681061c4743b74b3eedf548d56a50000000000000000000000002d5d7d31f671f86c782533cc367f14109a0827120000000000000000000000007ace1d4bb90d19826a88875ba0f60bd783bef31200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac000000000000000000000000115934131916c8b277dd010ee02de363c09d037c
Deployed Bytecode
0x60806040526004361061026b5760003560e01c806380d14b4a11610144578063b9d52d3c116100b6578063e5932c401161007a578063e5932c4014610744578063e8984c5f14610764578063ea15afc314610784578063ecefc705146107a4578063f2fde38b146107ba578063f640d508146107da57610272565b8063b9d52d3c146106a6578063c415b95c146106c6578063c93d732d146106e6578063d6821ed8146106f9578063e37c42501461072e57610272565b8063a42dce8011610108578063a42dce80146105f0578063a734f06e14610610578063a85f329814610630578063ab30469514610650578063ae551c6614610666578063b4c76fe01461068657610272565b806380d14b4a1461055f5780638928a29f146105935780638c821e90146105a65780638da5cb5b146105bc57806390f3f208146105da57610272565b806349160658116101dd5780635b769f3c116101a15780635b769f3c146104a95780635c3d258f146104c95780636076a0b4146104e9578063672383c414610517578063715018a6146105375780637184e28d1461054c57610272565b8063491606581461041357806352b721f814610433578063538ba4f91461044957806353fd7bf1146104695780635b18075e1461048957610272565b806331428a871161022f57806331428a87146103535780633aecd0e3146103735780633fc8cef314610393578063433b3c05146103b35780634399fa56146103d357806348c4d781146103f357610272565b8063116191b6146102815780631a98b2e0146102d2578063228cb733146102f257806323a9495e14610312578063245ab19e1461033257610272565b3661027257005b3332141561027f57600080fd5b005b34801561028d57600080fd5b506102b57f0000000000000000000000004f4495243837681061c4743b74b3eedf548d56a581565b6040516001600160a01b0390911681526020015b60405180910390f35b3480156102de57600080fd5b5061027f6102ed366004614045565b6107fa565b3480156102fe57600080fd5b50600c546102b5906001600160a01b031681565b34801561031e57600080fd5b5061027f61032d36600461411e565b6108fd565b610345610340366004614137565b610941565b6040519081526020016102c9565b34801561035f57600080fd5b50600a546102b5906001600160a01b031681565b34801561037f57600080fd5b5061034561038e366004614192565b610cfa565b34801561039f57600080fd5b506006546102b5906001600160a01b031681565b3480156103bf57600080fd5b506007546102b5906001600160a01b031681565b3480156103df57600080fd5b50600b546102b5906001600160a01b031681565b3480156103ff57600080fd5b5061027f61040e36600461411e565b610d1d565b34801561041f57600080fd5b5061027f61042e3660046141af565b610d98565b34801561043f57600080fd5b5061034560115481565b34801561045557600080fd5b506002546102b5906001600160a01b031681565b34801561047557600080fd5b5061027f610484366004614192565b610e81565b34801561049557600080fd5b50600d546102b5906001600160a01b031681565b3480156104b557600080fd5b5061027f6104c4366004614192565b610ed7565b3480156104d557600080fd5b5061027f6104e436600461411e565b610f2d565b3480156104f557600080fd5b50610509610504366004614252565b610f6a565b6040516102c9929190614298565b34801561052357600080fd5b506102b561053236600461411e565b611013565b34801561054357600080fd5b5061027f61103d565b61034561055a3660046142e6565b611051565b34801561056b57600080fd5b506102b57f0000000000000000000000002d5d7d31f671f86c782533cc367f14109a08271281565b61027f6105a1366004614444565b61174f565b3480156105b257600080fd5b5061034560045481565b3480156105c857600080fd5b506000546001600160a01b03166102b5565b3480156105e657600080fd5b5061034560055481565b3480156105fc57600080fd5b5061027f61060b366004614192565b611833565b34801561061c57600080fd5b506001546102b5906001600160a01b031681565b34801561063c57600080fd5b5061027f61064b36600461411e565b611889565b34801561065c57600080fd5b5061034560035481565b34801561067257600080fd5b50600e546102b5906001600160a01b031681565b34801561069257600080fd5b5061027f6106a1366004614192565b6118c6565b3480156106b257600080fd5b5061027f6106c1366004614192565b61191c565b3480156106d257600080fd5b50600f546102b5906001600160a01b031681565b6103456106f43660046144e8565b611972565b34801561070557600080fd5b50610719610714366004614523565b611e17565b604080519283526020830191909152016102c9565b34801561073a57600080fd5b5061034560105481565b34801561075057600080fd5b5061027f61075f366004614192565b611e47565b34801561077057600080fd5b5061027f61077f366004614192565b611e9d565b34801561079057600080fd5b5061027f61079f36600461457e565b611ef3565b3480156107b057600080fd5b5061034561271081565b3480156107c657600080fd5b5061027f6107d5366004614192565b611f9d565b3480156107e657600080fd5b5061027f6107f5366004614611565b612016565b6000858560405161080c929190614653565b604051908190038120631876eed960e01b825291506001600160a01b037f0000000000000000000000004f4495243837681061c4743b74b3eedf548d56a51690631876eed990610870908e908e908e908e908e9089908d908d908d9060040161468c565b602060405180830381600087803b15801561088a57600080fd5b505af115801561089e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108c291906146f9565b6108df57604051631403112d60e21b815260040160405180910390fd5b6108f08a8a8a8a8a8a8a8a8a612038565b5050505050505050505050565b610905612420565b60058190556040518181527f11e8ee12d79dc7314b845f4e82465af5bd3d2214081526061af36de8364eaa2e906020015b60405180910390a150565b600061094b61247a565b60008260c00135116109b05760405162461bcd60e51b8152602060048201526024808201527f54686520616d6f756e74206d7573742062652067726561746572207468616e206044820152637a65726f60e01b60648201526084015b60405180910390fd5b6109d8333060c08501356109c76020870187614192565b6001600160a01b03169291906124d4565b6000610a096109ea6020850185614192565b60c08501356109ff60a0870160808801614192565b8660a001356125c6565b905080610a2a610a1c6020860186614192565b6001600160a01b0316612914565b8015610a5857506006546001600160a01b0316610a4d6040860160208701614192565b6001600160a01b0316145b15610acb57600660009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b158015610aad57600080fd5b505af1158015610ac1573d6000803e3d6000fd5b5050505050610be5565b610be1610adb6020860186614192565b610aeb6040870160208801614192565b846003610b006101e08a016101c08b0161473b565b6003811115610b1157610b11614716565b1480610b3f57506001610b2c6101e08a016101c08b0161473b565b6003811115610b3d57610b3d614716565b145b610b4d6101808a018a614756565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610b90925050506101a08b018b61479c565b610b99916148bb565b610ba76101208c018c61479c565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506001925061294d915050565b5090505b610c19610bf86080860160608701614192565b82610c096040880160208901614192565b6001600160a01b03169190612ae2565b5030610c2b6060860160408701614192565b610c386020870187614192565b83610c496080890160608a01614192565b610c5b6101208a016101008b016148df565b6040516bffffffffffffffffffffffff19606097881b8116602083015295871b8616603482015293861b85166048850152605c84019290925290931b909116607c8201526001600160c01b031960c092831b811660908301524690921b909116609882015260a001604051602081830303815290604052805190602001209250610ce9848483336001612b5e565b5050610cf56001600955565b919050565b6000610d04612420565b610d176001600160a01b03831630612c15565b92915050565b610d25612420565b611388811115610d635760405162461bcd60e51b8152602060048201526009602482015268746f6f206c6172676560b81b60448201526064016109a7565b60108190556040518181527fa28aac6f4ba79029a647ee085b0ae88419c6aa87bae5dcf77d303dba45b3681b90602001610936565b60008282604051610daa929190614653565b604051908190038120635f6970c360e01b825291506001600160a01b037f0000000000000000000000004f4495243837681061c4743b74b3eedf548d56a51690635f6970c390610e08908b908b908b908b908b9089906004016148fa565b602060405180830381600087803b158015610e2257600080fd5b505af1158015610e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5a91906146f9565b610e7757604051631403112d60e21b815260040160405180910390fd5b5050505050505050565b610e89612420565b600b80546001600160a01b0319166001600160a01b0383169081179091556040519081527f35e63b7fefc2b1fb2ed78adeed6688b187514d96c2d7d56222e52f3e41c2fb2f90602001610936565b610edf612420565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527f41408be49f75701fe4bb8484ce88d68f1d82e03cb4eb44263b6682ce2dbd32f090602001610936565b610f35612420565b60118190556040518181527f8f817f25bf47abe304b519d80d1a633064758c57d280731736fe82ad20816c5590602001610936565b600a5460405163181da82d60e21b81526001600160a01b03868116600483015285811660248301526044820185905260648201849052600092606092911690636076a0b49060840160006040518083038186803b158015610fca57600080fd5b505afa158015610fde573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611006919081019061493b565b9097909650945050505050565b6008818154811061102357600080fd5b6000918252602090912001546001600160a01b0316905081565b611045612420565b61104f6000612caf565b565b600061105b61247a565b600061106683614aca565b905080610160015181610140015110156110925760405162461bcd60e51b81526004016109a790614d35565b8051602001516110aa906001600160a01b0316612914565b156110f75760405162461bcd60e51b815260206004820152601e60248201527f737263206465737420746f6b656e206d757374206e6f7420626520455448000060448201526064016109a7565b80515161110c906001600160a01b0316612914565b15611177578060a0015115611153578061012001518160c001516111309190614da0565b341461114e5760405162461bcd60e51b81526004016109a790614db8565b6111a4565b806101200151341461114e5760405162461bcd60e51b81526004016109a790614db8565b8060a00151156111a4578060c0015134146111a45760405162461bcd60e51b81526004016109a790614db8565b6101208101518151516111c6916001600160a01b0390911690339030906124d4565b60006111ea8260000151600001518361012001518460e001518561010001516125c6565b8251519091508190611204906001600160a01b0316612914565b801561122357506006548351602001516001600160a01b039081169116145b1561129657600660009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0836040518263ffffffff1660e01b81526004016000604051808303818588803b15801561127857600080fd5b505af115801561128c573d6000803e3d6000fd5b50505050506112fe565b825180516020909101516112fa919084600387610300015160038111156112bf576112bf614716565b14806112e15750600187610300015160038111156112df576112df614716565b145b876102800151886102c00151896101c00151600161294d565b5090505b8260a001516113195760c08301516113169082614de1565b90505b600081116113605760405162461bcd60e51b8152602060048201526014602482015273151a1948185b5bdd5b9d081d1bdbc81cdb585b1b60621b60448201526064016109a7565b8261014001518110156113c15760405162461bcd60e51b8152602060048201526024808201527f72657475726e20616d6f756e74206973206c6f776572207468616e206578706560448201526318dd195960e21b60648201526084016109a7565b60608301518351516102008501516102208601516040516113ee9430949093909287924690602001614e24565b60405160208183030381529060405280519060200120935060006040518061014001604052808561024001518152602001856102600151815260200185606001516001600160a01b031681526020018560200151600001516001600160a01b031681526020018560200151602001516001600160a01b03168152602001856103000151600381111561148257611482614716565b8152602001856102a001518152602001856102e001518152602001856101e0015181526020018561018001518152506040516020016114c19190614fbe565b60405160208183030381529060405290508360a001511561157d5760c084015161020085015160808601516040808801519051636316100160e11b81526001600160a01b037f0000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712169463c62c20029490936115469330938991908c90339060040161509c565b6000604051808303818588803b15801561155f57600080fd5b505af1158015611573573d6000803e3d6000fd5b5050505050611666565b60c08401518451602001516115bf916001600160a01b03909116907f0000000000000000000000002d5d7d31f671f86c782533cc367f14109a08271290612cff565b610200840151608085015160408087015187516020015160c0890151925163edb6b3a560e01b81526001600160a01b037f0000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712169563edb6b3a595611633953095929491938a93928c9290913390600401615115565b600060405180830381600087803b15801561164d57600080fd5b505af1158015611661573d6000803e3d6000fd5b505050505b8351602001516116a0906001600160a01b03167f0000000000000000000000004f4495243837681061c4743b74b3eedf548d56a585612cff565b7f0000000000000000000000004f4495243837681061c4743b74b3eedf548d56a56001600160a01b031663b54170848561020001518660800151848860400151876040518663ffffffff1660e01b81526004016117019594939291906151a4565b600060405180830381600087803b15801561171b57600080fd5b505af115801561172f573d6000803e3d6000fd5b50505050611741848684336001612ddf565b50505050610cf56001600955565b61175761247a565b866001600160a01b0316886001600160a01b031614156117895760405162461bcd60e51b81526004016109a790615204565b61179e6001600160a01b0389163330896124d4565b60006117ac898887876125c6565b90506117b9898284612e4a565b600b54604051630e47f70960e21b81526001600160a01b039091169063391fdc24906117f690339087908e908e908e908e9060009060040161524c565b600060405180830381600087803b15801561181057600080fd5b505af1158015611824573d6000803e3d6000fd5b5050505050610e776001600955565b61183b612420565b600f80546001600160a01b0319166001600160a01b0383169081179091556040519081527f12e1d17016b94668449f97876f4a8d5cc2c19f314db337418894734037cc19d490602001610936565b611891612420565b60048190556040518181527f70f24e12a9db25e0d80cbcde19ffef47d6a7c52c1089db4c71e53ce1856577fc90602001610936565b6118ce612420565b600780546001600160a01b0319166001600160a01b0383169081179091556040519081527f17780f3919f73af11f29e4157534858a06c91294d64b679fe4e49340122cd32290602001610936565b611924612420565b600e80546001600160a01b0319166001600160a01b0383169081179091556040519081527fe0209b1ff5892dc27d9ffb30000e308317645f928d78a0a018dd2e9289ecc29290602001610936565b600061197c61247a565b8160800135826060013510156119a45760405162461bcd60e51b81526004016109a790614d35565b6119b46040830160208401614192565b6001600160a01b03166119ca6020840184614192565b6001600160a01b031614156119f15760405162461bcd60e51b81526004016109a790615204565b60008060005b611a0561010086018661479c565b9050811015611a83576000611a1e61010087018761479c565b83818110611a2e57611a2e615290565b905060200201351115611a7157611a4961010086018661479c565b82818110611a5957611a59615290565b9050602002013583611a6b9190614da0565b92508091505b80611a7b816152a6565b9150506119f7565b5081611ae257611a99610a1c6020860186614192565b15611ad55760405133903480156108fc02916000818181858888f19350505050158015611aca573d6000803e3d6000fd5b503492505050611e0d565b5050506040810135611e0d565b611af9333060408701356109c76020890189614192565b6000611b2a611b0b6020870187614192565b6040870135611b2060c0890160a08a01614192565b8860c001356125c6565b9050611b96611b3d61010087018761479c565b80806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250859250879150869050611b8160208b018b614192565b611b9160408c0160208d01614192565b612f8e565b93508315611da0578460800135841015611bfe5760405162461bcd60e51b8152602060048201526024808201527f5377697463683a2052657475726e20616d6f756e7420776173206e6f7420656e6044820152630deeaced60e31b60648201526084016109a7565b8460600135841115611d1057611c33611c1e610100870160e08801614192565b6060870135610c096040890160208a01614192565b50600c54611c62906001600160a01b0316611c52606088013587614de1565b610c096040890160208a01614192565b50600b546001600160a01b031663391fdc2433611c86610100890160e08a01614192565b611c9360208a018a614192565b611ca360408b0160208c01614192565b60408b013560608c0135611cb7818d614de1565b6040518863ffffffff1660e01b8152600401611cd9979695949392919061524c565b600060405180830381600087803b158015611cf357600080fd5b505af1158015611d07573d6000803e3d6000fd5b50505050611e09565b611d35611d24610100870160e08801614192565b85610c096040890160208a01614192565b50600b546001600160a01b031663391fdc2433611d59610100890160e08a01614192565b611d6660208a018a614192565b611d7660408b0160208c01614192565b8a604001358a60006040518863ffffffff1660e01b8152600401611cd9979695949392919061524c565b6040850135611dc530611db66020890189614192565b6001600160a01b031690612c15565b1115611de757611de1336040870135610c096020890189614192565b50611e09565b61174133611dfc30611db660208a018a614192565b610c096020890189614192565b5050505b610cf56001600955565b600080612710611e2786856152c1565b611e3191906152f6565b9150611e3d8286614de1565b9050935093915050565b611e4f612420565b600c80546001600160a01b0319166001600160a01b0383169081179091556040519081527f53a596d7be747a5a4f4d39a6a36476d2eed407c93f6f2ba8a96c8b971240d5cd90602001610936565b611ea5612420565b600d80546001600160a01b0319166001600160a01b0383169081179091556040519081527f4528d04696417deba6006cd6c7e5bbb56b9874ac9d954a956e14b8d74f08d72b90602001610936565b611efb612420565b805160035560005b8151811015611f6d576008828281518110611f2057611f20615290565b60209081029190910181015182546001810184556000938452919092200180546001600160a01b0319166001600160a01b0390921691909117905580611f65816152a6565b915050611f03565b507fbbc63a7f378af7e269ef19f3fe0d08f044c91ee72930c0d045a58be58580f3d381604051610936919061530a565b611fa5612420565b6001600160a01b03811661200a5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016109a7565b61201381612caf565b50565b61201e612420565b6120326001600160a01b0384168284612ae2565b50505050565b6040516349ad89fb60e11b81526000906001600160a01b037f0000000000000000000000004f4495243837681061c4743b74b3eedf548d56a5169063935b13f6906120899087908790600401615357565b60206040518083038186803b1580156120a157600080fd5b505afa1580156120b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120d9919061536b565b905060006120e986880188615388565b90506001600160a01b03821661210157806060015191505b600060038260a00151600381111561211b5761211b614716565b148061213c575060028260a00151600381111561213a5761213a614716565b145b6040516370a0823160e01b81523060048201529091506000906001600160a01b038516906370a082319060240160206040518083038186803b15801561218157600080fd5b505afa158015612195573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b991906154a6565b905060008084608001516001600160a01b0316866001600160a01b031614156121e4578691506123d4565b846101200151871061221a5761221286866080015189878960c001518a60e001518b6101000151600061294d565b509150612314565b84608001516001600160a01b0316866001600160a01b03161461231457600061224f86608001516001600160a01b0316612914565b61225d57856080015161226a565b6006546001600160a01b03165b905061227d87828a8961010001516131be565b508093505061229886608001516001600160a01b0316612914565b80156122a357508215155b1561231257600660009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156122f857600080fd5b505af115801561230c573d6000803e3d6000fd5b50505050505b505b6040516370a0823160e01b81523060048201526000906001600160a01b038816906370a082319060240160206040518083038186803b15801561235657600080fd5b505afa15801561236a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238e91906154a6565b905061239a8885614de1565b8111156123d25760408601516123d090856123b58b85614da0565b6123bf9190614de1565b6001600160a01b038a169190612ae2565b505b505b81156124025761240085604001518387608001516001600160a01b0316612ae29092919063ffffffff16565b505b61240f858789858561334a565b505050505050505050505050505050565b6000546001600160a01b0316331461104f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109a7565b600260095414156124cd5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016109a7565b6002600955565b806124de57612032565b6124e784612914565b156125b1576001600160a01b038316331480156125045750803410155b6125645760405162461bcd60e51b815260206004820152602b60248201527f57726f6e6720757365616765206f66204554482e756e6976657273616c54726160448201526a6e7366657246726f6d282960a81b60648201526084016109a7565b6001600160a01b03821630146125ac576040516001600160a01b0383169082156108fc029083906000818181858888f193505050501580156125aa573d6000803e3d6000fd5b505b612032565b6120326001600160a01b038516848484613397565b600060105482111561261a5760405162461bcd60e51b815260206004820152601860248201527f706172746e65724665655261746520746f6f206c61726765000000000000000060448201526064016109a7565b5082811561290c57600f54604051637b8c4cdf60e01b81526001600160a01b0385811660048301526000921690637b8c4cdf9060240160206040518083038186803b15801561266857600080fd5b505afa15801561267c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126a091906154a6565b1561272757600f54604051637b8c4cdf60e01b81526001600160a01b03868116600483015290911690637b8c4cdf9060240160206040518083038186803b1580156126ea57600080fd5b505afa1580156126fe573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061272291906154a6565b61272b565b6011545b9050600061273b612710806152c1565b60115461274888876152c1565b61275291906152c1565b61275c91906152f6565b905060008161271061276e89886152c1565b61277891906152f6565b6127829190614de1565b9050612796886001600160a01b0316612914565b1561282957600f546001600160a01b031663eedd56e16127b68484614da0565b6040516001600160e01b031960e084901b1681526001600160a01b03808d16600483015260248201869052604482018790528a1660648201526084016000604051808303818588803b15801561280b57600080fd5b505af115801561281f573d6000803e3d6000fd5b50505050506128e5565b600f54612844906001600160a01b038a811691166000613402565b600f5461286f906001600160a01b031661285e8484614da0565b6001600160a01b038b169190613402565b600f5460405163eedd56e160e01b81526001600160a01b038a81166004830152602482018490526044820185905288811660648301529091169063eedd56e190608401600060405180830381600087803b1580156128cc57600080fd5b505af11580156128e0573d6000803e3d6000fd5b505050505b6127106128f288876152c1565b6128fc91906152f6565b6129069088614de1565b93505050505b949350505050565b60006001600160a01b0382161580610d1757506001600160a01b03821673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1492915050565b600080886001600160a01b03168a6001600160a01b0316141561297257879150612ad5565b60006129876001600160a01b038c1630612c15565b9050600061299e6001600160a01b038c1630612c15565b905088156129b8576129b28c8c8c8b613526565b50612a46565b865115612a4657865160005b81811015612a435760006129f28f8f8c85815181106129e5576129e5615290565b60200260200101516135f0565b505090508080612a00575087155b612a3a5760405162461bcd60e51b815260206004820152600b60248201526a14ddd85c0819985a5b195960aa1b60448201526064016109a7565b506001016129c4565b50505b6000612a5b6001600160a01b038e1630612c15565b905082612a68828d614da0565b612a729190614de1565b93508651600014158015612a8557508315155b15612aad576000612a988e8e878b6131be565b509050612aa58187614da0565b955060009450505b6000612ac26001600160a01b038e1630612c15565b9050612ace8382614de1565b9550505050505b9850989650505050505050565b600081612af157506001612b57565b612afa84612914565b15612b3f576040516001600160a01b0384169083156108fc029084906000818181858888f19350505050158015612b35573d6000803e3d6000fd5b5060019050612b57565b612b536001600160a01b03851684846136e2565b5060015b9392505050565b600b546001600160a01b0316630aea28c76101408701358661016089013586612b8a60208c018c614192565b612b9a60408d0160208e01614192565b612baa60408e0160208f01614192565b8d60c001358c8f60e001358c6040518c63ffffffff1660e01b8152600401612bdc9b9a999897969594939291906154bf565b600060405180830381600087803b158015612bf657600080fd5b505af1158015612c0a573d6000803e3d6000fd5b505050505050505050565b6000612c2083612914565b15612c3657506001600160a01b03811631610d17565b6040516370a0823160e01b81526001600160a01b0383811660048301528416906370a082319060240160206040518083038186803b158015612c7757600080fd5b505afa158015612c8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b5791906154a6565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b612d0883612914565b612d265780612d2b57612d266001600160a01b038416836000613402565b505050565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e9060440160206040518083038186803b158015612d7657600080fd5b505afa158015612d8a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dae91906154a6565b90508015612dcb57612dcb6001600160a01b038516846000613402565b6120326001600160a01b0385168484613402565b600b5461024086015161026087015187518051602091820151828b0151909201516101208b01516101a08c0151604051630aea28c760e01b81526001600160a01b0390981697630aea28c797612bdc9790968e9691958d95929491939092918f918e906004016154bf565b6000612e5e846001600160a01b0316612914565b15612eba5782471015612eb35760405162461bcd60e51b815260206004820152601b60248201527f4554482062616c616e636520697320696e73756666696369656e74000000000060448201526064016109a7565b5081612ed4565b600d54612ed4906001600160a01b03868116911685612cff565b600e546040516000916001600160a01b0316908390612ef4908690615533565b60006040518083038185875af1925050503d8060008114612f31576040519150601f19603f3d011682016040523d82523d6000602084013e612f36565b606091505b5050905080612f875760405162461bcd60e51b815260206004820152601960248201527f506172617377617020657865637574696f6e206661696c65640000000000000060448201526064016109a7565b5050505050565b6000600454600354612fa091906152c1565b875111156130205760405162461bcd60e51b815260206004820152604160248201527f5377697463683a20446973747269627574696f6e2061727261792073686f756c60448201527f64206e6f742065786365656420666163746f726965732061727261792073697a6064820152606560f81b608482015260a4016109a7565b856000805b89518110156131b15789818151811061304057613040615290565b6020026020010151600014156130555761319f565b6000888b838151811061306a5761306a615290565b60200260200101518b61307d91906152c1565b61308791906152f6565b9050878214156130945750825b61309e8185614de1565b9350600454826130ae919061554f565b6130f9576130f28787836008600454876130c891906152f6565b815481106130d8576130d8615290565b6000918252602090912001546001600160a01b0316613712565b9250613191565b600454613106908361554f565b6001141561314e576130f287878360086004548761312491906152f6565b8154811061313457613134615290565b6000918252602090912001546001600160a01b0316613729565b61318e87878360086004548761316491906152f6565b8154811061317457613174615290565b6000918252602090912001546001600160a01b0316613746565b92505b61319b8386614da0565b9450505b806131a9816152a6565b915050613025565b5050509695505050505050565b6000806000808451905060005b818110156132285760008682815181106131e7576131e7615290565b602002602001015111156132205785818151811061320757613207615290565b60200260200101518461321a9190614da0565b93508092505b6001016131cb565b50600083116132795760405162461bcd60e51b815260206004820152601a60248201527f696e76616c696420646973747269627574696f6e20706172616d00000000000060448201526064016109a7565b613287858785858c8c612f8e565b9350600084116132d05760405162461bcd60e51b81526020600482015260146024820152730a6eec2e040ccc2d2d8cac840cce4deda40c8caf60631b60448201526064016109a7565b600b54604051630e47f70960e21b81526001600160a01b039091169063391fdc249061330d90339030908d908d908d908c9060009060040161524c565b600060405180830381600087803b15801561332757600080fd5b505af115801561333b573d6000803e3d6000fd5b50505050505094509492505050565b600b548551602087015160408089015160808a0151915163424971a960e11b81526001600160a01b0390951694638492e35294612bdc9490939092918b91908b908b908b90600401615563565b6040516001600160a01b03808516602483015283166044820152606481018290526120329085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613763565b80158061348b5750604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015284169063dd62ed3e9060440160206040518083038186803b15801561345157600080fd5b505afa158015613465573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061348991906154a6565b155b6134f65760405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b60648201526084016109a7565b6040516001600160a01b038316602482015260448101829052612d2690849063095ea7b360e01b906064016133cb565b6000836001600160a01b0316856001600160a01b0316141561355a5760405162461bcd60e51b81526004016109a790615204565b613565858484612e4a565b6135786001600160a01b03851630612c15565b600b54604051630e47f70960e21b81529192506001600160a01b03169063391fdc24906135b690339030908a908a908a90899060009060040161524c565b600060405180830381600087803b1580156135d057600080fd5b505af11580156135e4573d6000803e3d6000fd5b50505050949350505050565b60008080806136086001600160a01b03871630612c15565b8551604087015190945090915061362a906001600160a01b0389169085612cff565b84602001516001600160a01b031661364a886001600160a01b0316612914565b613655576000613658565b85515b866060015160405161366a9190615533565b60006040518083038185875af1925050503d80600081146136a7576040519150601f19603f3d011682016040523d82523d6000602084013e6136ac565b606091505b509094505083156136d857806136cb6001600160a01b03881630612c15565b6136d59190614de1565b91505b5093509350939050565b6040516001600160a01b038316602482015260448101829052612d2690849063a9059cbb60e01b906064016133cb565b600061372085858585613838565b95945050505050565b6006546000906137209086906001600160a01b0316868686613ca4565b6007546000906137209086906001600160a01b0316868686613ca4565b60006137b8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316613cc79092919063ffffffff16565b90508051600014806137d95750808060200190518101906137d991906146f9565b612d265760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109a7565b600061384c856001600160a01b0316612914565b156138bb57600660009054906101000a90046001600160a01b03166001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b1580156138a157600080fd5b505af11580156138b5573d6000803e3d6000fd5b50505050505b60006138cf866001600160a01b0316612914565b6138d957856138e6565b6006546001600160a01b03165b905060006138fc866001600160a01b0316612914565b6139065785613913565b6006546001600160a01b03165b60405163e6a4390560e01b81526001600160a01b038481166004830152808316602483015291925060009186169063e6a439059060440160206040518083038186803b15801561396257600080fd5b505afa158015613976573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399a919061536b565b90506000806139b46001600160a01b03841686868b613cd6565b919750925090508115613a1957826001600160a01b031663fff6cae96040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156139fc57600080fd5b505af1158015613a10573d6000803e3d6000fd5b50505050613a8d565b8015613a8d5760405163bc25cf7760e01b81527346fd07da395799f113a7584563b8cb886f33c2bc60048201526001600160a01b0384169063bc25cf7790602401600060405180830381600087803b158015613a7457600080fd5b505af1158015613a88573d6000803e3d6000fd5b505050505b613aa16001600160a01b038616848a612ae2565b50836001600160a01b0316856001600160a01b03161015613b365760405163022c0d9f60e01b8152600060048201819052602482018890523060448301526080606483015260848201526001600160a01b0384169063022c0d9f9060a401600060405180830381600087803b158015613b1957600080fd5b505af1158015613b2d573d6000803e3d6000fd5b50505050613bac565b60405163022c0d9f60e01b8152600481018790526000602482018190523060448301526080606483015260848201526001600160a01b0384169063022c0d9f9060a401600060405180830381600087803b158015613b9357600080fd5b505af1158015613ba7573d6000803e3d6000fd5b505050505b613bbe896001600160a01b0316612914565b15613c97576006546040516370a0823160e01b81523060048201526001600160a01b0390911690632e1a7d4d9082906370a082319060240160206040518083038186803b158015613c0e57600080fd5b505afa158015613c22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c4691906154a6565b6040518263ffffffff1660e01b8152600401613c6491815260200190565b600060405180830381600087803b158015613c7e57600080fd5b505af1158015613c92573d6000803e3d6000fd5b505050505b5050505050949350505050565b6000613cbd8585613cb789898888613838565b85613838565b9695505050505050565b606061290c8484600085613e71565b6000808080613cee6001600160a01b03881689612c15565b90506000613d056001600160a01b0388168a612c15565b90506000808a6001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b158015613d4357600080fd5b505afa158015613d57573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d7b91906155d2565b5091509150886001600160a01b03168a6001600160a01b03161115613d9c57905b816001600160701b0316841080613dbb5750806001600160701b031683105b955085158015613de55750816001600160701b0316841180613de55750806001600160701b031683115b94506000613df5896103e56152c1565b90506000613e0c85846001600160701b0316613f4c565b613e1690836152c1565b9050600082613e2e88876001600160701b0316613f4c565b613e3a906103e86152c1565b613e449190614da0565b90508015613e5b57613e5681836152f6565b613e5e565b60005b9950505050505050509450945094915050565b606082471015613ed25760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016109a7565b600080866001600160a01b03168587604051613eee9190615533565b60006040518083038185875af1925050503d8060008114613f2b576040519150601f19603f3d011682016040523d82523d6000602084013e613f30565b606091505b5091509150613f4187838387613f62565b979650505050505050565b6000818310613f5b5781612b57565b5090919050565b60608315613fce578251613fc7576001600160a01b0385163b613fc75760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109a7565b508161290c565b61290c8383815115613fe35781518083602001fd5b8060405162461bcd60e51b81526004016109a79190615617565b60008083601f84011261400f57600080fd5b5081356001600160401b0381111561402657600080fd5b60208301915083602082850101111561403e57600080fd5b9250929050565b60008060008060008060008060008060c08b8d03121561406457600080fd5b8a35995060208b01356001600160401b038082111561408257600080fd5b61408e8e838f01613ffd565b909b50995060408d01359150808211156140a757600080fd5b6140b38e838f01613ffd565b909950975060608d01359150808211156140cc57600080fd5b6140d88e838f01613ffd565b909750955060808d01359150808211156140f157600080fd5b506140fe8d828e01613ffd565b9150809450508092505060a08b013590509295989b9194979a5092959850565b60006020828403121561413057600080fd5b5035919050565b60006020828403121561414957600080fd5b81356001600160401b0381111561415f57600080fd5b82016101e08185031215612b5757600080fd5b6001600160a01b038116811461201357600080fd5b8035610cf581614172565b6000602082840312156141a457600080fd5b8135612b5781614172565b60008060008060008060006080888a0312156141ca57600080fd5b8735965060208801356001600160401b03808211156141e857600080fd5b6141f48b838c01613ffd565b909850965060408a013591508082111561420d57600080fd5b6142198b838c01613ffd565b909650945060608a013591508082111561423257600080fd5b5061423f8a828b01613ffd565b989b979a50959850939692959293505050565b6000806000806080858703121561426857600080fd5b843561427381614172565b9350602085013561428381614172565b93969395505050506040820135916060013590565b6000604082018483526020604081850152818551808452606086019150828701935060005b818110156142d9578451835293830193918301916001016142bd565b5090979650505050505050565b6000602082840312156142f857600080fd5b81356001600160401b0381111561430e57600080fd5b82016103608185031215612b5757600080fd5b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b038111828210171561435957614359614321565b60405290565b60405161032081016001600160401b038111828210171561435957614359614321565b60405161014081016001600160401b038111828210171561435957614359614321565b604051601f8201601f191681016001600160401b03811182821017156143cd576143cd614321565b604052919050565b600082601f8301126143e657600080fd5b81356001600160401b038111156143ff576143ff614321565b614412601f8201601f19166020016143a5565b81815284602083860101111561442757600080fd5b816020850160208301376000918101602001919091529392505050565b600080600080600080600080610100898b03121561446157600080fd5b883561446c81614172565b9750602089013561447c81614172565b96506040890135955060608901359450608089013561449a81614172565b935060a0890135925060c08901356144b181614172565b915060e08901356001600160401b038111156144cc57600080fd5b6144d88b828c016143d5565b9150509295985092959890939650565b6000602082840312156144fa57600080fd5b81356001600160401b0381111561451057600080fd5b82016101208185031215612b5757600080fd5b60008060006060848603121561453857600080fd5b83359250602084013561454a81614172565b929592945050506040919091013590565b60006001600160401b0382111561457457614574614321565b5060051b60200190565b6000602080838503121561459157600080fd5b82356001600160401b038111156145a757600080fd5b8301601f810185136145b857600080fd5b80356145cb6145c68261455b565b6143a5565b81815260059190911b820183019083810190878311156145ea57600080fd5b928401925b82841015613f4157833561460281614172565b825292840192908401906145ef565b60008060006060848603121561462657600080fd5b833561463181614172565b925060208401359150604084013561464881614172565b809150509250925092565b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b89815260c0602082015260006146a660c083018a8c614663565b82810360408401526146b981898b614663565b905086606084015282810360808401526146d4818688614663565b9150508260a08301529a9950505050505050505050565b801515811461201357600080fd5b60006020828403121561470b57600080fd5b8151612b57816146eb565b634e487b7160e01b600052602160045260246000fd5b803560048110610cf557600080fd5b60006020828403121561474d57600080fd5b612b578261472c565b6000808335601e1984360301811261476d57600080fd5b8301803591506001600160401b0382111561478757600080fd5b60200191503681900382131561403e57600080fd5b6000808335601e198436030181126147b357600080fd5b8301803591506001600160401b038211156147cd57600080fd5b6020019150600581901b360382131561403e57600080fd5b60006147f36145c68461455b565b8381529050602080820190600585901b84018681111561481257600080fd5b845b818110156148b05780356001600160401b03808211156148345760008081fd5b908701906080828b0312156148495760008081fd5b614851614337565b823581528583013561486281614172565b8187015260408381013561487581614172565b908201526060838101358381111561488d5760008081fd5b6148998d8287016143d5565b918301919091525086525050928201928201614814565b505050509392505050565b6000612b573684846147e5565b80356001600160401b0381168114610cf557600080fd5b6000602082840312156148f157600080fd5b612b57826148c8565b868152608060208201526000614914608083018789614663565b8281036040840152614927818688614663565b915050826060830152979650505050505050565b6000806040838503121561494e57600080fd5b825191506020808401516001600160401b0381111561496c57600080fd5b8401601f8101861361497d57600080fd5b805161498b6145c68261455b565b81815260059190911b820183019083810190888311156149aa57600080fd5b928401925b828410156149c8578351825292840192908401906149af565b80955050505050509250929050565b6000604082840312156149e957600080fd5b604051604081018181106001600160401b0382111715614a0b57614a0b614321565b6040529050808235614a1c81614172565b81526020830135614a2c81614172565b6020919091015292915050565b8035610cf5816146eb565b600082601f830112614a5557600080fd5b81356020614a656145c68361455b565b82815260059290921b84018101918181019086841115614a8457600080fd5b8286015b84811015614a9f5780358352918301918301614a88565b509695505050505050565b600082601f830112614abb57600080fd5b612b57838335602085016147e5565b60006103608236031215614add57600080fd5b614ae561435f565b614aef36846149d7565b8152614afe36604085016149d7565b602082015260808301356001600160401b0380821115614b1d57600080fd5b614b29368387016143d5565b6040840152614b3a60a08601614187565b606084015260c0850135915080821115614b5357600080fd5b614b5f368387016143d5565b6080840152614b7060e08601614a39565b60a084015261010091508185013560c0840152610120614b91818701614187565b60e085015261014080870135848601526101609350838701358286015261018091508187013581860152506101a080870135848601526101c0935083870135828601526101e091508187013581860152506102008087013583811115614bf657600080fd5b614c0236828a01614a44565b858701525061022093508387013583811115614c1d57600080fd5b614c2936828a01614a44565b838701525061024091508187013583811115614c4457600080fd5b614c5036828a016143d5565b828701525050610260614c648188016148c8565b84860152610280935083870135828601526102a091508187013581860152506102c08087013583811115614c9757600080fd5b614ca336828a016143d5565b85870152506102e093508387013583811115614cbe57600080fd5b614cca36828a016143d5565b838701525061030091508187013583811115614ce557600080fd5b614cf136828a01614aaa565b82870152505061032086013582811115614d0a57600080fd5b614d1636828901614aaa565b8486015250614d28610340870161472c565b9084015250909392505050565b60208082526035908201527f657870656374656452657475726e206d75737420626520657175616c206f72206040820152743630b933b2b9103a3430b71036b4b72932ba3ab93760591b606082015260800190565b634e487b7160e01b600052601160045260246000fd5b60008219821115614db357614db3614d8a565b500190565b6020808252600f908201526e496e636f72726563742056616c756560881b604082015260600190565b600082821015614df357614df3614d8a565b500390565b60005b83811015614e13578181015183820152602001614dfb565b838111156120325750506000910152565b60006bffffffffffffffffffffffff19808a60601b168352808960601b166014840152808860601b1660288401525085603c8301528451614e6c81605c850160208901614df8565b6001600160c01b031960c095861b811691909301605c8101919091529290931b166064820152606c019695505050505050565b6004811061201357634e487b7160e01b600052602160045260246000fd5b614ec681614e9f565b9052565b60008151808452614ee2816020860160208601614df8565b601f01601f19169290920160200192915050565b600081518084526020808501808196508360051b8101915082860160005b85811015614f76578284038952815180518552858101516001600160a01b039081168787015260408083015190911690860152606090810151608091860182905290614f6281870183614eca565b9a87019a9550505090840190600101614f14565b5091979650505050505050565b600081518084526020808501945080840160005b83811015614fb357815187529582019590820190600101614f97565b509495945050505050565b60208152815160208201526020820151604082015260006040830151614fef60608401826001600160a01b03169052565b5060608301516001600160a01b03811660808401525060808301516001600160a01b03811660a08401525060a083015161502c60c0840182614ebd565b5060c08301516101408060e0850152615049610160850183614eca565b915060e0850151601f196101008187860301818801526150698584614ef6565b9450808801519250506101208187860301818801526150888584614f83565b970151959092019490945250929392505050565b600060018060a01b03808a16835260e060208401526150be60e084018a614eca565b83810360408501526150d0818a614eca565b905083810360608501526150e48189614eca565b905083810360808501526150f88188614eca565b60a0850196909652509290921660c0909101525095945050505050565b6001600160a01b038a811682526101206020830181905260009161513b8483018d614eca565b9150838203604085015261514f828c614eca565b91508382036060850152615163828b614eca565b91508382036080850152615177828a614eca565b60a085019890985295861660c0840152505060e08101929092529091166101009091015295945050505050565b60a0815260006151b760a0830188614eca565b82810360208401526151c98188614eca565b905082810360408401526151dd8187614eca565b905082810360608401526151f18186614eca565b9150508260808301529695505050505050565b60208082526028908201527f69742773206e6f7420616c6c6f77656420746f2073776170207769746820736160408201526736b2903a37b5b2b760c11b606082015260800190565b6001600160a01b03978816815295871660208701529386166040860152919094166060840152608083019390935260a082019290925260c081019190915260e00190565b634e487b7160e01b600052603260045260246000fd5b60006000198214156152ba576152ba614d8a565b5060010190565b60008160001904831182151516156152db576152db614d8a565b500290565b634e487b7160e01b600052601260045260246000fd5b600082615305576153056152e0565b500490565b6020808252825182820181905260009190848201906040850190845b8181101561534b5783516001600160a01b031683529284019291840191600101615326565b50909695505050505050565b60208152600061290c602083018486614663565b60006020828403121561537d57600080fd5b8151612b5781614172565b60006020828403121561539a57600080fd5b81356001600160401b03808211156153b157600080fd5b9083019061014082860312156153c657600080fd5b6153ce614382565b82358152602083013560208201526153e860408401614187565b60408201526153f960608401614187565b606082015261540a60808401614187565b608082015261541b60a0840161472c565b60a082015260c08301358281111561543257600080fd5b61543e878286016143d5565b60c08301525060e08301358281111561545657600080fd5b61546287828601614aaa565b60e083015250610100808401358381111561547c57600080fd5b61548888828701614a44565b91830191909152506101209283013592810192909252509392505050565b6000602082840312156154b857600080fd5b5051919050565b8b8152602081018b9052604081018a90526001600160a01b038981166060830152888116608083015287811660a0830152861660c082015260e0810185905261010081018490526101208101839052610160810161551c83614e9f565b826101408301529c9b505050505050505050505050565b60008251615545818460208701614df8565b9190910192915050565b60008261555e5761555e6152e0565b500690565b888152602081018890526001600160a01b03878116604083015286811660608301528516608082015260a0810184905260c0810183905261010081016155a883614e9f565b8260e08301529998505050505050505050565b80516001600160701b0381168114610cf557600080fd5b6000806000606084860312156155e757600080fd5b6155f0846155bb565b92506155fe602085016155bb565b9150604084015163ffffffff8116811461464857600080fd5b602081526000612b576020830184614eca56fea2646970667358221220a41f6d5f08985013aaba30bac52cbd51b13a929c0c9a85488e57ded14bfc570764736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000006b4aafe0a2c03b223b73a681b544b1617a976ccb000000000000000000000000410f724847c92bc3cdacbcd4922f1d7833ec280a000000000000000000000000216b4b4ba9f3e719726886d34a177484278bfcae000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee570000000000000000000000004f4495243837681061c4743b74b3eedf548d56a50000000000000000000000002d5d7d31f671f86c782533cc367f14109a0827120000000000000000000000007ace1d4bb90d19826a88875ba0f60bd783bef31200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac000000000000000000000000115934131916c8b277dd010ee02de363c09d037c
-----Decoded View---------------
Arg [0] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [1] : _otherToken (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [2] : _pathCountAndSplit (uint256[]): 2,2
Arg [3] : _factories (address[]): 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f,0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac,0x115934131916C8b277DD010Ee02de363c09d037c
Arg [4] : _switchViewAddress (address): 0x6B4AAFE0A2C03B223b73a681b544b1617A976CcB
Arg [5] : _switchEventAddress (address): 0x410f724847C92Bc3CdACBCD4922F1D7833Ec280A
Arg [6] : _paraswapProxy (address): 0x216B4B4Ba9F3e719726886d34a177484278Bfcae
Arg [7] : _augustusSwapper (address): 0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57
Arg [8] : _gateway (address): 0x4F4495243837681061C4743b74B3eEdf548D56A5
Arg [9] : _gasReceiver (address): 0x2d5d7d31F671F86C782533cc367F14109a082712
Arg [10] : _feeCollector (address): 0x7ACe1D4BB90d19826A88875BA0F60bd783beF312
-----Encoded View---------------
18 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [1] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [3] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [4] : 0000000000000000000000006b4aafe0a2c03b223b73a681b544b1617a976ccb
Arg [5] : 000000000000000000000000410f724847c92bc3cdacbcd4922f1d7833ec280a
Arg [6] : 000000000000000000000000216b4b4ba9f3e719726886d34a177484278bfcae
Arg [7] : 000000000000000000000000def171fe48cf0115b1d80b88dc8eab59176fee57
Arg [8] : 0000000000000000000000004f4495243837681061c4743b74b3eedf548d56a5
Arg [9] : 0000000000000000000000002d5d7d31f671f86c782533cc367f14109a082712
Arg [10] : 0000000000000000000000007ace1d4bb90d19826a88875ba0f60bd783bef312
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [15] : 0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f
Arg [16] : 000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac
Arg [17] : 000000000000000000000000115934131916c8b277dd010ee02de363c09d037c
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.