Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
HinkalInLogic
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 500 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;
import {HinkalInLogicBase} from "./HinkalInLogicBase.sol";
import {TokenWithAmountAndId, IHinkalInLogic} from "./types/IHinkalInLogic.sol";
import {CircomData} from "./types/CircomData.sol";
import {UTXO} from "./types/UTXO.sol";
import {StealthAddressStructure} from "./types/StealthAddressStructure.sol";
import {IExternalActionV2} from "./types/IExternalActionV2.sol";
// Inherits from HinkalInLogicBase
// Implements Logic Related to External Actions and Proofless Deposits
contract HinkalInLogic is IHinkalInLogic, HinkalInLogicBase {
///@notice handle running external actions
///@param circomData circom data.
function handleRunExternalAction(
CircomData calldata circomData,
int256[] memory approvalChangesPerToken
)
external
override(HinkalInLogicBase, IHinkalInLogic)
returns (UTXO[] memory)
{
int256[] memory deltaAmountChanges = new int256[](
circomData.erc20TokenAddresses.length
);
for (uint256 i = 0; i < circomData.erc20TokenAddresses.length; i++) {
deltaAmountChanges[i] = calculateDeltaAmount(
circomData,
approvalChangesPerToken,
i
);
if (deltaAmountChanges[i] < 0) {
transferToken(
circomData.erc20TokenAddresses[i],
circomData.externalAddress,
uint256(-deltaAmountChanges[i]),
circomData.tokenIds[i]
);
}
}
return
IExternalActionV2(circomData.externalAddress).runAction(
circomData,
deltaAmountChanges
);
}
function handleTransfersFromProoflessDeposit(
TokenWithAmountAndId[] memory uniqueTokens,
uint256 uniqueCount
) internal {
for (uint256 i = 0; i < uniqueCount; i++) {
address erc20Address = uniqueTokens[i].erc20Address;
uint256 amount = uniqueTokens[i].amount;
uint256 tokenId = uniqueTokens[i].tokenId;
uint256 balanceBefore = getERC20OrETHBalance(erc20Address);
if (erc20Address == address(0)) balanceBefore -= msg.value;
transferTokenFrom(
erc20Address,
msg.sender,
address(this),
amount,
tokenId
);
uint256 balanceAfter = getERC20OrETHBalance(erc20Address);
require(
balanceAfter - balanceBefore == amount,
"proofless deposit balances must be equal"
);
}
}
function handleUtxoCreationEach(
address erc20Address,
uint256 amount,
uint256 tokenId,
StealthAddressStructure calldata stealthAddressStructure
) internal view returns (UTXO memory) {
UTXO memory utxo = UTXO({
amount: amount,
erc20Address: erc20Address,
stealthAddressStructure: stealthAddressStructure,
tokenId: tokenId,
timeStamp: block.timestamp
});
return utxo;
}
function calcTokenChangesForProoflessDeposit(
address[] calldata erc20Addresses,
uint256[] calldata amounts,
uint256[] calldata tokenIds
)
internal
pure
returns (
TokenWithAmountAndId[] memory uniqueTokens,
uint256 uniqueCount
)
{
uniqueTokens = new TokenWithAmountAndId[](erc20Addresses.length);
for (uint256 i = 0; i < erc20Addresses.length; i++) {
bool found = false;
for (uint256 j = 0; j < uniqueCount; j++) {
if (
uniqueTokens[j].erc20Address == erc20Addresses[i] &&
uniqueTokens[j].tokenId == tokenIds[i]
) {
require(
tokenIds[i] == 0,
"you cannot send two NFTs with the same tokenId"
);
uniqueTokens[j].amount += amounts[i];
found = true;
break;
}
}
if (!found) {
uniqueTokens[uniqueCount] = TokenWithAmountAndId({
erc20Address: erc20Addresses[i],
amount: amounts[i],
tokenId: tokenIds[i]
});
uniqueCount++;
}
}
}
function handleProoflessDeposit(
address[] calldata erc20Addresses,
uint256[] calldata amounts,
uint256[] calldata tokenIds,
StealthAddressStructure[] calldata stealthAddressStructures
)
public
payable
override(HinkalInLogicBase, IHinkalInLogic)
returns (UTXO[] memory utxoArray)
{
uint256 addressesLength = erc20Addresses.length;
require(
tokenIds.length == addressesLength,
"tokenIds length must match"
);
require(amounts.length == addressesLength, "amounts length must match");
(
TokenWithAmountAndId[] memory uniqueTokens,
uint256 uniqueCount
) = calcTokenChangesForProoflessDeposit(
erc20Addresses,
amounts,
tokenIds
);
handleTransfersFromProoflessDeposit(uniqueTokens, uniqueCount);
utxoArray = new UTXO[](addressesLength);
for (uint256 i = 0; i < addressesLength; i++) {
utxoArray[i] = handleUtxoCreationEach(
erc20Addresses[i],
amounts[i],
tokenIds[i],
stealthAddressStructures[i]
);
}
}
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20.sol";
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol";
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
import {CircomData} from "./types/CircomData.sol";
contract DeltaAmountCalculator {
function calculateDeltaAmount(
CircomData calldata circomData,
int256[] memory approvalChanges,
uint256 index
) internal pure returns (int256) {
return
(
circomData.onChainCreation[index]
? int256(0)
: circomData.amountChanges[index]
) + approvalChanges[index];
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {FormUtxosAndCheckSpendingsArgs, IHinkalInLogic} from "./types/IHinkalInLogic.sol";
import {CircomData, UseApprovalUTXOData} from "./types/CircomData.sol";
import {UTXO, ApprovedUtxo} from "./types/UTXO.sol";
import {AddressMemorySet} from "./lib/AddressMemorySet.sol";
import {Transferer} from "./Transferer.sol";
import {InLogicBlacklistedMethodsWithoutData, InLogicBlacklistedMethodsWithData} from "./types/InLogicBlacklistedMethods.sol";
import {DeltaAmountCalculator} from "./DeltaAmountCalculator.sol";
import {StealthAddressStructure} from "./types/StealthAddressStructure.sol";
import {IHinkalInLogic} from "./types/IHinkalInLogic.sol";
import {HinkalInLogicMetadataParser} from "./HinkalInLogicMetadataParser.sol";
// This contract is needed only because evm has restrictions on bytecode size
// Hinkal.sol is delegate calling this contract: it's an extension contract
// Hinkal Base Manages only InHinkal Logic: related to approvals, direct execution, buffering, releasing from buffer, etc.
abstract contract HinkalInLogicBase is
IHinkalInLogic,
Transferer,
DeltaAmountCalculator,
HinkalInLogicMetadataParser
{
using SafeERC20 for IERC20;
using AddressMemorySet for AddressMemorySet.Set;
mapping(address => ApprovedUtxo[]) public approvedUtxos;
mapping(address => mapping(address => mapping(uint256 => uint256)))
public approvalsBuffer; // approvalTarget -> tokenAddress -> inHinkalAddress -> amount
function getApprovalsBufferValue(
address approveTo,
address tokenAddress,
uint256 inHinkalAddress
) external view returns (uint256) {
uint amount = approvalsBuffer[approveTo][tokenAddress][inHinkalAddress];
return amount;
}
function getInteractionApprovals(
address interaction
) external view returns (ApprovedUtxo[] memory) {
return approvedUtxos[interaction];
}
function bufferApprovals(
address[] calldata approvalTargets,
uint256[][] calldata indexes
) external {
require(
approvalTargets.length == indexes.length,
"addresss and indexes length should be the same"
);
for (uint256 i = 0; i < approvalTargets.length; i++) {
ApprovedUtxo[] storage approvedUtxosForAddress = approvedUtxos[
approvalTargets[i]
];
for (uint256 j = 0; j < indexes[i].length; j++) {
ApprovedUtxo storage approvedUtxo = approvedUtxosForAddress[
indexes[i][j]
];
address tokenAddress = approvedUtxo.tokenAddress;
uint256 inHinkalAddress = approvedUtxo.inHinkalAddress;
uint256 amount = approvedUtxo.amount;
removeApproval(approvedUtxosForAddress, indexes[i][j]);
// decreasing total approval amount
approveMore(
tokenAddress,
approvalTargets[i],
-SafeCast.toInt256(amount)
);
// update buffer
uint256 bufferAmount = approvalsBuffer[approvalTargets[i]][
tokenAddress
][inHinkalAddress];
approvalsBuffer[approvalTargets[i]][tokenAddress][
inHinkalAddress
] = bufferAmount + amount;
emit NewBufferEntry(
approvalTargets[i],
tokenAddress,
amount,
inHinkalAddress
);
}
}
}
function modifyOrRemoveApprovalUtxo(
address externalAddress,
address tokenAddress,
uint256 inHinkalAddress,
int256 approvalChange
) internal {
bool foundUtxo = false;
ApprovedUtxo[] storage approvedUtxosForAddress = approvedUtxos[
externalAddress
];
for (uint256 i = 0; i < approvedUtxosForAddress.length; i++) {
ApprovedUtxo storage currentApprovedUtxo = approvedUtxosForAddress[
i
];
if (
currentApprovedUtxo.inHinkalAddress != inHinkalAddress ||
currentApprovedUtxo.tokenAddress != tokenAddress
) continue;
uint256 newAmount = SafeCast.toUint256(
SafeCast.toInt256(currentApprovedUtxo.amount) + approvalChange
);
if (newAmount == 0) {
removeApproval(approvedUtxosForAddress, i);
} else {
currentApprovedUtxo.amount = newAmount;
}
foundUtxo = true;
break;
}
require(
foundUtxo || approvalChange >= 0,
"if there is no utxo in array, then approval change cannot be negative"
);
// if we do not find record we append approvals array
if (!foundUtxo) {
ApprovedUtxo memory approvedUtxo = ApprovedUtxo({
tokenAddress: tokenAddress,
amount: uint256(approvalChange), // approval change is positive
inHinkalAddress: inHinkalAddress
});
approvedUtxosForAddress.push(approvedUtxo);
}
approveMore(tokenAddress, externalAddress, approvalChange);
emit NewApprovedUtxo(
externalAddress,
tokenAddress,
approvalChange,
inHinkalAddress
);
}
function handleApprovalUtxos(
CircomData calldata circomData
) public returns (int256[] memory result) {
result = new int256[](circomData.erc20TokenAddresses.length);
for (
uint256 tokenIndex = 0;
tokenIndex < circomData.erc20TokenAddresses.length;
tokenIndex++
) {
int256 approvalChangeForToken = 0;
UseApprovalUTXOData memory useApprovalUTXOData = circomData
.hinkalLogicArgs
.useApprovalUtxoData[tokenIndex];
for (
uint256 externalAddressIndex = 0;
externalAddressIndex <
useApprovalUTXOData.externalApprovalAddresses.length;
externalAddressIndex++
) {
address externalAddress = useApprovalUTXOData
.externalApprovalAddresses[externalAddressIndex];
int256 currentApprovalChange = useApprovalUTXOData
.approvalChanges[externalAddressIndex];
if (externalAddress == address(0) || currentApprovalChange == 0)
continue;
approvalChangeForToken += currentApprovalChange;
modifyOrRemoveApprovalUtxo(
externalAddress,
circomData.erc20TokenAddresses[tokenIndex],
useApprovalUTXOData.conversionInHinkalAddress[
externalAddressIndex
],
currentApprovalChange
);
}
result[tokenIndex] = approvalChangeForToken;
}
}
function inHinkalTransact(
CircomData calldata circomData,
int256[] memory approvalChangesPerToken
) external payable returns (UTXO[] memory utxoSet) {
require(
msg.value == 0,
"msg.value non allowed for inHinkalTransactions"
);
// 1. ONLY APPROVAL CASE: skipped, just send funds to relay
if (circomData.hinkalLogicArgs.hinkalLogicAction == 1) {
sendToRelay(
circomData.relay,
circomData.feeStructure.flatFee,
circomData.feeStructure.feeToken
);
return utxoSet;
}
// 2. RELEASE FROM BUFFER CASE
if (circomData.hinkalLogicArgs.hinkalLogicAction == 2) {
releaseFromBuffer(circomData);
}
// 3. EXECUTION CASE
else if (circomData.hinkalLogicArgs.hinkalLogicAction == 3) {
utxoSet = inHinkalExecutionFlow(circomData);
} else {
revert("Unknown HinkalLogicAction");
}
}
/**
* @notice Executes a user-defined external action after spending any required approvals.
* @dev Spends user approvals using `spendApprovedUtxos(circomData)`
* to ensure the user has enough allowance for this operation.
* @param circomData The CircomData struct containing all parameters required for the approval flow
* @return UTXO[] The array of newly formed UTXOs.
*/
function inHinkalExecutionFlow(
CircomData calldata circomData
) internal returns (UTXO[] memory) {
FormUtxosAndCheckSpendingsArgs memory formUtxosAndCheckSpendingsArgs;
require(
msg.value == 0,
"direct call with positive msg.value not allowed"
);
(
address[] memory unspentTokens,
uint256 unspentTokensLength
) = spendApprovedUtxos(circomData);
uint256[] memory oldUnspentBalances = calculateBalances(
unspentTokens,
unspentTokensLength
);
// EXECUTION BLOCK STARTS
formUtxosAndCheckSpendingsArgs.circomData = circomData;
formUtxosAndCheckSpendingsArgs.oldBalances = calculateBalances(
circomData.erc20TokenAddresses
);
formUtxosAndCheckSpendingsArgs.oldAllowances = calculateAllowances(
circomData.erc20TokenAddresses,
circomData.externalAddress
);
erc20SafetyCheck(circomData);
ParsedInLogicMetadata memory parsedMetadata = parseInLogicMetadata(
circomData.externalActionMetadata
);
// we find if we are spending ethreum to attach it as msg.value
uint256 ethAmount;
for (uint256 i = 0; i < circomData.erc20TokenAddresses.length; i++) {
if (
circomData.erc20TokenAddresses[i] == address(0) &&
circomData.onChainCreation[i] == false
) {
if (circomData.amountChanges[i] < 0) {
ethAmount = uint256(-circomData.amountChanges[i]);
if (
circomData.relay != address(0) &&
circomData.feeStructure.feeToken == address(0)
) {
ethAmount -= circomData.feeStructure.flatFee;
}
}
}
}
(bool success, bytes memory returnData) = address(
circomData.externalAddress
).call{value: ethAmount}(parsedMetadata.externalCallData);
if (!success) {
// If there is return data, revert with the error message
if (returnData.length > 0) {
assembly {
let returnDataSize := mload(returnData)
revert(add(32, returnData), returnDataSize)
}
} else {
revert("Hinkal: External call failed");
}
}
// we are sending fees to Relayer
sendToRelay(
circomData.relay,
circomData.feeStructure.flatFee,
circomData.feeStructure.feeToken
);
formUtxosAndCheckSpendingsArgs.newBalances = calculateBalances(
circomData.erc20TokenAddresses
);
formUtxosAndCheckSpendingsArgs.newAllowances = calculateAllowances(
circomData.erc20TokenAddresses,
circomData.externalAddress
);
uint256[] memory newUnspentBalances = calculateBalances(
unspentTokens,
unspentTokensLength
);
// EXECUTION BLOCK FINISHES
UTXO[] memory utxoSet = formUtxosAndCheckSpendings(
formUtxosAndCheckSpendingsArgs
);
// check here instead of in formUtxosAndCheckSpendings, to prevent stack too deep error
require(
isArrayEqual(oldUnspentBalances, newUnspentBalances),
"array's must be equal"
);
return utxoSet;
}
function releaseFromBuffer(CircomData calldata circomData) internal {
address[][] memory approvalTargets = abi.decode(
circomData.externalActionMetadata,
(address[][])
);
uint256 inHinkalAddress = circomData.hinkalLogicArgs.inHinkalAddress;
require(
circomData.erc20TokenAddresses.length == approvalTargets.length,
"releaseFromBuffer check1"
);
address feeToken = circomData.feeStructure.feeToken;
uint256 flatFee = circomData.feeStructure.flatFee;
sendToRelay(circomData.relay, flatFee, feeToken);
for (uint256 i = 0; i < circomData.erc20TokenAddresses.length; i++) {
address erc20address = circomData.erc20TokenAddresses[i];
uint256 totalBufferAmount = 0;
for (uint256 j = 0; j < approvalTargets[i].length; j++) {
uint256 bufferAmount = approvalsBuffer[approvalTargets[i][j]][
erc20address
][inHinkalAddress];
require(
bufferAmount > 0,
"hinkal buffer amount should be more than zero"
);
totalBufferAmount += bufferAmount;
// nullifying buffer
approvalsBuffer[approvalTargets[i][j]][erc20address][
inHinkalAddress
] = 0;
emit BufferReleased(
approvalTargets[i][j],
erc20address,
inHinkalAddress
);
}
require(
SafeCast.toInt256(totalBufferAmount) ==
-circomData.hinkalLogicArgs.executeApprovalChanges[i],
"total buffer should equal to total disallowance"
);
require(
SafeCast.toInt256(totalBufferAmount) ==
(
circomData.onChainCreation[i]
? int256(0)
: circomData.amountChanges[i]
) +
(
feeToken == erc20address
? int256(flatFee)
: int256(0)
),
"total buffer amount should be equal to approvalChanges"
);
}
}
function spendApprovedUtxos(
CircomData calldata circomData
) internal returns (address[] memory, uint256 length) {
ApprovedUtxo[] storage approvedUtxosForAddress = approvedUtxos[
circomData.externalAddress
];
bool[] memory userTokenApprovals = new bool[](
circomData.erc20TokenAddresses.length
);
AddressMemorySet.Set memory unspentTokens = AddressMemorySet.init(
approvedUtxosForAddress.length + 1 // +1 is for circomData.externalAddress
);
int256 approvedUtxosLength = int256(approvedUtxosForAddress.length);
// erc20Array should include all the tokens in ApprovedUtxo
// users are allowed to spend from their approval amounts
// if user does not own approval for particular token, his spend approval should be zero
for (int256 i = 0; i < approvedUtxosLength; i++) {
uint256 uintI = uint256(i); // the reason: i--
ApprovedUtxo storage approvedUtxo = approvedUtxosForAddress[uintI];
bool foundToken = false;
uint256 tokenLength = circomData.erc20TokenAddresses.length;
for (uint256 j = 0; j < tokenLength; j++) {
if (
approvedUtxo.tokenAddress ==
circomData.erc20TokenAddresses[j]
) {
foundToken = true;
if (
approvedUtxo.inHinkalAddress ==
circomData.hinkalLogicArgs.inHinkalAddress
) {
userTokenApprovals[j] = true;
if (
circomData.hinkalLogicArgs.executeApprovalChanges[
j
] < 0
) {
int256 allowanceLeft = SafeCast.toInt256(
approvedUtxo.amount
) +
circomData
.hinkalLogicArgs
.executeApprovalChanges[j];
require(
allowanceLeft >= 0,
"Hinkal: You should spend exactly the same amount you approved"
);
approvedUtxo.amount = SafeCast.toUint256(
allowanceLeft
);
if (allowanceLeft == 0) {
removeApproval(approvedUtxosForAddress, uintI);
i--; // since we put the last element of approvedUtxosForAddress array to i position, we need to repeat once again
approvedUtxosLength--;
}
}
}
break;
}
}
// all tokens that are presented in approval utxos "tree" should be checked on balance change (to be zero)
if (!foundToken) unspentTokens.insert(approvedUtxo.tokenAddress);
}
// if there is no match both in address and owner, then approvalChanges should be zero
for (uint256 i = 0; i < userTokenApprovals.length; i++) {
if (userTokenApprovals[i] == false) {
require(
circomData.hinkalLogicArgs.executeApprovalChanges[i] == 0,
"you cannot spend something you do not own"
);
}
}
if (isERC20(circomData.externalAddress)) {
bool foundToken = false;
for (
uint256 i = 0;
i < circomData.erc20TokenAddresses.length;
i++
) {
if (
circomData.erc20TokenAddresses[i] ==
circomData.externalAddress
) {
foundToken = true;
break;
}
}
if (!foundToken) {
unspentTokens.insert(circomData.externalAddress);
}
}
// avoid copying to save gas
return (unspentTokens.inner, unspentTokens.length);
}
function calculateBalances(
address[] memory erc20TokenAddresses,
uint256 length
) internal view returns (uint256[] memory balances) {
balances = new uint256[](length);
for (uint64 i; i < length; i++) {
if (erc20TokenAddresses[i] == address(0)) {
balances[i] = address(this).balance;
} else {
balances[i] = IERC20(erc20TokenAddresses[i]).balanceOf(
address(this)
);
}
}
}
function calculateBalances(
address[] memory erc20TokenAddresses
) internal view returns (uint256[] memory balances) {
return
calculateBalances(erc20TokenAddresses, erc20TokenAddresses.length);
}
function calculateAllowances(
address[] calldata erc20TokenAddresses,
address approveTo
) internal view returns (uint256[] memory allowances) {
allowances = new uint256[](erc20TokenAddresses.length);
for (uint64 i; i < erc20TokenAddresses.length; i++) {
if (erc20TokenAddresses[i] == address(0)) {
allowances[i] = 0;
} else {
allowances[i] = IERC20(erc20TokenAddresses[i]).allowance(
address(this),
approveTo
);
}
}
}
function isERC20(address contractAddress) internal view returns (bool) {
// we can't use try/catch here because if address is an EOA it will revert no matter what
(bool success, bytes memory result) = contractAddress.staticcall(
abi.encodeWithSelector(IERC20.balanceOf.selector, address(this))
);
// note: just success check isn't enought, for some reason true is returned for EOAs.
return success && result.length == 32;
}
function erc20SafetyCheck(CircomData calldata circomData) internal view {
if (!isERC20(circomData.externalAddress)) return;
bytes4 selector = bytes4(circomData.externalActionMetadata);
bytes4[12] memory blacklistedArrays = [
InLogicBlacklistedMethodsWithoutData.increaseAllowance.selector,
InLogicBlacklistedMethodsWithoutData.decreaseAllowance.selector,
InLogicBlacklistedMethodsWithoutData.approve.selector,
InLogicBlacklistedMethodsWithoutData.mint.selector,
InLogicBlacklistedMethodsWithoutData.burn.selector,
InLogicBlacklistedMethodsWithoutData.transferFrom.selector,
InLogicBlacklistedMethodsWithoutData.authorizeOperator.selector,
InLogicBlacklistedMethodsWithoutData.revokeOperator.selector,
InLogicBlacklistedMethodsWithoutData.approveAndCall.selector,
InLogicBlacklistedMethodsWithoutData.transferFromAndCall.selector,
InLogicBlacklistedMethodsWithData.approveAndCall.selector,
InLogicBlacklistedMethodsWithData.transferFromAndCall.selector
];
for (uint256 i = 0; i < blacklistedArrays.length; i++) {
require(selector != blacklistedArrays[i], "blacklisted selector");
}
}
function isArrayEqual(
uint256[] memory a,
uint256[] memory b
) internal pure returns (bool) {
if (a.length != b.length) return false;
for (uint256 i = 0; i < a.length; i++) if (a[i] != b[i]) return false;
return true;
}
function formUtxosAndCheckSpendings(
FormUtxosAndCheckSpendingsArgs memory args
) internal returns (UTXO[] memory utxoSet) {
utxoSet = countPositiveTokens(
args.circomData.erc20TokenAddresses,
args.oldBalances,
args.newBalances
);
uint256 counter = 0;
for (
uint256 i = 0;
i < args.circomData.erc20TokenAddresses.length;
i++
) {
address tokenAddress = args.circomData.erc20TokenAddresses[i];
int256 balanceDif = SafeCast.toInt256(args.newBalances[i]) -
SafeCast.toInt256(args.oldBalances[i]);
int256 allowanceDif = SafeCast.toInt256(args.newAllowances[i]) -
SafeCast.toInt256(args.oldAllowances[i]);
if (balanceDif > 0) {
utxoSet[counter++] = UTXO({
amount: uint256(balanceDif),
erc20Address: tokenAddress,
stealthAddressStructure: args
.circomData
.stealthAddressStructure,
timeStamp: args.circomData.timeStamp,
tokenId: 0
});
} else if (balanceDif < 0) {
if (tokenAddress != address(0)) {
int256 relayFeeForToken = args
.circomData
.feeStructure
.feeToken == tokenAddress
? SafeCast.toInt256(
args.circomData.feeStructure.flatFee
)
: int256(0);
require(
balanceDif + relayFeeForToken == allowanceDif,
"balance and allowance Dif mismatch"
);
}
}
// CODE BELOW: if we spent more allowance than we have: we restore it
int256 approvalChange = args
.circomData
.hinkalLogicArgs
.executeApprovalChanges[i];
// int256 allowanceDif = int256(newAllowances[i]) - int256(oldAllowances[i]);
int256 excessApprovalSpend = allowanceDif - approvalChange;
// e.g. total allowanceDif = -2, individual approvalChange = -1; diff = -1
// in this case actual approval spend will be 2 > 1 = own approve spend
if (excessApprovalSpend != 0) {
// if we spent more approval than our own approval, we need to restore difference
// we bring change in actual approval to match change in individual approval
approveMore(
tokenAddress,
args.circomData.externalAddress,
-excessApprovalSpend
);
// this gurantees that total approval = sum of individual approvals
}
emit NewApprovedUtxo(
args.circomData.externalAddress,
tokenAddress,
approvalChange,
args.circomData.hinkalLogicArgs.inHinkalAddress
);
}
}
function countPositiveTokens(
address[] memory erc20TokenAddresses,
uint256[] memory oldBalances,
uint256[] memory newBalances
) internal pure returns (UTXO[] memory utxoSet) {
uint256 positiveTokens = 0;
for (uint64 i = 0; i < erc20TokenAddresses.length; i++) {
int256 balanceDif = SafeCast.toInt256(newBalances[i]) -
SafeCast.toInt256(oldBalances[i]);
if (balanceDif > 0) {
positiveTokens++;
}
}
utxoSet = new UTXO[](positiveTokens);
}
function approveMore(
address externalAddress,
address approveTo,
int256 additionalApprove
) internal {
uint256 aggregateAllowance = IERC20(externalAddress).allowance(
address(this),
approveTo
);
uint256 newApprove = additionalApprove > 0
? (aggregateAllowance + uint256(additionalApprove))
: (aggregateAllowance - uint256(-additionalApprove));
// next constraint will not be triggered, but logic should be obvious
require(newApprove >= 0, "Hinkal: allowance was already spent");
IERC20(externalAddress).forceApprove(approveTo, newApprove);
}
function removeApproval(
ApprovedUtxo[] storage approvedUtxosForAddress,
uint256 index
) internal {
uint256 approvalLength = approvedUtxosForAddress.length;
require(index < approvalLength, "removeApproval index is out of range");
if (index != approvalLength - 1) {
approvedUtxosForAddress[index] = approvedUtxosForAddress[
approvalLength - 1
];
}
delete approvedUtxosForAddress[approvalLength - 1];
approvedUtxosForAddress.pop();
}
function handleRunExternalAction(
CircomData calldata circomData,
int256[] memory approvalChangesPerToken
) external virtual returns (UTXO[] memory);
function handleProoflessDeposit(
address[] calldata erc20Addresses,
uint256[] calldata amounts,
uint256[] calldata tokenIds,
StealthAddressStructure[] calldata stealthAddressStructures
) public payable virtual returns (UTXO[] memory utxoArray);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
abstract contract HinkalInLogicMetadataParser {
struct ParsedInLogicMetadata {
bytes signature;
uint256 deadline;
address[] erc20TokenAddresses;
bytes externalCallData;
}
function parseInLogicMetadata(
bytes memory externalMetadata
) internal pure returns (ParsedInLogicMetadata memory result) {
(
bytes memory signature,
uint256 deadline,
address[] memory erc20TokenAddresses,
bytes memory externalCallData
) = abi.decode(externalMetadata, (bytes, uint256, address[], bytes));
result.signature = signature;
result.deadline = deadline;
result.erc20TokenAddresses = erc20TokenAddresses;
result.externalCallData = externalCallData;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;
// Note: purpose of this datastrucutre is to be stored in memory
// consider using EnumerableSet from openzeppelin if you would like a storage set
library AddressMemorySet {
struct Set {
address[] inner;
uint256 length;
uint256 maxLength;
}
function init(uint256 maxLength) internal pure returns (Set memory result) {
result = Set(new address[](maxLength), 0, maxLength);
}
function has(Set memory set, address value) internal pure returns (bool) {
uint256 length = set.length;
for (uint256 i = 0; i < length; i++)
if (set.inner[i] == value) return true;
return false;
}
function insert(Set memory set, address value) internal pure {
if (has(set, value)) return;
set.inner[set.length++] = value;
require(set.length <= set.maxLength, "Set MaxLength Reached");
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IERC721} from "@openzeppelin/contracts/interfaces/IERC721.sol";
import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {TransfererBase} from "./TransfererBase.sol";
contract Transferer is TransfererBase {
using SafeERC20 for IERC20;
function supportsInterface(bytes4 _interfaceId) public view virtual returns (bool) {
return
_interfaceId == type(IERC721Receiver).interfaceId ||
_interfaceId == type(IERC1155Receiver).interfaceId;
}
function onERC721Received(
address,
address,
uint256,
bytes calldata
) public pure returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes calldata
) public pure returns (bytes4) {
return IERC1155Receiver.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] calldata,
uint256[] calldata,
bytes calldata
) public pure returns (bytes4) {
return IERC1155Receiver.onERC1155BatchReceived.selector;
}
function unsafeApproveERC20Token(
address _erc20TokenAddress,
address _to,
uint256 _value
) internal {
IERC20(_erc20TokenAddress).approve(_to, 0);
IERC20(_erc20TokenAddress).approve(_to, _value);
}
function getERC20Allowance(
address _erc20TokenAddress,
address owner,
address spender
) internal view returns (uint256) {
IERC20 outToken = IERC20(_erc20TokenAddress);
return outToken.allowance(owner, spender);
}
function approveERC721Token(
address _erc20TokenAddress,
address _to,
uint256 _tokenId
) internal {
IERC721(_erc20TokenAddress).approve(_to, _tokenId);
}
function approveToken(
address _erc20TokenAddress,
address _to,
uint256 _tokenId,
uint256 _value
) internal {
if (_tokenId == 0) {
unsafeApproveERC20Token(_erc20TokenAddress, _to, _value);
} else {
approveERC721Token(_erc20TokenAddress, _to, _tokenId);
}
}
function transferERC20TokenFrom(
address _erc20TokenAddress,
address _from,
address _to,
uint256 _value
) internal {
IERC20(_erc20TokenAddress).safeTransferFrom(_from, _to, _value);
}
function transferNftFrom(
address _erc20TokenAddress,
address _from,
address _to,
uint256 _tokenId
) internal {
IERC721(_erc20TokenAddress).safeTransferFrom(_from, _to, _tokenId);
}
function transferERC20TokenOrETH(
address _erc20TokenAddress,
address _to,
uint256 _value
) internal {
if (_erc20TokenAddress == address(0)) {
transferETH(_to, _value);
} else {
transferERC20Token(_erc20TokenAddress, _to, _value);
}
}
function transferToken(
address _erc20TokenAddress,
address _to,
uint256 _value,
uint256 _tokenId
) internal {
if (_tokenId == 0) {
transferERC20TokenOrETH(_erc20TokenAddress, _to, _value);
} else {
transferNftFrom(_erc20TokenAddress, address(this), _to, _tokenId);
}
}
function multiTransfer(
address[] memory erc20TokenAddresses,
address _to,
uint256[] memory amounts
) internal returns (bool) {
for (uint64 i = 0; i < erc20TokenAddresses.length; i++) {
if (amounts[i] > 0)
transferERC20TokenOrETH(
erc20TokenAddresses[i],
_to,
amounts[i]
);
}
return true;
}
function transferERC20TokenFromOrCheckETH(
address _contractAddress,
address _from,
address _to,
uint256 _value
) internal {
if (_contractAddress == address(0)) {
require(
msg.value == _value,
"msg.value doesn't match needed amount"
);
if (_to != address(this)) {
transferETH(_to, _value);
}
} else {
transferERC20TokenFrom(_contractAddress, _from, _to, _value);
}
}
function transferTokenFrom(
address _erc20TokenAddress,
address _from,
address _to,
uint256 _value,
uint256 _tokenId
) internal {
if (_tokenId == 0) {
transferERC20TokenFromOrCheckETH(
_erc20TokenAddress,
_from,
_to,
_value
);
} else {
transferNftFrom(_erc20TokenAddress, _from, _to, _tokenId);
}
}
function multiTransferFrom(
address[] memory erc20TokenAddresses,
address _from,
address _to,
uint256[] memory amounts
) internal returns (bool) {
for (uint64 i = 0; i < erc20TokenAddresses.length; i++) {
if (amounts[i] > 0) {
transferERC20TokenFromOrCheckETH(
erc20TokenAddresses[i],
_from,
_to,
amounts[i]
);
}
}
return true;
}
function getERC20OrETHBalance(
address _erc20TokenAddress
) internal view returns (uint256) {
if (_erc20TokenAddress == address(0)) {
return address(this).balance;
} else {
IERC20 outToken = IERC20(_erc20TokenAddress);
return outToken.balanceOf(address(this));
}
}
function getNftBalance(
address _erc20TokenAddress,
uint256 tokenId
) internal view returns (uint256) {
IERC721 outToken = IERC721(_erc20TokenAddress);
try outToken.ownerOf(tokenId) returns (address owner) {
if (owner == address(this)) return 1;
else return 0;
} catch {
return 0;
}
}
function getBalancesForArrayMemory(
address[] memory erc20TokenAddresses
) internal view returns (uint256[] memory balances) {
balances = new uint256[](erc20TokenAddresses.length);
for (uint64 i; i < erc20TokenAddresses.length; i++) {
balances[i] = getERC20OrETHBalance(erc20TokenAddresses[i]);
}
}
function getBalancesForArrayMemory(
address[] memory erc20TokenAddresses,
uint256[] memory tokenIds
) internal view returns (uint256[] memory balances) {
balances = new uint256[](erc20TokenAddresses.length);
for (uint64 i; i < erc20TokenAddresses.length; i++) {
if (tokenIds[i] == 0) {
balances[i] = getERC20OrETHBalance(erc20TokenAddresses[i]);
} else {
balances[i] = getNftBalance(
erc20TokenAddresses[i],
tokenIds[i]
);
}
}
}
function getBalancesForArray(
address[] calldata erc20TokenAddresses
) internal view returns (uint256[] memory balances) {
balances = new uint256[](erc20TokenAddresses.length);
for (uint64 i; i < erc20TokenAddresses.length; i++) {
balances[i] = getERC20OrETHBalance(erc20TokenAddresses[i]);
}
}
function getBalancesForArray(
address[] calldata erc20TokenAddresses,
uint256[] calldata tokenIds
) internal view returns (uint256[] memory balances) {
balances = new uint256[](erc20TokenAddresses.length);
for (uint64 i; i < erc20TokenAddresses.length; i++) {
if (tokenIds[i] == 0) {
balances[i] = getERC20OrETHBalance(erc20TokenAddresses[i]);
} else {
balances[i] = getNftBalance(
erc20TokenAddresses[i],
tokenIds[i]
);
}
}
}
function sendToRelay(
address relay,
uint256 actualAmount,
address erc20TokenAddress
) internal {
if (relay != address(0) && actualAmount > 0) {
transferERC20TokenOrETH(
erc20TokenAddress,
relay,
uint256(actualAmount)
);
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract TransfererBase {
using SafeERC20 for IERC20;
function transferETH(address _recepient, uint256 _value) internal {
(bool success, ) = _recepient.call{value: _value}("");
require(success, "Transfer Failed");
}
function transferERC20Token(
address _erc20TokenAddress,
address _to,
uint256 _value
) internal {
IERC20(_erc20TokenAddress).safeTransfer(_to, _value);
}
function approveERC20Token(
address _erc20TokenAddress,
address _to,
uint256 _value
) internal {
IERC20(_erc20TokenAddress).safeApprove(_to, 0);
IERC20(_erc20TokenAddress).safeApprove(_to, _value);
}
function approveUnlimited(
address _erc20TokenAddress,
address _to
) internal {
if (
IERC20(_erc20TokenAddress).allowance(address(this), _to) <
type(uint256).max / 2
) {
IERC20(_erc20TokenAddress).safeApprove(_to, 0);
IERC20(_erc20TokenAddress).safeApprove(_to, type(uint256).max);
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.6;
struct AxelarChainInfo{
string destinationChain;
string destinationAddress;
uint256 messageFee;
}
struct AxelarCapsule{
AxelarChainInfo[] chains;
uint256 totalMessageFees;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.6;
import {StealthAddressStructure} from "./StealthAddressStructure.sol";
import {SignatureData} from "./IAccessToken.sol";
// enum HinkalLogicAction {
// NONE, // = 0
// ONLY_APPROVAL, // = 1
// RELEASE_BUFFER // = 2
// EXECUTE, // = 3
// }
struct UseApprovalUTXOData {
int256[] approvalChanges;
address[] externalApprovalAddresses;
uint256[] conversionInHinkalAddress;
}
struct HinkalLogicArgs {
uint256 hinkalLogicAction;
uint256 inHinkalAddress;
int256[] executeApprovalChanges;
bool doPreTxApproval;
UseApprovalUTXOData[] useApprovalUtxoData;
}
struct FeeStructure {
address feeToken;
uint256 flatFee;
uint256 variableRate; // measured in beeps = 0.01 of 1%
}
struct CircomData {
uint256 rootHashHinkal;
address[] erc20TokenAddresses;
uint256[] tokenIds;
int256[] amountChanges;
bool[] onChainCreation;
int256[] slippageValues;
uint256[][] inputNullifiers;
uint256[][] outCommitments;
bytes[][] encryptedOutputs;
FeeStructure feeStructure;
uint256 timeStamp;
StealthAddressStructure stealthAddressStructure;
uint256 rootHashAccessToken;
uint256 calldataHash;
uint16 publicSignalCount;
address relay;
address externalAddress;
uint256 externalActionId;
bytes externalActionMetadata;
HinkalLogicArgs hinkalLogicArgs;
HookData hookData;
SignatureData signatureData;
address originalSender;
}
struct HookData {
address preHookContract;
address hookContract;
bytes preHookMetadata;
bytes postHookMetadata;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;
import "./IMerkle.sol";
import "./AxelarInfo.sol";
struct SignatureData {
uint8 v;
bytes32 r;
bytes32 s;
uint256 accessKey;
uint256 nonce;
address ethereumAddress;
}
struct AccessTokenWithAddress {
uint256 accessToken;
address ethAddress;
}
interface IAccessToken {
event NewAccessKeyAdded(
uint256 accessKey,
uint256 index,
address senderAddress
);
event MintingFeeChanged(uint256 newMintingFee);
event AccessKeyBlacklisted(uint256 blacklistedAccessKey);
event AddressBlacklisted(address blacklistedAddress);
event AddressRemovedFromBlacklist(address addressToRestore);
event AccessKeyMigrationReceived(uint256 accessKey, string sourceChain);
event CrossChainAccessTokenRegistryChange(
string sourceChain,
address sourceAddress
);
struct CrossChainAccessTokenRegistryUpdate {
string sourceChain;
address sourceAddress;
}
function addToken(SignatureData calldata signatureData) external;
function hasToken(uint256 accessKey) external view returns (bool);
function blacklistAccessKey(uint256 accessKey, uint256 index) external;
function blacklistAddress(address _address) external;
function removeAddressFromBlacklist(address addressToRestore) external;
function setAxelarGasService(address _gasService) external;
function addTokenCrossChain(
SignatureData calldata signatureData,
AxelarCapsule calldata capsule
) external payable;
function migrateAccessToken(
AxelarCapsule calldata capsule,
uint256 accessKey
) external payable;
function registerCheck(address sender) external view;
function checkForRootHash(
uint256 rootHashAccessToken,
address sender
) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.6;
import {CircomData} from "./CircomData.sol";
import {UTXO} from "./UTXO.sol";
interface IExternalActionV2 {
function runAction(
CircomData calldata circomData,
int256[] calldata deltaAmountChanges
) external returns (UTXO[] memory);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;
import {CircomData} from "./CircomData.sol";
import {ApprovedUtxo, UTXO} from "./UTXO.sol";
import {StealthAddressStructure} from "./StealthAddressStructure.sol";
struct FormUtxosAndCheckSpendingsArgs {
CircomData circomData;
uint256[] oldBalances;
uint256[] newBalances;
uint256[] oldAllowances;
uint256[] newAllowances;
}
struct TokenWithAmountAndId {
address erc20Address;
uint256 amount;
uint256 tokenId;
}
interface IHinkalInLogic {
event NewApprovedUtxo(
address approveTo,
address tokenAddress,
int256 amount,
uint256 inHinkalAddress
);
event NewBufferEntry(
address approvalTarget,
address tokenAddress,
uint256 amount,
uint256 inHinkalAddress
);
event BufferReleased(
address approvalTarget,
address tokenAddress,
uint256 inHinkalAddress
);
function getApprovalsBufferValue(
address approveTo,
address tokenAddress,
uint256 inHinkalAddress
) external returns (uint256);
function inHinkalTransact(
CircomData calldata circomData,
int256[] memory approvalChangesPerToken
) external payable returns (UTXO[] memory);
function getInteractionApprovals(
address interaction
) external view returns (ApprovedUtxo[] memory);
function bufferApprovals(
address[] calldata approvalTargets,
uint256[][] calldata indexes
) external;
function handleApprovalUtxos(
CircomData calldata circomData
) external returns (int256[] memory);
function handleRunExternalAction(
CircomData memory circomDataMemory,
int256[] memory approvalChangesPerToken
) external returns (UTXO[] memory);
function handleProoflessDeposit(
address[] calldata erc20Addresses,
uint256[] calldata amounts,
uint256[] calldata tokenIds,
StealthAddressStructure[] calldata stealthAddressStructures
) external payable returns (UTXO[] memory utxoArray);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
interface IMerkle {
struct MerkleConstructorArgs {
uint128 levels;
address poseidon2;
address poseidon4;
address poseidon5;
}
function hash2(uint256 a, uint256 b) external view returns (uint256);
function getRootHash() external view returns (uint256);
function rootHashExists(uint256 _root) external view returns (bool);
function logarithm2(uint256 x) external pure returns (uint256);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;
// usefull for describing selectors, shouldn't be used as an actaul interface
interface InLogicBlacklistedMethodsWithoutData {
function increaseAllowance(
address spender,
uint256 increment
) external returns (bool);
function decreaseAllowance(
address spender,
uint256 decrement
) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function mint(address to, uint256 value) external returns (bool);
function burn(uint256 value) external;
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
// ERC-777
function authorizeOperator(address operator) external;
function revokeOperator(address operator) external;
// ERC-1363
function approveAndCall(
address spender,
uint256 value
) external returns (bool);
function transferFromAndCall(
address from,
address to,
uint256 value
) external returns (bool);
}
// we can't access .selector of methods if methods are overloaded.
// more info here: https://github.com/ethereum/solidity/issues/3556
interface InLogicBlacklistedMethodsWithData {
// ERC-1363
function approveAndCall(
address spender,
uint256 value,
bytes calldata data
) external returns (bool);
function transferFromAndCall(
address from,
address to,
uint256 value,
bytes calldata data
) external returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.6;
struct StealthAddressStructure {
uint256 extraRandomization;
uint256 stealthAddress;
uint256 H0;
uint256 H1;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.0;
import {StealthAddressStructure} from "./StealthAddressStructure.sol";
struct UTXO {
uint256 amount;
address erc20Address;
StealthAddressStructure stealthAddressStructure;
uint256 timeStamp;
uint256 tokenId;
}
struct ApprovedUtxo {
address tokenAddress;
uint256 amount;
uint256 inHinkalAddress;
}
struct OnChainCommitment {
UTXO utxo;
uint256 commitment;
}{
"optimizer": {
"enabled": true,
"runs": 500
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"approvalTarget","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"inHinkalAddress","type":"uint256"}],"name":"BufferReleased","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"approveTo","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"int256","name":"amount","type":"int256"},{"indexed":false,"internalType":"uint256","name":"inHinkalAddress","type":"uint256"}],"name":"NewApprovedUtxo","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"approvalTarget","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"inHinkalAddress","type":"uint256"}],"name":"NewBufferEntry","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approvalsBuffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approvedUtxos","outputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"inHinkalAddress","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"approvalTargets","type":"address[]"},{"internalType":"uint256[][]","name":"indexes","type":"uint256[][]"}],"name":"bufferApprovals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"approveTo","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"inHinkalAddress","type":"uint256"}],"name":"getApprovalsBufferValue","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"interaction","type":"address"}],"name":"getInteractionApprovals","outputs":[{"components":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"inHinkalAddress","type":"uint256"}],"internalType":"struct ApprovedUtxo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rootHashHinkal","type":"uint256"},{"internalType":"address[]","name":"erc20TokenAddresses","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"int256[]","name":"amountChanges","type":"int256[]"},{"internalType":"bool[]","name":"onChainCreation","type":"bool[]"},{"internalType":"int256[]","name":"slippageValues","type":"int256[]"},{"internalType":"uint256[][]","name":"inputNullifiers","type":"uint256[][]"},{"internalType":"uint256[][]","name":"outCommitments","type":"uint256[][]"},{"internalType":"bytes[][]","name":"encryptedOutputs","type":"bytes[][]"},{"components":[{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"flatFee","type":"uint256"},{"internalType":"uint256","name":"variableRate","type":"uint256"}],"internalType":"struct FeeStructure","name":"feeStructure","type":"tuple"},{"internalType":"uint256","name":"timeStamp","type":"uint256"},{"components":[{"internalType":"uint256","name":"extraRandomization","type":"uint256"},{"internalType":"uint256","name":"stealthAddress","type":"uint256"},{"internalType":"uint256","name":"H0","type":"uint256"},{"internalType":"uint256","name":"H1","type":"uint256"}],"internalType":"struct StealthAddressStructure","name":"stealthAddressStructure","type":"tuple"},{"internalType":"uint256","name":"rootHashAccessToken","type":"uint256"},{"internalType":"uint256","name":"calldataHash","type":"uint256"},{"internalType":"uint16","name":"publicSignalCount","type":"uint16"},{"internalType":"address","name":"relay","type":"address"},{"internalType":"address","name":"externalAddress","type":"address"},{"internalType":"uint256","name":"externalActionId","type":"uint256"},{"internalType":"bytes","name":"externalActionMetadata","type":"bytes"},{"components":[{"internalType":"uint256","name":"hinkalLogicAction","type":"uint256"},{"internalType":"uint256","name":"inHinkalAddress","type":"uint256"},{"internalType":"int256[]","name":"executeApprovalChanges","type":"int256[]"},{"internalType":"bool","name":"doPreTxApproval","type":"bool"},{"components":[{"internalType":"int256[]","name":"approvalChanges","type":"int256[]"},{"internalType":"address[]","name":"externalApprovalAddresses","type":"address[]"},{"internalType":"uint256[]","name":"conversionInHinkalAddress","type":"uint256[]"}],"internalType":"struct UseApprovalUTXOData[]","name":"useApprovalUtxoData","type":"tuple[]"}],"internalType":"struct HinkalLogicArgs","name":"hinkalLogicArgs","type":"tuple"},{"components":[{"internalType":"address","name":"preHookContract","type":"address"},{"internalType":"address","name":"hookContract","type":"address"},{"internalType":"bytes","name":"preHookMetadata","type":"bytes"},{"internalType":"bytes","name":"postHookMetadata","type":"bytes"}],"internalType":"struct HookData","name":"hookData","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"accessKey","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"ethereumAddress","type":"address"}],"internalType":"struct SignatureData","name":"signatureData","type":"tuple"},{"internalType":"address","name":"originalSender","type":"address"}],"internalType":"struct CircomData","name":"circomData","type":"tuple"}],"name":"handleApprovalUtxos","outputs":[{"internalType":"int256[]","name":"result","type":"int256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"erc20Addresses","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"components":[{"internalType":"uint256","name":"extraRandomization","type":"uint256"},{"internalType":"uint256","name":"stealthAddress","type":"uint256"},{"internalType":"uint256","name":"H0","type":"uint256"},{"internalType":"uint256","name":"H1","type":"uint256"}],"internalType":"struct StealthAddressStructure[]","name":"stealthAddressStructures","type":"tuple[]"}],"name":"handleProoflessDeposit","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"components":[{"internalType":"uint256","name":"extraRandomization","type":"uint256"},{"internalType":"uint256","name":"stealthAddress","type":"uint256"},{"internalType":"uint256","name":"H0","type":"uint256"},{"internalType":"uint256","name":"H1","type":"uint256"}],"internalType":"struct StealthAddressStructure","name":"stealthAddressStructure","type":"tuple"},{"internalType":"uint256","name":"timeStamp","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct UTXO[]","name":"utxoArray","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rootHashHinkal","type":"uint256"},{"internalType":"address[]","name":"erc20TokenAddresses","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"int256[]","name":"amountChanges","type":"int256[]"},{"internalType":"bool[]","name":"onChainCreation","type":"bool[]"},{"internalType":"int256[]","name":"slippageValues","type":"int256[]"},{"internalType":"uint256[][]","name":"inputNullifiers","type":"uint256[][]"},{"internalType":"uint256[][]","name":"outCommitments","type":"uint256[][]"},{"internalType":"bytes[][]","name":"encryptedOutputs","type":"bytes[][]"},{"components":[{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"flatFee","type":"uint256"},{"internalType":"uint256","name":"variableRate","type":"uint256"}],"internalType":"struct FeeStructure","name":"feeStructure","type":"tuple"},{"internalType":"uint256","name":"timeStamp","type":"uint256"},{"components":[{"internalType":"uint256","name":"extraRandomization","type":"uint256"},{"internalType":"uint256","name":"stealthAddress","type":"uint256"},{"internalType":"uint256","name":"H0","type":"uint256"},{"internalType":"uint256","name":"H1","type":"uint256"}],"internalType":"struct StealthAddressStructure","name":"stealthAddressStructure","type":"tuple"},{"internalType":"uint256","name":"rootHashAccessToken","type":"uint256"},{"internalType":"uint256","name":"calldataHash","type":"uint256"},{"internalType":"uint16","name":"publicSignalCount","type":"uint16"},{"internalType":"address","name":"relay","type":"address"},{"internalType":"address","name":"externalAddress","type":"address"},{"internalType":"uint256","name":"externalActionId","type":"uint256"},{"internalType":"bytes","name":"externalActionMetadata","type":"bytes"},{"components":[{"internalType":"uint256","name":"hinkalLogicAction","type":"uint256"},{"internalType":"uint256","name":"inHinkalAddress","type":"uint256"},{"internalType":"int256[]","name":"executeApprovalChanges","type":"int256[]"},{"internalType":"bool","name":"doPreTxApproval","type":"bool"},{"components":[{"internalType":"int256[]","name":"approvalChanges","type":"int256[]"},{"internalType":"address[]","name":"externalApprovalAddresses","type":"address[]"},{"internalType":"uint256[]","name":"conversionInHinkalAddress","type":"uint256[]"}],"internalType":"struct UseApprovalUTXOData[]","name":"useApprovalUtxoData","type":"tuple[]"}],"internalType":"struct HinkalLogicArgs","name":"hinkalLogicArgs","type":"tuple"},{"components":[{"internalType":"address","name":"preHookContract","type":"address"},{"internalType":"address","name":"hookContract","type":"address"},{"internalType":"bytes","name":"preHookMetadata","type":"bytes"},{"internalType":"bytes","name":"postHookMetadata","type":"bytes"}],"internalType":"struct HookData","name":"hookData","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"accessKey","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"ethereumAddress","type":"address"}],"internalType":"struct SignatureData","name":"signatureData","type":"tuple"},{"internalType":"address","name":"originalSender","type":"address"}],"internalType":"struct CircomData","name":"circomData","type":"tuple"},{"internalType":"int256[]","name":"approvalChangesPerToken","type":"int256[]"}],"name":"handleRunExternalAction","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"components":[{"internalType":"uint256","name":"extraRandomization","type":"uint256"},{"internalType":"uint256","name":"stealthAddress","type":"uint256"},{"internalType":"uint256","name":"H0","type":"uint256"},{"internalType":"uint256","name":"H1","type":"uint256"}],"internalType":"struct StealthAddressStructure","name":"stealthAddressStructure","type":"tuple"},{"internalType":"uint256","name":"timeStamp","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct UTXO[]","name":"","type":"tuple[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"rootHashHinkal","type":"uint256"},{"internalType":"address[]","name":"erc20TokenAddresses","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"int256[]","name":"amountChanges","type":"int256[]"},{"internalType":"bool[]","name":"onChainCreation","type":"bool[]"},{"internalType":"int256[]","name":"slippageValues","type":"int256[]"},{"internalType":"uint256[][]","name":"inputNullifiers","type":"uint256[][]"},{"internalType":"uint256[][]","name":"outCommitments","type":"uint256[][]"},{"internalType":"bytes[][]","name":"encryptedOutputs","type":"bytes[][]"},{"components":[{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"uint256","name":"flatFee","type":"uint256"},{"internalType":"uint256","name":"variableRate","type":"uint256"}],"internalType":"struct FeeStructure","name":"feeStructure","type":"tuple"},{"internalType":"uint256","name":"timeStamp","type":"uint256"},{"components":[{"internalType":"uint256","name":"extraRandomization","type":"uint256"},{"internalType":"uint256","name":"stealthAddress","type":"uint256"},{"internalType":"uint256","name":"H0","type":"uint256"},{"internalType":"uint256","name":"H1","type":"uint256"}],"internalType":"struct StealthAddressStructure","name":"stealthAddressStructure","type":"tuple"},{"internalType":"uint256","name":"rootHashAccessToken","type":"uint256"},{"internalType":"uint256","name":"calldataHash","type":"uint256"},{"internalType":"uint16","name":"publicSignalCount","type":"uint16"},{"internalType":"address","name":"relay","type":"address"},{"internalType":"address","name":"externalAddress","type":"address"},{"internalType":"uint256","name":"externalActionId","type":"uint256"},{"internalType":"bytes","name":"externalActionMetadata","type":"bytes"},{"components":[{"internalType":"uint256","name":"hinkalLogicAction","type":"uint256"},{"internalType":"uint256","name":"inHinkalAddress","type":"uint256"},{"internalType":"int256[]","name":"executeApprovalChanges","type":"int256[]"},{"internalType":"bool","name":"doPreTxApproval","type":"bool"},{"components":[{"internalType":"int256[]","name":"approvalChanges","type":"int256[]"},{"internalType":"address[]","name":"externalApprovalAddresses","type":"address[]"},{"internalType":"uint256[]","name":"conversionInHinkalAddress","type":"uint256[]"}],"internalType":"struct UseApprovalUTXOData[]","name":"useApprovalUtxoData","type":"tuple[]"}],"internalType":"struct HinkalLogicArgs","name":"hinkalLogicArgs","type":"tuple"},{"components":[{"internalType":"address","name":"preHookContract","type":"address"},{"internalType":"address","name":"hookContract","type":"address"},{"internalType":"bytes","name":"preHookMetadata","type":"bytes"},{"internalType":"bytes","name":"postHookMetadata","type":"bytes"}],"internalType":"struct HookData","name":"hookData","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"accessKey","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"ethereumAddress","type":"address"}],"internalType":"struct SignatureData","name":"signatureData","type":"tuple"},{"internalType":"address","name":"originalSender","type":"address"}],"internalType":"struct CircomData","name":"circomData","type":"tuple"},{"internalType":"int256[]","name":"approvalChangesPerToken","type":"int256[]"}],"name":"inHinkalTransact","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"erc20Address","type":"address"},{"components":[{"internalType":"uint256","name":"extraRandomization","type":"uint256"},{"internalType":"uint256","name":"stealthAddress","type":"uint256"},{"internalType":"uint256","name":"H0","type":"uint256"},{"internalType":"uint256","name":"H1","type":"uint256"}],"internalType":"struct StealthAddressStructure","name":"stealthAddressStructure","type":"tuple"},{"internalType":"uint256","name":"timeStamp","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"internalType":"struct UTXO[]","name":"utxoSet","type":"tuple[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b50615b4180620000216000396000f3fe6080604052600436106100d25760003560e01c8063771838b31161007f578063b79a391f11610059578063b79a391f146102b1578063bc197c81146102de578063e8ca3dd01461030d578063f23a6e611461032d57600080fd5b8063771838b3146102155780638273f1e514610242578063a9456ea51461028f57600080fd5b806335a61a2e116100b057806335a61a2e1461019657806335e3cb89146101b6578063770473981461020257600080fd5b806301ffc9a7146100d7578063150b7a021461010c578063178d2c4714610151575b600080fd5b3480156100e357600080fd5b506100f76100f2366004613cc8565b61035a565b60405190151581526020015b60405180910390f35b34801561011857600080fd5b50610138610127366004613d5d565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610103565b34801561015d57600080fd5b5061017161016c366004613dcf565b610391565b604080516001600160a01b039094168452602084019290925290820152606001610103565b6101a96101a4366004613e3f565b6103dd565b6040516101039190613f32565b3480156101c257600080fd5b506101f46101d1366004613fca565b600160209081526000938452604080852082529284528284209052825290205481565b604051908152602001610103565b6101a9610210366004614181565b6105ba565b34801561022157600080fd5b506102356102303660046141e4565b610708565b6040516101039190614253565b34801561024e57600080fd5b506101f461025d366004613fca565b6001600160a01b0392831660009081526001602090815260408083209490951682529283528381209181529152205490565b34801561029b57600080fd5b506102af6102aa366004614266565b6108f6565b005b3480156102bd57600080fd5b506102d16102cc3660046142d1565b610c6b565b60405161010391906142ee565b3480156102ea57600080fd5b506101386102f9366004614343565b63bc197c8160e01b98975050505050505050565b34801561031957600080fd5b506101a9610328366004614181565b610d01565b34801561033957600080fd5b50610138610348366004614401565b63f23a6e6160e01b9695505050505050565b60006001600160e01b03198216630a85bd0160e11b148061038b57506001600160e01b03198216630271189760e51b145b92915050565b600060205281600052604060002081815481106103ad57600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03909116935090915083565b6060878481146104345760405162461bcd60e51b815260206004820152601a60248201527f746f6b656e496473206c656e677468206d757374206d6174636800000000000060448201526064015b60405180910390fd5b8681146104835760405162461bcd60e51b815260206004820152601960248201527f616d6f756e7473206c656e677468206d757374206d6174636800000000000000604482015260640161042b565b6000806104948c8c8c8c8c8c610eef565b915091506104a282826111da565b826001600160401b038111156104ba576104ba61401e565b6040519080825280602002602001820160405280156104f357816020015b6104e0613a7f565b8152602001906001900390816104d85790505b50935060005b838110156105aa5761057a8d8d838181106105165761051661447c565b905060200201602081019061052b91906142d1565b8c8c8481811061053d5761053d61447c565b905060200201358b8b858181106105565761055661447c565b905060200201358a8a8681811061056f5761056f61447c565b905060800201611313565b85828151811061058c5761058c61447c565b602002602001018190525080806105a2906144a8565b9150506104f9565b5050505098975050505050505050565b606034156106305760405162461bcd60e51b815260206004820152602e60248201527f6d73672e76616c7565206e6f6e20616c6c6f77656420666f7220696e48696e6b60448201527f616c5472616e73616374696f6e73000000000000000000000000000000000000606482015260840161042b565b61063e6103008401846144c1565b3560010361067b5761067661065b6102a0850161028086016142d1565b61014085018035906106719061012088016142d1565b611364565b61038b565b6106896103008401846144c1565b3560020361069a576106768361138c565b6106a86103008401846144c1565b356003036106c0576106b98361189e565b905061038b565b60405162461bcd60e51b815260206004820152601960248201527f556e6b6e6f776e2048696e6b616c4c6f676963416374696f6e00000000000000604482015260640161042b565b606061071760208301836144e1565b90506001600160401b038111156107305761073061401e565b604051908082528060200260200182016040528015610759578160200160208202803683370190505b50905060005b61076c60208401846144e1565b90508110156108f0576000806107866103008601866144c1565b6107949060808101906144e1565b848181106107a4576107a461447c565b90506020028101906107b6919061452a565b6107bf90614637565b905060005b8160200151518110156108bb576000826020015182815181106107e9576107e961447c565b6020026020010151905060008360000151838151811061080b5761080b61447c565b6020026020010151905060006001600160a01b0316826001600160a01b03161480610834575080155b156108405750506108a9565b61084a8186614643565b94506108a68261085d60208b018b6144e1565b8981811061086d5761086d61447c565b905060200201602081019061088291906142d1565b866040015186815181106108985761089861447c565b602002602001015184611d37565b50505b806108b3816144a8565b9150506107c4565b50818484815181106108cf576108cf61447c565b602002602001018181525050505080806108e8906144a8565b91505061075f565b50919050565b82811461096b5760405162461bcd60e51b815260206004820152602e60248201527f616464726573737320616e6420696e6465786573206c656e6774682073686f7560448201527f6c64206265207468652073616d65000000000000000000000000000000000000606482015260840161042b565b60005b83811015610c6457600080600087878581811061098d5761098d61447c565b90506020020160208101906109a291906142d1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060005b8484848181106109d9576109d961447c565b90506020028101906109eb91906144e1565b9050811015610c4f57600082868686818110610a0957610a0961447c565b9050602002810190610a1b91906144e1565b84818110610a2b57610a2b61447c565b9050602002013581548110610a4257610a4261447c565b600091825260209091206003909102018054600282015460018301549293506001600160a01b0390911691610ab1868a8a8a818110610a8357610a8361447c565b9050602002810190610a9591906144e1565b88818110610aa557610aa561447c565b90506020020135611f69565b610af3838c8c8a818110610ac757610ac761447c565b9050602002016020810190610adc91906142d1565b610ae5846120e0565b610aee9061466b565b61214e565b6000600160008d8d8b818110610b0b57610b0b61447c565b9050602002016020810190610b2091906142d1565b6001600160a01b0390811682526020808301939093526040918201600090812091881681529083528181208682529092529020549050610b608282614687565b600160008e8e8c818110610b7657610b7661447c565b9050602002016020810190610b8b91906142d1565b6001600160a01b0390811682526020808301939093526040918201600090812091891681529083528181208782529092529020557f506e8439bc3a70b2c92f847e3c33b5029f2d99a565f3d2e483d3b5006f3963208c8c8a818110610bf257610bf261447c565b9050602002016020810190610c0791906142d1565b604080516001600160a01b039283168152918716602083015281018490526060810185905260800160405180910390a150505050508080610c47906144a8565b9150506109c7565b50508080610c5c906144a8565b91505061096e565b5050505050565b6001600160a01b038116600090815260208181526040808320805482518185028101850190935280835260609492939192909184015b82821015610cf6576000848152602090819020604080516060810182526003860290920180546001600160a01b0316835260018082015484860152600290910154918301919091529083529092019101610ca1565b505050509050919050565b60606000610d1260208501856144e1565b90506001600160401b03811115610d2b57610d2b61401e565b604051908082528060200260200182016040528015610d54578160200160208202803683370190505b50905060005b610d6760208601866144e1565b9050811015610e6057610d7b858583612205565b828281518110610d8d57610d8d61447c565b6020026020010181815250506000828281518110610dad57610dad61447c565b60200260200101511215610e4e57610e4e610dcb60208701876144e1565b83818110610ddb57610ddb61447c565b9050602002016020810190610df091906142d1565b610e026102c088016102a089016142d1565b848481518110610e1457610e1461447c565b6020026020010151610e259061466b565b610e3260408a018a6144e1565b86818110610e4257610e4261447c565b90506020020135612290565b80610e58816144a8565b915050610d5a565b50610e736102c085016102a086016142d1565b6001600160a01b0316633ce428c885836040518363ffffffff1660e01b8152600401610ea0929190614bb6565b6000604051808303816000875af1158015610ebf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ee79190810190614ea4565b949350505050565b60606000866001600160401b03811115610f0b57610f0b61401e565b604051908082528060200260200182016040528015610f6957816020015b610f56604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b815260200190600190039081610f295790505b50915060005b878110156111ce576000805b8381101561110f578a8a84818110610f9557610f9561447c565b9050602002016020810190610faa91906142d1565b6001600160a01b0316858281518110610fc557610fc561447c565b6020026020010151600001516001600160a01b031614801561101b5750868684818110610ff457610ff461447c565b9050602002013585828151811061100d5761100d61447c565b602002602001015160400151145b156110fd578686848181106110325761103261447c565b905060200201356000146110ae5760405162461bcd60e51b815260206004820152602e60248201527f796f752063616e6e6f742073656e642074776f204e465473207769746820746860448201527f652073616d6520746f6b656e4964000000000000000000000000000000000000606482015260840161042b565b8888848181106110c0576110c061447c565b905060200201358582815181106110d9576110d961447c565b60200260200101516020018181516110f19190614687565b9052506001915061110f565b80611107816144a8565b915050610f7b565b50806111bb5760405180606001604052808b8b858181106111325761113261447c565b905060200201602081019061114791906142d1565b6001600160a01b031681526020018989858181106111675761116761447c565b9050602002013581526020018787858181106111855761118561447c565b905060200201358152508484815181106111a1576111a161447c565b602002602001018190525082806111b7906144a8565b9350505b50806111c6816144a8565b915050610f6f565b50965096945050505050565b60005b8181101561130e5760008382815181106111f9576111f961447c565b6020026020010151600001519050600084838151811061121b5761121b61447c565b6020026020010151602001519050600085848151811061123d5761123d61447c565b60200260200101516040015190506000611256846122ba565b90506001600160a01b038416611273576112703482614fb3565b90505b6112808433308686612347565b600061128b856122ba565b9050836112988383614fb3565b146112f65760405162461bcd60e51b815260206004820152602860248201527f70726f6f666c657373206465706f7369742062616c616e636573206d75737420604482015267189948195c5d585b60c21b606482015260840161042b565b50505050508080611306906144a8565b9150506111dd565b505050565b61131b613a7f565b6040805160a0810182528581526001600160a01b0387166020820152600091810161134b3686900386018661500a565b8152426020820152604001859052915050949350505050565b6001600160a01b0383161580159061137c5750600082115b1561130e5761130e81848461236c565b600061139c6102e0830183615026565b8101906113a9919061506c565b905060006113bb6103008401846144c1565b60200135905081518380602001906113d391906144e1565b9050146114225760405162461bcd60e51b815260206004820152601860248201527f72656c6561736546726f6d42756666657220636865636b310000000000000000604482015260640161042b565b6000611436610140850161012086016142d1565b905061014084013561145a6114536102a0870161028088016142d1565b8284611364565b60005b61146a60208701876144e1565b905081101561189657600061148260208801886144e1565b838181106114925761149261447c565b90506020020160208101906114a791906142d1565b90506000805b8784815181106114bf576114bf61447c565b6020026020010151518110156116be576000600160008a87815181106114e7576114e761447c565b602002602001015184815181106115005761150061447c565b6020908102919091018101516001600160a01b039081168352828201939093526040918201600090812093881681529281528183208b845290529020549050806115a25760405162461bcd60e51b815260206004820152602d60248201527f68696e6b616c2062756666657220616d6f756e742073686f756c64206265206d60448201526c6f7265207468616e207a65726f60981b606482015260840161042b565b6115ac8184614687565b92506000600160008b88815181106115c6576115c661447c565b602002602001015185815181106115df576115df61447c565b6020908102919091018101516001600160a01b039081168352828201939093526040918201600090812093891681529281528183208c8452905290205588517f81ddad81ae937bc7486520a362bb81233e5dfe4afed88648c231dbb92e217d22908a90879081106116525761165261447c565b6020026020010151838151811061166b5761166b61447c565b6020026020010151858a6040516116a3939291906001600160a01b039384168152919092166020820152604081019190915260600190565b60405180910390a150806116b6816144a8565b9150506114ad565b506116cd6103008901896144c1565b6116db9060408101906144e1565b848181106116eb576116eb61447c565b905060200201356116fb9061466b565b611704826120e0565b146117775760405162461bcd60e51b815260206004820152602f60248201527f746f74616c206275666665722073686f756c6420657175616c20746f20746f7460448201527f616c20646973616c6c6f77616e63650000000000000000000000000000000000606482015260840161042b565b816001600160a01b0316856001600160a01b031614611797576000611799565b835b6117a660808a018a6144e1565b858181106117b6576117b661447c565b90506020020160208101906117cb919061511c565b6117f8576117dc60608a018a6144e1565b858181106117ec576117ec61447c565b905060200201356117fb565b60005b6118059190614643565b61180e826120e0565b146118815760405162461bcd60e51b815260206004820152603660248201527f746f74616c2062756666657220616d6f756e742073686f756c6420626520657160448201527f75616c20746f20617070726f76616c4368616e67657300000000000000000000606482015260840161042b565b5050808061188e906144a8565b91505061145d565b505050505050565b60606118a8613ae0565b341561191c5760405162461bcd60e51b815260206004820152602f60248201527f6469726563742063616c6c207769746820706f736974697665206d73672e766160448201527f6c7565206e6f7420616c6c6f7765640000000000000000000000000000000000606482015260840161042b565b6000806119288561238f565b915091506000611938838361286a565b9050611943866155f1565b845261198c61195560208801886144e1565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506129fd92505050565b6020808601919091526119bc906119a5908801886144e1565b6119b76102c08a016102a08b016142d1565b612a0a565b60608501526119ca86612bb6565b6000611a176119dd6102e0890189615026565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d2f92505050565b90506000805b611a2a60208a018a6144e1565b9050811015611b7a576000611a4260208b018b6144e1565b83818110611a5257611a5261447c565b9050602002016020810190611a6791906142d1565b6001600160a01b0316148015611aac5750611a8560808a018a6144e1565b82818110611a9557611a9561447c565b9050602002016020810190611aaa919061511c565b155b15611b68576000611ac060608b018b6144e1565b83818110611ad057611ad061447c565b905060200201351215611b6857611aea60608a018a6144e1565b82818110611afa57611afa61447c565b90506020020135611b0a9061466b565b91506000611b206102a08b016102808c016142d1565b6001600160a01b031614158015611b5157506000611b466101408b016101208c016142d1565b6001600160a01b0316145b15611b6857611b656101408a013583614fb3565b91505b80611b72816144a8565b915050611a1d565b50600080611b906102c08b016102a08c016142d1565b6001600160a01b0316838560600151604051611bac919061589d565b60006040518083038185875af1925050503d8060008114611be9576040519150601f19603f3d011682016040523d82523d6000602084013e611bee565b606091505b509150915081611c5057805115611c085780518082602001fd5b60405162461bcd60e51b815260206004820152601c60248201527f48696e6b616c3a2045787465726e616c2063616c6c206661696c656400000000604482015260640161042b565b611c7b611c656102a08c016102808d016142d1565b6101408c01803590610671906101208f016142d1565b611c8b61195560208c018c6144e1565b6040890152611cb2611ca060208c018c6144e1565b6119b76102c08e016102a08f016142d1565b60808901526000611cc3888861286a565b90506000611cd08a612d93565b9050611cdc878361307d565b611d285760405162461bcd60e51b815260206004820152601560248201527f61727261792773206d75737420626520657175616c0000000000000000000000604482015260640161042b565b9b9a5050505050505050505050565b6001600160a01b0384166000908152602081905260408120815b8154811015611e09576000828281548110611d6e57611d6e61447c565b90600052602060002090600302019050858160020154141580611d9e575080546001600160a01b03888116911614155b15611da95750611df7565b6000611dcb86611dbc84600101546120e0565b611dc69190614643565b6130fb565b905080600003611de457611ddf8484611f69565b611dec565b600182018190555b600194505050611e09565b80611e01816144a8565b915050611d51565b508180611e17575060008312155b611e975760405162461bcd60e51b815260206004820152604560248201527f6966207468657265206973206e6f207574786f20696e2061727261792c20746860448201527f656e20617070726f76616c206368616e67652063616e6e6f74206265206e6567606482015264617469766560d81b608482015260a40161042b565b81611f0457604080516060810182526001600160a01b03878116825260208083018781529383018881528554600180820188556000888152939093209451600390910290940180546001600160a01b03191694909316939093178255925192810192909255516002909101555b611f0f85878561214e565b604080516001600160a01b03808916825287166020820152908101849052606081018590527f5f5a1f32b36d48221c71fb0a2426912b82ec0140a32c2e57a27cf2590093b1039060800160405180910390a1505050505050565b8154808210611fc65760405162461bcd60e51b8152602060048201526024808201527f72656d6f7665417070726f76616c20696e646578206973206f7574206f662072604482015263616e676560e01b606482015260840161042b565b611fd1600182614fb3565b82146120565782611fe3600183614fb3565b81548110611ff357611ff361447c565b90600052602060002090600302018383815481106120135761201361447c565b60009182526020909120825460039092020180546001600160a01b0319166001600160a01b03909216919091178155600180830154908201556002918201549101555b82612062600183614fb3565b815481106120725761207261447c565b60009182526020822060039091020180546001600160a01b0319168155600181018290556002015582548390806120ab576120ab6158af565b60008281526020812060036000199093019283020180546001600160a01b031916815560018101829055600201559055505050565b60006001600160ff1b0382111561214a5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b606482015260840161042b565b5090565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801561219e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c291906158c5565b905060008083136121e5576121d68361466b565b6121e09083614fb3565b6121ef565b6121ef8383614687565b9050610c646001600160a01b038616858361314d565b60008282815181106122195761221961447c565b602002602001015184806080019061223191906144e1565b848181106122415761224161447c565b9050602002016020810190612256919061511c565b6122835761226760608601866144e1565b848181106122775761227761447c565b90506020020135612286565b60005b610ee79190614643565b806000036122a8576122a384848461236c565b6122b4565b6122b48430858461320f565b50505050565b60006001600160a01b0382166122d1575047919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015612317573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061233b91906158c5565b9392505050565b919050565b806000036123605761235b8585858561327f565b610c64565b610c648585858461320f565b6001600160a01b0383166123845761130e8282613310565b61130e8383836133b3565b606060008080806123a86102c087016102a088016142d1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060008480602001906123dc91906144e1565b90506001600160401b038111156123f5576123f561401e565b60405190808252806020026020018201604052801561241e578160200160208202803683370190505b50825490915060009061243b90612436906001614687565b6133c7565b835490915060005b818112156126a957600081905060008682815481106124645761246461447c565b906000526020600020906003020190506000808b806020019061248791906144e1565b9050905060005b81811015612676576124a360208e018e6144e1565b828181106124b3576124b361447c565b90506020020160208101906124c891906142d1565b84546001600160a01b0391821691160361266457600192506124ee6103008e018e6144c1565b6020013584600201540361265f5760018982815181106125105761251061447c565b9115156020928302919091019091015260006125306103008f018f6144c1565b61253e9060408101906144e1565b8381811061254e5761254e61447c565b90506020020135121561265f57600061256b6103008f018f6144c1565b6125799060408101906144e1565b838181106125895761258961447c565b9050602002013561259d86600101546120e0565b6125a79190614643565b905060008112156126205760405162461bcd60e51b815260206004820152603d60248201527f48696e6b616c3a20596f752073686f756c64207370656e642065786163746c7960448201527f207468652073616d6520616d6f756e7420796f7520617070726f766564000000606482015260840161042b565b612629816130fb565b6001860155600081900361265d576126418b87611f69565b8661264b816158de565b9750508780612659906158de565b9850505b505b612676565b8061266e816144a8565b91505061248e565b50816126925782546126929088906001600160a01b031661344c565b5050505080806126a1906158fb565b915050612443565b5060005b8351811015612781578381815181106126c8576126c861447c565b60200260200101511515600015150361276f576126e96103008901896144c1565b6126f79060408101906144e1565b828181106127075761270761447c565b9050602002013560001461276f5760405162461bcd60e51b815260206004820152602960248201527f796f752063616e6e6f74207370656e6420736f6d657468696e6720796f75206460448201526837903737ba1037bbb760b91b606482015260840161042b565b80612779816144a8565b9150506126ad565b5061279c6127976102c089016102a08a016142d1565b6134f7565b15612855576000805b6127b260208a018a6144e1565b9050811015612831576127cd6102c08a016102a08b016142d1565b6001600160a01b03166127e360208b018b6144e1565b838181106127f3576127f361447c565b905060200201602081019061280891906142d1565b6001600160a01b03160361281f5760019150612831565b80612829816144a8565b9150506127a5565b50806128535761285361284c6102c08a016102a08b016142d1565b849061344c565b505b50805160209091015190969095509350505050565b6060816001600160401b038111156128845761288461401e565b6040519080825280602002602001820160405280156128ad578160200160208202803683370190505b50905060005b82816001600160401b031610156129f65760006001600160a01b031684826001600160401b0316815181106128ea576128ea61447c565b60200260200101516001600160a01b03160361292d574782826001600160401b03168151811061291c5761291c61447c565b6020026020010181815250506129e4565b83816001600160401b0316815181106129485761294861447c565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015612998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129bc91906158c5565b82826001600160401b0316815181106129d7576129d761447c565b6020026020010181815250505b806129ee81615913565b9150506128b3565b5092915050565b606061038b82835161286a565b6060826001600160401b03811115612a2457612a2461401e565b604051908082528060200260200182016040528015612a4d578160200160208202803683370190505b50905060005b6001600160401b038116841115612bae57600085856001600160401b038416818110612a8157612a8161447c565b9050602002016020810190612a9691906142d1565b6001600160a01b031603612ad257600082826001600160401b031681518110612ac157612ac161447c565b602002602001018181525050612b9c565b8484826001600160401b0316818110612aed57612aed61447c565b9050602002016020810190612b0291906142d1565b604051636eb1769f60e11b81523060048201526001600160a01b038581166024830152919091169063dd62ed3e90604401602060405180830381865afa158015612b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b7491906158c5565b82826001600160401b031681518110612b8f57612b8f61447c565b6020026020010181815250505b80612ba681615913565b915050612a53565b509392505050565b612bcb6127976102c083016102a084016142d1565b612bd25750565b6000612be26102e0830183615026565b612beb91615939565b6040805161018081018252633950935160e01b815263a457c2d760e01b602082015263095ea7b360e01b918101919091526340c10f1960e01b6060820152630852cd8d60e31b60808201526323b872dd60e01b60a082015263959b8c3f60e01b60c0820152637d6c599560e11b60e0820152633177029f60e01b61010082015263363efa6560e21b61012082015263cae9ca5160e01b61014082015263c1d34b8960e01b61016082015290915060005b600c8110156122b4578181600c8110612cb657612cb661447c565b60200201516001600160e01b031916836001600160e01b03191603612d1d5760405162461bcd60e51b815260206004820152601460248201527f626c61636b6c69737465642073656c6563746f72000000000000000000000000604482015260640161042b565b80612d27816144a8565b915050612c9b565b612d5a6040518060800160405280606081526020016000815260200160608152602001606081525090565b60008060008085806020019051810190612d7491906159ac565b9288526020880191909152604087015260608601525092949350505050565b6060612db0826000015160200151836020015184604001516135a6565b90506000805b835160200151518110156130765760008460000151602001518281518110612de057612de061447c565b602002602001015190506000612e1286602001518481518110612e0557612e0561447c565b60200260200101516120e0565b612e2b87604001518581518110612e0557612e0561447c565b612e359190615a9b565b90506000612e5287606001518581518110612e0557612e0561447c565b612e6b88608001518681518110612e0557612e0561447c565b612e759190615a9b565b90506000821315612eea576040805160a0810182528381526001600160a01b03851660208201528851610160015191810191909152875161014001516060820152600060808201528686612ec8816144a8565b975081518110612eda57612eda61447c565b6020026020010181905250612fa1565b6000821215612fa1576001600160a01b03831615612fa15786516101200151516000906001600160a01b03858116911614612f26576000612f3a565b8751610120015160200151612f3a906120e0565b905081612f478285614643565b14612f9f5760405162461bcd60e51b815260206004820152602260248201527f62616c616e636520616e6420616c6c6f77616e636520446966206d69736d61746044820152610c6d60f31b606482015260840161042b565b505b600087600001516102600151604001518581518110612fc257612fc261447c565b6020026020010151905060008183612fda9190615a9b565b90508015612ff85788516102000151612ff8908690610aee8461466b565b885161020081015161026090910151602090810151604080516001600160a01b039485168152938916928401929092528282018590526060830152517f5f5a1f32b36d48221c71fb0a2426912b82ec0140a32c2e57a27cf2590093b1039181900360800190a15050505050808061306e906144a8565b915050612db6565b5050919050565b600081518351146130905750600061038b565b60005b83518110156130f1578281815181106130ae576130ae61447c565b60200260200101518482815181106130c8576130c861447c565b6020026020010151146130df57600091505061038b565b806130e9816144a8565b915050613093565b5060019392505050565b60008082121561214a5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015260640161042b565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261319e848261368e565b6122b4576040516001600160a01b03841660248201526000604482015261320590859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613735565b6122b48482613735565b604051632142170760e11b81526001600160a01b0384811660048301528381166024830152604482018390528516906342842e0e90606401600060405180830381600087803b15801561326157600080fd5b505af1158015613275573d6000803e3d6000fd5b5050505050505050565b6001600160a01b038416613304578034146132ea5760405162461bcd60e51b815260206004820152602560248201527f6d73672e76616c756520646f65736e2774206d61746368206e656564656420616044820152641b5bdd5b9d60da1b606482015260840161042b565b6001600160a01b03821630146122a3576122a38282613310565b6122b48484848461380a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461335d576040519150601f19603f3d011682016040523d82523d6000602084013e613362565b606091505b505090508061130e5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572204661696c65640000000000000000000000000000000000604482015260640161042b565b61130e6001600160a01b038416838361381f565b6133eb60405180606001604052806060815260200160008152602001600081525090565b6040518060600160405280836001600160401b0381111561340e5761340e61401e565b604051908082528060200260200182016040528015613437578160200160208202803683370190505b50815260006020820152604001929092525090565b613456828261384f565b1561345f575050565b8151602083018051839291613473826144a8565b9052815181106134855761348561447c565b6001600160a01b0390921660209283029190910182015260408301519083015111156134f35760405162461bcd60e51b815260206004820152601560248201527f536574204d61784c656e67746820526561636865640000000000000000000000604482015260640161042b565b5050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b1790529051600091829182916001600160a01b0386169161354e919061589d565b600060405180830381855afa9150503d8060008114613589576040519150601f19603f3d011682016040523d82523d6000602084013e61358e565b606091505b5091509150818015610ee75750516020149392505050565b60606000805b8551816001600160401b031610156136325760006135de86836001600160401b031681518110612e0557612e0561447c565b6135fc86846001600160401b031681518110612e0557612e0561447c565b6136069190615a9b565b9050600081131561361f578261361b816144a8565b9350505b508061362a81615913565b9150506135ac565b50806001600160401b0381111561364b5761364b61401e565b60405190808252806020026020018201604052801561368457816020015b613671613a7f565b8152602001906001900390816136695790505b5095945050505050565b6000806000846001600160a01b0316846040516136ab919061589d565b6000604051808303816000865af19150503d80600081146136e8576040519150601f19603f3d011682016040523d82523d6000602084013e6136ed565b606091505b50915091508180156137175750805115806137175750808060200190518101906137179190615abb565b801561372c57506001600160a01b0385163b15155b95945050505050565b600061378a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166138bf9092919063ffffffff16565b90508051600014806137ab5750808060200190518101906137ab9190615abb565b61130e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161042b565b6122b46001600160a01b0385168484846138ce565b6040516001600160a01b03831660248201526044810182905261130e90849063a9059cbb60e01b906064016131ce565b6020820151600090815b818110156138b457836001600160a01b0316856000015182815181106138815761388161447c565b60200260200101516001600160a01b0316036138a25760019250505061038b565b806138ac816144a8565b915050613859565b506000949350505050565b6060610ee78484600085613906565b6040516001600160a01b03808516602483015283166044820152606481018290526122b49085906323b872dd60e01b906084016131ce565b6060824710156139675760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161042b565b600080866001600160a01b03168587604051613983919061589d565b60006040518083038185875af1925050503d80600081146139c0576040519150601f19603f3d011682016040523d82523d6000602084013e6139c5565b606091505b50915091506139d6878383876139e1565b979650505050505050565b60608315613a50578251600003613a49576001600160a01b0385163b613a495760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161042b565b5081610ee7565b610ee78383815115613a655781518083602001fd5b8060405162461bcd60e51b815260040161042b9190615ad8565b6040518060a001604052806000815260200160006001600160a01b03168152602001613acc6040518060800160405280600081526020016000815260200160008152602001600081525090565b815260200160008152602001600081525090565b6040518060a00160405280613af3613b15565b8152602001606081526020016060815260200160608152602001606081525090565b604051806102e00160405280600081526020016060815260200160608152602001606081526020016060815260200160608152602001606081526020016060815260200160608152602001613b8d604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b815260200160008152602001613bc46040518060800160405280600081526020016000815260200160008152602001600081525090565b81526020016000815260200160008152602001600061ffff16815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160608152602001613c446040518060a00160405280600081526020016000815260200160608152602001600015158152602001606081525090565b8152602001613c86604051806080016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001606081525090565b81526040805160c08101825260008082526020828101829052928201819052606082018190526080820181905260a08201529101908152600060209091015290565b600060208284031215613cda57600080fd5b81356001600160e01b03198116811461233b57600080fd5b6001600160a01b0381168114613d0757600080fd5b50565b803561234281613cf2565b60008083601f840112613d2757600080fd5b5081356001600160401b03811115613d3e57600080fd5b602083019150836020828501011115613d5657600080fd5b9250929050565b600080600080600060808688031215613d7557600080fd5b8535613d8081613cf2565b94506020860135613d9081613cf2565b93506040860135925060608601356001600160401b03811115613db257600080fd5b613dbe88828901613d15565b969995985093965092949392505050565b60008060408385031215613de257600080fd5b8235613ded81613cf2565b946020939093013593505050565b60008083601f840112613e0d57600080fd5b5081356001600160401b03811115613e2457600080fd5b6020830191508360208260051b8501011115613d5657600080fd5b6000806000806000806000806080898b031215613e5b57600080fd5b88356001600160401b0380821115613e7257600080fd5b613e7e8c838d01613dfb565b909a50985060208b0135915080821115613e9757600080fd5b613ea38c838d01613dfb565b909850965060408b0135915080821115613ebc57600080fd5b613ec88c838d01613dfb565b909650945060608b0135915080821115613ee157600080fd5b818b0191508b601f830112613ef557600080fd5b813581811115613f0457600080fd5b8c60208260071b8501011115613f1957600080fd5b6020830194508093505050509295985092959890939650565b602080825282518282018190526000919060409081850190868401855b82811015613fbd57815180518552868101516001600160a01b0316878601528581015180518787015280880151606080880191909152818801516080808901919091529181015160a088015282015160c0870152015160e08501526101009093019290850190600101613f4f565b5091979650505050505050565b600080600060608486031215613fdf57600080fd5b8335613fea81613cf2565b92506020840135613ffa81613cf2565b929592945050506040919091013590565b600061042082840312156108f057600080fd5b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156140565761405661401e565b60405290565b60405160a081016001600160401b03811182821017156140565761405661401e565b604051608081016001600160401b03811182821017156140565761405661401e565b6040516102e081016001600160401b03811182821017156140565761405661401e565b604051601f8201601f191681016001600160401b03811182821017156140eb576140eb61401e565b604052919050565b60006001600160401b0382111561410c5761410c61401e565b5060051b60200190565b600082601f83011261412757600080fd5b8135602061413c614137836140f3565b6140c3565b82815260059290921b8401810191818101908684111561415b57600080fd5b8286015b84811015614176578035835291830191830161415f565b509695505050505050565b6000806040838503121561419457600080fd5b82356001600160401b03808211156141ab57600080fd5b6141b78683870161400b565b935060208501359150808211156141cd57600080fd5b506141da85828601614116565b9150509250929050565b6000602082840312156141f657600080fd5b81356001600160401b0381111561420c57600080fd5b610ee78482850161400b565b600081518084526020808501945080840160005b838110156142485781518752958201959082019060010161422c565b509495945050505050565b60208152600061233b6020830184614218565b6000806000806040858703121561427c57600080fd5b84356001600160401b038082111561429357600080fd5b61429f88838901613dfb565b909650945060208701359150808211156142b857600080fd5b506142c587828801613dfb565b95989497509550505050565b6000602082840312156142e357600080fd5b813561233b81613cf2565b602080825282518282018190526000919060409081850190868401855b82811015613fbd57815180516001600160a01b031685528681015187860152850151858501526060909301929085019060010161430b565b60008060008060008060008060a0898b03121561435f57600080fd5b883561436a81613cf2565b9750602089013561437a81613cf2565b965060408901356001600160401b038082111561439657600080fd5b6143a28c838d01613dfb565b909850965060608b01359150808211156143bb57600080fd5b6143c78c838d01613dfb565b909650945060808b01359150808211156143e057600080fd5b506143ed8b828c01613d15565b999c989b5096995094979396929594505050565b60008060008060008060a0878903121561441a57600080fd5b863561442581613cf2565b9550602087013561443581613cf2565b9450604087013593506060870135925060808701356001600160401b0381111561445e57600080fd5b61446a89828a01613d15565b979a9699509497509295939492505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016144ba576144ba614492565b5060010190565b60008235609e198336030181126144d757600080fd5b9190910192915050565b6000808335601e198436030181126144f857600080fd5b8301803591506001600160401b0382111561451257600080fd5b6020019150600581901b3603821315613d5657600080fd5b60008235605e198336030181126144d757600080fd5b600082601f83011261455157600080fd5b81356020614561614137836140f3565b82815260059290921b8401810191818101908684111561458057600080fd5b8286015b8481101561417657803561459781613cf2565b8352918301918301614584565b6000606082840312156145b657600080fd5b6145be614034565b905081356001600160401b03808211156145d757600080fd5b6145e385838601614116565b835260208401359150808211156145f957600080fd5b61460585838601614540565b6020840152604084013591508082111561461e57600080fd5b5061462b84828501614116565b60408301525092915050565b600061038b36836145a4565b808201828112600083128015821682158216171561466357614663614492565b505092915050565b6000600160ff1b820161468057614680614492565b5060000390565b8082018082111561038b5761038b614492565b6000808335601e198436030181126146b157600080fd5b83016020810192503590506001600160401b038111156146d057600080fd5b8060051b3603821315613d5657600080fd5b8183526000602080850194508260005b8581101561424857813561470581613cf2565b6001600160a01b0316875295820195908201906001016146f2565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561475257600080fd5b8260051b80836020870137939093016020019392505050565b8183526000602080850194508260005b858110156142485781358752958201959082019060010161477b565b8015158114613d0757600080fd5b8183526000602080850194508260005b858110156142485781356147c881614797565b1515875295820195908201906001016147b5565b81835260006020808501808196508560051b810191508460005b87811015613fbd57828403895261480d828861469a565b614818868284614720565b9a87019a95505050908401906001016147f6565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261486c57600080fd5b83016020810192503590506001600160401b0381111561488b57600080fd5b803603821315613d5657600080fd5b81835260006020808501808196506005915085821b8101856000805b8981101561492e578484038b526148cd838a61469a565b80865288860181891b87018a0183865b8481101561491757898303601f190184526148f88287614855565b61490385828461482c565b958f019594505050908c01906001016148dd565b50509d8a019d9650505092870192506001016148b6565b50919998505050505050505050565b803561494881613cf2565b6001600160a01b0316825260208181013590830152604090810135910152565b803561ffff8116811461234257600080fd5b60008235609e1983360301811261499057600080fd5b90910192915050565b8035825260006020808301358185015260406149b78185018561469a565b60a0838801526149cb60a08801828461476b565b9150506060808601356149dd81614797565b1515878201526149f0608087018761469a565b88840360808a0152808452858401600582901b85018701836000805b85811015614aa757888403601f19018552823536889003605e19018112614a31578283fd5b8701614a3d818061469a565b8a8752614a4d8b8801828461476b565b915050614a5c8d83018361469a565b8783038f890152614a6e8382846146e2565b92505050614a7e8c83018361469a565b92508682038d880152614a92828483614720565b978e019796505050928b019250600101614a0c565b50919c9b505050505050505050505050565b60008235607e1983360301811261499057600080fd5b60008135614adc81613cf2565b6001600160a01b039081168452602083013590614af882613cf2565b166020840152614b0b6040830183614855565b60806040860152614b2060808601828461482c565b915050614b306060840184614855565b8583036060870152614b4383828461482c565b9695505050505050565b803560ff8116811461234257600080fd5b60ff614b6982614b4d565b1682526020810135602083015260408101356040830152606081013560608301526080810135608083015260a0810135614ba281613cf2565b6001600160a01b03811660a0840152505050565b60408152823560408201526000614bd0602085018561469a565b6104206060850152614be7610460850182846146e2565b915050614bf7604086018661469a565b603f1980868503016080870152614c0f848385614720565b9350614c1e606089018961469a565b93509150808685030160a0870152614c3784848461476b565b9350614c46608089018961469a565b93509150808685030160c0870152614c5f8484846147a5565b9350614c6e60a089018961469a565b93509150808685030160e0870152614c8784848461476b565b9350614c9660c089018961469a565b93509150610100818786030181880152614cb18585856147dc565b9450614cc060e08a018a61469a565b94509250610120828887030181890152614cdb8686866147dc565b9550614ce9828b018b61469a565b955093508288870301610140890152614d0386868661489a565b9550614d156101608901828c0161493d565b50506101808801356101c0870152614d566101e087016101a08a01803582526020810135602083015260408101356040830152606081013560608301525050565b610260925061022088013583870152610280915061024088013582870152614d7f838901614968565b92506102a0614d938188018561ffff169052565b614d9e838a01613d0a565b93506102c09250614db9838801856001600160a01b03169052565b614dc4818a01613d0a565b9350506102e0614dde818801856001600160a01b03169052565b61030093508289013584880152614df7818a018a614855565b93509050610320828887030181890152614e1286858461482c565b9550614e20858b018b61497a565b94506103409350828887030184890152614e3a8686614999565b9550614e48818b018b614ab9565b94505050808685030161036087015250614e628383614acf565b9250614e746103808601828901614b5e565b5050614e836104008601613d0a565b6001600160a01b0316610440840152828103602084015261372c8185614218565b60006020808385031215614eb757600080fd5b82516001600160401b03811115614ecd57600080fd5b8301601f81018513614ede57600080fd5b8051614eec614137826140f3565b81815260089190911b82018301908381019087831115614f0b57600080fd5b928401925b828410156139d657838803610100811215614f2b5760008081fd5b614f3361405c565b8551815286860151614f4481613cf2565b8188015260406080603f198401811315614f5e5760008081fd5b614f6661407e565b8883015181526060808a01518b830152828a01518483015260a08a0151818301529284015260c08801519183019190915260e0870151908201528352506101009093019290840190614f10565b8181038181111561038b5761038b614492565b600060808284031215614fd857600080fd5b614fe061407e565b90508135815260208201356020820152604082013560408201526060820135606082015292915050565b60006080828403121561501c57600080fd5b61233b8383614fc6565b6000808335601e1984360301811261503d57600080fd5b8301803591506001600160401b0382111561505757600080fd5b602001915036819003821315613d5657600080fd5b6000602080838503121561507f57600080fd5b82356001600160401b038082111561509657600080fd5b818501915085601f8301126150aa57600080fd5b81356150b8614137826140f3565b81815260059190911b830184019084810190888311156150d757600080fd5b8585015b8381101561510f578035858111156150f35760008081fd5b6151018b89838a0101614540565b8452509186019186016150db565b5098975050505050505050565b60006020828403121561512e57600080fd5b813561233b81614797565b600082601f83011261514a57600080fd5b8135602061515a614137836140f3565b82815260059290921b8401810191818101908684111561517957600080fd5b8286015b8481101561417657803561519081614797565b835291830191830161517d565b600082601f8301126151ae57600080fd5b813560206151be614137836140f3565b82815260059290921b840181019181810190868411156151dd57600080fd5b8286015b848110156141765780356001600160401b038111156152005760008081fd5b61520e8986838b0101614116565b8452509183019183016151e1565b60006001600160401b038211156152355761523561401e565b50601f01601f191660200190565b600082601f83011261525457600080fd5b81356152626141378261521c565b81815284602083860101111561527757600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126152a557600080fd5b813560206152b5614137836140f3565b82815260059290921b840181019181810190868411156152d457600080fd5b8286015b848110156141765780356001600160401b03808211156152f757600080fd5b818901915089603f83011261530b57600080fd5b8582013561531b614137826140f3565b81815260059190911b830160400190878101908c83111561533b57600080fd5b604085015b838110156153745780358581111561535757600080fd5b6153668f6040838a0101615243565b845250918901918901615340565b508752505050928401925083016152d8565b60006060828403121561539857600080fd5b6153a0614034565b905081356153ad81613cf2565b80825250602082013560208201526040820135604082015292915050565b600060a082840312156153dd57600080fd5b6153e561405c565b9050813581526020808301358183015260408301356001600160401b038082111561540f57600080fd5b61541b86838701614116565b60408501526060850135915061543082614797565b816060850152608085013591508082111561544a57600080fd5b818501915085601f83011261545e57600080fd5b813561546c614137826140f3565b81815260059190911b8301840190848101908883111561548b57600080fd5b8585015b838110156154c3578035858111156154a75760008081fd5b6154b58b89838a01016145a4565b84525091860191860161548f565b50608087015250939695505050505050565b6000608082840312156154e757600080fd5b6154ef61407e565b905081356154fc81613cf2565b8152602082013561550c81613cf2565b602082015260408201356001600160401b038082111561552b57600080fd5b61553785838601615243565b6040840152606084013591508082111561555057600080fd5b5061555d84828501615243565b60608301525092915050565b600060c0828403121561557b57600080fd5b60405160c081018181106001600160401b038211171561559d5761559d61401e565b6040529050806155ac83614b4d565b81526020830135602082015260408301356040820152606083013560608201526080830135608082015260a08301356155e481613cf2565b60a0919091015292915050565b6000610420823603121561560457600080fd5b61560c6140a0565b8235815260208301356001600160401b038082111561562a57600080fd5b61563636838701614540565b6020840152604085013591508082111561564f57600080fd5b61565b36838701614116565b6040840152606085013591508082111561567457600080fd5b61568036838701614116565b6060840152608085013591508082111561569957600080fd5b6156a536838701615139565b608084015260a08501359150808211156156be57600080fd5b6156ca36838701614116565b60a084015260c08501359150808211156156e357600080fd5b6156ef3683870161519d565b60c084015260e085013591508082111561570857600080fd5b6157143683870161519d565b60e08401526101009150818501358181111561572f57600080fd5b61573b36828801615294565b8385015250610120915061575136838701615386565b828401526101809150818501356101408401526101a061577336828801614fc6565b61016085015261022080870135848601526102409350838701358286015261026091506157a1828801614968565b6101c08601526102806157b5818901613d0a565b6101e08701526102a06157c9818a01613d0a565b6102008801526102c0808a0135848901526102e08a01359350858411156157ef57600080fd5b6157fb36858c01615243565b878901526103008a013596508587111561581457600080fd5b61582036888c016153cb565b858901526103208a013596508587111561583957600080fd5b61584536888c016154d5565b83890152615857366103408c01615569565b828901526158686104008b01613d0a565b908801525094979650505050505050565b60005b8381101561589457818101518382015260200161587c565b50506000910152565b600082516144d7818460208701615879565b634e487b7160e01b600052603160045260246000fd5b6000602082840312156158d757600080fd5b5051919050565b6000600160ff1b82016158f3576158f3614492565b506000190190565b60006001600160ff1b0382036144ba576144ba614492565b60006001600160401b0380831681810361592f5761592f614492565b6001019392505050565b6001600160e01b031981358181169160048510156146635760049490940360031b84901b1690921692915050565b600082601f83011261597857600080fd5b81516159866141378261521c565b81815284602083860101111561599b57600080fd5b610ee7826020830160208701615879565b600080600080608085870312156159c257600080fd5b84516001600160401b03808211156159d957600080fd5b6159e588838901615967565b955060209150818701519450604087015181811115615a0357600080fd5b8701601f81018913615a1457600080fd5b8051615a22614137826140f3565b81815260059190911b8201840190848101908b831115615a4157600080fd5b928501925b82841015615a68578351615a5981613cf2565b82529285019290850190615a46565b60608b0151909750945050505080821115615a8257600080fd5b50615a8f87828801615967565b91505092959194509250565b81810360008312801583831316838312821617156129f6576129f6614492565b600060208284031215615acd57600080fd5b815161233b81614797565b6020815260008251806020840152615af7816040850160208701615879565b601f01601f1916919091016040019291505056fea2646970667358221220fefb0f16d516ab83f2a733b5eb9af83d43dae20553b1b677936767d82c45b21764736f6c63430008110033
Deployed Bytecode
0x6080604052600436106100d25760003560e01c8063771838b31161007f578063b79a391f11610059578063b79a391f146102b1578063bc197c81146102de578063e8ca3dd01461030d578063f23a6e611461032d57600080fd5b8063771838b3146102155780638273f1e514610242578063a9456ea51461028f57600080fd5b806335a61a2e116100b057806335a61a2e1461019657806335e3cb89146101b6578063770473981461020257600080fd5b806301ffc9a7146100d7578063150b7a021461010c578063178d2c4714610151575b600080fd5b3480156100e357600080fd5b506100f76100f2366004613cc8565b61035a565b60405190151581526020015b60405180910390f35b34801561011857600080fd5b50610138610127366004613d5d565b630a85bd0160e11b95945050505050565b6040516001600160e01b03199091168152602001610103565b34801561015d57600080fd5b5061017161016c366004613dcf565b610391565b604080516001600160a01b039094168452602084019290925290820152606001610103565b6101a96101a4366004613e3f565b6103dd565b6040516101039190613f32565b3480156101c257600080fd5b506101f46101d1366004613fca565b600160209081526000938452604080852082529284528284209052825290205481565b604051908152602001610103565b6101a9610210366004614181565b6105ba565b34801561022157600080fd5b506102356102303660046141e4565b610708565b6040516101039190614253565b34801561024e57600080fd5b506101f461025d366004613fca565b6001600160a01b0392831660009081526001602090815260408083209490951682529283528381209181529152205490565b34801561029b57600080fd5b506102af6102aa366004614266565b6108f6565b005b3480156102bd57600080fd5b506102d16102cc3660046142d1565b610c6b565b60405161010391906142ee565b3480156102ea57600080fd5b506101386102f9366004614343565b63bc197c8160e01b98975050505050505050565b34801561031957600080fd5b506101a9610328366004614181565b610d01565b34801561033957600080fd5b50610138610348366004614401565b63f23a6e6160e01b9695505050505050565b60006001600160e01b03198216630a85bd0160e11b148061038b57506001600160e01b03198216630271189760e51b145b92915050565b600060205281600052604060002081815481106103ad57600080fd5b60009182526020909120600390910201805460018201546002909201546001600160a01b03909116935090915083565b6060878481146104345760405162461bcd60e51b815260206004820152601a60248201527f746f6b656e496473206c656e677468206d757374206d6174636800000000000060448201526064015b60405180910390fd5b8681146104835760405162461bcd60e51b815260206004820152601960248201527f616d6f756e7473206c656e677468206d757374206d6174636800000000000000604482015260640161042b565b6000806104948c8c8c8c8c8c610eef565b915091506104a282826111da565b826001600160401b038111156104ba576104ba61401e565b6040519080825280602002602001820160405280156104f357816020015b6104e0613a7f565b8152602001906001900390816104d85790505b50935060005b838110156105aa5761057a8d8d838181106105165761051661447c565b905060200201602081019061052b91906142d1565b8c8c8481811061053d5761053d61447c565b905060200201358b8b858181106105565761055661447c565b905060200201358a8a8681811061056f5761056f61447c565b905060800201611313565b85828151811061058c5761058c61447c565b602002602001018190525080806105a2906144a8565b9150506104f9565b5050505098975050505050505050565b606034156106305760405162461bcd60e51b815260206004820152602e60248201527f6d73672e76616c7565206e6f6e20616c6c6f77656420666f7220696e48696e6b60448201527f616c5472616e73616374696f6e73000000000000000000000000000000000000606482015260840161042b565b61063e6103008401846144c1565b3560010361067b5761067661065b6102a0850161028086016142d1565b61014085018035906106719061012088016142d1565b611364565b61038b565b6106896103008401846144c1565b3560020361069a576106768361138c565b6106a86103008401846144c1565b356003036106c0576106b98361189e565b905061038b565b60405162461bcd60e51b815260206004820152601960248201527f556e6b6e6f776e2048696e6b616c4c6f676963416374696f6e00000000000000604482015260640161042b565b606061071760208301836144e1565b90506001600160401b038111156107305761073061401e565b604051908082528060200260200182016040528015610759578160200160208202803683370190505b50905060005b61076c60208401846144e1565b90508110156108f0576000806107866103008601866144c1565b6107949060808101906144e1565b848181106107a4576107a461447c565b90506020028101906107b6919061452a565b6107bf90614637565b905060005b8160200151518110156108bb576000826020015182815181106107e9576107e961447c565b6020026020010151905060008360000151838151811061080b5761080b61447c565b6020026020010151905060006001600160a01b0316826001600160a01b03161480610834575080155b156108405750506108a9565b61084a8186614643565b94506108a68261085d60208b018b6144e1565b8981811061086d5761086d61447c565b905060200201602081019061088291906142d1565b866040015186815181106108985761089861447c565b602002602001015184611d37565b50505b806108b3816144a8565b9150506107c4565b50818484815181106108cf576108cf61447c565b602002602001018181525050505080806108e8906144a8565b91505061075f565b50919050565b82811461096b5760405162461bcd60e51b815260206004820152602e60248201527f616464726573737320616e6420696e6465786573206c656e6774682073686f7560448201527f6c64206265207468652073616d65000000000000000000000000000000000000606482015260840161042b565b60005b83811015610c6457600080600087878581811061098d5761098d61447c565b90506020020160208101906109a291906142d1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060005b8484848181106109d9576109d961447c565b90506020028101906109eb91906144e1565b9050811015610c4f57600082868686818110610a0957610a0961447c565b9050602002810190610a1b91906144e1565b84818110610a2b57610a2b61447c565b9050602002013581548110610a4257610a4261447c565b600091825260209091206003909102018054600282015460018301549293506001600160a01b0390911691610ab1868a8a8a818110610a8357610a8361447c565b9050602002810190610a9591906144e1565b88818110610aa557610aa561447c565b90506020020135611f69565b610af3838c8c8a818110610ac757610ac761447c565b9050602002016020810190610adc91906142d1565b610ae5846120e0565b610aee9061466b565b61214e565b6000600160008d8d8b818110610b0b57610b0b61447c565b9050602002016020810190610b2091906142d1565b6001600160a01b0390811682526020808301939093526040918201600090812091881681529083528181208682529092529020549050610b608282614687565b600160008e8e8c818110610b7657610b7661447c565b9050602002016020810190610b8b91906142d1565b6001600160a01b0390811682526020808301939093526040918201600090812091891681529083528181208782529092529020557f506e8439bc3a70b2c92f847e3c33b5029f2d99a565f3d2e483d3b5006f3963208c8c8a818110610bf257610bf261447c565b9050602002016020810190610c0791906142d1565b604080516001600160a01b039283168152918716602083015281018490526060810185905260800160405180910390a150505050508080610c47906144a8565b9150506109c7565b50508080610c5c906144a8565b91505061096e565b5050505050565b6001600160a01b038116600090815260208181526040808320805482518185028101850190935280835260609492939192909184015b82821015610cf6576000848152602090819020604080516060810182526003860290920180546001600160a01b0316835260018082015484860152600290910154918301919091529083529092019101610ca1565b505050509050919050565b60606000610d1260208501856144e1565b90506001600160401b03811115610d2b57610d2b61401e565b604051908082528060200260200182016040528015610d54578160200160208202803683370190505b50905060005b610d6760208601866144e1565b9050811015610e6057610d7b858583612205565b828281518110610d8d57610d8d61447c565b6020026020010181815250506000828281518110610dad57610dad61447c565b60200260200101511215610e4e57610e4e610dcb60208701876144e1565b83818110610ddb57610ddb61447c565b9050602002016020810190610df091906142d1565b610e026102c088016102a089016142d1565b848481518110610e1457610e1461447c565b6020026020010151610e259061466b565b610e3260408a018a6144e1565b86818110610e4257610e4261447c565b90506020020135612290565b80610e58816144a8565b915050610d5a565b50610e736102c085016102a086016142d1565b6001600160a01b0316633ce428c885836040518363ffffffff1660e01b8152600401610ea0929190614bb6565b6000604051808303816000875af1158015610ebf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610ee79190810190614ea4565b949350505050565b60606000866001600160401b03811115610f0b57610f0b61401e565b604051908082528060200260200182016040528015610f6957816020015b610f56604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b815260200190600190039081610f295790505b50915060005b878110156111ce576000805b8381101561110f578a8a84818110610f9557610f9561447c565b9050602002016020810190610faa91906142d1565b6001600160a01b0316858281518110610fc557610fc561447c565b6020026020010151600001516001600160a01b031614801561101b5750868684818110610ff457610ff461447c565b9050602002013585828151811061100d5761100d61447c565b602002602001015160400151145b156110fd578686848181106110325761103261447c565b905060200201356000146110ae5760405162461bcd60e51b815260206004820152602e60248201527f796f752063616e6e6f742073656e642074776f204e465473207769746820746860448201527f652073616d6520746f6b656e4964000000000000000000000000000000000000606482015260840161042b565b8888848181106110c0576110c061447c565b905060200201358582815181106110d9576110d961447c565b60200260200101516020018181516110f19190614687565b9052506001915061110f565b80611107816144a8565b915050610f7b565b50806111bb5760405180606001604052808b8b858181106111325761113261447c565b905060200201602081019061114791906142d1565b6001600160a01b031681526020018989858181106111675761116761447c565b9050602002013581526020018787858181106111855761118561447c565b905060200201358152508484815181106111a1576111a161447c565b602002602001018190525082806111b7906144a8565b9350505b50806111c6816144a8565b915050610f6f565b50965096945050505050565b60005b8181101561130e5760008382815181106111f9576111f961447c565b6020026020010151600001519050600084838151811061121b5761121b61447c565b6020026020010151602001519050600085848151811061123d5761123d61447c565b60200260200101516040015190506000611256846122ba565b90506001600160a01b038416611273576112703482614fb3565b90505b6112808433308686612347565b600061128b856122ba565b9050836112988383614fb3565b146112f65760405162461bcd60e51b815260206004820152602860248201527f70726f6f666c657373206465706f7369742062616c616e636573206d75737420604482015267189948195c5d585b60c21b606482015260840161042b565b50505050508080611306906144a8565b9150506111dd565b505050565b61131b613a7f565b6040805160a0810182528581526001600160a01b0387166020820152600091810161134b3686900386018661500a565b8152426020820152604001859052915050949350505050565b6001600160a01b0383161580159061137c5750600082115b1561130e5761130e81848461236c565b600061139c6102e0830183615026565b8101906113a9919061506c565b905060006113bb6103008401846144c1565b60200135905081518380602001906113d391906144e1565b9050146114225760405162461bcd60e51b815260206004820152601860248201527f72656c6561736546726f6d42756666657220636865636b310000000000000000604482015260640161042b565b6000611436610140850161012086016142d1565b905061014084013561145a6114536102a0870161028088016142d1565b8284611364565b60005b61146a60208701876144e1565b905081101561189657600061148260208801886144e1565b838181106114925761149261447c565b90506020020160208101906114a791906142d1565b90506000805b8784815181106114bf576114bf61447c565b6020026020010151518110156116be576000600160008a87815181106114e7576114e761447c565b602002602001015184815181106115005761150061447c565b6020908102919091018101516001600160a01b039081168352828201939093526040918201600090812093881681529281528183208b845290529020549050806115a25760405162461bcd60e51b815260206004820152602d60248201527f68696e6b616c2062756666657220616d6f756e742073686f756c64206265206d60448201526c6f7265207468616e207a65726f60981b606482015260840161042b565b6115ac8184614687565b92506000600160008b88815181106115c6576115c661447c565b602002602001015185815181106115df576115df61447c565b6020908102919091018101516001600160a01b039081168352828201939093526040918201600090812093891681529281528183208c8452905290205588517f81ddad81ae937bc7486520a362bb81233e5dfe4afed88648c231dbb92e217d22908a90879081106116525761165261447c565b6020026020010151838151811061166b5761166b61447c565b6020026020010151858a6040516116a3939291906001600160a01b039384168152919092166020820152604081019190915260600190565b60405180910390a150806116b6816144a8565b9150506114ad565b506116cd6103008901896144c1565b6116db9060408101906144e1565b848181106116eb576116eb61447c565b905060200201356116fb9061466b565b611704826120e0565b146117775760405162461bcd60e51b815260206004820152602f60248201527f746f74616c206275666665722073686f756c6420657175616c20746f20746f7460448201527f616c20646973616c6c6f77616e63650000000000000000000000000000000000606482015260840161042b565b816001600160a01b0316856001600160a01b031614611797576000611799565b835b6117a660808a018a6144e1565b858181106117b6576117b661447c565b90506020020160208101906117cb919061511c565b6117f8576117dc60608a018a6144e1565b858181106117ec576117ec61447c565b905060200201356117fb565b60005b6118059190614643565b61180e826120e0565b146118815760405162461bcd60e51b815260206004820152603660248201527f746f74616c2062756666657220616d6f756e742073686f756c6420626520657160448201527f75616c20746f20617070726f76616c4368616e67657300000000000000000000606482015260840161042b565b5050808061188e906144a8565b91505061145d565b505050505050565b60606118a8613ae0565b341561191c5760405162461bcd60e51b815260206004820152602f60248201527f6469726563742063616c6c207769746820706f736974697665206d73672e766160448201527f6c7565206e6f7420616c6c6f7765640000000000000000000000000000000000606482015260840161042b565b6000806119288561238f565b915091506000611938838361286a565b9050611943866155f1565b845261198c61195560208801886144e1565b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152506129fd92505050565b6020808601919091526119bc906119a5908801886144e1565b6119b76102c08a016102a08b016142d1565b612a0a565b60608501526119ca86612bb6565b6000611a176119dd6102e0890189615026565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612d2f92505050565b90506000805b611a2a60208a018a6144e1565b9050811015611b7a576000611a4260208b018b6144e1565b83818110611a5257611a5261447c565b9050602002016020810190611a6791906142d1565b6001600160a01b0316148015611aac5750611a8560808a018a6144e1565b82818110611a9557611a9561447c565b9050602002016020810190611aaa919061511c565b155b15611b68576000611ac060608b018b6144e1565b83818110611ad057611ad061447c565b905060200201351215611b6857611aea60608a018a6144e1565b82818110611afa57611afa61447c565b90506020020135611b0a9061466b565b91506000611b206102a08b016102808c016142d1565b6001600160a01b031614158015611b5157506000611b466101408b016101208c016142d1565b6001600160a01b0316145b15611b6857611b656101408a013583614fb3565b91505b80611b72816144a8565b915050611a1d565b50600080611b906102c08b016102a08c016142d1565b6001600160a01b0316838560600151604051611bac919061589d565b60006040518083038185875af1925050503d8060008114611be9576040519150601f19603f3d011682016040523d82523d6000602084013e611bee565b606091505b509150915081611c5057805115611c085780518082602001fd5b60405162461bcd60e51b815260206004820152601c60248201527f48696e6b616c3a2045787465726e616c2063616c6c206661696c656400000000604482015260640161042b565b611c7b611c656102a08c016102808d016142d1565b6101408c01803590610671906101208f016142d1565b611c8b61195560208c018c6144e1565b6040890152611cb2611ca060208c018c6144e1565b6119b76102c08e016102a08f016142d1565b60808901526000611cc3888861286a565b90506000611cd08a612d93565b9050611cdc878361307d565b611d285760405162461bcd60e51b815260206004820152601560248201527f61727261792773206d75737420626520657175616c0000000000000000000000604482015260640161042b565b9b9a5050505050505050505050565b6001600160a01b0384166000908152602081905260408120815b8154811015611e09576000828281548110611d6e57611d6e61447c565b90600052602060002090600302019050858160020154141580611d9e575080546001600160a01b03888116911614155b15611da95750611df7565b6000611dcb86611dbc84600101546120e0565b611dc69190614643565b6130fb565b905080600003611de457611ddf8484611f69565b611dec565b600182018190555b600194505050611e09565b80611e01816144a8565b915050611d51565b508180611e17575060008312155b611e975760405162461bcd60e51b815260206004820152604560248201527f6966207468657265206973206e6f207574786f20696e2061727261792c20746860448201527f656e20617070726f76616c206368616e67652063616e6e6f74206265206e6567606482015264617469766560d81b608482015260a40161042b565b81611f0457604080516060810182526001600160a01b03878116825260208083018781529383018881528554600180820188556000888152939093209451600390910290940180546001600160a01b03191694909316939093178255925192810192909255516002909101555b611f0f85878561214e565b604080516001600160a01b03808916825287166020820152908101849052606081018590527f5f5a1f32b36d48221c71fb0a2426912b82ec0140a32c2e57a27cf2590093b1039060800160405180910390a1505050505050565b8154808210611fc65760405162461bcd60e51b8152602060048201526024808201527f72656d6f7665417070726f76616c20696e646578206973206f7574206f662072604482015263616e676560e01b606482015260840161042b565b611fd1600182614fb3565b82146120565782611fe3600183614fb3565b81548110611ff357611ff361447c565b90600052602060002090600302018383815481106120135761201361447c565b60009182526020909120825460039092020180546001600160a01b0319166001600160a01b03909216919091178155600180830154908201556002918201549101555b82612062600183614fb3565b815481106120725761207261447c565b60009182526020822060039091020180546001600160a01b0319168155600181018290556002015582548390806120ab576120ab6158af565b60008281526020812060036000199093019283020180546001600160a01b031916815560018101829055600201559055505050565b60006001600160ff1b0382111561214a5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b606482015260840161042b565b5090565b604051636eb1769f60e11b81523060048201526001600160a01b0383811660248301526000919085169063dd62ed3e90604401602060405180830381865afa15801561219e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c291906158c5565b905060008083136121e5576121d68361466b565b6121e09083614fb3565b6121ef565b6121ef8383614687565b9050610c646001600160a01b038616858361314d565b60008282815181106122195761221961447c565b602002602001015184806080019061223191906144e1565b848181106122415761224161447c565b9050602002016020810190612256919061511c565b6122835761226760608601866144e1565b848181106122775761227761447c565b90506020020135612286565b60005b610ee79190614643565b806000036122a8576122a384848461236c565b6122b4565b6122b48430858461320f565b50505050565b60006001600160a01b0382166122d1575047919050565b6040516370a0823160e01b815230600482015282906001600160a01b038216906370a0823190602401602060405180830381865afa158015612317573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061233b91906158c5565b9392505050565b919050565b806000036123605761235b8585858561327f565b610c64565b610c648585858461320f565b6001600160a01b0383166123845761130e8282613310565b61130e8383836133b3565b606060008080806123a86102c087016102a088016142d1565b6001600160a01b03166001600160a01b03168152602001908152602001600020905060008480602001906123dc91906144e1565b90506001600160401b038111156123f5576123f561401e565b60405190808252806020026020018201604052801561241e578160200160208202803683370190505b50825490915060009061243b90612436906001614687565b6133c7565b835490915060005b818112156126a957600081905060008682815481106124645761246461447c565b906000526020600020906003020190506000808b806020019061248791906144e1565b9050905060005b81811015612676576124a360208e018e6144e1565b828181106124b3576124b361447c565b90506020020160208101906124c891906142d1565b84546001600160a01b0391821691160361266457600192506124ee6103008e018e6144c1565b6020013584600201540361265f5760018982815181106125105761251061447c565b9115156020928302919091019091015260006125306103008f018f6144c1565b61253e9060408101906144e1565b8381811061254e5761254e61447c565b90506020020135121561265f57600061256b6103008f018f6144c1565b6125799060408101906144e1565b838181106125895761258961447c565b9050602002013561259d86600101546120e0565b6125a79190614643565b905060008112156126205760405162461bcd60e51b815260206004820152603d60248201527f48696e6b616c3a20596f752073686f756c64207370656e642065786163746c7960448201527f207468652073616d6520616d6f756e7420796f7520617070726f766564000000606482015260840161042b565b612629816130fb565b6001860155600081900361265d576126418b87611f69565b8661264b816158de565b9750508780612659906158de565b9850505b505b612676565b8061266e816144a8565b91505061248e565b50816126925782546126929088906001600160a01b031661344c565b5050505080806126a1906158fb565b915050612443565b5060005b8351811015612781578381815181106126c8576126c861447c565b60200260200101511515600015150361276f576126e96103008901896144c1565b6126f79060408101906144e1565b828181106127075761270761447c565b9050602002013560001461276f5760405162461bcd60e51b815260206004820152602960248201527f796f752063616e6e6f74207370656e6420736f6d657468696e6720796f75206460448201526837903737ba1037bbb760b91b606482015260840161042b565b80612779816144a8565b9150506126ad565b5061279c6127976102c089016102a08a016142d1565b6134f7565b15612855576000805b6127b260208a018a6144e1565b9050811015612831576127cd6102c08a016102a08b016142d1565b6001600160a01b03166127e360208b018b6144e1565b838181106127f3576127f361447c565b905060200201602081019061280891906142d1565b6001600160a01b03160361281f5760019150612831565b80612829816144a8565b9150506127a5565b50806128535761285361284c6102c08a016102a08b016142d1565b849061344c565b505b50805160209091015190969095509350505050565b6060816001600160401b038111156128845761288461401e565b6040519080825280602002602001820160405280156128ad578160200160208202803683370190505b50905060005b82816001600160401b031610156129f65760006001600160a01b031684826001600160401b0316815181106128ea576128ea61447c565b60200260200101516001600160a01b03160361292d574782826001600160401b03168151811061291c5761291c61447c565b6020026020010181815250506129e4565b83816001600160401b0316815181106129485761294861447c565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa158015612998573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129bc91906158c5565b82826001600160401b0316815181106129d7576129d761447c565b6020026020010181815250505b806129ee81615913565b9150506128b3565b5092915050565b606061038b82835161286a565b6060826001600160401b03811115612a2457612a2461401e565b604051908082528060200260200182016040528015612a4d578160200160208202803683370190505b50905060005b6001600160401b038116841115612bae57600085856001600160401b038416818110612a8157612a8161447c565b9050602002016020810190612a9691906142d1565b6001600160a01b031603612ad257600082826001600160401b031681518110612ac157612ac161447c565b602002602001018181525050612b9c565b8484826001600160401b0316818110612aed57612aed61447c565b9050602002016020810190612b0291906142d1565b604051636eb1769f60e11b81523060048201526001600160a01b038581166024830152919091169063dd62ed3e90604401602060405180830381865afa158015612b50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b7491906158c5565b82826001600160401b031681518110612b8f57612b8f61447c565b6020026020010181815250505b80612ba681615913565b915050612a53565b509392505050565b612bcb6127976102c083016102a084016142d1565b612bd25750565b6000612be26102e0830183615026565b612beb91615939565b6040805161018081018252633950935160e01b815263a457c2d760e01b602082015263095ea7b360e01b918101919091526340c10f1960e01b6060820152630852cd8d60e31b60808201526323b872dd60e01b60a082015263959b8c3f60e01b60c0820152637d6c599560e11b60e0820152633177029f60e01b61010082015263363efa6560e21b61012082015263cae9ca5160e01b61014082015263c1d34b8960e01b61016082015290915060005b600c8110156122b4578181600c8110612cb657612cb661447c565b60200201516001600160e01b031916836001600160e01b03191603612d1d5760405162461bcd60e51b815260206004820152601460248201527f626c61636b6c69737465642073656c6563746f72000000000000000000000000604482015260640161042b565b80612d27816144a8565b915050612c9b565b612d5a6040518060800160405280606081526020016000815260200160608152602001606081525090565b60008060008085806020019051810190612d7491906159ac565b9288526020880191909152604087015260608601525092949350505050565b6060612db0826000015160200151836020015184604001516135a6565b90506000805b835160200151518110156130765760008460000151602001518281518110612de057612de061447c565b602002602001015190506000612e1286602001518481518110612e0557612e0561447c565b60200260200101516120e0565b612e2b87604001518581518110612e0557612e0561447c565b612e359190615a9b565b90506000612e5287606001518581518110612e0557612e0561447c565b612e6b88608001518681518110612e0557612e0561447c565b612e759190615a9b565b90506000821315612eea576040805160a0810182528381526001600160a01b03851660208201528851610160015191810191909152875161014001516060820152600060808201528686612ec8816144a8565b975081518110612eda57612eda61447c565b6020026020010181905250612fa1565b6000821215612fa1576001600160a01b03831615612fa15786516101200151516000906001600160a01b03858116911614612f26576000612f3a565b8751610120015160200151612f3a906120e0565b905081612f478285614643565b14612f9f5760405162461bcd60e51b815260206004820152602260248201527f62616c616e636520616e6420616c6c6f77616e636520446966206d69736d61746044820152610c6d60f31b606482015260840161042b565b505b600087600001516102600151604001518581518110612fc257612fc261447c565b6020026020010151905060008183612fda9190615a9b565b90508015612ff85788516102000151612ff8908690610aee8461466b565b885161020081015161026090910151602090810151604080516001600160a01b039485168152938916928401929092528282018590526060830152517f5f5a1f32b36d48221c71fb0a2426912b82ec0140a32c2e57a27cf2590093b1039181900360800190a15050505050808061306e906144a8565b915050612db6565b5050919050565b600081518351146130905750600061038b565b60005b83518110156130f1578281815181106130ae576130ae61447c565b60200260200101518482815181106130c8576130c861447c565b6020026020010151146130df57600091505061038b565b806130e9816144a8565b915050613093565b5060019392505050565b60008082121561214a5760405162461bcd60e51b815260206004820181905260248201527f53616665436173743a2076616c7565206d75737420626520706f736974697665604482015260640161042b565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b17905261319e848261368e565b6122b4576040516001600160a01b03841660248201526000604482015261320590859063095ea7b360e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152613735565b6122b48482613735565b604051632142170760e11b81526001600160a01b0384811660048301528381166024830152604482018390528516906342842e0e90606401600060405180830381600087803b15801561326157600080fd5b505af1158015613275573d6000803e3d6000fd5b5050505050505050565b6001600160a01b038416613304578034146132ea5760405162461bcd60e51b815260206004820152602560248201527f6d73672e76616c756520646f65736e2774206d61746368206e656564656420616044820152641b5bdd5b9d60da1b606482015260840161042b565b6001600160a01b03821630146122a3576122a38282613310565b6122b48484848461380a565b6000826001600160a01b03168260405160006040518083038185875af1925050503d806000811461335d576040519150601f19603f3d011682016040523d82523d6000602084013e613362565b606091505b505090508061130e5760405162461bcd60e51b815260206004820152600f60248201527f5472616e73666572204661696c65640000000000000000000000000000000000604482015260640161042b565b61130e6001600160a01b038416838361381f565b6133eb60405180606001604052806060815260200160008152602001600081525090565b6040518060600160405280836001600160401b0381111561340e5761340e61401e565b604051908082528060200260200182016040528015613437578160200160208202803683370190505b50815260006020820152604001929092525090565b613456828261384f565b1561345f575050565b8151602083018051839291613473826144a8565b9052815181106134855761348561447c565b6001600160a01b0390921660209283029190910182015260408301519083015111156134f35760405162461bcd60e51b815260206004820152601560248201527f536574204d61784c656e67746820526561636865640000000000000000000000604482015260640161042b565b5050565b604080513060248083019190915282518083039091018152604490910182526020810180516001600160e01b03166370a0823160e01b1790529051600091829182916001600160a01b0386169161354e919061589d565b600060405180830381855afa9150503d8060008114613589576040519150601f19603f3d011682016040523d82523d6000602084013e61358e565b606091505b5091509150818015610ee75750516020149392505050565b60606000805b8551816001600160401b031610156136325760006135de86836001600160401b031681518110612e0557612e0561447c565b6135fc86846001600160401b031681518110612e0557612e0561447c565b6136069190615a9b565b9050600081131561361f578261361b816144a8565b9350505b508061362a81615913565b9150506135ac565b50806001600160401b0381111561364b5761364b61401e565b60405190808252806020026020018201604052801561368457816020015b613671613a7f565b8152602001906001900390816136695790505b5095945050505050565b6000806000846001600160a01b0316846040516136ab919061589d565b6000604051808303816000865af19150503d80600081146136e8576040519150601f19603f3d011682016040523d82523d6000602084013e6136ed565b606091505b50915091508180156137175750805115806137175750808060200190518101906137179190615abb565b801561372c57506001600160a01b0385163b15155b95945050505050565b600061378a826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166138bf9092919063ffffffff16565b90508051600014806137ab5750808060200190518101906137ab9190615abb565b61130e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161042b565b6122b46001600160a01b0385168484846138ce565b6040516001600160a01b03831660248201526044810182905261130e90849063a9059cbb60e01b906064016131ce565b6020820151600090815b818110156138b457836001600160a01b0316856000015182815181106138815761388161447c565b60200260200101516001600160a01b0316036138a25760019250505061038b565b806138ac816144a8565b915050613859565b506000949350505050565b6060610ee78484600085613906565b6040516001600160a01b03808516602483015283166044820152606481018290526122b49085906323b872dd60e01b906084016131ce565b6060824710156139675760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161042b565b600080866001600160a01b03168587604051613983919061589d565b60006040518083038185875af1925050503d80600081146139c0576040519150601f19603f3d011682016040523d82523d6000602084013e6139c5565b606091505b50915091506139d6878383876139e1565b979650505050505050565b60608315613a50578251600003613a49576001600160a01b0385163b613a495760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161042b565b5081610ee7565b610ee78383815115613a655781518083602001fd5b8060405162461bcd60e51b815260040161042b9190615ad8565b6040518060a001604052806000815260200160006001600160a01b03168152602001613acc6040518060800160405280600081526020016000815260200160008152602001600081525090565b815260200160008152602001600081525090565b6040518060a00160405280613af3613b15565b8152602001606081526020016060815260200160608152602001606081525090565b604051806102e00160405280600081526020016060815260200160608152602001606081526020016060815260200160608152602001606081526020016060815260200160608152602001613b8d604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b815260200160008152602001613bc46040518060800160405280600081526020016000815260200160008152602001600081525090565b81526020016000815260200160008152602001600061ffff16815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160608152602001613c446040518060a00160405280600081526020016000815260200160608152602001600015158152602001606081525090565b8152602001613c86604051806080016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160608152602001606081525090565b81526040805160c08101825260008082526020828101829052928201819052606082018190526080820181905260a08201529101908152600060209091015290565b600060208284031215613cda57600080fd5b81356001600160e01b03198116811461233b57600080fd5b6001600160a01b0381168114613d0757600080fd5b50565b803561234281613cf2565b60008083601f840112613d2757600080fd5b5081356001600160401b03811115613d3e57600080fd5b602083019150836020828501011115613d5657600080fd5b9250929050565b600080600080600060808688031215613d7557600080fd5b8535613d8081613cf2565b94506020860135613d9081613cf2565b93506040860135925060608601356001600160401b03811115613db257600080fd5b613dbe88828901613d15565b969995985093965092949392505050565b60008060408385031215613de257600080fd5b8235613ded81613cf2565b946020939093013593505050565b60008083601f840112613e0d57600080fd5b5081356001600160401b03811115613e2457600080fd5b6020830191508360208260051b8501011115613d5657600080fd5b6000806000806000806000806080898b031215613e5b57600080fd5b88356001600160401b0380821115613e7257600080fd5b613e7e8c838d01613dfb565b909a50985060208b0135915080821115613e9757600080fd5b613ea38c838d01613dfb565b909850965060408b0135915080821115613ebc57600080fd5b613ec88c838d01613dfb565b909650945060608b0135915080821115613ee157600080fd5b818b0191508b601f830112613ef557600080fd5b813581811115613f0457600080fd5b8c60208260071b8501011115613f1957600080fd5b6020830194508093505050509295985092959890939650565b602080825282518282018190526000919060409081850190868401855b82811015613fbd57815180518552868101516001600160a01b0316878601528581015180518787015280880151606080880191909152818801516080808901919091529181015160a088015282015160c0870152015160e08501526101009093019290850190600101613f4f565b5091979650505050505050565b600080600060608486031215613fdf57600080fd5b8335613fea81613cf2565b92506020840135613ffa81613cf2565b929592945050506040919091013590565b600061042082840312156108f057600080fd5b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156140565761405661401e565b60405290565b60405160a081016001600160401b03811182821017156140565761405661401e565b604051608081016001600160401b03811182821017156140565761405661401e565b6040516102e081016001600160401b03811182821017156140565761405661401e565b604051601f8201601f191681016001600160401b03811182821017156140eb576140eb61401e565b604052919050565b60006001600160401b0382111561410c5761410c61401e565b5060051b60200190565b600082601f83011261412757600080fd5b8135602061413c614137836140f3565b6140c3565b82815260059290921b8401810191818101908684111561415b57600080fd5b8286015b84811015614176578035835291830191830161415f565b509695505050505050565b6000806040838503121561419457600080fd5b82356001600160401b03808211156141ab57600080fd5b6141b78683870161400b565b935060208501359150808211156141cd57600080fd5b506141da85828601614116565b9150509250929050565b6000602082840312156141f657600080fd5b81356001600160401b0381111561420c57600080fd5b610ee78482850161400b565b600081518084526020808501945080840160005b838110156142485781518752958201959082019060010161422c565b509495945050505050565b60208152600061233b6020830184614218565b6000806000806040858703121561427c57600080fd5b84356001600160401b038082111561429357600080fd5b61429f88838901613dfb565b909650945060208701359150808211156142b857600080fd5b506142c587828801613dfb565b95989497509550505050565b6000602082840312156142e357600080fd5b813561233b81613cf2565b602080825282518282018190526000919060409081850190868401855b82811015613fbd57815180516001600160a01b031685528681015187860152850151858501526060909301929085019060010161430b565b60008060008060008060008060a0898b03121561435f57600080fd5b883561436a81613cf2565b9750602089013561437a81613cf2565b965060408901356001600160401b038082111561439657600080fd5b6143a28c838d01613dfb565b909850965060608b01359150808211156143bb57600080fd5b6143c78c838d01613dfb565b909650945060808b01359150808211156143e057600080fd5b506143ed8b828c01613d15565b999c989b5096995094979396929594505050565b60008060008060008060a0878903121561441a57600080fd5b863561442581613cf2565b9550602087013561443581613cf2565b9450604087013593506060870135925060808701356001600160401b0381111561445e57600080fd5b61446a89828a01613d15565b979a9699509497509295939492505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016144ba576144ba614492565b5060010190565b60008235609e198336030181126144d757600080fd5b9190910192915050565b6000808335601e198436030181126144f857600080fd5b8301803591506001600160401b0382111561451257600080fd5b6020019150600581901b3603821315613d5657600080fd5b60008235605e198336030181126144d757600080fd5b600082601f83011261455157600080fd5b81356020614561614137836140f3565b82815260059290921b8401810191818101908684111561458057600080fd5b8286015b8481101561417657803561459781613cf2565b8352918301918301614584565b6000606082840312156145b657600080fd5b6145be614034565b905081356001600160401b03808211156145d757600080fd5b6145e385838601614116565b835260208401359150808211156145f957600080fd5b61460585838601614540565b6020840152604084013591508082111561461e57600080fd5b5061462b84828501614116565b60408301525092915050565b600061038b36836145a4565b808201828112600083128015821682158216171561466357614663614492565b505092915050565b6000600160ff1b820161468057614680614492565b5060000390565b8082018082111561038b5761038b614492565b6000808335601e198436030181126146b157600080fd5b83016020810192503590506001600160401b038111156146d057600080fd5b8060051b3603821315613d5657600080fd5b8183526000602080850194508260005b8581101561424857813561470581613cf2565b6001600160a01b0316875295820195908201906001016146f2565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111561475257600080fd5b8260051b80836020870137939093016020019392505050565b8183526000602080850194508260005b858110156142485781358752958201959082019060010161477b565b8015158114613d0757600080fd5b8183526000602080850194508260005b858110156142485781356147c881614797565b1515875295820195908201906001016147b5565b81835260006020808501808196508560051b810191508460005b87811015613fbd57828403895261480d828861469a565b614818868284614720565b9a87019a95505050908401906001016147f6565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6000808335601e1984360301811261486c57600080fd5b83016020810192503590506001600160401b0381111561488b57600080fd5b803603821315613d5657600080fd5b81835260006020808501808196506005915085821b8101856000805b8981101561492e578484038b526148cd838a61469a565b80865288860181891b87018a0183865b8481101561491757898303601f190184526148f88287614855565b61490385828461482c565b958f019594505050908c01906001016148dd565b50509d8a019d9650505092870192506001016148b6565b50919998505050505050505050565b803561494881613cf2565b6001600160a01b0316825260208181013590830152604090810135910152565b803561ffff8116811461234257600080fd5b60008235609e1983360301811261499057600080fd5b90910192915050565b8035825260006020808301358185015260406149b78185018561469a565b60a0838801526149cb60a08801828461476b565b9150506060808601356149dd81614797565b1515878201526149f0608087018761469a565b88840360808a0152808452858401600582901b85018701836000805b85811015614aa757888403601f19018552823536889003605e19018112614a31578283fd5b8701614a3d818061469a565b8a8752614a4d8b8801828461476b565b915050614a5c8d83018361469a565b8783038f890152614a6e8382846146e2565b92505050614a7e8c83018361469a565b92508682038d880152614a92828483614720565b978e019796505050928b019250600101614a0c565b50919c9b505050505050505050505050565b60008235607e1983360301811261499057600080fd5b60008135614adc81613cf2565b6001600160a01b039081168452602083013590614af882613cf2565b166020840152614b0b6040830183614855565b60806040860152614b2060808601828461482c565b915050614b306060840184614855565b8583036060870152614b4383828461482c565b9695505050505050565b803560ff8116811461234257600080fd5b60ff614b6982614b4d565b1682526020810135602083015260408101356040830152606081013560608301526080810135608083015260a0810135614ba281613cf2565b6001600160a01b03811660a0840152505050565b60408152823560408201526000614bd0602085018561469a565b6104206060850152614be7610460850182846146e2565b915050614bf7604086018661469a565b603f1980868503016080870152614c0f848385614720565b9350614c1e606089018961469a565b93509150808685030160a0870152614c3784848461476b565b9350614c46608089018961469a565b93509150808685030160c0870152614c5f8484846147a5565b9350614c6e60a089018961469a565b93509150808685030160e0870152614c8784848461476b565b9350614c9660c089018961469a565b93509150610100818786030181880152614cb18585856147dc565b9450614cc060e08a018a61469a565b94509250610120828887030181890152614cdb8686866147dc565b9550614ce9828b018b61469a565b955093508288870301610140890152614d0386868661489a565b9550614d156101608901828c0161493d565b50506101808801356101c0870152614d566101e087016101a08a01803582526020810135602083015260408101356040830152606081013560608301525050565b610260925061022088013583870152610280915061024088013582870152614d7f838901614968565b92506102a0614d938188018561ffff169052565b614d9e838a01613d0a565b93506102c09250614db9838801856001600160a01b03169052565b614dc4818a01613d0a565b9350506102e0614dde818801856001600160a01b03169052565b61030093508289013584880152614df7818a018a614855565b93509050610320828887030181890152614e1286858461482c565b9550614e20858b018b61497a565b94506103409350828887030184890152614e3a8686614999565b9550614e48818b018b614ab9565b94505050808685030161036087015250614e628383614acf565b9250614e746103808601828901614b5e565b5050614e836104008601613d0a565b6001600160a01b0316610440840152828103602084015261372c8185614218565b60006020808385031215614eb757600080fd5b82516001600160401b03811115614ecd57600080fd5b8301601f81018513614ede57600080fd5b8051614eec614137826140f3565b81815260089190911b82018301908381019087831115614f0b57600080fd5b928401925b828410156139d657838803610100811215614f2b5760008081fd5b614f3361405c565b8551815286860151614f4481613cf2565b8188015260406080603f198401811315614f5e5760008081fd5b614f6661407e565b8883015181526060808a01518b830152828a01518483015260a08a0151818301529284015260c08801519183019190915260e0870151908201528352506101009093019290840190614f10565b8181038181111561038b5761038b614492565b600060808284031215614fd857600080fd5b614fe061407e565b90508135815260208201356020820152604082013560408201526060820135606082015292915050565b60006080828403121561501c57600080fd5b61233b8383614fc6565b6000808335601e1984360301811261503d57600080fd5b8301803591506001600160401b0382111561505757600080fd5b602001915036819003821315613d5657600080fd5b6000602080838503121561507f57600080fd5b82356001600160401b038082111561509657600080fd5b818501915085601f8301126150aa57600080fd5b81356150b8614137826140f3565b81815260059190911b830184019084810190888311156150d757600080fd5b8585015b8381101561510f578035858111156150f35760008081fd5b6151018b89838a0101614540565b8452509186019186016150db565b5098975050505050505050565b60006020828403121561512e57600080fd5b813561233b81614797565b600082601f83011261514a57600080fd5b8135602061515a614137836140f3565b82815260059290921b8401810191818101908684111561517957600080fd5b8286015b8481101561417657803561519081614797565b835291830191830161517d565b600082601f8301126151ae57600080fd5b813560206151be614137836140f3565b82815260059290921b840181019181810190868411156151dd57600080fd5b8286015b848110156141765780356001600160401b038111156152005760008081fd5b61520e8986838b0101614116565b8452509183019183016151e1565b60006001600160401b038211156152355761523561401e565b50601f01601f191660200190565b600082601f83011261525457600080fd5b81356152626141378261521c565b81815284602083860101111561527757600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f8301126152a557600080fd5b813560206152b5614137836140f3565b82815260059290921b840181019181810190868411156152d457600080fd5b8286015b848110156141765780356001600160401b03808211156152f757600080fd5b818901915089603f83011261530b57600080fd5b8582013561531b614137826140f3565b81815260059190911b830160400190878101908c83111561533b57600080fd5b604085015b838110156153745780358581111561535757600080fd5b6153668f6040838a0101615243565b845250918901918901615340565b508752505050928401925083016152d8565b60006060828403121561539857600080fd5b6153a0614034565b905081356153ad81613cf2565b80825250602082013560208201526040820135604082015292915050565b600060a082840312156153dd57600080fd5b6153e561405c565b9050813581526020808301358183015260408301356001600160401b038082111561540f57600080fd5b61541b86838701614116565b60408501526060850135915061543082614797565b816060850152608085013591508082111561544a57600080fd5b818501915085601f83011261545e57600080fd5b813561546c614137826140f3565b81815260059190911b8301840190848101908883111561548b57600080fd5b8585015b838110156154c3578035858111156154a75760008081fd5b6154b58b89838a01016145a4565b84525091860191860161548f565b50608087015250939695505050505050565b6000608082840312156154e757600080fd5b6154ef61407e565b905081356154fc81613cf2565b8152602082013561550c81613cf2565b602082015260408201356001600160401b038082111561552b57600080fd5b61553785838601615243565b6040840152606084013591508082111561555057600080fd5b5061555d84828501615243565b60608301525092915050565b600060c0828403121561557b57600080fd5b60405160c081018181106001600160401b038211171561559d5761559d61401e565b6040529050806155ac83614b4d565b81526020830135602082015260408301356040820152606083013560608201526080830135608082015260a08301356155e481613cf2565b60a0919091015292915050565b6000610420823603121561560457600080fd5b61560c6140a0565b8235815260208301356001600160401b038082111561562a57600080fd5b61563636838701614540565b6020840152604085013591508082111561564f57600080fd5b61565b36838701614116565b6040840152606085013591508082111561567457600080fd5b61568036838701614116565b6060840152608085013591508082111561569957600080fd5b6156a536838701615139565b608084015260a08501359150808211156156be57600080fd5b6156ca36838701614116565b60a084015260c08501359150808211156156e357600080fd5b6156ef3683870161519d565b60c084015260e085013591508082111561570857600080fd5b6157143683870161519d565b60e08401526101009150818501358181111561572f57600080fd5b61573b36828801615294565b8385015250610120915061575136838701615386565b828401526101809150818501356101408401526101a061577336828801614fc6565b61016085015261022080870135848601526102409350838701358286015261026091506157a1828801614968565b6101c08601526102806157b5818901613d0a565b6101e08701526102a06157c9818a01613d0a565b6102008801526102c0808a0135848901526102e08a01359350858411156157ef57600080fd5b6157fb36858c01615243565b878901526103008a013596508587111561581457600080fd5b61582036888c016153cb565b858901526103208a013596508587111561583957600080fd5b61584536888c016154d5565b83890152615857366103408c01615569565b828901526158686104008b01613d0a565b908801525094979650505050505050565b60005b8381101561589457818101518382015260200161587c565b50506000910152565b600082516144d7818460208701615879565b634e487b7160e01b600052603160045260246000fd5b6000602082840312156158d757600080fd5b5051919050565b6000600160ff1b82016158f3576158f3614492565b506000190190565b60006001600160ff1b0382036144ba576144ba614492565b60006001600160401b0380831681810361592f5761592f614492565b6001019392505050565b6001600160e01b031981358181169160048510156146635760049490940360031b84901b1690921692915050565b600082601f83011261597857600080fd5b81516159866141378261521c565b81815284602083860101111561599b57600080fd5b610ee7826020830160208701615879565b600080600080608085870312156159c257600080fd5b84516001600160401b03808211156159d957600080fd5b6159e588838901615967565b955060209150818701519450604087015181811115615a0357600080fd5b8701601f81018913615a1457600080fd5b8051615a22614137826140f3565b81815260059190911b8201840190848101908b831115615a4157600080fd5b928501925b82841015615a68578351615a5981613cf2565b82529285019290850190615a46565b60608b0151909750945050505080821115615a8257600080fd5b50615a8f87828801615967565b91505092959194509250565b81810360008312801583831316838312821617156129f6576129f6614492565b600060208284031215615acd57600080fd5b815161233b81614797565b6020815260008251806020840152615af7816040850160208701615879565b601f01601f1916919091016040019291505056fea2646970667358221220fefb0f16d516ab83f2a733b5eb9af83d43dae20553b1b677936767d82c45b21764736f6c63430008110033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.