Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 26,331 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Batch Payments | 10244547 | 11 hrs ago | IN | 0 ETH | 0.00103447 | ||||
| Batch Payments | 10244541 | 11 hrs ago | IN | 0 ETH | 0.00068894 | ||||
| Batch Payments | 10244538 | 12 hrs ago | IN | 0 ETH | 0.00090527 | ||||
| Batch Payments | 10244538 | 12 hrs ago | IN | 0 ETH | 0.00151078 | ||||
| Batch Payments | 10244529 | 12 hrs ago | IN | 0 ETH | 0.00133047 | ||||
| Batch Payments | 10244513 | 12 hrs ago | IN | 0.00037158 ETH | 0.00286451 | ||||
| Batch Payments | 10244510 | 12 hrs ago | IN | 0 ETH | 0.00308658 | ||||
| Batch Payments | 10244507 | 12 hrs ago | IN | 0 ETH | 0.00152663 | ||||
| Batch Payments | 10244222 | 13 hrs ago | IN | 0 ETH | 0.00098121 | ||||
| Batch Payments | 10244221 | 13 hrs ago | IN | 0 ETH | 0.00106827 | ||||
| Batch Payments | 10244217 | 13 hrs ago | IN | 0 ETH | 0.00061958 | ||||
| Batch Payments | 10244215 | 13 hrs ago | IN | 0 ETH | 0.00077503 | ||||
| Batch Payments | 10244208 | 13 hrs ago | IN | 0 ETH | 0.00124094 | ||||
| Batch Payments | 10244197 | 13 hrs ago | IN | 0.00037308 ETH | 0.00298561 | ||||
| Batch Payments | 10244195 | 13 hrs ago | IN | 0 ETH | 0.00269085 | ||||
| Batch Payments | 10244194 | 13 hrs ago | IN | 0 ETH | 0.00135306 | ||||
| Batch Payments | 10239787 | 28 hrs ago | IN | 0 ETH | 0.00113869 | ||||
| Batch Payments | 10239781 | 28 hrs ago | IN | 0 ETH | 0.00128305 | ||||
| Batch Payments | 10239775 | 28 hrs ago | IN | 0 ETH | 0.00080084 | ||||
| Batch Payments | 10239772 | 28 hrs ago | IN | 0 ETH | 0.00082118 | ||||
| Batch Payments | 10239765 | 28 hrs ago | IN | 0 ETH | 0.00099733 | ||||
| Batch Payments | 10239751 | 28 hrs ago | IN | 0.00038274 ETH | 0.00484455 | ||||
| Batch Payments | 10239748 | 28 hrs ago | IN | 0 ETH | 0.00374692 | ||||
| Batch Payments | 10239747 | 28 hrs ago | IN | 0 ETH | 0.0017152 | ||||
| Batch Payments | 10239615 | 29 hrs ago | IN | 0 ETH | 0.00150641 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
To
|
Amount
|
||
|---|---|---|---|---|---|---|---|
| Transfer | 10244513 | 12 hrs ago | 0.00001083 ETH | ||||
| Transfer | 10244513 | 12 hrs ago | 0.00001083 ETH | ||||
| Transfer With Re... | 10244513 | 12 hrs ago | 0.00007096 ETH | ||||
| Transfer | 10244513 | 12 hrs ago | 0.00007096 ETH | ||||
| Transfer With Re... | 10244513 | 12 hrs ago | 0.00013108 ETH | ||||
| Transfer | 10244513 | 12 hrs ago | 0.00013108 ETH | ||||
| Transfer With Re... | 10244513 | 12 hrs ago | 0.0001912 ETH | ||||
| Transfer | 10244513 | 12 hrs ago | 0.0001912 ETH | ||||
| Transfer With Re... | 10244513 | 12 hrs ago | 0.00025133 ETH | ||||
| Transfer | 10244513 | 12 hrs ago | 0.00025133 ETH | ||||
| Transfer With Re... | 10244513 | 12 hrs ago | 0.00031145 ETH | ||||
| Transfer | 10244513 | 12 hrs ago | 0.00031145 ETH | ||||
| Transfer With Re... | 10244513 | 12 hrs ago | 0.00037158 ETH | ||||
| Transfer | 10244197 | 13 hrs ago | 0.00001086 ETH | ||||
| Transfer | 10244197 | 13 hrs ago | 0.00001086 ETH | ||||
| Transfer With Re... | 10244197 | 13 hrs ago | 0.00007123 ETH | ||||
| Transfer | 10244197 | 13 hrs ago | 0.00007123 ETH | ||||
| Transfer With Re... | 10244197 | 13 hrs ago | 0.0001316 ETH | ||||
| Transfer | 10244197 | 13 hrs ago | 0.0001316 ETH | ||||
| Transfer With Re... | 10244197 | 13 hrs ago | 0.00019197 ETH | ||||
| Transfer | 10244197 | 13 hrs ago | 0.00019197 ETH | ||||
| Transfer With Re... | 10244197 | 13 hrs ago | 0.00025234 ETH | ||||
| Transfer | 10244197 | 13 hrs ago | 0.00025234 ETH | ||||
| Transfer With Re... | 10244197 | 13 hrs ago | 0.00031271 ETH | ||||
| Transfer | 10244197 | 13 hrs ago | 0.00031271 ETH |
Loading...
Loading
Loading...
Loading
Loading...
Loading
Contract Name:
BatchConversionPayments
Compiler Version
v0.8.9+commit.e5eed63a
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import './interfaces/IERC20ConversionProxy.sol';
import './interfaces/IEthConversionProxy.sol';
import './BatchNoConversionPayments.sol';
/**
* @title BatchConversionPayments
* @notice This contract makes multiple conversion payments with references, in one transaction:
* - on:
* - ERC20 tokens: using Erc20ConversionProxy and ERC20FeeProxy
* - Native tokens: (e.g. ETH) using EthConversionProxy and EthereumFeeProxy
* - to: multiple addresses
* - fees: conversion proxy fees and additional batch conversion fees are paid to the same address.
* batchPayments is the main function to batch all kinds of payments at once.
* If one transaction of the batch fails, all transactions are reverted.
* @dev batchPayments is the main function, but other batch payment functions are "public" in order to do
* gas optimization in some cases.
*/
contract BatchConversionPayments is BatchNoConversionPayments {
using SafeERC20 for IERC20;
IERC20ConversionProxy public paymentErc20ConversionProxy;
IEthConversionProxy public paymentNativeConversionProxy;
/** payerAuthorized is set to true to workaround the non-payable aspect in batch native conversion */
bool private payerAuthorized = false;
/**
* @dev Used by the batchPayments to handle information for heterogeneous batches, grouped by payment network:
* - paymentNetworkId: from 0 to 4, cf. `batchPayments()` method
* - requestDetails all the data required for conversion and no conversion requests to be paid
*/
struct MetaDetail {
uint256 paymentNetworkId;
RequestDetail[] requestDetails;
}
/**
* @param _paymentErc20Proxy The ERC20 payment proxy address to use.
* @param _paymentNativeProxy The native payment proxy address to use.
* @param _paymentErc20ConversionProxy The ERC20 Conversion payment proxy address to use.
* @param _paymentNativeConversionFeeProxy The native Conversion payment proxy address to use.
* @param _chainlinkConversionPath The address of the conversion path contract.
* @param _owner Owner of the contract.
*/
constructor(
address _paymentErc20Proxy,
address _paymentNativeProxy,
address _paymentErc20ConversionProxy,
address _paymentNativeConversionFeeProxy,
address _chainlinkConversionPath,
address _owner
)
BatchNoConversionPayments(
_paymentErc20Proxy,
_paymentNativeProxy,
_chainlinkConversionPath,
_owner
)
{
paymentErc20ConversionProxy = IERC20ConversionProxy(_paymentErc20ConversionProxy);
paymentNativeConversionProxy = IEthConversionProxy(_paymentNativeConversionFeeProxy);
}
/**
* This contract is non-payable.
* Making a Native payment with conversion requires the contract to accept incoming Native tokens.
* @dev See the end of `paymentNativeConversionProxy.transferWithReferenceAndFee` where the leftover is given back.
*/
receive() external payable override {
require(payerAuthorized || msg.value == 0, 'Non-payable');
}
/**
* @notice Batch payments on different payment networks at once.
* @param metaDetails contains paymentNetworkId and requestDetails
* - batchMultiERC20ConversionPayments, paymentNetworkId=0
* - batchERC20Payments, paymentNetworkId=1
* - batchMultiERC20Payments, paymentNetworkId=2
* - batchNativePayments, paymentNetworkId=3
* - batchNativeConversionPayments, paymentNetworkId=4
* If metaDetails use paymentNetworkId = 4, it must be at the end of the list, or the transaction can be reverted.
* @param pathsToUSD The list of paths into USD for every token, used to limit the batch fees.
* For batch native, mock an array of array to apply the limit, e.g: [[]]
* Without paths, there is not limitation, neither for the batch native functions.
* @param feeAddress The address where fees should be paid.
* @dev Use pathsToUSD only if you are pretty sure the batch fees will higher than the
* USD limit batchFeeAmountUSDLimit, because it increase gas consumption.
* batchPayments only reduces gas consumption when using more than a single payment network.
* For single payment network payments, it is more efficient to use the suited batch function.
*/
function batchPayments(
MetaDetail[] calldata metaDetails,
address[][] calldata pathsToUSD,
address feeAddress
) external payable {
require(metaDetails.length < 6, 'more than 5 metaDetails');
uint256 batchFeeAmountUSD = 0;
for (uint256 i = 0; i < metaDetails.length; i++) {
MetaDetail calldata metaDetail = metaDetails[i];
if (metaDetail.paymentNetworkId == 0) {
batchFeeAmountUSD += _batchMultiERC20ConversionPayments(
metaDetail.requestDetails,
batchFeeAmountUSD,
pathsToUSD,
feeAddress
);
} else if (metaDetail.paymentNetworkId == 1) {
batchFeeAmountUSD += _batchERC20Payments(
metaDetail.requestDetails,
pathsToUSD,
batchFeeAmountUSD,
payable(feeAddress)
);
} else if (metaDetail.paymentNetworkId == 2) {
batchFeeAmountUSD += _batchMultiERC20Payments(
metaDetail.requestDetails,
pathsToUSD,
batchFeeAmountUSD,
feeAddress
);
} else if (metaDetail.paymentNetworkId == 3) {
if (metaDetails[metaDetails.length - 1].paymentNetworkId == 4) {
// Set to false only if batchNativeConversionPayments is called after this function
transferBackRemainingNativeTokens = false;
}
batchFeeAmountUSD += _batchNativePayments(
metaDetail.requestDetails,
pathsToUSD.length == 0,
batchFeeAmountUSD,
payable(feeAddress)
);
if (metaDetails[metaDetails.length - 1].paymentNetworkId == 4) {
transferBackRemainingNativeTokens = true;
}
} else if (metaDetail.paymentNetworkId == 4) {
batchFeeAmountUSD += _batchNativeConversionPayments(
metaDetail.requestDetails,
pathsToUSD.length == 0,
batchFeeAmountUSD,
payable(feeAddress)
);
} else {
revert('Wrong paymentNetworkId');
}
}
}
/**
* @notice Send a batch of ERC20 payments with amounts based on a request
* currency (e.g. fiat), with fees and paymentReferences to multiple accounts, with multiple tokens.
* @param requestDetails List of ERC20 requests denominated in fiat to pay.
* @param pathsToUSD The list of paths into USD for every token, used to limit the batch fees.
* Without paths, there is not a fee limitation, and it consumes less gas.
* @param feeAddress The fee recipient.
*/
function batchMultiERC20ConversionPayments(
RequestDetail[] calldata requestDetails,
address[][] calldata pathsToUSD,
address feeAddress
) public returns (uint256) {
return _batchMultiERC20ConversionPayments(requestDetails, 0, pathsToUSD, feeAddress);
}
/**
* @notice Send a batch of Native conversion payments with fees and paymentReferences to multiple accounts.
* If one payment fails, the whole batch is reverted.
* @param requestDetails List of native requests denominated in fiat to pay.
* @param skipFeeUSDLimit Setting the value to true skips the USD fee limit, and reduces gas consumption.
* @param feeAddress The fee recipient.
* @dev It uses NativeConversionProxy (EthereumConversionProxy) to pay an invoice and fees.
* Please:
* Note that if there is not enough Native token attached to the function call,
* the following error is thrown: "revert paymentProxy transferExactEthWithReferenceAndFee failed"
*/
function batchNativeConversionPayments(
RequestDetail[] calldata requestDetails,
bool skipFeeUSDLimit,
address payable feeAddress
) public payable returns (uint256) {
return _batchNativeConversionPayments(requestDetails, skipFeeUSDLimit, 0, feeAddress);
}
/**
* @notice Send a batch of ERC20 payments with amounts based on a request
* currency (e.g. fiat), with fees and paymentReferences to multiple accounts, with multiple tokens.
* @param requestDetails List of ERC20 requests denominated in fiat to pay.
* @param batchFeeAmountUSD The batch fee amount in USD already paid.
* @param pathsToUSD The list of paths into USD for every token, used to limit the batch fees.
* Without paths, there is not a fee limitation, and it consumes less gas.
* @param feeAddress The fee recipient.
*/
function _batchMultiERC20ConversionPayments(
RequestDetail[] calldata requestDetails,
uint256 batchFeeAmountUSD,
address[][] calldata pathsToUSD,
address feeAddress
) private returns (uint256) {
Token[] memory uTokens = getUTokens(requestDetails);
IERC20 requestedToken;
// For each token: check allowance, transfer funds on the contract and approve the paymentProxy to spend if needed
for (uint256 k = 0; k < uTokens.length && uTokens[k].amountAndFee > 0; k++) {
uTokens[k].batchFeeAmount = (uTokens[k].amountAndFee * batchFee) / feeDenominator;
requestedToken = IERC20(uTokens[k].tokenAddress);
transferToContract(
requestedToken,
uTokens[k].amountAndFee,
uTokens[k].batchFeeAmount,
address(paymentErc20ConversionProxy)
);
}
// Batch pays the requests using Erc20ConversionFeeProxy
for (uint256 i = 0; i < requestDetails.length; i++) {
RequestDetail calldata rD = requestDetails[i];
paymentErc20ConversionProxy.transferFromWithReferenceAndFee(
rD.recipient,
rD.requestAmount,
rD.path,
rD.paymentReference,
rD.feeAmount,
feeAddress,
rD.maxToSpend,
rD.maxRateTimespan
);
}
// Batch sends back to the payer the tokens not spent and pays the batch fee
for (uint256 k = 0; k < uTokens.length && uTokens[k].amountAndFee > 0; k++) {
requestedToken = IERC20(uTokens[k].tokenAddress);
// Batch sends back to the payer the tokens not spent = excessAmount
// excessAmount = maxToSpend - reallySpent, which is equal to the remaining tokens on the contract
uint256 excessAmount = requestedToken.balanceOf(address(this));
if (excessAmount > 0) {
requestedToken.safeTransfer(msg.sender, excessAmount);
}
// Calculate batch fee to pay
uint256 batchFeeToPay = ((uTokens[k].amountAndFee - excessAmount) * batchFee) /
feeDenominator;
(batchFeeToPay, batchFeeAmountUSD) = calculateBatchFeeToPay(
batchFeeToPay,
uTokens[k].tokenAddress,
batchFeeAmountUSD,
pathsToUSD
);
// Payer pays the exact batch fees amount
require(
safeTransferFrom(uTokens[k].tokenAddress, feeAddress, batchFeeToPay),
'Batch fee transferFrom() failed'
);
}
return batchFeeAmountUSD;
}
/**
* @notice Send a batch of Native conversion payments with fees and paymentReferences to multiple accounts.
* If one payment fails, the whole batch is reverted.
* @param requestDetails List of native requests denominated in fiat to pay.
* @param skipFeeUSDLimit Setting the value to true skips the USD fee limit, and reduces gas consumption.
* @param batchFeeAmountUSD The batch fee amount in USD already paid.
* @param feeAddress The fee recipient.
* @dev It uses NativeConversionProxy (EthereumConversionProxy) to pay an invoice and fees.
* Please:
* Note that if there is not enough Native token attached to the function call,
* the following error is thrown: "revert paymentProxy transferExactEthWithReferenceAndFee failed"
*/
function _batchNativeConversionPayments(
RequestDetail[] calldata requestDetails,
bool skipFeeUSDLimit,
uint256 batchFeeAmountUSD,
address payable feeAddress
) private returns (uint256) {
uint256 contractBalance = address(this).balance;
payerAuthorized = true;
// Batch contract pays the requests through nativeConversionProxy
for (uint256 i = 0; i < requestDetails.length; i++) {
RequestDetail calldata rD = requestDetails[i];
paymentNativeConversionProxy.transferWithReferenceAndFee{value: address(this).balance}(
payable(rD.recipient),
rD.requestAmount,
rD.path,
rD.paymentReference,
rD.feeAmount,
feeAddress,
rD.maxRateTimespan
);
}
// Batch contract pays batch fee
uint256 batchFeeToPay = (((contractBalance - address(this).balance)) * batchFee) /
feeDenominator;
if (skipFeeUSDLimit == false) {
(batchFeeToPay, batchFeeAmountUSD) = calculateBatchFeeToPay(
batchFeeToPay,
pathsNativeToUSD[0][0],
batchFeeAmountUSD,
pathsNativeToUSD
);
}
require(address(this).balance >= batchFeeToPay, 'Not enough funds for batch conversion fees');
feeAddress.transfer(batchFeeToPay);
// Batch contract transfers the remaining native tokens to the payer
(bool sendBackSuccess, ) = payable(msg.sender).call{value: address(this).balance}('');
require(sendBackSuccess, 'Could not send remaining funds to the payer');
payerAuthorized = false;
return batchFeeAmountUSD;
}
/*
* Admin functions to edit the conversion proxies address and fees.
*/
/**
* @param _paymentErc20ConversionProxy The address of the ERC20 Conversion payment proxy to use.
* Update cautiously, the proxy has to match the invoice proxy.
*/
function setPaymentErc20ConversionProxy(address _paymentErc20ConversionProxy) external onlyOwner {
paymentErc20ConversionProxy = IERC20ConversionProxy(_paymentErc20ConversionProxy);
}
/**
* @param _paymentNativeConversionProxy The address of the native Conversion payment proxy to use.
* Update cautiously, the proxy has to match the invoice proxy.
*/
function setPaymentNativeConversionProxy(address _paymentNativeConversionProxy)
external
onlyOwner
{
paymentNativeConversionProxy = IEthConversionProxy(_paymentNativeConversionProxy);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IEthConversionProxy
* @notice This contract converts from chainlink then swaps ETH (or native token)
* before paying a request thanks to a conversion payment proxy.
* The inheritance from ReentrancyGuard is required to perform
* "transferExactEthWithReferenceAndFee" on the eth-fee-proxy contract
*/
interface IEthConversionProxy {
// Event to declare a conversion with a reference
event TransferWithConversionAndReference(
uint256 amount,
address currency,
bytes indexed paymentReference,
uint256 feeAmount,
uint256 maxRateTimespan
);
// Event to declare a transfer with a reference
// This event is emitted by this contract from a delegate call of the payment-proxy
event TransferWithReferenceAndFee(
address to,
uint256 amount,
bytes indexed paymentReference,
uint256 feeAmount,
address feeAddress
);
/**
* @notice Performs an ETH transfer with a reference computing the payment amount based on the request amount
* @param _to Transfer recipient of the payement
* @param _requestAmount Request amount
* @param _path Conversion path
* @param _paymentReference Reference of the payment related
* @param _feeAmount The amount of the payment fee
* @param _feeAddress The fee recipient
* @param _maxRateTimespan Max time span with the oldestrate, ignored if zero
*/
function transferWithReferenceAndFee(
address _to,
uint256 _requestAmount,
address[] calldata _path,
bytes calldata _paymentReference,
uint256 _feeAmount,
address _feeAddress,
uint256 _maxRateTimespan
) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20ConversionProxy {
// Event to declare a conversion with a reference
event TransferWithConversionAndReference(
uint256 amount,
address currency,
bytes indexed paymentReference,
uint256 feeAmount,
uint256 maxRateTimespan
);
// Event to declare a transfer with a reference
event TransferWithReferenceAndFee(
address tokenAddress,
address to,
uint256 amount,
bytes indexed paymentReference,
uint256 feeAmount,
address feeAddress
);
function transferFromWithReferenceAndFee(
address _to,
uint256 _requestAmount,
address[] calldata _path,
bytes calldata _paymentReference,
uint256 _feeAmount,
address _feeAddress,
uint256 _maxToSpend,
uint256 _maxRateTimespan
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import './lib/SafeERC20.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import './interfaces/ERC20FeeProxy.sol';
import './interfaces/EthereumFeeProxy.sol';
import './ChainlinkConversionPath.sol';
/**
* @title BatchNoConversionPayments
* @notice This contract makes multiple payments with references, in one transaction:
* - on: ERC20 Payment Proxy and Native (ETH) Payment Proxy of the Request Network protocol
* - to: multiple addresses
* - fees: ERC20 and Native (ETH) proxies fees are paid to the same address
* An additional batch fee is paid to the same address
* If one transaction of the batch fail, every transactions are reverted.
* @dev It is a clone of BatchPayment.sol, with three main modifications:
* - function "receive" has one other condition: payerAuthorized
* - fees are now divided by 10_000 instead of 1_000 in previous version
* - batch payment functions have new names and are now public, instead of external
*/
contract BatchNoConversionPayments is Ownable {
using SafeERC20 for IERC20;
IERC20FeeProxy public paymentErc20Proxy;
IEthereumFeeProxy public paymentNativeProxy;
ChainlinkConversionPath public chainlinkConversionPath;
/** Used to calculate batch fees: batchFee = 30 represent 0.30% of fee */
uint16 public batchFee;
/** Used to calculate batch fees: divide batchFee by feeDenominator */
uint16 internal feeDenominator = 10000;
/** The amount of the batch fee cannot exceed a predefined amount in USD, e.g:
batchFeeAmountUSDLimit = 150 * 1e8 represents $150 */
uint64 public batchFeeAmountUSDLimit;
/** transferBackRemainingNativeTokens is set to false only if the payer use batchPayments
and call both batchNativePayments and batchNativeConversionPayments */
bool internal transferBackRemainingNativeTokens = true;
address public USDAddress;
address public NativeAddress;
address[][] public pathsNativeToUSD;
/** Contains the address of a token, the sum of the amount and fees paid with it, and the batch fee amount */
struct Token {
address tokenAddress;
uint256 amountAndFee;
uint256 batchFeeAmount;
}
/**
* @dev All the information of a request, except the feeAddress
* recipient: Recipient address of the payment
* requestAmount: Request amount, in fiat for conversion payment
* path: Only for conversion payment: the conversion path
* paymentReference: Unique reference of the payment
* feeAmount: The fee amount, denominated in the first currency of `path` for conversion payment
* maxToSpend: Only for conversion payment:
* Maximum amount the payer wants to spend, denominated in the last currency of `path`:
* it includes fee proxy but NOT the batch fees to pay
* maxRateTimespan: Only for conversion payment:
* Max acceptable times span for conversion rates, ignored if zero
*/
struct RequestDetail {
address recipient;
uint256 requestAmount;
address[] path;
bytes paymentReference;
uint256 feeAmount;
uint256 maxToSpend;
uint256 maxRateTimespan;
}
/**
* @param _paymentErc20Proxy The address to the ERC20 fee payment proxy to use.
* @param _paymentNativeProxy The address to the Native fee payment proxy to use.
* @param _chainlinkConversionPath The address of the conversion path contract.
* @param _owner Owner of the contract.
*/
constructor(
address _paymentErc20Proxy,
address _paymentNativeProxy,
address _chainlinkConversionPath,
address _owner
) {
paymentErc20Proxy = IERC20FeeProxy(_paymentErc20Proxy);
paymentNativeProxy = IEthereumFeeProxy(_paymentNativeProxy);
chainlinkConversionPath = ChainlinkConversionPath(_chainlinkConversionPath);
transferOwnership(_owner);
batchFee = 0;
}
/**
* This contract is non-payable.
* @dev See the end of `paymentNativeProxy.transferWithReferenceAndFee` where the leftover is given back.
*/
receive() external payable virtual {
require(msg.value == 0, 'Non-payable');
}
/**
* @notice Send a batch of Native token payments with fees and paymentReferences to multiple accounts.
* If one payment fails, the whole batch reverts.
* @param requestDetails List of Native tokens requests to pay.
* @param skipFeeUSDLimit Setting the value to true skips the USD fee limit, and reduces gas consumption.
* @param feeAddress The fee recipient.
* @dev It uses NativeFeeProxy (EthereumFeeProxy) to pay an invoice and fees with a payment reference.
* Make sure: msg.value >= sum(_amouts)+sum(_feeAmounts)+sumBatchFeeAmount
*/
function batchNativePayments(
RequestDetail[] calldata requestDetails,
bool skipFeeUSDLimit,
address payable feeAddress
) public payable returns (uint256) {
return _batchNativePayments(requestDetails, skipFeeUSDLimit, 0, payable(feeAddress));
}
/**
* @notice Send a batch of ERC20 payments with fees and paymentReferences to multiple accounts.
* @param requestDetails List of ERC20 requests to pay, with only one ERC20 token.
* @param pathsToUSD The list of paths into USD for every token, used to limit the batch fees.
* Without paths, there is not a fee limitation, and it consumes less gas.
* @param feeAddress The fee recipient.
* @dev Uses ERC20FeeProxy to pay an invoice and fees, with a payment reference.
* Make sure this contract has enough allowance to spend the payer's token.
* Make sure the payer has enough tokens to pay the amount, the fee, and the batch fee.
*/
function batchERC20Payments(
RequestDetail[] calldata requestDetails,
address[][] calldata pathsToUSD,
address feeAddress
) public returns (uint256) {
return _batchERC20Payments(requestDetails, pathsToUSD, 0, feeAddress);
}
/**
* @notice Send a batch of ERC20 payments with fees and paymentReferences to multiple accounts, with multiple tokens.
* @param requestDetails List of ERC20 requests to pay.
* @param pathsToUSD The list of paths into USD for every token, used to limit the batch fees.
* Without paths, there is not a fee limitation, and it consumes less gas.
* @param feeAddress The fee recipient.
* @dev It uses ERC20FeeProxy to pay an invoice and fees, with a payment reference.
* Make sure this contract has enough allowance to spend the payer's token.
* Make sure the payer has enough tokens to pay the amount, the fee, and the batch fee.
*/
function batchMultiERC20Payments(
RequestDetail[] calldata requestDetails,
address[][] calldata pathsToUSD,
address feeAddress
) public returns (uint256) {
return _batchMultiERC20Payments(requestDetails, pathsToUSD, 0, feeAddress);
}
/**
* @notice Send a batch of Native token payments with fees and paymentReferences to multiple accounts.
* If one payment fails, the whole batch reverts.
* @param requestDetails List of Native tokens requests to pay.
* @param skipFeeUSDLimit Setting the value to true skips the USD fee limit, and reduces gas consumption.
* @param batchFeeAmountUSD The batch fee amount in USD already paid.
* @param feeAddress The fee recipient.
* @dev It uses NativeFeeProxy (EthereumFeeProxy) to pay an invoice and fees with a payment reference.
* Make sure: msg.value >= sum(_amouts)+sum(_feeAmounts)+sumBatchFeeAmount
*/
function _batchNativePayments(
RequestDetail[] calldata requestDetails,
bool skipFeeUSDLimit,
uint256 batchFeeAmountUSD,
address payable feeAddress
) internal returns (uint256) {
// amount is used to get the total amount and then used as batch fee amount
uint256 amount = 0;
// Batch contract pays the requests thourgh NativeFeeProxy (EthFeeProxy)
for (uint256 i = 0; i < requestDetails.length; i++) {
RequestDetail calldata rD = requestDetails[i];
require(address(this).balance >= rD.requestAmount + rD.feeAmount, 'Not enough funds');
amount += rD.requestAmount;
paymentNativeProxy.transferWithReferenceAndFee{value: rD.requestAmount + rD.feeAmount}(
payable(rD.recipient),
rD.paymentReference,
rD.feeAmount,
payable(feeAddress)
);
}
// amount is updated into batch fee amount
amount = (amount * batchFee) / feeDenominator;
if (skipFeeUSDLimit == false) {
(amount, batchFeeAmountUSD) = calculateBatchFeeToPay(
amount,
pathsNativeToUSD[0][0],
batchFeeAmountUSD,
pathsNativeToUSD
);
}
// Check that batch contract has enough funds to pay batch fee
require(address(this).balance >= amount, 'Not enough funds for batch fee');
// Batch pays batch fee
feeAddress.transfer(amount);
// Batch contract transfers the remaining Native tokens to the payer
if (transferBackRemainingNativeTokens && address(this).balance > 0) {
(bool sendBackSuccess, ) = payable(msg.sender).call{value: address(this).balance}('');
require(sendBackSuccess, 'Could not send remaining funds to the payer');
}
return batchFeeAmountUSD;
}
/**
* @notice Send a batch of ERC20 payments with fees and paymentReferences to multiple accounts.
* @param requestDetails List of ERC20 requests to pay, with only one ERC20 token.
* @param pathsToUSD The list of paths into USD for every token, used to limit the batch fees.
* Without paths, there is not a fee limitation, and it consumes less gas.
* @param batchFeeAmountUSD The batch fee amount in USD already paid.
* @param feeAddress The fee recipient.
* @dev Uses ERC20FeeProxy to pay an invoice and fees, with a payment reference.
* Make sure this contract has enough allowance to spend the payer's token.
* Make sure the payer has enough tokens to pay the amount, the fee, and the batch fee.
*/
function _batchERC20Payments(
RequestDetail[] calldata requestDetails,
address[][] calldata pathsToUSD,
uint256 batchFeeAmountUSD,
address feeAddress
) internal returns (uint256) {
uint256 amountAndFee = 0;
uint256 batchFeeAmount = 0;
for (uint256 i = 0; i < requestDetails.length; i++) {
amountAndFee += requestDetails[i].requestAmount + requestDetails[i].feeAmount;
batchFeeAmount += requestDetails[i].requestAmount;
}
batchFeeAmount = (batchFeeAmount * batchFee) / feeDenominator;
// batchFeeToPay and batchFeeAmountUSD are updated if needed
(batchFeeAmount, batchFeeAmountUSD) = calculateBatchFeeToPay(
batchFeeAmount,
requestDetails[0].path[0],
batchFeeAmountUSD,
pathsToUSD
);
IERC20 requestedToken = IERC20(requestDetails[0].path[0]);
transferToContract(requestedToken, amountAndFee, batchFeeAmount, address(paymentErc20Proxy));
// Payer pays batch fee amount
require(
safeTransferFrom(requestDetails[0].path[0], feeAddress, batchFeeAmount),
'Batch fee transferFrom() failed'
);
// Batch contract pays the requests using Erc20FeeProxy
for (uint256 i = 0; i < requestDetails.length; i++) {
RequestDetail calldata rD = requestDetails[i];
paymentErc20Proxy.transferFromWithReferenceAndFee(
rD.path[0],
rD.recipient,
rD.requestAmount,
rD.paymentReference,
rD.feeAmount,
feeAddress
);
}
return batchFeeAmountUSD;
}
/**
* @notice Send a batch of ERC20 payments with fees and paymentReferences to multiple accounts, with multiple tokens.
* @param requestDetails List of ERC20 requests to pay.
* @param pathsToUSD The list of paths into USD for every token, used to limit the batch fees.
* Without paths, there is not a fee limitation, and it consumes less gas.
* @param batchFeeAmountUSD The batch fee amount in USD already paid.
* @param feeAddress The fee recipient.
* @dev It uses ERC20FeeProxy to pay an invoice and fees, with a payment reference.
* Make sure this contract has enough allowance to spend the payer's token.
* Make sure the payer has enough tokens to pay the amount, the fee, and the batch fee.
*/
function _batchMultiERC20Payments(
RequestDetail[] calldata requestDetails,
address[][] calldata pathsToUSD,
uint256 batchFeeAmountUSD,
address feeAddress
) internal returns (uint256) {
Token[] memory uTokens = getUTokens(requestDetails);
// The payer transfers tokens to the batch contract and pays batch fee
for (uint256 i = 0; i < uTokens.length && uTokens[i].amountAndFee > 0; i++) {
uTokens[i].batchFeeAmount = (uTokens[i].batchFeeAmount * batchFee) / feeDenominator;
IERC20 requestedToken = IERC20(uTokens[i].tokenAddress);
transferToContract(
requestedToken,
uTokens[i].amountAndFee,
uTokens[i].batchFeeAmount,
address(paymentErc20Proxy)
);
// Payer pays batch fee amount
uint256 batchFeeToPay = uTokens[i].batchFeeAmount;
(batchFeeToPay, batchFeeAmountUSD) = calculateBatchFeeToPay(
batchFeeToPay,
uTokens[i].tokenAddress,
batchFeeAmountUSD,
pathsToUSD
);
require(
safeTransferFrom(uTokens[i].tokenAddress, feeAddress, batchFeeToPay),
'Batch fee transferFrom() failed'
);
}
// Batch contract pays the requests using Erc20FeeProxy
for (uint256 i = 0; i < requestDetails.length; i++) {
RequestDetail calldata rD = requestDetails[i];
paymentErc20Proxy.transferFromWithReferenceAndFee(
rD.path[0],
rD.recipient,
rD.requestAmount,
rD.paymentReference,
rD.feeAmount,
feeAddress
);
}
return batchFeeAmountUSD;
}
/*
* Helper functions
*/
/**
* Top up the contract with enough `requestedToken` to pay `amountAndFee`.
* The contract is NOT topped-up for `batchFeeAmount`.
*
* It also performs a few checks:
* - checks that the batch contract has enough allowance from the payer
* - checks that the payer has enough funds, including batch fees
* - increases the allowance of the contract to use the payment proxy if needed
*
* @param requestedToken The token to pay
* @param amountAndFee The amount and the fee for a token to pay
* @param batchFeeAmount The batch fee amount for a token to pay
* @param paymentProxyAddress The payment proxy address used to pay
*/
function transferToContract(
IERC20 requestedToken,
uint256 amountAndFee,
uint256 batchFeeAmount,
address paymentProxyAddress
) internal {
// Check proxy's allowance from user
require(
requestedToken.allowance(msg.sender, address(this)) >= amountAndFee,
'Insufficient allowance for batch to pay'
);
// Check user's funds to pay amounts, it is an approximation for conversion payment
require(
requestedToken.balanceOf(msg.sender) >= amountAndFee + batchFeeAmount,
'Not enough funds, including fees'
);
// Transfer the amount and fees (no batch fees) required for the token on the batch contract
require(
safeTransferFrom(address(requestedToken), address(this), amountAndFee),
'payment transferFrom() failed'
);
// Batch contract approves Erc20ConversionProxy to spend the token
if (requestedToken.allowance(address(this), paymentProxyAddress) < amountAndFee) {
approvePaymentProxyToSpend(address(requestedToken), paymentProxyAddress);
}
}
/**
* It create a list of unique tokens used and the amounts associated.
* It only considers tokens having: requestAmount + feeAmount > 0.
* Regarding ERC20 no conversion payments:
* batchFeeAmount is the sum of requestAmount and feeAmount.
* Out of the function, batch fee rate is applied
* @param requestDetails List of requests to pay.
*/
function getUTokens(RequestDetail[] calldata requestDetails)
internal
pure
returns (Token[] memory uTokens)
{
// A list of unique tokens, with the sum of maxToSpend by token
uTokens = new Token[](requestDetails.length);
for (uint256 i = 0; i < requestDetails.length; i++) {
for (uint256 k = 0; k < requestDetails.length; k++) {
RequestDetail calldata rD = requestDetails[i];
// If the token is already in the existing uTokens list
if (uTokens[k].tokenAddress == rD.path[rD.path.length - 1]) {
if (rD.path.length > 1) {
uTokens[k].amountAndFee += rD.maxToSpend;
} else {
// It is not a conversion payment
uTokens[k].amountAndFee += rD.requestAmount + rD.feeAmount;
uTokens[k].batchFeeAmount += rD.requestAmount;
}
break;
}
// If the token is not in the list (amountAndFee = 0)
else if (
uTokens[k].amountAndFee == 0 && (rD.maxToSpend > 0 || rD.requestAmount + rD.feeAmount > 0)
) {
uTokens[k].tokenAddress = rD.path[rD.path.length - 1];
if (rD.path.length > 1) {
// amountAndFee is used to store _maxToSpend, useful to send enough tokens to this contract
uTokens[k].amountAndFee = rD.maxToSpend;
} else {
// It is not a conversion payment
uTokens[k].amountAndFee = rD.requestAmount + rD.feeAmount;
uTokens[k].batchFeeAmount = rD.requestAmount;
}
break;
}
}
}
}
/**
* Calculate the batch fee amount to pay, using the USD fee limitation.
* Without pathsToUSD or a wrong one, the fee limitation is not applied.
* @param batchFeeToPay The amount of batch fee to pay
* @param tokenAddress The address of the token
* @param batchFeeAmountUSD The batch fee amount in USD already paid.
* @param pathsToUSD The list of paths into USD for every token, used to limit the batch fees.
* Without paths, there is not a fee limitation, and it consumes less gas.
*/
function calculateBatchFeeToPay(
uint256 batchFeeToPay,
address tokenAddress,
uint256 batchFeeAmountUSD,
address[][] memory pathsToUSD
) internal view returns (uint256, uint256) {
// Fees are not limited if there is no pathsToUSD
// Excepted if batchFeeAmountUSD is already >= batchFeeAmountUSDLimit
if (pathsToUSD.length == 0 && batchFeeAmountUSD < batchFeeAmountUSDLimit) {
return (batchFeeToPay, batchFeeAmountUSD);
}
// Apply the fee limit and calculate if needed batchFeeToPay
if (batchFeeAmountUSD < batchFeeAmountUSDLimit) {
for (uint256 i = 0; i < pathsToUSD.length; i++) {
// Check if the pathToUSD is right
if (
pathsToUSD[i][0] == tokenAddress && pathsToUSD[i][pathsToUSD[i].length - 1] == USDAddress
) {
(uint256 conversionUSD, ) = chainlinkConversionPath.getConversion(
batchFeeToPay,
pathsToUSD[i]
);
// Calculate the batch fee to pay, taking care of the batchFeeAmountUSDLimit
uint256 conversionToPayUSD = conversionUSD;
if (batchFeeAmountUSD + conversionToPayUSD > batchFeeAmountUSDLimit) {
conversionToPayUSD = batchFeeAmountUSDLimit - batchFeeAmountUSD;
batchFeeToPay = (batchFeeToPay * conversionToPayUSD) / conversionUSD;
}
batchFeeAmountUSD += conversionToPayUSD;
// Add only once the fees
break;
}
}
} else {
batchFeeToPay = 0;
}
return (batchFeeToPay, batchFeeAmountUSD);
}
/**
* @notice Authorizes the proxy to spend a new request currency (ERC20).
* @param _erc20Address Address of an ERC20 used as the request currency.
* @param _paymentErc20Proxy Address of the proxy.
*/
function approvePaymentProxyToSpend(address _erc20Address, address _paymentErc20Proxy) internal {
IERC20 erc20 = IERC20(_erc20Address);
uint256 max = 2**256 - 1;
erc20.safeApprove(address(_paymentErc20Proxy), max);
}
/**
* @notice Call transferFrom ERC20 function and validates the return data of a ERC20 contract call.
* @dev This is necessary because of non-standard ERC20 tokens that don't have a return value.
* @return result The return value of the ERC20 call, returning true for non-standard tokens
*/
function safeTransferFrom(
address _tokenAddress,
address _to,
uint256 _amount
) internal returns (bool result) {
/* solium-disable security/no-inline-assembly */
// check if the address is a contract
assembly {
if iszero(extcodesize(_tokenAddress)) {
revert(0, 0)
}
}
// solium-disable-next-line security/no-low-level-calls
(bool success, ) = _tokenAddress.call(
abi.encodeWithSignature('transferFrom(address,address,uint256)', msg.sender, _to, _amount)
);
assembly {
switch returndatasize()
case 0 {
// Not a standard erc20
result := 1
}
case 32 {
// Standard erc20
returndatacopy(0, 0, 32)
result := mload(0)
}
default {
// Anything else, should revert for safety
revert(0, 0)
}
}
require(success, 'transferFrom() has been reverted');
/* solium-enable security/no-inline-assembly */
return result;
}
/*
* Admin functions to edit the proxies address and fees
*/
/**
* @notice Fees added when using Erc20/Native batch functions
* @param _batchFee Between 0 and 200, i.e: batchFee = 30 represent 0.30% of fee
*/
function setBatchFee(uint16 _batchFee) external onlyOwner {
// safety to avoid wrong setting
require(_batchFee <= 200, 'The batch fee value is too high: > 2%');
batchFee = _batchFee;
}
/**
* @param _paymentErc20Proxy The address to the Erc20 fee payment proxy to use.
*/
function setPaymentErc20Proxy(address _paymentErc20Proxy) external onlyOwner {
paymentErc20Proxy = IERC20FeeProxy(_paymentErc20Proxy);
}
/**
* @param _paymentNativeProxy The address to the Native fee payment proxy to use.
*/
function setPaymentNativeProxy(address _paymentNativeProxy) external onlyOwner {
paymentNativeProxy = IEthereumFeeProxy(_paymentNativeProxy);
}
/**
* @notice Update the conversion path contract used to fetch conversions.
* @param _chainlinkConversionPath The address of the conversion path contract.
*/
function setChainlinkConversionPath(address _chainlinkConversionPath) external onlyOwner {
chainlinkConversionPath = ChainlinkConversionPath(_chainlinkConversionPath);
}
/**
* This function define variables allowing to limit the fees:
* NativeAddress, USDAddress, and pathsNativeToUSD.
* @param _NativeAddress The address representing the Native currency.
* @param _USDAddress The address representing the USD currency.
*/
function setNativeAndUSDAddress(address _NativeAddress, address _USDAddress) external onlyOwner {
NativeAddress = _NativeAddress;
USDAddress = _USDAddress;
pathsNativeToUSD = [[NativeAddress, USDAddress]];
}
/**
* @param _batchFeeAmountUSDLimit The limitation of the batch fee amount in USD, e.g:
* batchFeeAmountUSDLimit = 150 * 1e8 represents $150
*/
function setBatchFeeAmountUSDLimit(uint64 _batchFeeAmountUSDLimit) external onlyOwner {
batchFeeAmountUSDLimit = _batchFeeAmountUSDLimit;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import './legacy_openzeppelin/contracts/access/roles/WhitelistAdminRole.sol';
interface ERC20fraction {
function decimals() external view returns (uint8);
}
interface AggregatorFraction {
function decimals() external view returns (uint8);
function latestAnswer() external view returns (int256);
function latestTimestamp() external view returns (uint256);
}
/**
* @title ChainlinkConversionPath
*
* @notice ChainlinkConversionPath is a contract computing currency conversion rates based on Chainlink aggretators
*/
contract ChainlinkConversionPath is WhitelistAdminRole {
uint256 constant PRECISION = 1e18;
uint256 constant NATIVE_TOKEN_DECIMALS = 18;
uint256 constant FIAT_DECIMALS = 8;
address public nativeTokenHash;
/**
* @param _nativeTokenHash hash of the native token
* @param _owner Owner of the contract.
*/
constructor(address _nativeTokenHash, address _owner) {
nativeTokenHash = _nativeTokenHash;
renounceWhitelistAdmin();
_addWhitelistAdmin(_owner);
}
// Mapping of Chainlink aggregators (input currency => output currency => contract address)
// input & output currencies are the addresses of the ERC20 contracts OR the sha3("currency code")
mapping(address => mapping(address => address)) public allAggregators;
// declare a new aggregator
event AggregatorUpdated(address _input, address _output, address _aggregator);
/**
* @notice Update an aggregator
* @param _input address representing the input currency
* @param _output address representing the output currency
* @param _aggregator address of the aggregator contract
*/
function updateAggregator(
address _input,
address _output,
address _aggregator
) external onlyWhitelistAdmin {
allAggregators[_input][_output] = _aggregator;
emit AggregatorUpdated(_input, _output, _aggregator);
}
/**
* @notice Update a list of aggregators
* @param _inputs list of addresses representing the input currencies
* @param _outputs list of addresses representing the output currencies
* @param _aggregators list of addresses of the aggregator contracts
*/
function updateAggregatorsList(
address[] calldata _inputs,
address[] calldata _outputs,
address[] calldata _aggregators
) external onlyWhitelistAdmin {
require(_inputs.length == _outputs.length, 'arrays must have the same length');
require(_inputs.length == _aggregators.length, 'arrays must have the same length');
// For every conversions of the path
for (uint256 i; i < _inputs.length; i++) {
allAggregators[_inputs[i]][_outputs[i]] = _aggregators[i];
emit AggregatorUpdated(_inputs[i], _outputs[i], _aggregators[i]);
}
}
/**
* @notice Computes the conversion of an amount through a list of intermediate conversions
* @param _amountIn Amount to convert
* @param _path List of addresses representing the currencies for the intermediate conversions
* @return result The result after all the conversions
* @return oldestRateTimestamp The oldest timestamp of the path
*/
function getConversion(uint256 _amountIn, address[] calldata _path)
external
view
returns (uint256 result, uint256 oldestRateTimestamp)
{
(uint256 rate, uint256 timestamp, uint256 decimals) = getRate(_path);
// initialize the result
result = (_amountIn * rate) / decimals;
oldestRateTimestamp = timestamp;
}
/**
* @notice Computes the conversion rate from a list of currencies
* @param _path List of addresses representing the currencies for the conversions
* @return rate The rate
* @return oldestRateTimestamp The oldest timestamp of the path
* @return decimals of the conversion rate
*/
function getRate(address[] memory _path)
public
view
returns (
uint256 rate,
uint256 oldestRateTimestamp,
uint256 decimals
)
{
// initialize the result with 18 decimals (for more precision)
rate = PRECISION;
decimals = PRECISION;
oldestRateTimestamp = block.timestamp;
// For every conversion of the path
for (uint256 i; i < _path.length - 1; i++) {
(
AggregatorFraction aggregator,
bool reverseAggregator,
uint256 decimalsInput,
uint256 decimalsOutput
) = getAggregatorAndDecimals(_path[i], _path[i + 1]);
// store the latest timestamp of the path
uint256 currentTimestamp = aggregator.latestTimestamp();
if (currentTimestamp < oldestRateTimestamp) {
oldestRateTimestamp = currentTimestamp;
}
// get the rate of the current step
uint256 currentRate = uint256(aggregator.latestAnswer());
// get the number of decimals of the current rate
uint256 decimalsAggregator = uint256(aggregator.decimals());
// mul with the difference of decimals before the current rate computation (for more precision)
if (decimalsAggregator > decimalsInput) {
rate = rate * (10**(decimalsAggregator - decimalsInput));
}
if (decimalsAggregator < decimalsOutput) {
rate = rate * (10**(decimalsOutput - decimalsAggregator));
}
// Apply the current rate (if path uses an aggregator in the reverse way, div instead of mul)
if (reverseAggregator) {
rate = (rate * (10**decimalsAggregator)) / currentRate;
} else {
rate = (rate * currentRate) / (10**decimalsAggregator);
}
// div with the difference of decimals AFTER the current rate computation (for more precision)
if (decimalsAggregator < decimalsInput) {
rate = rate / (10**(decimalsInput - decimalsAggregator));
}
if (decimalsAggregator > decimalsOutput) {
rate = rate / (10**(decimalsAggregator - decimalsOutput));
}
}
}
/**
* @notice Gets aggregators and decimals of two currencies
* @param _input input Address
* @param _output output Address
* @return aggregator to get the rate between the two currencies
* @return reverseAggregator true if the aggregator returned give the rate from _output to _input
* @return decimalsInput decimals of _input
* @return decimalsOutput decimals of _output
*/
function getAggregatorAndDecimals(address _input, address _output)
private
view
returns (
AggregatorFraction aggregator,
bool reverseAggregator,
uint256 decimalsInput,
uint256 decimalsOutput
)
{
// Try to get the right aggregator for the conversion
aggregator = AggregatorFraction(allAggregators[_input][_output]);
reverseAggregator = false;
// if no aggregator found we try to find an aggregator in the reverse way
if (address(aggregator) == address(0x00)) {
aggregator = AggregatorFraction(allAggregators[_output][_input]);
reverseAggregator = true;
}
require(address(aggregator) != address(0x00), 'No aggregator found');
// get the decimals for the two currencies
decimalsInput = getDecimals(_input);
decimalsOutput = getDecimals(_output);
}
/**
* @notice Gets decimals from an address currency
* @param _addr address to check
* @return decimals number of decimals
*/
function getDecimals(address _addr) private view returns (uint256 decimals) {
// by default we assume it is fiat
decimals = FIAT_DECIMALS;
// if address is the hash of the ETH currency
if (_addr == nativeTokenHash) {
decimals = NATIVE_TOKEN_DECIMALS;
} else if (isContract(_addr)) {
// otherwise, we get the decimals from the erc20 directly
decimals = ERC20fraction(_addr).decimals();
}
}
/**
* @notice Checks if an address is a contract
* @param _addr Address to check
* @return true if the address hosts a contract, false otherwise
*/
function isContract(address _addr) private view returns (bool) {
uint32 size;
// solium-disable security/no-inline-assembly
assembly {
size := extcodesize(_addr)
}
return (size > 0);
}
/**
* @notice Update the native token hash
* @param _nativeTokenHash hash of the native token represented as an eth address
*/
function updateNativeTokenHash(address _nativeTokenHash) external onlyWhitelistAdmin {
nativeTokenHash = _nativeTokenHash;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
/**
* @title SafeERC20
* @notice Works around implementations of ERC20 with transferFrom not returning success status.
*/
library SafeERC20 {
/**
* @notice Call transferFrom ERC20 function and validates the return data of a ERC20 contract call.
* @dev This is necessary because of non-standard ERC20 tokens that don't have a return value.
* @return result The return value of the ERC20 call, returning true for non-standard tokens
*/
function safeTransferFrom(
IERC20 _token,
address _from,
address _to,
uint256 _amount
) internal returns (bool result) {
// solium-disable-next-line security/no-low-level-calls
(bool success, bytes memory data) = address(_token).call(
abi.encodeWithSignature('transferFrom(address,address,uint256)', _from, _to, _amount)
);
return success && (data.length == 0 || abi.decode(data, (bool)));
}
/**
* @notice Call approve ERC20 function and validates the return data of a ERC20 contract call.
* @dev This is necessary because of non-standard ERC20 tokens that don't have a return value.
* @return result The return value of the ERC20 call, returning true for non-standard tokens
*/
function safeApprove(
IERC20 _token,
address _spender,
uint256 _amount
) internal returns (bool result) {
// solium-disable-next-line security/no-low-level-calls
(bool success, bytes memory data) = address(_token).call(
abi.encodeWithSignature('approve(address,uint256)', _spender, _amount)
);
return success && (data.length == 0 || abi.decode(data, (bool)));
}
/**
* @notice Call transfer ERC20 function and validates the return data of a ERC20 contract call.
* @dev This is necessary because of non-standard ERC20 tokens that don't have a return value.
* @return result The return value of the ERC20 call, returning true for non-standard tokens
*/
function safeTransfer(
IERC20 _token,
address _to,
uint256 _amount
) internal returns (bool result) {
// solium-disable-next-line security/no-low-level-calls
(bool success, bytes memory data) = address(_token).call(
abi.encodeWithSignature('transfer(address,uint256)', _to, _amount)
);
return success && (data.length == 0 || abi.decode(data, (bool)));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20FeeProxy {
event TransferWithReferenceAndFee(
address tokenAddress,
address to,
uint256 amount,
bytes indexed paymentReference,
uint256 feeAmount,
address feeAddress
);
function transferFromWithReferenceAndFee(
address _tokenAddress,
address _to,
uint256 _amount,
bytes calldata _paymentReference,
uint256 _feeAmount,
address _feeAddress
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IEthereumFeeProxy {
event TransferWithReferenceAndFee(
address to,
uint256 amount,
bytes indexed paymentReference,
uint256 feeAmount,
address feeAddress
);
function transferWithReferenceAndFee(
address payable _to,
bytes calldata _paymentReference,
uint256 _feeAmount,
address payable _feeAddress
) external payable;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* 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 `sender` to `recipient` 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 sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (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 Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing 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
pragma solidity ^0.8.0;
import '@openzeppelin/contracts/utils/Context.sol';
import '../Roles.sol';
/**
* @title WhitelistAdminRole
* @dev WhitelistAdmins are responsible for assigning and removing Whitelisted accounts.
*/
abstract contract WhitelistAdminRole is Context {
using Roles for Roles.Role;
event WhitelistAdminAdded(address indexed account);
event WhitelistAdminRemoved(address indexed account);
Roles.Role private _whitelistAdmins;
constructor() {
_addWhitelistAdmin(_msgSender());
}
modifier onlyWhitelistAdmin() {
require(
isWhitelistAdmin(_msgSender()),
'WhitelistAdminRole: caller does not have the WhitelistAdmin role'
);
_;
}
function isWhitelistAdmin(address account) public view returns (bool) {
return _whitelistAdmins.has(account);
}
function addWhitelistAdmin(address account) public onlyWhitelistAdmin {
_addWhitelistAdmin(account);
}
function renounceWhitelistAdmin() public {
_removeWhitelistAdmin(_msgSender());
}
function _addWhitelistAdmin(address account) internal {
_whitelistAdmins.add(account);
emit WhitelistAdminAdded(account);
}
function _removeWhitelistAdmin(address account) internal {
_whitelistAdmins.remove(account);
emit WhitelistAdminRemoved(account);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title Roles
* @dev Library for managing addresses assigned to a Role.
*/
library Roles {
struct Role {
mapping(address => bool) bearer;
}
/**
* @dev Give an account access to this role.
*/
function add(Role storage role, address account) internal {
require(!has(role, account), 'Roles: account already has role');
role.bearer[account] = true;
}
/**
* @dev Remove an account's access to this role.
*/
function remove(Role storage role, address account) internal {
require(has(role, account), 'Roles: account does not have role');
role.bearer[account] = false;
}
/**
* @dev Check if an account has this role.
* @return bool
*/
function has(Role storage role, address account) internal view returns (bool) {
require(account != address(0), 'Roles: account is the zero address');
return role.bearer[account];
}
}// 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
// OpenZeppelin Contracts v4.4.1 (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][_msgSender()];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
unchecked {
_approve(sender, _msgSender(), currentAllowance - amount);
}
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
uint256 currentAllowance = _allowances[_msgSender()][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(_msgSender(), spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `sender` to `recipient`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[sender] = senderBalance - amount;
}
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
_afterTokenTransfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}{
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract ABI
API[{"inputs":[{"internalType":"address","name":"_paymentErc20Proxy","type":"address"},{"internalType":"address","name":"_paymentNativeProxy","type":"address"},{"internalType":"address","name":"_paymentErc20ConversionProxy","type":"address"},{"internalType":"address","name":"_paymentNativeConversionFeeProxy","type":"address"},{"internalType":"address","name":"_chainlinkConversionPath","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"NativeAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"USDAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"requestAmount","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bytes","name":"paymentReference","type":"bytes"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"maxToSpend","type":"uint256"},{"internalType":"uint256","name":"maxRateTimespan","type":"uint256"}],"internalType":"struct BatchNoConversionPayments.RequestDetail[]","name":"requestDetails","type":"tuple[]"},{"internalType":"address[][]","name":"pathsToUSD","type":"address[][]"},{"internalType":"address","name":"feeAddress","type":"address"}],"name":"batchERC20Payments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"batchFee","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"batchFeeAmountUSDLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"requestAmount","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bytes","name":"paymentReference","type":"bytes"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"maxToSpend","type":"uint256"},{"internalType":"uint256","name":"maxRateTimespan","type":"uint256"}],"internalType":"struct BatchNoConversionPayments.RequestDetail[]","name":"requestDetails","type":"tuple[]"},{"internalType":"address[][]","name":"pathsToUSD","type":"address[][]"},{"internalType":"address","name":"feeAddress","type":"address"}],"name":"batchMultiERC20ConversionPayments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"requestAmount","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bytes","name":"paymentReference","type":"bytes"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"maxToSpend","type":"uint256"},{"internalType":"uint256","name":"maxRateTimespan","type":"uint256"}],"internalType":"struct BatchNoConversionPayments.RequestDetail[]","name":"requestDetails","type":"tuple[]"},{"internalType":"address[][]","name":"pathsToUSD","type":"address[][]"},{"internalType":"address","name":"feeAddress","type":"address"}],"name":"batchMultiERC20Payments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"requestAmount","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bytes","name":"paymentReference","type":"bytes"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"maxToSpend","type":"uint256"},{"internalType":"uint256","name":"maxRateTimespan","type":"uint256"}],"internalType":"struct BatchNoConversionPayments.RequestDetail[]","name":"requestDetails","type":"tuple[]"},{"internalType":"bool","name":"skipFeeUSDLimit","type":"bool"},{"internalType":"address payable","name":"feeAddress","type":"address"}],"name":"batchNativeConversionPayments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"requestAmount","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bytes","name":"paymentReference","type":"bytes"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"maxToSpend","type":"uint256"},{"internalType":"uint256","name":"maxRateTimespan","type":"uint256"}],"internalType":"struct BatchNoConversionPayments.RequestDetail[]","name":"requestDetails","type":"tuple[]"},{"internalType":"bool","name":"skipFeeUSDLimit","type":"bool"},{"internalType":"address payable","name":"feeAddress","type":"address"}],"name":"batchNativePayments","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"paymentNetworkId","type":"uint256"},{"components":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"requestAmount","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"bytes","name":"paymentReference","type":"bytes"},{"internalType":"uint256","name":"feeAmount","type":"uint256"},{"internalType":"uint256","name":"maxToSpend","type":"uint256"},{"internalType":"uint256","name":"maxRateTimespan","type":"uint256"}],"internalType":"struct BatchNoConversionPayments.RequestDetail[]","name":"requestDetails","type":"tuple[]"}],"internalType":"struct BatchConversionPayments.MetaDetail[]","name":"metaDetails","type":"tuple[]"},{"internalType":"address[][]","name":"pathsToUSD","type":"address[][]"},{"internalType":"address","name":"feeAddress","type":"address"}],"name":"batchPayments","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"chainlinkConversionPath","outputs":[{"internalType":"contract ChainlinkConversionPath","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"pathsNativeToUSD","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paymentErc20ConversionProxy","outputs":[{"internalType":"contract IERC20ConversionProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paymentErc20Proxy","outputs":[{"internalType":"contract IERC20FeeProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paymentNativeConversionProxy","outputs":[{"internalType":"contract IEthConversionProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paymentNativeProxy","outputs":[{"internalType":"contract IEthereumFeeProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_batchFee","type":"uint16"}],"name":"setBatchFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"_batchFeeAmountUSDLimit","type":"uint64"}],"name":"setBatchFeeAmountUSDLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_chainlinkConversionPath","type":"address"}],"name":"setChainlinkConversionPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_NativeAddress","type":"address"},{"internalType":"address","name":"_USDAddress","type":"address"}],"name":"setNativeAndUSDAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentErc20ConversionProxy","type":"address"}],"name":"setPaymentErc20ConversionProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentErc20Proxy","type":"address"}],"name":"setPaymentErc20Proxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentNativeConversionProxy","type":"address"}],"name":"setPaymentNativeConversionProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentNativeProxy","type":"address"}],"name":"setPaymentNativeProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6080604052612710600360166101000a81548161ffff021916908361ffff1602179055506001600460006101000a81548160ff0219169083151502179055506000600860146101000a81548160ff0219169083151502179055503480156200006657600080fd5b5060405162005a2e38038062005a2e83398181016040528101906200008c9190620004a9565b85858383620000b0620000a46200023460201b60201c565b6200023c60201b60201c565b83600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555062000184816200030060201b60201c565b6000600360146101000a81548161ffff021916908361ffff1602179055505050505083600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050505050505062000660565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b620003106200023460201b60201c565b73ffffffffffffffffffffffffffffffffffffffff16620003366200041660201b60201c565b73ffffffffffffffffffffffffffffffffffffffff16146200038f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200038690620005a6565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141562000402576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620003f9906200063e565b60405180910390fd5b62000413816200023c60201b60201c565b50565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620004718262000444565b9050919050565b620004838162000464565b81146200048f57600080fd5b50565b600081519050620004a38162000478565b92915050565b60008060008060008060c08789031215620004c957620004c86200043f565b5b6000620004d989828a0162000492565b9650506020620004ec89828a0162000492565b9550506040620004ff89828a0162000492565b94505060606200051289828a0162000492565b93505060806200052589828a0162000492565b92505060a06200053889828a0162000492565b9150509295509295509295565b600082825260208201905092915050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006200058e60208362000545565b91506200059b8262000556565b602082019050919050565b60006020820190508181036000830152620005c1816200057f565b9050919050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b60006200062660268362000545565b91506200063382620005c8565b604082019050919050565b60006020820190508181036000830152620006598162000617565b9050919050565b6153be80620006706000396000f3fe6080604052600436106101a05760003560e01c80638da2f6d8116100ec578063b677bf0e1161008a578063e695f75c11610064578063e695f75c14610606578063f2fde38b1461062f578063f4d0841214610658578063f8b823e41461068157610201565b8063b677bf0e14610575578063dae3d6bb146105b2578063df6557ec146105dd57610201565b8063946647f1116100c6578063946647f1146104a557806397aa096e146104d05780639af8a581146104fb578063a4b519ff1461053857610201565b80638da2f6d8146104355780638da5cb5b1461045e57806392cddb911461048957610201565b80633085df631161015957806360be74e61161013357806360be74e6146103a1578063715018a6146103cc5780637abff543146103e357806381fe66ce1461040c57610201565b80633085df631461030b578063333ec062146103485780634465549a1461037857610201565b80630917377f146102065780630a9157c4146102315780630e48b8db1461025c57806316ac30a91461028c5780632e2f0ca0146102b55780632fae95bf146102e057610201565b3661020157600860149054906101000a900460ff16806101c05750600034145b6101ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f690613a00565b60405180910390fd5b005b600080fd5b34801561021257600080fd5b5061021b6106ac565b6040516102289190613a61565b60405180910390f35b34801561023d57600080fd5b506102466106d2565b6040516102539190613adb565b60405180910390f35b61027660048036038101906102719190613be5565b6106f8565b6040516102839190613c72565b60405180910390f35b34801561029857600080fd5b506102b360048036038101906102ae9190613ccd565b610712565b005b3480156102c157600080fd5b506102ca6107ba565b6040516102d79190613d1b565b60405180910390f35b3480156102ec57600080fd5b506102f56107e0565b6040516103029190613d45565b60405180910390f35b34801561031757600080fd5b50610332600480360381019061032d9190613d8c565b6107fa565b60405161033f9190613a61565b60405180910390f35b610362600480360381019061035d9190613be5565b610854565b60405161036f9190613c72565b60405180910390f35b34801561038457600080fd5b5061039f600480360381019061039a9190613df8565b61086e565b005b3480156103ad57600080fd5b506103b661092e565b6040516103c39190613e46565b60405180910390f35b3480156103d857600080fd5b506103e1610954565b005b3480156103ef57600080fd5b5061040a60048036038101906104059190613df8565b6109dc565b005b34801561041857600080fd5b50610433600480360381019061042e9190613df8565b610a9c565b005b34801561044157600080fd5b5061045c60048036038101906104579190613df8565b610b5c565b005b34801561046a57600080fd5b50610473610c1c565b6040516104809190613a61565b60405180910390f35b6104a3600480360381019061049e9190613f0d565b610c45565b005b3480156104b157600080fd5b506104ba610f07565b6040516104c79190613fc3565b60405180910390f35b3480156104dc57600080fd5b506104e5610f2d565b6040516104f29190613a61565b60405180910390f35b34801561050757600080fd5b50610522600480360381019061051d9190613fde565b610f53565b60405161052f9190613c72565b60405180910390f35b34801561054457600080fd5b5061055f600480360381019061055a9190613fde565b610f6f565b60405161056c9190613c72565b60405180910390f35b34801561058157600080fd5b5061059c60048036038101906105979190613fde565b610f8b565b6040516105a99190613c72565b60405180910390f35b3480156105be57600080fd5b506105c7610fa7565b6040516105d49190614094565b60405180910390f35b3480156105e957600080fd5b5061060460048036038101906105ff91906140af565b610fcd565b005b34801561061257600080fd5b5061062d60048036038101906106289190613df8565b61119f565b005b34801561063b57600080fd5b5061065660048036038101906106519190613df8565b61125f565b005b34801561066457600080fd5b5061067f600480360381019061067a9190614129565b611357565b005b34801561068d57600080fd5b5061069661143b565b6040516106a39190614165565b60405180910390f35b600460019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061070885858560008661144f565b9050949350505050565b61071a61188c565b73ffffffffffffffffffffffffffffffffffffffff16610738610c1c565b73ffffffffffffffffffffffffffffffffffffffff161461078e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610785906141cc565b60405180910390fd5b80600360186101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600360189054906101000a900467ffffffffffffffff1681565b6006828154811061080a57600080fd5b90600052602060002001818154811061082257600080fd5b906000526020600020016000915091509054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000610864858585600086611894565b9050949350505050565b61087661188c565b73ffffffffffffffffffffffffffffffffffffffff16610894610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146108ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141cc565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61095c61188c565b73ffffffffffffffffffffffffffffffffffffffff1661097a610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146109d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c7906141cc565b60405180910390fd5b6109da6000611d0d565b565b6109e461188c565b73ffffffffffffffffffffffffffffffffffffffff16610a02610c1c565b73ffffffffffffffffffffffffffffffffffffffff1614610a58576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4f906141cc565b60405180910390fd5b80600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610aa461188c565b73ffffffffffffffffffffffffffffffffffffffff16610ac2610c1c565b73ffffffffffffffffffffffffffffffffffffffff1614610b18576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0f906141cc565b60405180910390fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610b6461188c565b73ffffffffffffffffffffffffffffffffffffffff16610b82610c1c565b73ffffffffffffffffffffffffffffffffffffffff1614610bd8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bcf906141cc565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60068585905010610c8b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c8290614238565b60405180910390fd5b6000805b86869050811015610efe5736878783818110610cae57610cad614258565b5b9050602002810190610cc09190614296565b9050600081600001351415610cfd57610ceb818060200190610ce291906142be565b85898989611dd1565b83610cf69190614350565b9250610eea565b600181600001351415610d3857610d26818060200190610d1d91906142be565b888887896122b3565b83610d319190614350565b9250610ee9565b600281600001351415610d7357610d61818060200190610d5891906142be565b888887896126bd565b83610d6c9190614350565b9250610ee8565b600381600001351415610e6b576004888860018b8b9050610d9491906143a6565b818110610da457610da3614258565b5b9050602002810190610db69190614296565b600001351415610ddc576000600460006101000a81548160ff0219169083151502179055505b610dfd818060200190610def91906142be565b600089899050148688611894565b83610e089190614350565b92506004888860018b8b9050610e1e91906143a6565b818110610e2e57610e2d614258565b5b9050602002810190610e409190614296565b600001351415610e66576001600460006101000a81548160ff0219169083151502179055505b610ee7565b600481600001351415610eab57610e99818060200190610e8b91906142be565b60008989905014868861144f565b83610ea49190614350565b9250610ee6565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610edd90614426565b60405180910390fd5b5b5b5b5b508080610ef690614446565b915050610c8f565b50505050505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000610f64868686866000876122b3565b905095945050505050565b6000610f80868686866000876126bd565b905095945050505050565b6000610f9c86866000878787611dd1565b905095945050505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610fd561188c565b73ffffffffffffffffffffffffffffffffffffffff16610ff3610c1c565b73ffffffffffffffffffffffffffffffffffffffff1614611049576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611040906141cc565b60405180910390fd5b81600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060405180602001604052806040518060400160405280600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600460019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250815250600690600161119a929190613825565b505050565b6111a761188c565b73ffffffffffffffffffffffffffffffffffffffff166111c5610c1c565b73ffffffffffffffffffffffffffffffffffffffff161461121b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611212906141cc565b60405180910390fd5b80600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61126761188c565b73ffffffffffffffffffffffffffffffffffffffff16611285610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146112db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d2906141cc565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561134b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161134290614501565b60405180910390fd5b61135481611d0d565b50565b61135f61188c565b73ffffffffffffffffffffffffffffffffffffffff1661137d610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146113d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113ca906141cc565b60405180910390fd5b60c88161ffff16111561141b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141290614593565b60405180910390fd5b80600360146101000a81548161ffff021916908361ffff16021790555050565b600360149054906101000a900461ffff1681565b6000804790506001600860146101000a81548160ff02191690831515021790555060005b87879050811015611592573688888381811061149257611491614258565b5b90506020028101906114a491906145b3565b9050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ac473c8a478360000160208101906114f89190613df8565b846020013585806040019061150d91906145db565b87806060019061151d919061463e565b89608001358e8b60c001356040518b63ffffffff1660e01b815260040161154c999897969594939291906147e3565b6000604051808303818588803b15801561156557600080fd5b505af1158015611579573d6000803e3d6000fd5b505050505050808061158a90614446565b915050611473565b506000600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff1647846115cb91906143a6565b6115d59190614864565b6115df91906148ed565b905060001515861515141561172c5761172381600660008154811061160757611606614258565b5b9060005260206000200160008154811061162457611623614258565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16876006805480602002602001604051908101604052809291908181526020016000905b8282101561171a5783829060005260206000200180548060200260200160405190810160405280929190818152602001828054801561170657602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116116bc575b505050505081526020019060010190611672565b50505050612a3e565b80965081925050505b8047101561176f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161176690614990565b60405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156117b5573d6000803e3d6000fd5b5060003373ffffffffffffffffffffffffffffffffffffffff16476040516117dc906149e1565b60006040518083038185875af1925050503d8060008114611819576040519150601f19603f3d011682016040523d82523d6000602084013e61181e565b606091505b5050905080611862576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161185990614a68565b60405180910390fd5b6000600860146101000a81548160ff02191690831515021790555085935050505095945050505050565b600033905090565b6000806000905060005b87879050811015611a1a57368888838181106118bd576118bc614258565b5b90506020028101906118cf91906145b3565b9050806080013581602001356118e59190614350565b471015611927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161191e90614ad4565b60405180910390fd5b8060200135836119379190614350565b9250600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b868980b8260800135836020013561198b9190614350565b83600001602081019061199e9190613df8565b8480606001906119ae919061463e565b86608001358b6040518763ffffffff1660e01b81526004016119d4959493929190614b03565b6000604051808303818588803b1580156119ed57600080fd5b505af1158015611a01573d6000803e3d6000fd5b5050505050508080611a1290614446565b91505061189e565b50600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff1682611a509190614864565b611a5a91906148ed565b9050600015158515151415611ba757611b9e816006600081548110611a8257611a81614258565b5b90600052602060002001600081548110611a9f57611a9e614258565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16866006805480602002602001604051908101604052809291908181526020016000905b82821015611b9557838290600052602060002001805480602002602001604051908101604052809291908181526020018280548015611b8157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611b37575b505050505081526020019060010190611aed565b50505050612a3e565b80955081925050505b80471015611bea576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611be190614b9d565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611c30573d6000803e3d6000fd5b50600460009054906101000a900460ff168015611c4d5750600047115b15611d005760003373ffffffffffffffffffffffffffffffffffffffff1647604051611c78906149e1565b60006040518083038185875af1925050503d8060008114611cb5576040519150601f19603f3d011682016040523d82523d6000602084013e611cba565b606091505b5050905080611cfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cf590614a68565b60405180910390fd5b505b8391505095945050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080611dde8888612d60565b9050600080600090505b825181108015611e1657506000838281518110611e0857611e07614258565b5b602002602001015160200151115b15611f3957600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff16848381518110611e5857611e57614258565b5b602002602001015160200151611e6e9190614864565b611e7891906148ed565b838281518110611e8b57611e8a614258565b5b60200260200101516040018181525050828181518110611eae57611ead614258565b5b6020026020010151600001519150611f2682848381518110611ed357611ed2614258565b5b602002602001015160200151858481518110611ef257611ef1614258565b5b602002602001015160400151600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16613152565b8080611f3190614446565b915050611de8565b5060005b8989905081101561206157368a8a83818110611f5c57611f5b614258565b5b9050602002810190611f6e91906145b3565b9050600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633af2c012826000016020810190611fc19190613df8565b8360200135848060400190611fd691906145db565b868060600190611fe6919061463e565b88608001358e8a60a001358b60c001356040518b63ffffffff1660e01b815260040161201b9a99989796959493929190614bbd565b600060405180830381600087803b15801561203557600080fd5b505af1158015612049573d6000803e3d6000fd5b5050505050808061205990614446565b915050611f3d565b5060005b8251811080156120935750600083828151811061208557612084614258565b5b602002602001015160200151115b156122a3578281815181106120ab576120aa614258565b5b602002602001015160000151915060008273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016120f49190613a61565b60206040518083038186803b15801561210c57600080fd5b505afa158015612120573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121449190614c62565b9050600081111561217c5761217a33828573ffffffffffffffffffffffffffffffffffffffff166133e29092919063ffffffff16565b505b6000600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff16838786815181106121bc576121bb614258565b5b6020026020010151602001516121d291906143a6565b6121dc9190614864565b6121e691906148ed565b905061221e818685815181106121ff576121fe614258565b5b6020026020010151600001518c8c8c906122199190614e80565b612a3e565b809b50819250505061224f85848151811061223c5761223b614258565b5b6020026020010151600001518883613516565b61228e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161228590614ee1565b60405180910390fd5b5050808061229b90614446565b915050612065565b5086925050509695505050505050565b600080600090506000805b8989905081101561237b578989828181106122dc576122db614258565b5b90506020028101906122ee91906145b3565b608001358a8a8381811061230557612304614258565b5b905060200281019061231791906145b3565b602001356123259190614350565b836123309190614350565b925089898281811061234557612344614258565b5b905060200281019061235791906145b3565b60200135826123669190614350565b9150808061237390614446565b9150506122be565b50600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff16826123b19190614864565b6123bb91906148ed565b9050612430818a8a60008181106123d5576123d4614258565b5b90506020028101906123e791906145b3565b80604001906123f691906145db565b600081811061240857612407614258565b5b905060200201602081019061241d9190613df8565b878a8a9061242b9190614e80565b612a3e565b809650819250505060008989600081811061244e5761244d614258565b5b905060200281019061246091906145b3565b806040019061246f91906145db565b600081811061248157612480614258565b5b90506020020160208101906124969190613df8565b90506124c6818484600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16613152565b61252c8a8a60008181106124dd576124dc614258565b5b90506020028101906124ef91906145b3565b80604001906124fe91906145db565b60008181106125105761250f614258565b5b90506020020160208101906125259190613df8565b8684613516565b61256b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161256290614ee1565b60405180910390fd5b60005b8a8a90508110156126ac57368b8b8381811061258d5761258c614258565b5b905060200281019061259f91906145b3565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c219a14d8280604001906125ef91906145db565b600081811061260157612600614258565b5b90506020020160208101906126169190613df8565b8360000160208101906126299190613df8565b846020013585806060019061263e919061463e565b87608001358e6040518863ffffffff1660e01b81526004016126669796959493929190614f01565b600060405180830381600087803b15801561268057600080fd5b505af1158015612694573d6000803e3d6000fd5b505050505080806126a490614446565b91505061256e565b508593505050509695505050505050565b6000806126ca8888612d60565b905060005b8151811080156126fd575060008282815181106126ef576126ee614258565b5b602002602001015160200151115b156128ed57600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff1683838151811061273f5761273e614258565b5b6020026020010151604001516127559190614864565b61275f91906148ed565b82828151811061277257612771614258565b5b60200260200101516040018181525050600082828151811061279757612796614258565b5b602002602001015160000151905061280f818484815181106127bc576127bb614258565b5b6020026020010151602001518585815181106127db576127da614258565b5b602002602001015160400151600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16613152565b600083838151811061282457612823614258565b5b60200260200101516040015190506128688185858151811061284957612848614258565b5b602002602001015160000151898c8c906128639190614e80565b612a3e565b809850819250505061289984848151811061288657612885614258565b5b6020026020010151600001518783613516565b6128d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128cf90614ee1565b60405180910390fd5b505080806128e590614446565b9150506126cf565b5060005b88889050811015612a2f57368989838181106129105761290f614258565b5b905060200281019061292291906145b3565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c219a14d82806040019061297291906145db565b600081811061298457612983614258565b5b90506020020160208101906129999190613df8565b8360000160208101906129ac9190613df8565b84602001358580606001906129c1919061463e565b87608001358c6040518863ffffffff1660e01b81526004016129e99796959493929190614f01565b600060405180830381600087803b158015612a0357600080fd5b505af1158015612a17573d6000803e3d6000fd5b50505050508080612a2790614446565b9150506128f1565b50839150509695505050505050565b60008060008351148015612a715750600360189054906101000a900467ffffffffffffffff1667ffffffffffffffff1684105b15612a8157858491509150612d57565b600360189054906101000a900467ffffffffffffffff1667ffffffffffffffff16841015612d4b5760005b8351811015612d45578573ffffffffffffffffffffffffffffffffffffffff16848281518110612adf57612ade614258565b5b6020026020010151600081518110612afa57612af9614258565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16148015612bcd5750600460019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16848281518110612b6c57612b6b614258565b5b60200260200101516001868481518110612b8957612b88614258565b5b602002602001015151612b9c91906143a6565b81518110612bad57612bac614258565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16145b15612d32576000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fbd4122a89878581518110612c2657612c25614258565b5b60200260200101516040518363ffffffff1660e01b8152600401612c4b929190614ff1565b604080518083038186803b158015612c6257600080fd5b505afa158015612c76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9a9190615021565b5090506000819050600360189054906101000a900467ffffffffffffffff1667ffffffffffffffff168188612ccf9190614350565b1115612d1d5786600360189054906101000a900467ffffffffffffffff1667ffffffffffffffff16612d0191906143a6565b905081818a612d109190614864565b612d1a91906148ed565b98505b8087612d299190614350565b96505050612d45565b8080612d3d90614446565b915050612aac565b50612d50565b600095505b8584915091505b94509492505050565b60608282905067ffffffffffffffff811115612d7f57612d7e614c8f565b5b604051908082528060200260200182016040528015612db857816020015b612da5613880565b815260200190600190039081612d9d5790505b50905060005b8383905081101561314b5760005b848490508110156131375736858584818110612deb57612dea614258565b5b9050602002810190612dfd91906145b3565b9050808060400190612e0f91906145db565b6001838060400190612e2191906145db565b9050612e2d91906143a6565b818110612e3d57612e3c614258565b5b9050602002016020810190612e529190613df8565b73ffffffffffffffffffffffffffffffffffffffff16848381518110612e7b57612e7a614258565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff161415612f7d576001818060400190612eb591906145db565b90501115612ef9578060a00135848381518110612ed557612ed4614258565b5b6020026020010151602001818151612eed9190614350565b91508181525050612f77565b80608001358160200135612f0d9190614350565b848381518110612f2057612f1f614258565b5b6020026020010151602001818151612f389190614350565b915081815250508060200135848381518110612f5757612f56614258565b5b6020026020010151604001818151612f6f9190614350565b915081815250505b50613137565b6000848381518110612f9257612f91614258565b5b602002602001015160200151148015612fcd575060008160a001351180612fcc5750600081608001358260200135612fca9190614350565b115b5b1561312357808060400190612fe291906145db565b6001838060400190612ff491906145db565b905061300091906143a6565b8181106130105761300f614258565b5b90506020020160208101906130259190613df8565b84838151811061303857613037614258565b5b60200260200101516000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600181806040019061308891906145db565b905011156130bd578060a001358483815181106130a8576130a7614258565b5b6020026020010151602001818152505061311d565b806080013581602001356130d19190614350565b8483815181106130e4576130e3614258565b5b60200260200101516020018181525050806020013584838151811061310c5761310b614258565b5b602002602001015160400181815250505b50613137565b50808061312f90614446565b915050612dcc565b50808061314390614446565b915050612dbe565b5092915050565b828473ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b815260040161318e929190615061565b60206040518083038186803b1580156131a657600080fd5b505afa1580156131ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131de9190614c62565b101561321f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613216906150fc565b60405180910390fd5b818361322b9190614350565b8473ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016132649190613a61565b60206040518083038186803b15801561327c57600080fd5b505afa158015613290573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b49190614c62565b10156132f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016132ec90615168565b60405180910390fd5b613300843085613516565b61333f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613336906151d4565b60405180910390fd5b828473ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30846040518363ffffffff1660e01b815260040161337b929190615061565b60206040518083038186803b15801561339357600080fd5b505afa1580156133a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133cb9190614c62565b10156133dc576133db8482613695565b5b50505050565b60008060008573ffffffffffffffffffffffffffffffffffffffff1685856040516024016134119291906151f4565b6040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161349b919061528c565b6000604051808303816000865af19150503d80600081146134d8576040519150601f19603f3d011682016040523d82523d6000602084013e6134dd565b606091505b509150915081801561350b575060008151148061350a57508080602001905181019061350991906152b8565b5b5b925050509392505050565b6000833b61352357600080fd5b60008473ffffffffffffffffffffffffffffffffffffffff16338585604051602401613551939291906152e5565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516135db919061528c565b6000604051808303816000865af19150503d8060008114613618576040519150601f19603f3d011682016040523d82523d6000602084013e61361d565b606091505b505090503d60008114613637576020811461364057600080fd5b6001925061364c565b60206000803e60005192505b508061368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161368490615368565b60405180910390fd5b509392505050565b600082905060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90506136ea83828473ffffffffffffffffffffffffffffffffffffffff166136f19092919063ffffffff16565b5050505050565b60008060008573ffffffffffffffffffffffffffffffffffffffff1685856040516024016137209291906151f4565b6040516020818303038152906040527f095ea7b3000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516137aa919061528c565b6000604051808303816000865af19150503d80600081146137e7576040519150601f19603f3d011682016040523d82523d6000602084013e6137ec565b606091505b509150915081801561381a575060008151148061381957508080602001905181019061381891906152b8565b5b5b925050509392505050565b82805482825590600052602060002090810192821561386f579160200282015b8281111561386e5782518290600261385e9291906138b7565b5091602001919060010190613845565b5b50905061387c9190613941565b5090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b828054828255906000526020600020908101928215613930579160200282015b8281111561392f5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906138d7565b5b50905061393d9190613965565b5090565b5b8082111561396157600081816139589190613982565b50600101613942565b5090565b5b8082111561397e576000816000905550600101613966565b5090565b50805460008255906000526020600020908101906139a09190613965565b50565b600082825260208201905092915050565b7f4e6f6e2d70617961626c65000000000000000000000000000000000000000000600082015250565b60006139ea600b836139a3565b91506139f5826139b4565b602082019050919050565b60006020820190508181036000830152613a19816139dd565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613a4b82613a20565b9050919050565b613a5b81613a40565b82525050565b6000602082019050613a766000830184613a52565b92915050565b6000819050919050565b6000613aa1613a9c613a9784613a20565b613a7c565b613a20565b9050919050565b6000613ab382613a86565b9050919050565b6000613ac582613aa8565b9050919050565b613ad581613aba565b82525050565b6000602082019050613af06000830184613acc565b92915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112613b2f57613b2e613b0a565b5b8235905067ffffffffffffffff811115613b4c57613b4b613b0f565b5b602083019150836020820283011115613b6857613b67613b14565b5b9250929050565b60008115159050919050565b613b8481613b6f565b8114613b8f57600080fd5b50565b600081359050613ba181613b7b565b92915050565b6000613bb282613a20565b9050919050565b613bc281613ba7565b8114613bcd57600080fd5b50565b600081359050613bdf81613bb9565b92915050565b60008060008060608587031215613bff57613bfe613b00565b5b600085013567ffffffffffffffff811115613c1d57613c1c613b05565b5b613c2987828801613b19565b94509450506020613c3c87828801613b92565b9250506040613c4d87828801613bd0565b91505092959194509250565b6000819050919050565b613c6c81613c59565b82525050565b6000602082019050613c876000830184613c63565b92915050565b600067ffffffffffffffff82169050919050565b613caa81613c8d565b8114613cb557600080fd5b50565b600081359050613cc781613ca1565b92915050565b600060208284031215613ce357613ce2613b00565b5b6000613cf184828501613cb8565b91505092915050565b6000613d0582613aa8565b9050919050565b613d1581613cfa565b82525050565b6000602082019050613d306000830184613d0c565b92915050565b613d3f81613c8d565b82525050565b6000602082019050613d5a6000830184613d36565b92915050565b613d6981613c59565b8114613d7457600080fd5b50565b600081359050613d8681613d60565b92915050565b60008060408385031215613da357613da2613b00565b5b6000613db185828601613d77565b9250506020613dc285828601613d77565b9150509250929050565b613dd581613a40565b8114613de057600080fd5b50565b600081359050613df281613dcc565b92915050565b600060208284031215613e0e57613e0d613b00565b5b6000613e1c84828501613de3565b91505092915050565b6000613e3082613aa8565b9050919050565b613e4081613e25565b82525050565b6000602082019050613e5b6000830184613e37565b92915050565b60008083601f840112613e7757613e76613b0a565b5b8235905067ffffffffffffffff811115613e9457613e93613b0f565b5b602083019150836020820283011115613eb057613eaf613b14565b5b9250929050565b60008083601f840112613ecd57613ecc613b0a565b5b8235905067ffffffffffffffff811115613eea57613ee9613b0f565b5b602083019150836020820283011115613f0657613f05613b14565b5b9250929050565b600080600080600060608688031215613f2957613f28613b00565b5b600086013567ffffffffffffffff811115613f4757613f46613b05565b5b613f5388828901613e61565b9550955050602086013567ffffffffffffffff811115613f7657613f75613b05565b5b613f8288828901613eb7565b93509350506040613f9588828901613de3565b9150509295509295909350565b6000613fad82613aa8565b9050919050565b613fbd81613fa2565b82525050565b6000602082019050613fd86000830184613fb4565b92915050565b600080600080600060608688031215613ffa57613ff9613b00565b5b600086013567ffffffffffffffff81111561401857614017613b05565b5b61402488828901613b19565b9550955050602086013567ffffffffffffffff81111561404757614046613b05565b5b61405388828901613eb7565b9350935050604061406688828901613de3565b9150509295509295909350565b600061407e82613aa8565b9050919050565b61408e81614073565b82525050565b60006020820190506140a96000830184614085565b92915050565b600080604083850312156140c6576140c5613b00565b5b60006140d485828601613de3565b92505060206140e585828601613de3565b9150509250929050565b600061ffff82169050919050565b614106816140ef565b811461411157600080fd5b50565b600081359050614123816140fd565b92915050565b60006020828403121561413f5761413e613b00565b5b600061414d84828501614114565b91505092915050565b61415f816140ef565b82525050565b600060208201905061417a6000830184614156565b92915050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006141b66020836139a3565b91506141c182614180565b602082019050919050565b600060208201905081810360008301526141e5816141a9565b9050919050565b7f6d6f7265207468616e2035206d65746144657461696c73000000000000000000600082015250565b60006142226017836139a3565b915061422d826141ec565b602082019050919050565b6000602082019050818103600083015261425181614215565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b6000823560016040038336030381126142b2576142b1614287565b5b80830191505092915050565b600080833560016020038436030381126142db576142da614287565b5b80840192508235915067ffffffffffffffff8211156142fd576142fc61428c565b5b60208301925060208202360383131561431957614318614291565b5b509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061435b82613c59565b915061436683613c59565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561439b5761439a614321565b5b828201905092915050565b60006143b182613c59565b91506143bc83613c59565b9250828210156143cf576143ce614321565b5b828203905092915050565b7f57726f6e67207061796d656e744e6574776f726b496400000000000000000000600082015250565b60006144106016836139a3565b915061441b826143da565b602082019050919050565b6000602082019050818103600083015261443f81614403565b9050919050565b600061445182613c59565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561448457614483614321565b5b600182019050919050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b60006144eb6026836139a3565b91506144f68261448f565b604082019050919050565b6000602082019050818103600083015261451a816144de565b9050919050565b7f546865206261746368206665652076616c756520697320746f6f20686967683a60008201527f203e203225000000000000000000000000000000000000000000000000000000602082015250565b600061457d6025836139a3565b915061458882614521565b604082019050919050565b600060208201905081810360008301526145ac81614570565b9050919050565b60008235600160e0038336030381126145cf576145ce614287565b5b80830191505092915050565b600080833560016020038436030381126145f8576145f7614287565b5b80840192508235915067ffffffffffffffff82111561461a5761461961428c565b5b60208301925060208202360383131561463657614635614291565b5b509250929050565b6000808335600160200384360303811261465b5761465a614287565b5b80840192508235915067ffffffffffffffff82111561467d5761467c61428c565b5b60208301925060018202360383131561469957614698614291565b5b509250929050565b60006146ac82613aa8565b9050919050565b6146bc816146a1565b82525050565b600082825260208201905092915050565b6000819050919050565b6146e681613a40565b82525050565b60006146f883836146dd565b60208301905092915050565b60006147136020840184613de3565b905092915050565b6000602082019050919050565b600061473483856146c2565b935061473f826146d3565b8060005b85811015614778576147558284614704565b61475f88826146ec565b975061476a8361471b565b925050600181019050614743565b5085925050509392505050565b600082825260208201905092915050565b82818337600083830152505050565b6000601f19601f8301169050919050565b60006147c28385614785565b93506147cf838584614796565b6147d8836147a5565b840190509392505050565b600060e0820190506147f8600083018c6146b3565b614805602083018b613c63565b818103604083015261481881898b614728565b9050818103606083015261482d8187896147b6565b905061483c6080830186613c63565b61484960a08301856146b3565b61485660c0830184613c63565b9a9950505050505050505050565b600061486f82613c59565b915061487a83613c59565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148b3576148b2614321565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006148f882613c59565b915061490383613c59565b925082614913576149126148be565b5b828204905092915050565b7f4e6f7420656e6f7567682066756e647320666f7220626174636820636f6e766560008201527f7273696f6e206665657300000000000000000000000000000000000000000000602082015250565b600061497a602a836139a3565b91506149858261491e565b604082019050919050565b600060208201905081810360008301526149a98161496d565b9050919050565b600081905092915050565b50565b60006149cb6000836149b0565b91506149d6826149bb565b600082019050919050565b60006149ec826149be565b9150819050919050565b7f436f756c64206e6f742073656e642072656d61696e696e672066756e6473207460008201527f6f20746865207061796572000000000000000000000000000000000000000000602082015250565b6000614a52602b836139a3565b9150614a5d826149f6565b604082019050919050565b60006020820190508181036000830152614a8181614a45565b9050919050565b7f4e6f7420656e6f7567682066756e647300000000000000000000000000000000600082015250565b6000614abe6010836139a3565b9150614ac982614a88565b602082019050919050565b60006020820190508181036000830152614aed81614ab1565b9050919050565b614afd81613ba7565b82525050565b6000608082019050614b186000830188614af4565b8181036020830152614b2b8186886147b6565b9050614b3a6040830185613c63565b614b476060830184614af4565b9695505050505050565b7f4e6f7420656e6f7567682066756e647320666f72206261746368206665650000600082015250565b6000614b87601e836139a3565b9150614b9282614b51565b602082019050919050565b60006020820190508181036000830152614bb681614b7a565b9050919050565b600061010082019050614bd3600083018d613a52565b614be0602083018c613c63565b8181036040830152614bf3818a8c614728565b90508181036060830152614c0881888a6147b6565b9050614c176080830187613c63565b614c2460a0830186613a52565b614c3160c0830185613c63565b614c3e60e0830184613c63565b9b9a5050505050505050505050565b600081519050614c5c81613d60565b92915050565b600060208284031215614c7857614c77613b00565b5b6000614c8684828501614c4d565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b614cc7826147a5565b810181811067ffffffffffffffff82111715614ce657614ce5614c8f565b5b80604052505050565b6000614cf9613af6565b9050614d058282614cbe565b919050565b600067ffffffffffffffff821115614d2557614d24614c8f565b5b602082029050602081019050919050565b600067ffffffffffffffff821115614d5157614d50614c8f565b5b602082029050602081019050919050565b6000614d75614d7084614d36565b614cef565b90508083825260208201905060208402830185811115614d9857614d97613b14565b5b835b81811015614dc15780614dad8882613de3565b845260208401935050602081019050614d9a565b5050509392505050565b600082601f830112614de057614ddf613b0a565b5b8135614df0848260208601614d62565b91505092915050565b6000614e0c614e0784614d0a565b614cef565b90508083825260208201905060208402830185811115614e2f57614e2e613b14565b5b835b81811015614e7657803567ffffffffffffffff811115614e5457614e53613b0a565b5b808601614e618982614dcb565b85526020850194505050602081019050614e31565b5050509392505050565b6000614e8d368484614df9565b905092915050565b7f426174636820666565207472616e7366657246726f6d2829206661696c656400600082015250565b6000614ecb601f836139a3565b9150614ed682614e95565b602082019050919050565b60006020820190508181036000830152614efa81614ebe565b9050919050565b600060c082019050614f16600083018a613a52565b614f236020830189613a52565b614f306040830188613c63565b8181036060830152614f438186886147b6565b9050614f526080830185613c63565b614f5f60a0830184613a52565b98975050505050505050565b600081519050919050565b6000819050602082019050919050565b6000602082019050919050565b6000614f9e82614f6b565b614fa881856146c2565b9350614fb383614f76565b8060005b83811015614fe4578151614fcb88826146ec565b9750614fd683614f86565b925050600181019050614fb7565b5085935050505092915050565b60006040820190506150066000830185613c63565b81810360208301526150188184614f93565b90509392505050565b6000806040838503121561503857615037613b00565b5b600061504685828601614c4d565b925050602061505785828601614c4d565b9150509250929050565b60006040820190506150766000830185613a52565b6150836020830184613a52565b9392505050565b7f496e73756666696369656e7420616c6c6f77616e636520666f7220626174636860008201527f20746f2070617900000000000000000000000000000000000000000000000000602082015250565b60006150e66027836139a3565b91506150f18261508a565b604082019050919050565b60006020820190508181036000830152615115816150d9565b9050919050565b7f4e6f7420656e6f7567682066756e64732c20696e636c7564696e672066656573600082015250565b60006151526020836139a3565b915061515d8261511c565b602082019050919050565b6000602082019050818103600083015261518181615145565b9050919050565b7f7061796d656e74207472616e7366657246726f6d2829206661696c6564000000600082015250565b60006151be601d836139a3565b91506151c982615188565b602082019050919050565b600060208201905081810360008301526151ed816151b1565b9050919050565b60006040820190506152096000830185613a52565b6152166020830184613c63565b9392505050565b600081519050919050565b60005b8381101561524657808201518184015260208101905061522b565b83811115615255576000848401525b50505050565b60006152668261521d565b61527081856149b0565b9350615280818560208601615228565b80840191505092915050565b6000615298828461525b565b915081905092915050565b6000815190506152b281613b7b565b92915050565b6000602082840312156152ce576152cd613b00565b5b60006152dc848285016152a3565b91505092915050565b60006060820190506152fa6000830186613a52565b6153076020830185613a52565b6153146040830184613c63565b949350505050565b7f7472616e7366657246726f6d282920686173206265656e207265766572746564600082015250565b60006153526020836139a3565b915061535d8261531c565b602082019050919050565b6000602082019050818103600083015261538181615345565b905091905056fea2646970667358221220c2ad28c14e7169d3be5c99424f831837ebb48de4f2e9479c34b1b23d6777f71f64736f6c63430008090033000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e64c2d06d19d13061e62e291b2c4e9fe5679b93
Deployed Bytecode
0x6080604052600436106101a05760003560e01c80638da2f6d8116100ec578063b677bf0e1161008a578063e695f75c11610064578063e695f75c14610606578063f2fde38b1461062f578063f4d0841214610658578063f8b823e41461068157610201565b8063b677bf0e14610575578063dae3d6bb146105b2578063df6557ec146105dd57610201565b8063946647f1116100c6578063946647f1146104a557806397aa096e146104d05780639af8a581146104fb578063a4b519ff1461053857610201565b80638da2f6d8146104355780638da5cb5b1461045e57806392cddb911461048957610201565b80633085df631161015957806360be74e61161013357806360be74e6146103a1578063715018a6146103cc5780637abff543146103e357806381fe66ce1461040c57610201565b80633085df631461030b578063333ec062146103485780634465549a1461037857610201565b80630917377f146102065780630a9157c4146102315780630e48b8db1461025c57806316ac30a91461028c5780632e2f0ca0146102b55780632fae95bf146102e057610201565b3661020157600860149054906101000a900460ff16806101c05750600034145b6101ff576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101f690613a00565b60405180910390fd5b005b600080fd5b34801561021257600080fd5b5061021b6106ac565b6040516102289190613a61565b60405180910390f35b34801561023d57600080fd5b506102466106d2565b6040516102539190613adb565b60405180910390f35b61027660048036038101906102719190613be5565b6106f8565b6040516102839190613c72565b60405180910390f35b34801561029857600080fd5b506102b360048036038101906102ae9190613ccd565b610712565b005b3480156102c157600080fd5b506102ca6107ba565b6040516102d79190613d1b565b60405180910390f35b3480156102ec57600080fd5b506102f56107e0565b6040516103029190613d45565b60405180910390f35b34801561031757600080fd5b50610332600480360381019061032d9190613d8c565b6107fa565b60405161033f9190613a61565b60405180910390f35b610362600480360381019061035d9190613be5565b610854565b60405161036f9190613c72565b60405180910390f35b34801561038457600080fd5b5061039f600480360381019061039a9190613df8565b61086e565b005b3480156103ad57600080fd5b506103b661092e565b6040516103c39190613e46565b60405180910390f35b3480156103d857600080fd5b506103e1610954565b005b3480156103ef57600080fd5b5061040a60048036038101906104059190613df8565b6109dc565b005b34801561041857600080fd5b50610433600480360381019061042e9190613df8565b610a9c565b005b34801561044157600080fd5b5061045c60048036038101906104579190613df8565b610b5c565b005b34801561046a57600080fd5b50610473610c1c565b6040516104809190613a61565b60405180910390f35b6104a3600480360381019061049e9190613f0d565b610c45565b005b3480156104b157600080fd5b506104ba610f07565b6040516104c79190613fc3565b60405180910390f35b3480156104dc57600080fd5b506104e5610f2d565b6040516104f29190613a61565b60405180910390f35b34801561050757600080fd5b50610522600480360381019061051d9190613fde565b610f53565b60405161052f9190613c72565b60405180910390f35b34801561054457600080fd5b5061055f600480360381019061055a9190613fde565b610f6f565b60405161056c9190613c72565b60405180910390f35b34801561058157600080fd5b5061059c60048036038101906105979190613fde565b610f8b565b6040516105a99190613c72565b60405180910390f35b3480156105be57600080fd5b506105c7610fa7565b6040516105d49190614094565b60405180910390f35b3480156105e957600080fd5b5061060460048036038101906105ff91906140af565b610fcd565b005b34801561061257600080fd5b5061062d60048036038101906106289190613df8565b61119f565b005b34801561063b57600080fd5b5061065660048036038101906106519190613df8565b61125f565b005b34801561066457600080fd5b5061067f600480360381019061067a9190614129565b611357565b005b34801561068d57600080fd5b5061069661143b565b6040516106a39190614165565b60405180910390f35b600460019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600061070885858560008661144f565b9050949350505050565b61071a61188c565b73ffffffffffffffffffffffffffffffffffffffff16610738610c1c565b73ffffffffffffffffffffffffffffffffffffffff161461078e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610785906141cc565b60405180910390fd5b80600360186101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555050565b600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600360189054906101000a900467ffffffffffffffff1681565b6006828154811061080a57600080fd5b90600052602060002001818154811061082257600080fd5b906000526020600020016000915091509054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000610864858585600086611894565b9050949350505050565b61087661188c565b73ffffffffffffffffffffffffffffffffffffffff16610894610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146108ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141cc565b60405180910390fd5b80600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61095c61188c565b73ffffffffffffffffffffffffffffffffffffffff1661097a610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146109d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109c7906141cc565b60405180910390fd5b6109da6000611d0d565b565b6109e461188c565b73ffffffffffffffffffffffffffffffffffffffff16610a02610c1c565b73ffffffffffffffffffffffffffffffffffffffff1614610a58576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4f906141cc565b60405180910390fd5b80600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610aa461188c565b73ffffffffffffffffffffffffffffffffffffffff16610ac2610c1c565b73ffffffffffffffffffffffffffffffffffffffff1614610b18576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b0f906141cc565b60405180910390fd5b80600760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b610b6461188c565b73ffffffffffffffffffffffffffffffffffffffff16610b82610c1c565b73ffffffffffffffffffffffffffffffffffffffff1614610bd8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bcf906141cc565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60068585905010610c8b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c8290614238565b60405180910390fd5b6000805b86869050811015610efe5736878783818110610cae57610cad614258565b5b9050602002810190610cc09190614296565b9050600081600001351415610cfd57610ceb818060200190610ce291906142be565b85898989611dd1565b83610cf69190614350565b9250610eea565b600181600001351415610d3857610d26818060200190610d1d91906142be565b888887896122b3565b83610d319190614350565b9250610ee9565b600281600001351415610d7357610d61818060200190610d5891906142be565b888887896126bd565b83610d6c9190614350565b9250610ee8565b600381600001351415610e6b576004888860018b8b9050610d9491906143a6565b818110610da457610da3614258565b5b9050602002810190610db69190614296565b600001351415610ddc576000600460006101000a81548160ff0219169083151502179055505b610dfd818060200190610def91906142be565b600089899050148688611894565b83610e089190614350565b92506004888860018b8b9050610e1e91906143a6565b818110610e2e57610e2d614258565b5b9050602002810190610e409190614296565b600001351415610e66576001600460006101000a81548160ff0219169083151502179055505b610ee7565b600481600001351415610eab57610e99818060200190610e8b91906142be565b60008989905014868861144f565b83610ea49190614350565b9250610ee6565b6040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610edd90614426565b60405180910390fd5b5b5b5b5b508080610ef690614446565b915050610c8f565b50505050505050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000610f64868686866000876122b3565b905095945050505050565b6000610f80868686866000876126bd565b905095945050505050565b6000610f9c86866000878787611dd1565b905095945050505050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610fd561188c565b73ffffffffffffffffffffffffffffffffffffffff16610ff3610c1c565b73ffffffffffffffffffffffffffffffffffffffff1614611049576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611040906141cc565b60405180910390fd5b81600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460016101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060405180602001604052806040518060400160405280600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001600460019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815250815250600690600161119a929190613825565b505050565b6111a761188c565b73ffffffffffffffffffffffffffffffffffffffff166111c5610c1c565b73ffffffffffffffffffffffffffffffffffffffff161461121b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611212906141cc565b60405180910390fd5b80600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b61126761188c565b73ffffffffffffffffffffffffffffffffffffffff16611285610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146112db576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016112d2906141cc565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561134b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161134290614501565b60405180910390fd5b61135481611d0d565b50565b61135f61188c565b73ffffffffffffffffffffffffffffffffffffffff1661137d610c1c565b73ffffffffffffffffffffffffffffffffffffffff16146113d3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016113ca906141cc565b60405180910390fd5b60c88161ffff16111561141b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161141290614593565b60405180910390fd5b80600360146101000a81548161ffff021916908361ffff16021790555050565b600360149054906101000a900461ffff1681565b6000804790506001600860146101000a81548160ff02191690831515021790555060005b87879050811015611592573688888381811061149257611491614258565b5b90506020028101906114a491906145b3565b9050600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ac473c8a478360000160208101906114f89190613df8565b846020013585806040019061150d91906145db565b87806060019061151d919061463e565b89608001358e8b60c001356040518b63ffffffff1660e01b815260040161154c999897969594939291906147e3565b6000604051808303818588803b15801561156557600080fd5b505af1158015611579573d6000803e3d6000fd5b505050505050808061158a90614446565b915050611473565b506000600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff1647846115cb91906143a6565b6115d59190614864565b6115df91906148ed565b905060001515861515141561172c5761172381600660008154811061160757611606614258565b5b9060005260206000200160008154811061162457611623614258565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16876006805480602002602001604051908101604052809291908181526020016000905b8282101561171a5783829060005260206000200180548060200260200160405190810160405280929190818152602001828054801561170657602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190600101908083116116bc575b505050505081526020019060010190611672565b50505050612a3e565b80965081925050505b8047101561176f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161176690614990565b60405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156117b5573d6000803e3d6000fd5b5060003373ffffffffffffffffffffffffffffffffffffffff16476040516117dc906149e1565b60006040518083038185875af1925050503d8060008114611819576040519150601f19603f3d011682016040523d82523d6000602084013e61181e565b606091505b5050905080611862576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161185990614a68565b60405180910390fd5b6000600860146101000a81548160ff02191690831515021790555085935050505095945050505050565b600033905090565b6000806000905060005b87879050811015611a1a57368888838181106118bd576118bc614258565b5b90506020028101906118cf91906145b3565b9050806080013581602001356118e59190614350565b471015611927576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161191e90614ad4565b60405180910390fd5b8060200135836119379190614350565b9250600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b868980b8260800135836020013561198b9190614350565b83600001602081019061199e9190613df8565b8480606001906119ae919061463e565b86608001358b6040518763ffffffff1660e01b81526004016119d4959493929190614b03565b6000604051808303818588803b1580156119ed57600080fd5b505af1158015611a01573d6000803e3d6000fd5b5050505050508080611a1290614446565b91505061189e565b50600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff1682611a509190614864565b611a5a91906148ed565b9050600015158515151415611ba757611b9e816006600081548110611a8257611a81614258565b5b90600052602060002001600081548110611a9f57611a9e614258565b5b9060005260206000200160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16866006805480602002602001604051908101604052809291908181526020016000905b82821015611b9557838290600052602060002001805480602002602001604051908101604052809291908181526020018280548015611b8157602002820191906000526020600020905b8160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019060010190808311611b37575b505050505081526020019060010190611aed565b50505050612a3e565b80955081925050505b80471015611bea576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611be190614b9d565b60405180910390fd5b8273ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611c30573d6000803e3d6000fd5b50600460009054906101000a900460ff168015611c4d5750600047115b15611d005760003373ffffffffffffffffffffffffffffffffffffffff1647604051611c78906149e1565b60006040518083038185875af1925050503d8060008114611cb5576040519150601f19603f3d011682016040523d82523d6000602084013e611cba565b606091505b5050905080611cfe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cf590614a68565b60405180910390fd5b505b8391505095945050505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080611dde8888612d60565b9050600080600090505b825181108015611e1657506000838281518110611e0857611e07614258565b5b602002602001015160200151115b15611f3957600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff16848381518110611e5857611e57614258565b5b602002602001015160200151611e6e9190614864565b611e7891906148ed565b838281518110611e8b57611e8a614258565b5b60200260200101516040018181525050828181518110611eae57611ead614258565b5b6020026020010151600001519150611f2682848381518110611ed357611ed2614258565b5b602002602001015160200151858481518110611ef257611ef1614258565b5b602002602001015160400151600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16613152565b8080611f3190614446565b915050611de8565b5060005b8989905081101561206157368a8a83818110611f5c57611f5b614258565b5b9050602002810190611f6e91906145b3565b9050600760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633af2c012826000016020810190611fc19190613df8565b8360200135848060400190611fd691906145db565b868060600190611fe6919061463e565b88608001358e8a60a001358b60c001356040518b63ffffffff1660e01b815260040161201b9a99989796959493929190614bbd565b600060405180830381600087803b15801561203557600080fd5b505af1158015612049573d6000803e3d6000fd5b5050505050808061205990614446565b915050611f3d565b5060005b8251811080156120935750600083828151811061208557612084614258565b5b602002602001015160200151115b156122a3578281815181106120ab576120aa614258565b5b602002602001015160000151915060008273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b81526004016120f49190613a61565b60206040518083038186803b15801561210c57600080fd5b505afa158015612120573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121449190614c62565b9050600081111561217c5761217a33828573ffffffffffffffffffffffffffffffffffffffff166133e29092919063ffffffff16565b505b6000600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff16838786815181106121bc576121bb614258565b5b6020026020010151602001516121d291906143a6565b6121dc9190614864565b6121e691906148ed565b905061221e818685815181106121ff576121fe614258565b5b6020026020010151600001518c8c8c906122199190614e80565b612a3e565b809b50819250505061224f85848151811061223c5761223b614258565b5b6020026020010151600001518883613516565b61228e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161228590614ee1565b60405180910390fd5b5050808061229b90614446565b915050612065565b5086925050509695505050505050565b600080600090506000805b8989905081101561237b578989828181106122dc576122db614258565b5b90506020028101906122ee91906145b3565b608001358a8a8381811061230557612304614258565b5b905060200281019061231791906145b3565b602001356123259190614350565b836123309190614350565b925089898281811061234557612344614258565b5b905060200281019061235791906145b3565b60200135826123669190614350565b9150808061237390614446565b9150506122be565b50600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff16826123b19190614864565b6123bb91906148ed565b9050612430818a8a60008181106123d5576123d4614258565b5b90506020028101906123e791906145b3565b80604001906123f691906145db565b600081811061240857612407614258565b5b905060200201602081019061241d9190613df8565b878a8a9061242b9190614e80565b612a3e565b809650819250505060008989600081811061244e5761244d614258565b5b905060200281019061246091906145b3565b806040019061246f91906145db565b600081811061248157612480614258565b5b90506020020160208101906124969190613df8565b90506124c6818484600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16613152565b61252c8a8a60008181106124dd576124dc614258565b5b90506020028101906124ef91906145b3565b80604001906124fe91906145db565b60008181106125105761250f614258565b5b90506020020160208101906125259190613df8565b8684613516565b61256b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161256290614ee1565b60405180910390fd5b60005b8a8a90508110156126ac57368b8b8381811061258d5761258c614258565b5b905060200281019061259f91906145b3565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c219a14d8280604001906125ef91906145db565b600081811061260157612600614258565b5b90506020020160208101906126169190613df8565b8360000160208101906126299190613df8565b846020013585806060019061263e919061463e565b87608001358e6040518863ffffffff1660e01b81526004016126669796959493929190614f01565b600060405180830381600087803b15801561268057600080fd5b505af1158015612694573d6000803e3d6000fd5b505050505080806126a490614446565b91505061256e565b508593505050509695505050505050565b6000806126ca8888612d60565b905060005b8151811080156126fd575060008282815181106126ef576126ee614258565b5b602002602001015160200151115b156128ed57600360169054906101000a900461ffff1661ffff16600360149054906101000a900461ffff1661ffff1683838151811061273f5761273e614258565b5b6020026020010151604001516127559190614864565b61275f91906148ed565b82828151811061277257612771614258565b5b60200260200101516040018181525050600082828151811061279757612796614258565b5b602002602001015160000151905061280f818484815181106127bc576127bb614258565b5b6020026020010151602001518585815181106127db576127da614258565b5b602002602001015160400151600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16613152565b600083838151811061282457612823614258565b5b60200260200101516040015190506128688185858151811061284957612848614258565b5b602002602001015160000151898c8c906128639190614e80565b612a3e565b809850819250505061289984848151811061288657612885614258565b5b6020026020010151600001518783613516565b6128d8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016128cf90614ee1565b60405180910390fd5b505080806128e590614446565b9150506126cf565b5060005b88889050811015612a2f57368989838181106129105761290f614258565b5b905060200281019061292291906145b3565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c219a14d82806040019061297291906145db565b600081811061298457612983614258565b5b90506020020160208101906129999190613df8565b8360000160208101906129ac9190613df8565b84602001358580606001906129c1919061463e565b87608001358c6040518863ffffffff1660e01b81526004016129e99796959493929190614f01565b600060405180830381600087803b158015612a0357600080fd5b505af1158015612a17573d6000803e3d6000fd5b50505050508080612a2790614446565b9150506128f1565b50839150509695505050505050565b60008060008351148015612a715750600360189054906101000a900467ffffffffffffffff1667ffffffffffffffff1684105b15612a8157858491509150612d57565b600360189054906101000a900467ffffffffffffffff1667ffffffffffffffff16841015612d4b5760005b8351811015612d45578573ffffffffffffffffffffffffffffffffffffffff16848281518110612adf57612ade614258565b5b6020026020010151600081518110612afa57612af9614258565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16148015612bcd5750600460019054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16848281518110612b6c57612b6b614258565b5b60200260200101516001868481518110612b8957612b88614258565b5b602002602001015151612b9c91906143a6565b81518110612bad57612bac614258565b5b602002602001015173ffffffffffffffffffffffffffffffffffffffff16145b15612d32576000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663fbd4122a89878581518110612c2657612c25614258565b5b60200260200101516040518363ffffffff1660e01b8152600401612c4b929190614ff1565b604080518083038186803b158015612c6257600080fd5b505afa158015612c76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c9a9190615021565b5090506000819050600360189054906101000a900467ffffffffffffffff1667ffffffffffffffff168188612ccf9190614350565b1115612d1d5786600360189054906101000a900467ffffffffffffffff1667ffffffffffffffff16612d0191906143a6565b905081818a612d109190614864565b612d1a91906148ed565b98505b8087612d299190614350565b96505050612d45565b8080612d3d90614446565b915050612aac565b50612d50565b600095505b8584915091505b94509492505050565b60608282905067ffffffffffffffff811115612d7f57612d7e614c8f565b5b604051908082528060200260200182016040528015612db857816020015b612da5613880565b815260200190600190039081612d9d5790505b50905060005b8383905081101561314b5760005b848490508110156131375736858584818110612deb57612dea614258565b5b9050602002810190612dfd91906145b3565b9050808060400190612e0f91906145db565b6001838060400190612e2191906145db565b9050612e2d91906143a6565b818110612e3d57612e3c614258565b5b9050602002016020810190612e529190613df8565b73ffffffffffffffffffffffffffffffffffffffff16848381518110612e7b57612e7a614258565b5b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff161415612f7d576001818060400190612eb591906145db565b90501115612ef9578060a00135848381518110612ed557612ed4614258565b5b6020026020010151602001818151612eed9190614350565b91508181525050612f77565b80608001358160200135612f0d9190614350565b848381518110612f2057612f1f614258565b5b6020026020010151602001818151612f389190614350565b915081815250508060200135848381518110612f5757612f56614258565b5b6020026020010151604001818151612f6f9190614350565b915081815250505b50613137565b6000848381518110612f9257612f91614258565b5b602002602001015160200151148015612fcd575060008160a001351180612fcc5750600081608001358260200135612fca9190614350565b115b5b1561312357808060400190612fe291906145db565b6001838060400190612ff491906145db565b905061300091906143a6565b8181106130105761300f614258565b5b90506020020160208101906130259190613df8565b84838151811061303857613037614258565b5b60200260200101516000019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff1681525050600181806040019061308891906145db565b905011156130bd578060a001358483815181106130a8576130a7614258565b5b6020026020010151602001818152505061311d565b806080013581602001356130d19190614350565b8483815181106130e4576130e3614258565b5b60200260200101516020018181525050806020013584838151811061310c5761310b614258565b5b602002602001015160400181815250505b50613137565b50808061312f90614446565b915050612dcc565b50808061314390614446565b915050612dbe565b5092915050565b828473ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e33306040518363ffffffff1660e01b815260040161318e929190615061565b60206040518083038186803b1580156131a657600080fd5b505afa1580156131ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131de9190614c62565b101561321f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613216906150fc565b60405180910390fd5b818361322b9190614350565b8473ffffffffffffffffffffffffffffffffffffffff166370a08231336040518263ffffffff1660e01b81526004016132649190613a61565b60206040518083038186803b15801561327c57600080fd5b505afa158015613290573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132b49190614c62565b10156132f5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016132ec90615168565b60405180910390fd5b613300843085613516565b61333f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613336906151d4565b60405180910390fd5b828473ffffffffffffffffffffffffffffffffffffffff1663dd62ed3e30846040518363ffffffff1660e01b815260040161337b929190615061565b60206040518083038186803b15801561339357600080fd5b505afa1580156133a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133cb9190614c62565b10156133dc576133db8482613695565b5b50505050565b60008060008573ffffffffffffffffffffffffffffffffffffffff1685856040516024016134119291906151f4565b6040516020818303038152906040527fa9059cbb000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161349b919061528c565b6000604051808303816000865af19150503d80600081146134d8576040519150601f19603f3d011682016040523d82523d6000602084013e6134dd565b606091505b509150915081801561350b575060008151148061350a57508080602001905181019061350991906152b8565b5b5b925050509392505050565b6000833b61352357600080fd5b60008473ffffffffffffffffffffffffffffffffffffffff16338585604051602401613551939291906152e5565b6040516020818303038152906040527f23b872dd000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516135db919061528c565b6000604051808303816000865af19150503d8060008114613618576040519150601f19603f3d011682016040523d82523d6000602084013e61361d565b606091505b505090503d60008114613637576020811461364057600080fd5b6001925061364c565b60206000803e60005192505b508061368d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161368490615368565b60405180910390fd5b509392505050565b600082905060007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90506136ea83828473ffffffffffffffffffffffffffffffffffffffff166136f19092919063ffffffff16565b5050505050565b60008060008573ffffffffffffffffffffffffffffffffffffffff1685856040516024016137209291906151f4565b6040516020818303038152906040527f095ea7b3000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516137aa919061528c565b6000604051808303816000865af19150503d80600081146137e7576040519150601f19603f3d011682016040523d82523d6000602084013e6137ec565b606091505b509150915081801561381a575060008151148061381957508080602001905181019061381891906152b8565b5b5b925050509392505050565b82805482825590600052602060002090810192821561386f579160200282015b8281111561386e5782518290600261385e9291906138b7565b5091602001919060010190613845565b5b50905061387c9190613941565b5090565b6040518060600160405280600073ffffffffffffffffffffffffffffffffffffffff16815260200160008152602001600081525090565b828054828255906000526020600020908101928215613930579160200282015b8281111561392f5782518260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550916020019190600101906138d7565b5b50905061393d9190613965565b5090565b5b8082111561396157600081816139589190613982565b50600101613942565b5090565b5b8082111561397e576000816000905550600101613966565b5090565b50805460008255906000526020600020908101906139a09190613965565b50565b600082825260208201905092915050565b7f4e6f6e2d70617961626c65000000000000000000000000000000000000000000600082015250565b60006139ea600b836139a3565b91506139f5826139b4565b602082019050919050565b60006020820190508181036000830152613a19816139dd565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613a4b82613a20565b9050919050565b613a5b81613a40565b82525050565b6000602082019050613a766000830184613a52565b92915050565b6000819050919050565b6000613aa1613a9c613a9784613a20565b613a7c565b613a20565b9050919050565b6000613ab382613a86565b9050919050565b6000613ac582613aa8565b9050919050565b613ad581613aba565b82525050565b6000602082019050613af06000830184613acc565b92915050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f840112613b2f57613b2e613b0a565b5b8235905067ffffffffffffffff811115613b4c57613b4b613b0f565b5b602083019150836020820283011115613b6857613b67613b14565b5b9250929050565b60008115159050919050565b613b8481613b6f565b8114613b8f57600080fd5b50565b600081359050613ba181613b7b565b92915050565b6000613bb282613a20565b9050919050565b613bc281613ba7565b8114613bcd57600080fd5b50565b600081359050613bdf81613bb9565b92915050565b60008060008060608587031215613bff57613bfe613b00565b5b600085013567ffffffffffffffff811115613c1d57613c1c613b05565b5b613c2987828801613b19565b94509450506020613c3c87828801613b92565b9250506040613c4d87828801613bd0565b91505092959194509250565b6000819050919050565b613c6c81613c59565b82525050565b6000602082019050613c876000830184613c63565b92915050565b600067ffffffffffffffff82169050919050565b613caa81613c8d565b8114613cb557600080fd5b50565b600081359050613cc781613ca1565b92915050565b600060208284031215613ce357613ce2613b00565b5b6000613cf184828501613cb8565b91505092915050565b6000613d0582613aa8565b9050919050565b613d1581613cfa565b82525050565b6000602082019050613d306000830184613d0c565b92915050565b613d3f81613c8d565b82525050565b6000602082019050613d5a6000830184613d36565b92915050565b613d6981613c59565b8114613d7457600080fd5b50565b600081359050613d8681613d60565b92915050565b60008060408385031215613da357613da2613b00565b5b6000613db185828601613d77565b9250506020613dc285828601613d77565b9150509250929050565b613dd581613a40565b8114613de057600080fd5b50565b600081359050613df281613dcc565b92915050565b600060208284031215613e0e57613e0d613b00565b5b6000613e1c84828501613de3565b91505092915050565b6000613e3082613aa8565b9050919050565b613e4081613e25565b82525050565b6000602082019050613e5b6000830184613e37565b92915050565b60008083601f840112613e7757613e76613b0a565b5b8235905067ffffffffffffffff811115613e9457613e93613b0f565b5b602083019150836020820283011115613eb057613eaf613b14565b5b9250929050565b60008083601f840112613ecd57613ecc613b0a565b5b8235905067ffffffffffffffff811115613eea57613ee9613b0f565b5b602083019150836020820283011115613f0657613f05613b14565b5b9250929050565b600080600080600060608688031215613f2957613f28613b00565b5b600086013567ffffffffffffffff811115613f4757613f46613b05565b5b613f5388828901613e61565b9550955050602086013567ffffffffffffffff811115613f7657613f75613b05565b5b613f8288828901613eb7565b93509350506040613f9588828901613de3565b9150509295509295909350565b6000613fad82613aa8565b9050919050565b613fbd81613fa2565b82525050565b6000602082019050613fd86000830184613fb4565b92915050565b600080600080600060608688031215613ffa57613ff9613b00565b5b600086013567ffffffffffffffff81111561401857614017613b05565b5b61402488828901613b19565b9550955050602086013567ffffffffffffffff81111561404757614046613b05565b5b61405388828901613eb7565b9350935050604061406688828901613de3565b9150509295509295909350565b600061407e82613aa8565b9050919050565b61408e81614073565b82525050565b60006020820190506140a96000830184614085565b92915050565b600080604083850312156140c6576140c5613b00565b5b60006140d485828601613de3565b92505060206140e585828601613de3565b9150509250929050565b600061ffff82169050919050565b614106816140ef565b811461411157600080fd5b50565b600081359050614123816140fd565b92915050565b60006020828403121561413f5761413e613b00565b5b600061414d84828501614114565b91505092915050565b61415f816140ef565b82525050565b600060208201905061417a6000830184614156565b92915050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006141b66020836139a3565b91506141c182614180565b602082019050919050565b600060208201905081810360008301526141e5816141a9565b9050919050565b7f6d6f7265207468616e2035206d65746144657461696c73000000000000000000600082015250565b60006142226017836139a3565b915061422d826141ec565b602082019050919050565b6000602082019050818103600083015261425181614215565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b6000823560016040038336030381126142b2576142b1614287565b5b80830191505092915050565b600080833560016020038436030381126142db576142da614287565b5b80840192508235915067ffffffffffffffff8211156142fd576142fc61428c565b5b60208301925060208202360383131561431957614318614291565b5b509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061435b82613c59565b915061436683613c59565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561439b5761439a614321565b5b828201905092915050565b60006143b182613c59565b91506143bc83613c59565b9250828210156143cf576143ce614321565b5b828203905092915050565b7f57726f6e67207061796d656e744e6574776f726b496400000000000000000000600082015250565b60006144106016836139a3565b915061441b826143da565b602082019050919050565b6000602082019050818103600083015261443f81614403565b9050919050565b600061445182613c59565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82141561448457614483614321565b5b600182019050919050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b60006144eb6026836139a3565b91506144f68261448f565b604082019050919050565b6000602082019050818103600083015261451a816144de565b9050919050565b7f546865206261746368206665652076616c756520697320746f6f20686967683a60008201527f203e203225000000000000000000000000000000000000000000000000000000602082015250565b600061457d6025836139a3565b915061458882614521565b604082019050919050565b600060208201905081810360008301526145ac81614570565b9050919050565b60008235600160e0038336030381126145cf576145ce614287565b5b80830191505092915050565b600080833560016020038436030381126145f8576145f7614287565b5b80840192508235915067ffffffffffffffff82111561461a5761461961428c565b5b60208301925060208202360383131561463657614635614291565b5b509250929050565b6000808335600160200384360303811261465b5761465a614287565b5b80840192508235915067ffffffffffffffff82111561467d5761467c61428c565b5b60208301925060018202360383131561469957614698614291565b5b509250929050565b60006146ac82613aa8565b9050919050565b6146bc816146a1565b82525050565b600082825260208201905092915050565b6000819050919050565b6146e681613a40565b82525050565b60006146f883836146dd565b60208301905092915050565b60006147136020840184613de3565b905092915050565b6000602082019050919050565b600061473483856146c2565b935061473f826146d3565b8060005b85811015614778576147558284614704565b61475f88826146ec565b975061476a8361471b565b925050600181019050614743565b5085925050509392505050565b600082825260208201905092915050565b82818337600083830152505050565b6000601f19601f8301169050919050565b60006147c28385614785565b93506147cf838584614796565b6147d8836147a5565b840190509392505050565b600060e0820190506147f8600083018c6146b3565b614805602083018b613c63565b818103604083015261481881898b614728565b9050818103606083015261482d8187896147b6565b905061483c6080830186613c63565b61484960a08301856146b3565b61485660c0830184613c63565b9a9950505050505050505050565b600061486f82613c59565b915061487a83613c59565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff04831182151516156148b3576148b2614321565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006148f882613c59565b915061490383613c59565b925082614913576149126148be565b5b828204905092915050565b7f4e6f7420656e6f7567682066756e647320666f7220626174636820636f6e766560008201527f7273696f6e206665657300000000000000000000000000000000000000000000602082015250565b600061497a602a836139a3565b91506149858261491e565b604082019050919050565b600060208201905081810360008301526149a98161496d565b9050919050565b600081905092915050565b50565b60006149cb6000836149b0565b91506149d6826149bb565b600082019050919050565b60006149ec826149be565b9150819050919050565b7f436f756c64206e6f742073656e642072656d61696e696e672066756e6473207460008201527f6f20746865207061796572000000000000000000000000000000000000000000602082015250565b6000614a52602b836139a3565b9150614a5d826149f6565b604082019050919050565b60006020820190508181036000830152614a8181614a45565b9050919050565b7f4e6f7420656e6f7567682066756e647300000000000000000000000000000000600082015250565b6000614abe6010836139a3565b9150614ac982614a88565b602082019050919050565b60006020820190508181036000830152614aed81614ab1565b9050919050565b614afd81613ba7565b82525050565b6000608082019050614b186000830188614af4565b8181036020830152614b2b8186886147b6565b9050614b3a6040830185613c63565b614b476060830184614af4565b9695505050505050565b7f4e6f7420656e6f7567682066756e647320666f72206261746368206665650000600082015250565b6000614b87601e836139a3565b9150614b9282614b51565b602082019050919050565b60006020820190508181036000830152614bb681614b7a565b9050919050565b600061010082019050614bd3600083018d613a52565b614be0602083018c613c63565b8181036040830152614bf3818a8c614728565b90508181036060830152614c0881888a6147b6565b9050614c176080830187613c63565b614c2460a0830186613a52565b614c3160c0830185613c63565b614c3e60e0830184613c63565b9b9a5050505050505050505050565b600081519050614c5c81613d60565b92915050565b600060208284031215614c7857614c77613b00565b5b6000614c8684828501614c4d565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b614cc7826147a5565b810181811067ffffffffffffffff82111715614ce657614ce5614c8f565b5b80604052505050565b6000614cf9613af6565b9050614d058282614cbe565b919050565b600067ffffffffffffffff821115614d2557614d24614c8f565b5b602082029050602081019050919050565b600067ffffffffffffffff821115614d5157614d50614c8f565b5b602082029050602081019050919050565b6000614d75614d7084614d36565b614cef565b90508083825260208201905060208402830185811115614d9857614d97613b14565b5b835b81811015614dc15780614dad8882613de3565b845260208401935050602081019050614d9a565b5050509392505050565b600082601f830112614de057614ddf613b0a565b5b8135614df0848260208601614d62565b91505092915050565b6000614e0c614e0784614d0a565b614cef565b90508083825260208201905060208402830185811115614e2f57614e2e613b14565b5b835b81811015614e7657803567ffffffffffffffff811115614e5457614e53613b0a565b5b808601614e618982614dcb565b85526020850194505050602081019050614e31565b5050509392505050565b6000614e8d368484614df9565b905092915050565b7f426174636820666565207472616e7366657246726f6d2829206661696c656400600082015250565b6000614ecb601f836139a3565b9150614ed682614e95565b602082019050919050565b60006020820190508181036000830152614efa81614ebe565b9050919050565b600060c082019050614f16600083018a613a52565b614f236020830189613a52565b614f306040830188613c63565b8181036060830152614f438186886147b6565b9050614f526080830185613c63565b614f5f60a0830184613a52565b98975050505050505050565b600081519050919050565b6000819050602082019050919050565b6000602082019050919050565b6000614f9e82614f6b565b614fa881856146c2565b9350614fb383614f76565b8060005b83811015614fe4578151614fcb88826146ec565b9750614fd683614f86565b925050600181019050614fb7565b5085935050505092915050565b60006040820190506150066000830185613c63565b81810360208301526150188184614f93565b90509392505050565b6000806040838503121561503857615037613b00565b5b600061504685828601614c4d565b925050602061505785828601614c4d565b9150509250929050565b60006040820190506150766000830185613a52565b6150836020830184613a52565b9392505050565b7f496e73756666696369656e7420616c6c6f77616e636520666f7220626174636860008201527f20746f2070617900000000000000000000000000000000000000000000000000602082015250565b60006150e66027836139a3565b91506150f18261508a565b604082019050919050565b60006020820190508181036000830152615115816150d9565b9050919050565b7f4e6f7420656e6f7567682066756e64732c20696e636c7564696e672066656573600082015250565b60006151526020836139a3565b915061515d8261511c565b602082019050919050565b6000602082019050818103600083015261518181615145565b9050919050565b7f7061796d656e74207472616e7366657246726f6d2829206661696c6564000000600082015250565b60006151be601d836139a3565b91506151c982615188565b602082019050919050565b600060208201905081810360008301526151ed816151b1565b9050919050565b60006040820190506152096000830185613a52565b6152166020830184613c63565b9392505050565b600081519050919050565b60005b8381101561524657808201518184015260208101905061522b565b83811115615255576000848401525b50505050565b60006152668261521d565b61527081856149b0565b9350615280818560208601615228565b80840191505092915050565b6000615298828461525b565b915081905092915050565b6000815190506152b281613b7b565b92915050565b6000602082840312156152ce576152cd613b00565b5b60006152dc848285016152a3565b91505092915050565b60006060820190506152fa6000830186613a52565b6153076020830185613a52565b6153146040830184613c63565b949350505050565b7f7472616e7366657246726f6d282920686173206265656e207265766572746564600082015250565b60006153526020836139a3565b915061535d8261531c565b602082019050919050565b6000602082019050818103600083015261538181615345565b905091905056fea2646970667358221220c2ad28c14e7169d3be5c99424f831837ebb48de4f2e9479c34b1b23d6777f71f64736f6c63430008090033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e64c2d06d19d13061e62e291b2c4e9fe5679b93
-----Decoded View---------------
Arg [0] : _paymentErc20Proxy (address): 0x0000000000000000000000000000000000000000
Arg [1] : _paymentNativeProxy (address): 0x0000000000000000000000000000000000000000
Arg [2] : _paymentErc20ConversionProxy (address): 0x0000000000000000000000000000000000000000
Arg [3] : _paymentNativeConversionFeeProxy (address): 0x0000000000000000000000000000000000000000
Arg [4] : _chainlinkConversionPath (address): 0x0000000000000000000000000000000000000000
Arg [5] : _owner (address): 0x4E64C2d06d19D13061e62E291b2C4e9fe5679b93
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000004e64c2d06d19d13061e62e291b2c4e9fe5679b93
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.