Source Code
Latest 25 from a total of 789 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Redeem Card | 38060320 | 16 hrs ago | IN | 0 ETH | 0.00000054 | ||||
| Redeem Card | 37996077 | 2 days ago | IN | 0 ETH | 0.00000066 | ||||
| Redeem Card | 37987815 | 2 days ago | IN | 0 ETH | 0.00000058 | ||||
| Redeem Card | 37876998 | 4 days ago | IN | 0 ETH | 0.0000006 | ||||
| Deposit ERC20 | 37876936 | 4 days ago | IN | 0 ETH | 0.00000179 | ||||
| Redeem Card | 37876840 | 4 days ago | IN | 0 ETH | 0.00000062 | ||||
| Deposit ERC20 | 37876803 | 4 days ago | IN | 0 ETH | 0.00000183 | ||||
| Redeem Card | 37876651 | 4 days ago | IN | 0 ETH | 0.00000065 | ||||
| Deposit ERC20 | 37876594 | 4 days ago | IN | 0 ETH | 0.00000185 | ||||
| Redeem Card | 37467468 | 14 days ago | IN | 0 ETH | 0.00000174 | ||||
| Redeem Card | 37384016 | 16 days ago | IN | 0 ETH | 0.00000191 | ||||
| Redeem Card | 37360820 | 16 days ago | IN | 0 ETH | 0.00000104 | ||||
| Redeem Card | 37317324 | 17 days ago | IN | 0 ETH | 0.00000189 | ||||
| Cancel Card | 37119505 | 22 days ago | IN | 0 ETH | 0.0000015 | ||||
| Deposit ERC20 | 37119014 | 22 days ago | IN | 0 ETH | 0.000002 | ||||
| Redeem Card | 37040203 | 24 days ago | IN | 0 ETH | 0.00000049 | ||||
| Redeem Card | 37039825 | 24 days ago | IN | 0 ETH | 0.00000036 | ||||
| Redeem Card | 37039183 | 24 days ago | IN | 0 ETH | 0.00000073 | ||||
| Cancel Card | 36799127 | 29 days ago | IN | 0 ETH | 0.00000084 | ||||
| Deposit ERC20 | 36798968 | 29 days ago | IN | 0 ETH | 0.00000262 | ||||
| Redeem Card | 36511474 | 36 days ago | IN | 0 ETH | 0.00000051 | ||||
| Redeem Card | 36458058 | 37 days ago | IN | 0 ETH | 0.00000026 | ||||
| Redeem Card | 36458038 | 37 days ago | IN | 0 ETH | 0.00000026 | ||||
| Deposit ETH | 36416845 | 38 days ago | IN | 0.00000101 ETH | 0.00000076 | ||||
| Redeem Card | 36363994 | 39 days ago | IN | 0 ETH | 0.0000008 |
Latest 23 internal transactions
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 35752955 | 54 days ago | 0.00000001 ETH | ||||
| 35752707 | 54 days ago | 0.0001 ETH | ||||
| 35007167 | 71 days ago | 0.0001 ETH | ||||
| 34487831 | 83 days ago | 0.002 ETH | ||||
| 34487831 | 83 days ago | 0.001 ETH | ||||
| 34484080 | 83 days ago | 0.0025 ETH | ||||
| 34483904 | 83 days ago | 0.003 ETH | ||||
| 34483445 | 83 days ago | 0.002 ETH | ||||
| 33710013 | 101 days ago | 0 ETH | ||||
| 33710013 | 101 days ago | 0 ETH | ||||
| 32422424 | 131 days ago | 0.0001 ETH | ||||
| 32404845 | 131 days ago | 0.0001 ETH | ||||
| 32404813 | 131 days ago | 0.0001 ETH | ||||
| 32371565 | 132 days ago | 0.0001 ETH | ||||
| 31824554 | 145 days ago | 0.0001 ETH | ||||
| 31823064 | 145 days ago | 0.02 ETH | ||||
| 31823064 | 145 days ago | 0.0001 ETH | ||||
| 31823064 | 145 days ago | 0.0001 ETH | ||||
| 31822291 | 145 days ago | 0.0001 ETH | ||||
| 31811083 | 145 days ago | 0.00001 ETH | ||||
| 31811031 | 145 days ago | 0.0001 ETH | ||||
| 31805854 | 145 days ago | 0.01 ETH | ||||
| 31629702 | 149 days ago | 0.01 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
UniVoucher
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
// Copyright (C) 2025 UniVoucher (pseudonymous). All Rights Reserved.
/**
* Business Source License 1.1
*
* Licensed Work: UniVoucher Smart Contract
* Additional Use Grant: None
* Change Date: 2035-05-04
* Change License: MIT
*
* This source code is licensed under the Business Source License 1.1, which
* restricts use in production. After the Change Date, this code will be
* available under the MIT License.
*/
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title UniVoucher
* @dev A contract that allows users to create crypto gift cards with ETH or ERC20 tokens
* that can be redeemed by the holder of a card secret.
*/
contract UniVoucher is ReentrancyGuard, Ownable {
using SafeERC20 for IERC20;
using ECDSA for bytes32;
// State variables for protocol configuration
uint256 public feePercentage = 100; // 1% (in basis points: 100/10000 = 0.01)
uint256 public nextCardNumber = 1;
string public chainPrefix;
string public versionPrefix;
/**
* @dev Emitted when a new gift card is created
*/
event CardCreated(string cardId, address indexed slotId, address indexed creator, address tokenAddress, uint256 tokenAmount, uint256 feePaid, string message, string encryptedPrivateKey, uint256 timestamp);
/**
* @dev Emitted when a gift card is redeemed
*/
event CardRedeemed(string cardId, address indexed slotId, address indexed to, address tokenAddress, uint256 amount, address indexed partner, uint256 timestamp);
/**
* @dev Emitted when a gift card is cancelled
*/
event CardCancelled(string cardId, address indexed slotId, address indexed creator, address tokenAddress, uint256 amount, uint256 timestamp);
/**
* @dev Emitted when fee percentage is updated
*/
event FeePercentageUpdated(uint256 oldFeePercentage, uint256 newFeePercentage, uint256 timestamp);
/**
* @dev Emitted when protocol fees are withdrawn
*/
event FeesWithdrawn(address indexed token, address indexed recipient, uint256 amount, uint256 timestamp);
struct TokenSlot {
// True if this slot is active (funds available), false if inactive or redeemed
bool active;
// The token contract address (address(0) for ETH)
address tokenAddress;
// Amount of tokens stored
uint256 tokenAmount;
// Fee paid when creating the card
uint256 feePaid;
// Original creator (for cancellation)
address creator;
// Optional message attached to the gift card
string message;
// Encrypted private key (optional - for card secret format)
string encryptedPrivateKey;
// Timestamp when the card was created
uint256 timestamp;
// Address that redeemed the card (address(0) if not redeemed)
address redeemedBy;
// Address that cancelled the card (address(0) if not cancelled)
address cancelledBy;
// Partner address used during redemption (address(0) if no partner)
address partnerAddress;
// Timestamp when the card was redeemed or cancelled
uint256 finalizedTimestamp;
}
// Mapping from slot ID (public key) to token slot data
mapping(address => TokenSlot) internal _slots;
// Mapping from card ID to slot ID
mapping(string => address) public cardToSlot;
// Mapping from slot ID to card ID
mapping(address => string) public slotToCard;
// Accumulated fees by token address
mapping(address => uint256) public accumulatedFees;
/**
* @dev Contract constructor
* @param _chainPrefix The prefix indicating the chain (e.g., "01" for Ethereum)
* @param _versionPrefix The version prefix (e.g., "1" for version 1)
*/
constructor(string memory _chainPrefix, string memory _versionPrefix) Ownable(msg.sender) {
chainPrefix = _chainPrefix;
versionPrefix = _versionPrefix;
}
/**
* @dev Generate a new card ID
* @return cardId The generated card ID
*/
function _generateCardId() internal returns (string memory) {
string memory cardId = string(abi.encodePacked(
versionPrefix,
chainPrefix,
_uintToString(nextCardNumber)
));
nextCardNumber++;
return cardId;
}
/**
* @dev Converts a uint to a string
* @param _value The uint value to convert
* @return The string representation
*/
function _uintToString(uint256 _value) internal pure returns (string memory) {
if (_value == 0) {
return "0";
}
uint256 temp = _value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (_value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(_value % 10)));
_value /= 10;
}
return string(buffer);
}
/**
* @dev Check if a string is empty
* @param str The string to check
* @return True if the string is empty
*/
function _isEmptyString(string memory str) internal pure returns (bool) {
return bytes(str).length == 0;
}
/**
* @dev Calculate the fee for a given amount
* @param amount The amount to calculate fee for
* @return fee The calculated fee amount
*/
function calculateFee(uint256 amount) public view returns (uint256) {
uint256 calculatedFee = (amount * feePercentage) / 10000;
uint256 minFee = 1; // Minimum fee of 1 wei
return calculatedFee > minFee ? calculatedFee : minFee;
}
/**
* @dev Deposit ETH to create a new gift card.
* @param slotId The public key / address of the gift card
* @param message The message attached to the gift card
* @param encryptedPrivateKey The encrypted private key (optional)
*/
function depositETH(
address slotId,
uint256 amount,
string memory message,
string memory encryptedPrivateKey
) external payable {
require(amount > 0, "Cannot deposit 0 ETH");
// Calculate fee on top of the amount
uint256 fee = calculateFee(amount);
// Ensure the total sent covers the amount plus fee
require(msg.value >= amount + fee, "Insufficient ETH sent");
// Accumulate the fee
accumulatedFees[address(0)] += fee;
// Create the gift card with the specified amount
_createCard(slotId, address(0), amount, fee, message, encryptedPrivateKey);
// Return excess ETH if any
uint256 excess = msg.value - (amount + fee);
if (excess > 0) {
(bool sent, ) = payable(msg.sender).call{value: excess}("");
require(sent, "Failed to return excess ETH");
}
}
/**
* @dev Deposit ERC20 tokens to create a new gift card.
* @param slotId The public key / address of the gift card
* @param tokenAddress The address of the ERC20 token
* @param amount The amount of tokens to deposit
* @param message The message attached to the gift card (optional)
* @param encryptedPrivateKey The encrypted private key (optional)
*/
function depositERC20(
address slotId,
address tokenAddress,
uint256 amount,
string memory message,
string memory encryptedPrivateKey
) external {
require(tokenAddress != address(0), "Use depositETH for native currency");
require(amount > 0, "Cannot deposit 0 tokens");
// Calculate fee on top of the amount
uint256 fee = calculateFee(amount);
uint256 totalRequired = amount + fee;
// Transfer tokens from sender to this contract (amount + fee)
IERC20(tokenAddress).safeTransferFrom(msg.sender, address(this), totalRequired);
// Accumulate the fee
accumulatedFees[tokenAddress] += fee;
// Create the gift card with the specified amount
_createCard(slotId, tokenAddress, amount, fee, message, encryptedPrivateKey);
}
/**
* @dev Internal function to create a gift card
*/
function _createCard(
address slotId,
address tokenAddress,
uint256 amount,
uint256 fee,
string memory message,
string memory encryptedPrivateKey
) internal {
require(slotId != address(0), "Cannot use zero address as slot ID");
require(_isEmptyString(slotToCard[slotId]), "Slot ID already used");
// Generate a unique card ID
string memory cardId = _generateCardId();
// Store the mappings
cardToSlot[cardId] = slotId;
slotToCard[slotId] = cardId;
// Create the slot
_slots[slotId] = TokenSlot({
active: true,
tokenAddress: tokenAddress,
tokenAmount: amount,
feePaid: fee,
creator: msg.sender,
message: message,
encryptedPrivateKey: encryptedPrivateKey,
timestamp: block.timestamp,
redeemedBy: address(0),
cancelledBy: address(0),
partnerAddress: address(0),
finalizedTimestamp: 0
});
emit CardCreated(cardId, slotId, msg.sender, tokenAddress, amount, fee, message, encryptedPrivateKey, block.timestamp);
}
/**
* @dev Redeem a gift card using its ID and signature.
* @param cardId The ID of the gift card to redeem
* @param to The address where to send the redeemed tokens
* @param signature A signature proving ownership of the card secret
* @param partner Optional partner address to receive 1% of the card amount (use address(0) for no partner)
*/
function redeemCard(string memory cardId, address payable to, bytes memory signature, address payable partner) external nonReentrant {
address slotId = cardToSlot[cardId];
require(slotId != address(0), "Invalid card ID");
require(_slots[slotId].active, "Card already redeemed or cancelled");
require(to != address(0), "Cannot redeem to zero address");
// Create a message that includes the recipient address to prevent front-running
bytes32 messageHash = keccak256(abi.encodePacked("Redeem card:", cardId, "to:", to));
// Add the Ethereum Signed Message prefix
bytes32 ethSignedMessageHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash));
// Recover the signer address from the signature
address signer = ethSignedMessageHash.recover(signature);
// Verify the signer matches the slot ID (which is the public key)
require(signer == slotId, "Invalid signature");
// Make a copy of the slot data as we are about to overwrite it
TokenSlot memory slotCopy = _slots[slotId];
// Mark the slot as redeemed before transferring funds
_slots[slotId].active = false;
// Record who redeemed the card and partner info
_slots[slotId].redeemedBy = to;
_slots[slotId].partnerAddress = partner;
_slots[slotId].finalizedTimestamp = block.timestamp;
// Calculate partner fee (1% if partner is provided, minimum 1 wei)
uint256 partnerAmount = (partner != address(0)) ?
(slotCopy.tokenAmount / 100 > 0 ? slotCopy.tokenAmount / 100 : 1) : 0;
// Transfer the assets
if (slotCopy.tokenAddress == address(0)) {
// Transfer ETH
if (partnerAmount > 0) {
(bool sentPartner, ) = partner.call{value: partnerAmount}("");
require(sentPartner, "Failed to send ETH to partner");
}
(bool sent, ) = to.call{value: slotCopy.tokenAmount - partnerAmount}("");
require(sent, "Failed to send ETH");
} else {
// Transfer ERC20 tokens
if (partnerAmount > 0) {
IERC20(slotCopy.tokenAddress).safeTransfer(partner, partnerAmount);
}
IERC20(slotCopy.tokenAddress).safeTransfer(to, slotCopy.tokenAmount - partnerAmount);
}
emit CardRedeemed(cardId, slotId, to, slotCopy.tokenAddress, slotCopy.tokenAmount, partner, block.timestamp);
}
/**
* @dev Cancel a gift card and return funds to the caller (msg.sender).
* @param cardId The ID of the gift card to cancel
*/
function cancelCard(string memory cardId) external nonReentrant {
address slotId = cardToSlot[cardId];
require(slotId != address(0), "Invalid card ID");
TokenSlot memory slot = _slots[slotId];
require(slot.active, "Card already redeemed or cancelled");
// Either the creator can cancel anytime OR the owner can cancel if the card is abandoned after 5 years.
require(
slot.creator == msg.sender ||
(msg.sender == owner() && block.timestamp > slot.timestamp + 1825 days),
"Not authorized: must be creator or owner (if abandoned)"
);
// Mark the slot as inactive before transferring funds
_slots[slotId].active = false;
// Record who cancelled the card
_slots[slotId].cancelledBy = msg.sender;
_slots[slotId].finalizedTimestamp = block.timestamp;
// Transfer the assets directly to the caller (msg.sender)
if (slot.tokenAddress == address(0)) {
// Transfer ETH
(bool sent, ) = payable(msg.sender).call{value: slot.tokenAmount}("");
require(sent, "Failed to send ETH");
} else {
// Transfer ERC20 tokens
IERC20(slot.tokenAddress).safeTransfer(msg.sender, slot.tokenAmount);
}
emit CardCancelled(cardId, slotId, slot.creator, slot.tokenAddress, slot.tokenAmount, block.timestamp);
}
/**
* @dev Update the fee percentage.
* @param newFeePercentage The new fee percentage in basis points (1/100 of a percent)
*/
function setFeePercentage(uint256 newFeePercentage) external onlyOwner {
require(newFeePercentage <= 200, "Fee cannot exceed 2%");
uint256 oldFeePercentage = feePercentage;
feePercentage = newFeePercentage;
emit FeePercentageUpdated(oldFeePercentage, newFeePercentage, block.timestamp);
}
/**
* @dev Withdraw accumulated fees.
* @param tokenAddress The token address to withdraw fees for (address(0) for ETH)
*/
function withdrawFees(address tokenAddress) external onlyOwner {
uint256 amount = accumulatedFees[tokenAddress];
require(amount > 0, "No fees to withdraw");
// Reset accumulated fees before transfer
accumulatedFees[tokenAddress] = 0;
if (tokenAddress == address(0)) {
// Transfer ETH
(bool sent, ) = payable(msg.sender).call{value: amount}("");
require(sent, "Failed to send ETH");
} else {
// Transfer ERC20 tokens
IERC20(tokenAddress).safeTransfer(msg.sender, amount);
}
emit FeesWithdrawn(tokenAddress, msg.sender, amount, block.timestamp);
}
/**
* @dev Get the data for a specific card.
* @param cardId The ID of the card
* @return active Whether the card is active
* @return tokenAddress The token address (address(0) for ETH)
* @return tokenAmount The token amount
* @return feePaid fee paid for this card
* @return creator The creator address
* @return message The card message
* @return encryptedPrivateKey The encrypted private key (if available)
* @return slotId The slot ID (public key)
* @return timestamp The timestamp when the card was created
* @return redeemedBy The address that redeemed the card (address(0) if not redeemed)
* @return cancelledBy The address that cancelled the card (address(0) if not cancelled)
* @return partnerAddress The partner address used during redemption (address(0) if no partner)
* @return finalizedTimestamp The timestamp when the card was redeemed or cancelled
*/
function getCardData(string memory cardId) external view returns (
bool active,
address tokenAddress,
uint256 tokenAmount,
uint256 feePaid,
address creator,
string memory message,
string memory encryptedPrivateKey,
address slotId,
uint256 timestamp,
address redeemedBy,
address cancelledBy,
address partnerAddress,
uint256 finalizedTimestamp
) {
slotId = cardToSlot[cardId];
require(slotId != address(0), "Invalid card ID");
TokenSlot memory slot = _slots[slotId];
return (
slot.active,
slot.tokenAddress,
slot.tokenAmount,
slot.feePaid,
slot.creator,
slot.message,
slot.encryptedPrivateKey,
slotId,
slot.timestamp,
slot.redeemedBy,
slot.cancelledBy,
slot.partnerAddress,
slot.finalizedTimestamp
);
}
/**
* @dev Get the card ID for a slot ID.
* @param slotId The slot ID (public key)
* @return The card ID
*/
function getCardId(address slotId) external view returns (string memory) {
return slotToCard[slotId];
}
/**
* @dev Deposit ETH to create multiple gift cards.
* @param slotIds Array of public keys / addresses for the gift cards
* @param amounts Array of amounts for each card
* @param messages Array of messages for each card
* @param encryptedPrivateKeys Array of encrypted private keys
*/
function bulkDepositETH(
address[] calldata slotIds,
uint256[] calldata amounts,
string[] calldata messages,
string[] calldata encryptedPrivateKeys
) external payable {
require(slotIds.length > 0, "Must create at least one card");
require(slotIds.length == amounts.length, "Arrays length mismatch");
require(slotIds.length == messages.length, "Arrays length mismatch");
require(slotIds.length == encryptedPrivateKeys.length, "Arrays length mismatch");
// Calculate total amount and fee
uint256 totalAmount = 0;
uint256 totalFee = 0;
// Pre-calculate fees for each card
uint256[] memory fees = new uint256[](amounts.length);
for (uint256 i = 0; i < amounts.length; i++) {
require(amounts[i] > 0, "Cannot deposit 0 ETH");
totalAmount += amounts[i];
fees[i] = calculateFee(amounts[i]);
totalFee += fees[i];
}
// Ensure sufficient ETH was sent
require(msg.value >= totalAmount + totalFee, "Insufficient ETH sent");
// Accumulate the fee
accumulatedFees[address(0)] += totalFee;
// Create each card with its specific fee
for (uint256 i = 0; i < slotIds.length; i++) {
_createCard(slotIds[i], address(0), amounts[i], fees[i], messages[i], encryptedPrivateKeys[i]);
}
// Return excess ETH if any
uint256 excess = msg.value - (totalAmount + totalFee);
if (excess > 0) {
(bool sent, ) = payable(msg.sender).call{value: excess}("");
require(sent, "Failed to return excess ETH");
}
}
/**
* @dev Deposit ERC20 tokens to create multiple gift cards.
* @param slotIds Array of public keys / addresses for the gift cards
* @param tokenAddress The address of the ERC20 token (same for all cards)
* @param amounts Array of amounts for each card
* @param messages Array of messages for each card
* @param encryptedPrivateKeys Array of encrypted private keys
*/
function bulkDepositERC20(
address[] calldata slotIds,
address tokenAddress,
uint256[] calldata amounts,
string[] calldata messages,
string[] calldata encryptedPrivateKeys
) external {
require(tokenAddress != address(0), "Use bulkDepositETH instead");
require(slotIds.length > 0, "Must create at least one card");
require(slotIds.length == amounts.length, "Arrays length mismatch");
require(slotIds.length == messages.length, "Arrays length mismatch");
require(slotIds.length == encryptedPrivateKeys.length, "Arrays length mismatch");
// Calculate total amount and fee
uint256 totalAmount = 0;
uint256 totalFee = 0;
// Pre-calculate fees for each card
uint256[] memory fees = new uint256[](amounts.length);
for (uint256 i = 0; i < amounts.length; i++) {
require(amounts[i] > 0, "Cannot deposit 0 tokens");
totalAmount += amounts[i];
fees[i] = calculateFee(amounts[i]);
totalFee += fees[i];
}
uint256 totalRequired = totalAmount + totalFee;
// Transfer the total tokens needed
IERC20(tokenAddress).safeTransferFrom(msg.sender, address(this), totalRequired);
// Accumulate the fee
accumulatedFees[tokenAddress] += totalFee;
// Create each card with its specific fee
for (uint256 i = 0; i < slotIds.length; i++) {
_createCard(slotIds[i], tokenAddress, amounts[i], fees[i], messages[i], encryptedPrivateKeys[i]);
}
}
/**
* @dev Cancel multiple gift cards and return funds to the caller.
* @param cardIds Array of card IDs to cancel
*/
function bulkCancelCards(string[] memory cardIds) external nonReentrant {
require(cardIds.length > 0, "Must cancel at least one card");
for (uint256 i = 0; i < cardIds.length; i++) {
string memory cardId = cardIds[i];
address slotId = cardToSlot[cardId];
require(slotId != address(0), "Invalid card ID");
TokenSlot memory slot = _slots[slotId];
require(slot.active, "Card already redeemed or cancelled");
// Either the creator can cancel anytime OR the owner can cancel if the card is abandoned.
require(
slot.creator == msg.sender ||
(msg.sender == owner() && block.timestamp > slot.timestamp + 1825 days),
"Not authorized: must be creator or owner (if abandoned)"
);
// Mark the slot as inactive before transferring funds
_slots[slotId].active = false;
// Record who cancelled the card
_slots[slotId].cancelledBy = msg.sender;
_slots[slotId].finalizedTimestamp = block.timestamp;
// Transfer the assets directly to the caller (msg.sender)
if (slot.tokenAddress == address(0)) {
// Transfer ETH
(bool sent, ) = payable(msg.sender).call{value: slot.tokenAmount}("");
require(sent, "Failed to send ETH");
} else {
// Transfer ERC20 tokens
IERC20(slot.tokenAddress).safeTransfer(msg.sender, slot.tokenAmount);
}
emit CardCancelled(cardId, slotId, slot.creator, slot.tokenAddress, slot.tokenAmount, block.timestamp);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @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.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, bytes memory returndata) = recipient.call{value: amount}("");
if (!success) {
_revert(returndata);
}
}
/**
* @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 or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* 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.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @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`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
*/
function _revert(bytes memory returndata) 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
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.20;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS
}
/**
* @dev The signature derives the `address(0)`.
*/
error ECDSAInvalidSignature();
/**
* @dev The signature has an invalid length.
*/
error ECDSAInvalidSignatureLength(uint256 length);
/**
* @dev The signature has an S value that is in the upper half order.
*/
error ECDSAInvalidSignatureS(bytes32 s);
/**
* @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not
* return address(0) without also returning an error description. Errors are documented using an enum (error type)
* and a bytes32 providing additional information about the error.
*
* If no error is returned, then the address can be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*/
function tryRecover(
bytes32 hash,
bytes memory signature
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
assembly ("memory-safe") {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[ERC-2098 short signatures]
*/
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
unchecked {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
// We do not check for an overflow here since the shift operation results in 0 or 1.
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address recovered, RecoverError err, bytes32 errArg) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS, s);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature, bytes32(0));
}
return (signer, RecoverError.NoError, bytes32(0));
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
_throwError(error, errorArg);
return recovered;
}
/**
* @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
*/
function _throwError(RecoverError error, bytes32 errorArg) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert ECDSAInvalidSignature();
} else if (error == RecoverError.InvalidSignatureLength) {
revert ECDSAInvalidSignatureLength(uint256(errorArg));
} else if (error == RecoverError.InvalidSignatureS) {
revert ECDSAInvalidSignatureS(errorArg);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 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 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, 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.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @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.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @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 {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @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 silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* 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[ERC 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);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": []
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"_chainPrefix","type":"string"},{"internalType":"string","name":"_versionPrefix","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ECDSAInvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"ECDSAInvalidSignatureLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"ECDSAInvalidSignatureS","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"cardId","type":"string"},{"indexed":true,"internalType":"address","name":"slotId","type":"address"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"CardCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"cardId","type":"string"},{"indexed":true,"internalType":"address","name":"slotId","type":"address"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feePaid","type":"uint256"},{"indexed":false,"internalType":"string","name":"message","type":"string"},{"indexed":false,"internalType":"string","name":"encryptedPrivateKey","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"CardCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"cardId","type":"string"},{"indexed":true,"internalType":"address","name":"slotId","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"partner","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"CardRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldFeePercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newFeePercentage","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeePercentageUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeesWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accumulatedFees","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string[]","name":"cardIds","type":"string[]"}],"name":"bulkCancelCards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"slotIds","type":"address[]"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"string[]","name":"messages","type":"string[]"},{"internalType":"string[]","name":"encryptedPrivateKeys","type":"string[]"}],"name":"bulkDepositERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"slotIds","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"string[]","name":"messages","type":"string[]"},{"internalType":"string[]","name":"encryptedPrivateKeys","type":"string[]"}],"name":"bulkDepositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"calculateFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"cardId","type":"string"}],"name":"cancelCard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"cardToSlot","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainPrefix","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"slotId","type":"address"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"message","type":"string"},{"internalType":"string","name":"encryptedPrivateKey","type":"string"}],"name":"depositERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"slotId","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"message","type":"string"},{"internalType":"string","name":"encryptedPrivateKey","type":"string"}],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"feePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"cardId","type":"string"}],"name":"getCardData","outputs":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"uint256","name":"feePaid","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"string","name":"message","type":"string"},{"internalType":"string","name":"encryptedPrivateKey","type":"string"},{"internalType":"address","name":"slotId","type":"address"},{"internalType":"uint256","name":"timestamp","type":"uint256"},{"internalType":"address","name":"redeemedBy","type":"address"},{"internalType":"address","name":"cancelledBy","type":"address"},{"internalType":"address","name":"partnerAddress","type":"address"},{"internalType":"uint256","name":"finalizedTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"slotId","type":"address"}],"name":"getCardId","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextCardNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"cardId","type":"string"},{"internalType":"address payable","name":"to","type":"address"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"address payable","name":"partner","type":"address"}],"name":"redeemCard","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeePercentage","type":"uint256"}],"name":"setFeePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"slotToCard","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"versionPrefix","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"}],"name":"withdrawFees","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6080604052606460025560016003553480156200001a575f80fd5b5060405162003be538038062003be58339810160408190526200003d91620001ab565b60015f5533806200006757604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b620000728162000099565b5060046200008183826200029b565b5060056200009082826200029b565b50505062000367565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126200010e575f80fd5b81516001600160401b03808211156200012b576200012b620000ea565b604051601f8301601f19908116603f01168101908282118183101715620001565762000156620000ea565b816040528381526020925086602085880101111562000173575f80fd5b5f91505b8382101562000196578582018301518183018401529082019062000177565b5f602085830101528094505050505092915050565b5f8060408385031215620001bd575f80fd5b82516001600160401b0380821115620001d4575f80fd5b620001e286838701620000fe565b93506020850151915080821115620001f8575f80fd5b506200020785828601620000fe565b9150509250929050565b600181811c908216806200022657607f821691505b6020821081036200024557634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200029657805f5260205f20601f840160051c81016020851015620002725750805b601f840160051c820191505b8181101562000293575f81556001016200027e565b50505b505050565b81516001600160401b03811115620002b757620002b7620000ea565b620002cf81620002c8845462000211565b846200024b565b602080601f83116001811462000305575f8415620002ed5750858301515b5f19600386901b1c1916600185901b1785556200035f565b5f85815260208120601f198616915b82811015620003355788860151825594840194600190910190840162000314565b50858210156200035357878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b61387080620003755f395ff3fe608060405260043610610131575f3560e01c8063961b6aed116100a8578063ae06c1b71161006d578063ae06c1b71461034e578063b52e019f1461036d578063db079ebc1461038c578063f2fde38b146103ab578063f5a3a442146103ca578063fcf66664146103e9575f80fd5b8063961b6aed146102e057806399a5d747146102f3578063a001ecdd14610312578063a862c34b14610327578063a91db16b1461033a575f80fd5b8063576efc35116100f9578063576efc35146101f657806365a93b5614610215578063715018a61461026d5780637366f8ef146102815780638da5cb5b146102a457806393484daf146102c1575f80fd5b80630134edd614610135578063047086f214610156578063164e68de1461017557806332c5b4de146101945780634d2bf197146101be575b5f80fd5b348015610140575f80fd5b5061015461014f366004612d56565b610414565b005b348015610161575f80fd5b50610154610170366004612e11565b610878565b348015610180575f80fd5b5061015461018f366004612e56565b610c52565b34801561019f575f80fd5b506101a8610d99565b6040516101b59190612ebe565b60405180910390f35b3480156101c9575f80fd5b506101dd6101d8366004612e11565b610e25565b6040516101b59d9c9b9a99989796959493929190612ed0565b348015610201575f80fd5b50610154610210366004612f92565b61110f565b348015610220575f80fd5b5061025561022f366004612e11565b80516020818301810180516007825292820191909301209152546001600160a01b031681565b6040516001600160a01b0390911681526020016101b5565b348015610278575f80fd5b5061015461172b565b34801561028c575f80fd5b5061029660035481565b6040519081526020016101b5565b3480156102af575f80fd5b506001546001600160a01b0316610255565b3480156102cc575f80fd5b506101a86102db366004612e56565b61173e565b6101546102ee366004613071565b6117e7565b3480156102fe575f80fd5b5061029661030d36600461312b565b611c50565b34801561031d575f80fd5b5061029660025481565b610154610335366004613142565b611c88565b348015610345575f80fd5b506101a8611e35565b348015610359575f80fd5b5061015461036836600461312b565b611e42565b348015610378575f80fd5b506101546103873660046131bc565b611edd565b348015610397575f80fd5b506101a86103a6366004612e56565b611ff0565b3480156103b6575f80fd5b506101546103c5366004612e56565b612008565b3480156103d5575f80fd5b506101546103e4366004613248565b612042565b3480156103f4575f80fd5b50610296610403366004612e56565b60096020525f908152604090205481565b61041c6123b8565b5f8151116104715760405162461bcd60e51b815260206004820152601d60248201527f4d7573742063616e63656c206174206c65617374206f6e65206361726400000060448201526064015b60405180910390fd5b5f5b815181101561086b575f82828151811061048f5761048f613318565b602002602001015190505f6007826040516104aa919061332c565b908152604051908190036020019020546001600160a01b03169050806104e25760405162461bcd60e51b815260040161046890613347565b6001600160a01b038082165f908152600660209081526040808320815161018081018352815460ff811615158252610100900486169381019390935260018101549183019190915260028101546060830152600381015490931660808201526004830180549293919260a08401919061055a90613370565b80601f016020809104026020016040519081016040528092919081815260200182805461058690613370565b80156105d15780601f106105a8576101008083540402835291602001916105d1565b820191905f5260205f20905b8154815290600101906020018083116105b457829003601f168201915b505050505081526020016005820180546105ea90613370565b80601f016020809104026020016040519081016040528092919081815260200182805461061690613370565b80156106615780601f1061063857610100808354040283529160200191610661565b820191905f5260205f20905b81548152906001019060200180831161064457829003601f168201915b50505091835250506006820154602082015260078201546001600160a01b0390811660408301526008830154811660608301526009830154166080820152600a9091015460a09091015280519091506106cc5760405162461bcd60e51b8152600401610468906133a8565b60808101516001600160a01b031633148061070d57506001546001600160a01b03163314801561070d575060e081015161070a9063096601806133fe565b42115b6107295760405162461bcd60e51b815260040161046890613411565b6001600160a01b038083165f908152600660209081526040909120805460ff191681556008810180546001600160a01b0319163317905542600a90910155820151166107dd5760408082015190515f9133918381818185875af1925050503d805f81146107b1576040519150601f19603f3d011682016040523d82523d5f602084013e6107b6565b606091505b50509050806107d75760405162461bcd60e51b81526004016104689061346e565b50610803565b61080333826040015183602001516001600160a01b031661240f9092919063ffffffff16565b80608001516001600160a01b0316826001600160a01b03167f5afb313cb5bbcdcfd5b0665bc8c4d3afb9eb69992797d9726b4ea64760814209858460200151856040015142604051610858949392919061349a565b60405180910390a3505050600101610473565b5061087560015f55565b50565b6108806123b8565b5f600782604051610891919061332c565b908152604051908190036020019020546001600160a01b03169050806108c95760405162461bcd60e51b815260040161046890613347565b6001600160a01b038082165f908152600660209081526040808320815161018081018352815460ff811615158252610100900486169381019390935260018101549183019190915260028101546060830152600381015490931660808201526004830180549293919260a08401919061094190613370565b80601f016020809104026020016040519081016040528092919081815260200182805461096d90613370565b80156109b85780601f1061098f576101008083540402835291602001916109b8565b820191905f5260205f20905b81548152906001019060200180831161099b57829003601f168201915b505050505081526020016005820180546109d190613370565b80601f01602080910402602001604051908101604052809291908181526020018280546109fd90613370565b8015610a485780601f10610a1f57610100808354040283529160200191610a48565b820191905f5260205f20905b815481529060010190602001808311610a2b57829003601f168201915b50505091835250506006820154602082015260078201546001600160a01b0390811660408301526008830154811660608301526009830154166080820152600a9091015460a0909101528051909150610ab35760405162461bcd60e51b8152600401610468906133a8565b60808101516001600160a01b0316331480610af457506001546001600160a01b031633148015610af4575060e0810151610af19063096601806133fe565b42115b610b105760405162461bcd60e51b815260040161046890613411565b6001600160a01b038083165f908152600660209081526040909120805460ff191681556008810180546001600160a01b0319163317905542600a9091015582015116610bc45760408082015190515f9133918381818185875af1925050503d805f8114610b98576040519150601f19603f3d011682016040523d82523d5f602084013e610b9d565b606091505b5050905080610bbe5760405162461bcd60e51b81526004016104689061346e565b50610bea565b610bea33826040015183602001516001600160a01b031661240f9092919063ffffffff16565b80608001516001600160a01b0316826001600160a01b03167f5afb313cb5bbcdcfd5b0665bc8c4d3afb9eb69992797d9726b4ea64760814209858460200151856040015142604051610c3f949392919061349a565b60405180910390a3505061087560015f55565b610c5a612473565b6001600160a01b0381165f9081526009602052604090205480610cb55760405162461bcd60e51b81526020600482015260136024820152724e6f206665657320746f20776974686472617760681b6044820152606401610468565b6001600160a01b0382165f81815260096020526040812055610d3c576040515f90339083908381818185875af1925050503d805f8114610d10576040519150601f19603f3d011682016040523d82523d5f602084013e610d15565b606091505b5050905080610d365760405162461bcd60e51b81526004016104689061346e565b50610d50565b610d506001600160a01b038316338361240f565b6040805182815242602082015233916001600160a01b038516917fc7966d68b12e948d7c237e7d9137565fcd716dbc3d168b724fc57c3a92859b2c910160405180910390a35050565b60048054610da690613370565b80601f0160208091040260200160405190810160405280929190818152602001828054610dd290613370565b8015610e1d5780601f10610df457610100808354040283529160200191610e1d565b820191905f5260205f20905b815481529060010190602001808311610e0057829003601f168201915b505050505081565b5f805f805f6060805f805f805f8060078e604051610e43919061332c565b908152604051908190036020019020546001600160a01b0316955085610e7b5760405162461bcd60e51b815260040161046890613347565b6001600160a01b038087165f908152600660209081526040808320815161018081018352815460ff811615158252610100900486169381019390935260018101549183019190915260028101546060830152600381015490931660808201526004830180549293919260a084019190610ef390613370565b80601f0160208091040260200160405190810160405280929190818152602001828054610f1f90613370565b8015610f6a5780601f10610f4157610100808354040283529160200191610f6a565b820191905f5260205f20905b815481529060010190602001808311610f4d57829003601f168201915b50505050508152602001600582018054610f8390613370565b80601f0160208091040260200160405190810160405280929190818152602001828054610faf90613370565b8015610ffa5780601f10610fd157610100808354040283529160200191610ffa565b820191905f5260205f20905b815481529060010190602001808311610fdd57829003601f168201915b5050505050815260200160068201548152602001600782015f9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600882015f9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600982015f9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600a820154815250509050805f015181602001518260400151836060015184608001518560a001518660c001518d8860e001518961010001518a61012001518b61014001518c61016001519d509d509d509d509d509d509d509d509d509d509d509d509d505091939597999b9d90929496989a9c50565b6111176123b8565b5f600785604051611128919061332c565b908152604051908190036020019020546001600160a01b03169050806111605760405162461bcd60e51b815260040161046890613347565b6001600160a01b0381165f9081526006602052604090205460ff166111975760405162461bcd60e51b8152600401610468906133a8565b6001600160a01b0384166111ed5760405162461bcd60e51b815260206004820152601d60248201527f43616e6e6f742072656465656d20746f207a65726f20616464726573730000006044820152606401610468565b5f85856040516020016112019291906134d1565b6040516020818303038152906040528051906020012090505f8160405160200161125791907f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b60408051601f19818403018152919052805160209091012090505f61127c82876124a0565b9050836001600160a01b0316816001600160a01b0316146112d35760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610468565b6001600160a01b038085165f908152600660209081526040808320815161018081018352815460ff811615158252610100900486169381019390935260018101549183019190915260028101546060830152600381015490931660808201526004830180549293919260a08401919061134b90613370565b80601f016020809104026020016040519081016040528092919081815260200182805461137790613370565b80156113c25780601f10611399576101008083540402835291602001916113c2565b820191905f5260205f20905b8154815290600101906020018083116113a557829003601f168201915b505050505081526020016005820180546113db90613370565b80601f016020809104026020016040519081016040528092919081815260200182805461140790613370565b80156114525780601f1061142957610100808354040283529160200191611452565b820191905f5260205f20905b81548152906001019060200180831161143557829003601f168201915b50505091835250506006828101546020808401919091526007808501546001600160a01b0390811660408087019190915260088701548216606087015260098088015483166080880152600a9788015460a0909701969096528c82165f90815294909352918320805460ff1916815590810180548f84166001600160a01b0319918216179091559381018054928d16929094168217909355429290930191909155919250611500575f61152f565b5f60648360400151611512919061353f565b1161151e57600161152f565b6064826040015161152f919061353f565b60208301519091506001600160a01b031661166b5780156115eb575f876001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611593576040519150601f19603f3d011682016040523d82523d5f602084013e611598565b606091505b50509050806115e95760405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f2073656e642045544820746f20706172746e65720000006044820152606401610468565b505b5f896001600160a01b03168284604001516116069190613552565b6040515f81818185875af1925050503d805f811461163f576040519150601f19603f3d011682016040523d82523d5f602084013e611644565b606091505b50509050806116655760405162461bcd60e51b81526004016104689061346e565b506116b3565b801561168a57602082015161168a906001600160a01b0316888361240f565b6116b38982846040015161169e9190613552565b60208501516001600160a01b0316919061240f565b866001600160a01b0316896001600160a01b0316876001600160a01b03167fa8aea98c2125c6a7d663e933034cbdcfc17683f069aeda216aae38f93790f98c8d866020015187604001514260405161170e949392919061349a565b60405180910390a450505050505061172560015f55565b50505050565b611733612473565b61173c5f6124ca565b565b6001600160a01b0381165f90815260086020526040902080546060919061176490613370565b80601f016020809104026020016040519081016040528092919081815260200182805461179090613370565b80156117db5780601f106117b2576101008083540402835291602001916117db565b820191905f5260205f20905b8154815290600101906020018083116117be57829003601f168201915b50505050509050919050565b866118345760405162461bcd60e51b815260206004820152601d60248201527f4d75737420637265617465206174206c65617374206f6e6520636172640000006044820152606401610468565b8685146118535760405162461bcd60e51b815260040161046890613565565b8683146118725760405162461bcd60e51b815260040161046890613565565b8681146118915760405162461bcd60e51b815260040161046890613565565b5f8080876001600160401b038111156118ac576118ac612c99565b6040519080825280602002602001820160405280156118d5578160200160208202803683370190505b5090505f5b888110156119d4575f8a8a838181106118f5576118f5613318565b90506020020135116119405760405162461bcd60e51b8152602060048201526014602482015273086c2dcdcdee840c8cae0dee6d2e84060408aa8960631b6044820152606401610468565b89898281811061195257611952613318565b905060200201358461196491906133fe565b93506119878a8a8381811061197b5761197b613318565b90506020020135611c50565b82828151811061199957611999613318565b6020026020010181815250508181815181106119b7576119b7613318565b6020026020010151836119ca91906133fe565b92506001016118da565b506119df82846133fe565b341015611a265760405162461bcd60e51b8152602060048201526015602482015274125b9cdd59999a58da595b9d08115512081cd95b9d605a1b6044820152606401610468565b5f80805260096020527fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b8054849290611a609084906133fe565b909155505f90505b8a811015611b8d57611b858c8c83818110611a8557611a85613318565b9050602002016020810190611a9a9190612e56565b5f8c8c85818110611aad57611aad613318565b90506020020135858581518110611ac657611ac6613318565b60200260200101518c8c87818110611ae057611ae0613318565b9050602002810190611af29190613595565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508e92508d9150899050818110611b3a57611b3a613318565b9050602002810190611b4c9190613595565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061251b92505050565b600101611a68565b505f611b9983856133fe565b611ba39034613552565b90508015611c42576040515f90339083908381818185875af1925050503d805f8114611bea576040519150601f19603f3d011682016040523d82523d5f602084013e611bef565b606091505b5050905080611c405760405162461bcd60e51b815260206004820152601b60248201527f4661696c656420746f2072657475726e206578636573732045544800000000006044820152606401610468565b505b505050505050505050505050565b5f8061271060025484611c6391906135d7565b611c6d919061353f565b90506001808211611c7e5780611c80565b815b949350505050565b5f8311611cce5760405162461bcd60e51b8152602060048201526014602482015273086c2dcdcdee840c8cae0dee6d2e84060408aa8960631b6044820152606401610468565b5f611cd884611c50565b9050611ce481856133fe565b341015611d2b5760405162461bcd60e51b8152602060048201526015602482015274125b9cdd59999a58da595b9d08115512081cd95b9d605a1b6044820152606401610468565b5f80805260096020527fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b8054839290611d659084906133fe565b90915550611d799050855f8684878761251b565b5f611d8482866133fe565b611d8e9034613552565b90508015611e2d576040515f90339083908381818185875af1925050503d805f8114611dd5576040519150601f19603f3d011682016040523d82523d5f602084013e611dda565b606091505b5050905080611e2b5760405162461bcd60e51b815260206004820152601b60248201527f4661696c656420746f2072657475726e206578636573732045544800000000006044820152606401610468565b505b505050505050565b60058054610da690613370565b611e4a612473565b60c8811115611e925760405162461bcd60e51b81526020600482015260146024820152734665652063616e6e6f742065786365656420322560601b6044820152606401610468565b60028054908290556040805182815260208101849052428183015290517f5d94a8aa43f58b2ea6ffdb6ec89bb71f9b57edb28d82934dac8d2dc6e52d18419181900360600190a15050565b6001600160a01b038416611f3e5760405162461bcd60e51b815260206004820152602260248201527f557365206465706f73697445544820666f72206e61746976652063757272656e604482015261637960f01b6064820152608401610468565b5f8311611f875760405162461bcd60e51b815260206004820152601760248201527643616e6e6f74206465706f736974203020746f6b656e7360481b6044820152606401610468565b5f611f9184611c50565b90505f611f9e82866133fe565b9050611fb56001600160a01b0387163330846128db565b6001600160a01b0386165f9081526009602052604081208054849290611fdc9084906133fe565b90915550611e2b905087878785888861251b565b60086020525f908152604090208054610da690613370565b612010612473565b6001600160a01b03811661203957604051631e4fbdf760e01b81525f6004820152602401610468565b610875816124ca565b6001600160a01b0387166120985760405162461bcd60e51b815260206004820152601a60248201527f5573652062756c6b4465706f73697445544820696e73746561640000000000006044820152606401610468565b876120e55760405162461bcd60e51b815260206004820152601d60248201527f4d75737420637265617465206174206c65617374206f6e6520636172640000006044820152606401610468565b8785146121045760405162461bcd60e51b815260040161046890613565565b8783146121235760405162461bcd60e51b815260040161046890613565565b8781146121425760405162461bcd60e51b815260040161046890613565565b5f8080876001600160401b0381111561215d5761215d612c99565b604051908082528060200260200182016040528015612186578160200160208202803683370190505b5090505f5b8881101561227c575f8a8a838181106121a6576121a6613318565b90506020020135116121f45760405162461bcd60e51b815260206004820152601760248201527643616e6e6f74206465706f736974203020746f6b656e7360481b6044820152606401610468565b89898281811061220657612206613318565b905060200201358461221891906133fe565b935061222f8a8a8381811061197b5761197b613318565b82828151811061224157612241613318565b60200260200101818152505081818151811061225f5761225f613318565b60200260200101518361227291906133fe565b925060010161218b565b505f61228883856133fe565b905061229f6001600160a01b038c163330846128db565b6001600160a01b038b165f90815260096020526040812080548592906122c69084906133fe565b909155505f90505b8c8110156123a8576123a08e8e838181106122eb576122eb613318565b90506020020160208101906123009190612e56565b8d8d8d8581811061231357612313613318565b9050602002013586858151811061232c5761232c613318565b60200260200101518d8d8781811061234657612346613318565b90506020028101906123589190613595565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508f92508e9150899050818110611b3a57611b3a613318565b6001016122ce565b5050505050505050505050505050565b60025f54036124095760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610468565b60025f55565b6040516001600160a01b0383811660248301526044820183905261246e91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612914565b505050565b6001546001600160a01b0316331461173c5760405163118cdaa760e01b8152336004820152602401610468565b5f805f806124ae8686612980565b9250925092506124be82826129c9565b50909150505b92915050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b03861661257c5760405162461bcd60e51b815260206004820152602260248201527f43616e6e6f7420757365207a65726f206164647265737320617320736c6f7420604482015261125160f21b6064820152608401610468565b6001600160a01b0386165f908152600860205260409020805461262491906125a390613370565b80601f01602080910402602001604051908101604052809291908181526020018280546125cf90613370565b801561261a5780601f106125f15761010080835404028352916020019161261a565b820191905f5260205f20905b8154815290600101906020018083116125fd57829003601f168201915b5050505050511590565b6126675760405162461bcd60e51b815260206004820152601460248201527314db1bdd08125108185b1c9958591e481d5cd95960621b6044820152606401610468565b5f612670612a85565b905086600782604051612683919061332c565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039485161790559189165f9081526008909152206126c58282613639565b50604051806101800160405280600115158152602001876001600160a01b03168152602001868152602001858152602001336001600160a01b031681526020018481526020018381526020014281526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81525060065f896001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160010155606082015181600201556080820151816003015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160040190816128099190613639565b5060c0820151600582019061281e9082613639565b5060e082015160068201556101008201516007820180546001600160a01b03199081166001600160a01b0393841617909155610120840151600884018054831691841691909117905561014084015160098401805490921690831617905561016090920151600a9091015560405133918916907fd2fcff1668b7c7615b3b77bc5ce8c16b211ba473fab592938b645eb5af6add96906128ca9085908b908b908b908b908b9042906136f4565b60405180910390a350505050505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526117259186918216906323b872dd9060840161243c565b5f8060205f8451602086015f885af180612933576040513d5f823e3d81fd5b50505f513d9150811561294a578060011415612957565b6001600160a01b0384163b155b1561172557604051635274afe760e01b81526001600160a01b0385166004820152602401610468565b5f805f83516041036129b7576020840151604085015160608601515f1a6129a988828585612ad5565b9550955095505050506129c2565b505081515f91506002905b9250925092565b5f8260038111156129dc576129dc61375e565b036129e5575050565b60018260038111156129f9576129f961375e565b03612a175760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115612a2b57612a2b61375e565b03612a4c5760405163fce698f760e01b815260048101829052602401610468565b6003826003811115612a6057612a6061375e565b03612a81576040516335e2f38360e21b815260048101829052602401610468565b5050565b60605f60056004612a97600354612b9d565b604051602001612aa9939291906137e1565b60408051601f19818403018152919052600380549192505f612aca8361380f565b909155509092915050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115612b0e57505f91506003905082612b93565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015612b5f573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116612b8a57505f925060019150829050612b93565b92505f91508190505b9450945094915050565b6060815f03612bc35750506040805180820190915260018152600360fc1b602082015290565b815f5b8115612bec5780612bd68161380f565b9150612be59050600a8361353f565b9150612bc6565b5f816001600160401b03811115612c0557612c05612c99565b6040519080825280601f01601f191660200182016040528015612c2f576020820181803683370190505b5090505b8415611c8057612c44600183613552565b9150612c51600a86613827565b612c5c9060306133fe565b60f81b818381518110612c7157612c71613318565b60200101906001600160f81b03191690815f1a905350612c92600a8661353f565b9450612c33565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715612cd557612cd5612c99565b604052919050565b5f6001600160401b03831115612cf557612cf5612c99565b612d08601f8401601f1916602001612cad565b9050828152838383011115612d1b575f80fd5b828260208301375f602084830101529392505050565b5f82601f830112612d40575f80fd5b612d4f83833560208501612cdd565b9392505050565b5f6020808385031215612d67575f80fd5b82356001600160401b0380821115612d7d575f80fd5b818501915085601f830112612d90575f80fd5b813581811115612da257612da2612c99565b8060051b612db1858201612cad565b9182528381018501918581019089841115612dca575f80fd5b86860192505b83831015612e0457823585811115612de6575f80fd5b612df48b89838a0101612d31565b8352509186019190860190612dd0565b9998505050505050505050565b5f60208284031215612e21575f80fd5b81356001600160401b03811115612e36575f80fd5b611c8084828501612d31565b6001600160a01b0381168114610875575f80fd5b5f60208284031215612e66575f80fd5b8135612d4f81612e42565b5f5b83811015612e8b578181015183820152602001612e73565b50505f910152565b5f8151808452612eaa816020860160208601612e71565b601f01601f19169290920160200192915050565b602081525f612d4f6020830184612e93565b8d151581526001600160a01b038d81166020830152604082018d9052606082018c90528a1660808201525f6101a08060a0840152612f108184018c612e93565b905082810360c0840152612f24818b612e93565b915050612f3c60e08301896001600160a01b03169052565b86610100830152612f596101208301876001600160a01b03169052565b6001600160a01b0385166101408301526001600160a01b038416610160830152826101808301529e9d5050505050505050505050505050565b5f805f8060808587031215612fa5575f80fd5b84356001600160401b0380821115612fbb575f80fd5b612fc788838901612d31565b955060208701359150612fd982612e42565b90935060408601359080821115612fee575f80fd5b508501601f81018713612fff575f80fd5b61300e87823560208401612cdd565b925050606085013561301f81612e42565b939692955090935050565b5f8083601f84011261303a575f80fd5b5081356001600160401b03811115613050575f80fd5b6020830191508360208260051b850101111561306a575f80fd5b9250929050565b5f805f805f805f806080898b031215613088575f80fd5b88356001600160401b038082111561309e575f80fd5b6130aa8c838d0161302a565b909a50985060208b01359150808211156130c2575f80fd5b6130ce8c838d0161302a565b909850965060408b01359150808211156130e6575f80fd5b6130f28c838d0161302a565b909650945060608b013591508082111561310a575f80fd5b506131178b828c0161302a565b999c989b5096995094979396929594505050565b5f6020828403121561313b575f80fd5b5035919050565b5f805f8060808587031215613155575f80fd5b843561316081612e42565b93506020850135925060408501356001600160401b0380821115613182575f80fd5b61318e88838901612d31565b935060608701359150808211156131a3575f80fd5b506131b087828801612d31565b91505092959194509250565b5f805f805f60a086880312156131d0575f80fd5b85356131db81612e42565b945060208601356131eb81612e42565b93506040860135925060608601356001600160401b038082111561320d575f80fd5b61321989838a01612d31565b9350608088013591508082111561322e575f80fd5b5061323b88828901612d31565b9150509295509295909350565b5f805f805f805f805f60a08a8c031215613260575f80fd5b89356001600160401b0380821115613276575f80fd5b6132828d838e0161302a565b909b50995060208c0135915061329782612e42565b90975060408b013590808211156132ac575f80fd5b6132b88d838e0161302a565b909850965060608c01359150808211156132d0575f80fd5b6132dc8d838e0161302a565b909650945060808c01359150808211156132f4575f80fd5b506133018c828d0161302a565b915080935050809150509295985092959850929598565b634e487b7160e01b5f52603260045260245ffd5b5f825161333d818460208701612e71565b9190910192915050565b6020808252600f908201526e125b9d985b1a590818d85c99081251608a1b604082015260600190565b600181811c9082168061338457607f821691505b6020821081036133a257634e487b7160e01b5f52602260045260245ffd5b50919050565b60208082526022908201527f4361726420616c72656164792072656465656d6564206f722063616e63656c6c604082015261195960f21b606082015260800190565b634e487b7160e01b5f52601160045260245ffd5b808201808211156124c4576124c46133ea565b60208082526037908201527f4e6f7420617574686f72697a65643a206d7573742062652063726561746f722060408201527f6f72206f776e657220286966206162616e646f6e656429000000000000000000606082015260800190565b60208082526012908201527108cc2d2d8cac840e8de40e6cadcc8408aa8960731b604082015260600190565b608081525f6134ac6080830187612e93565b6001600160a01b03959095166020830152506040810192909252606090910152919050565b6b2932b232b2b69031b0b9321d60a11b81525f83516134f781600c850160208801612e71565b623a379d60e91b600c93909101928301525060609190911b6bffffffffffffffffffffffff1916600f820152602301919050565b634e487b7160e01b5f52601260045260245ffd5b5f8261354d5761354d61352b565b500490565b818103818111156124c4576124c46133ea565b602080825260169082015275082e4e4c2f2e640d8cadccee8d040dad2e6dac2e8c6d60531b604082015260600190565b5f808335601e198436030181126135aa575f80fd5b8301803591506001600160401b038211156135c3575f80fd5b60200191503681900382131561306a575f80fd5b80820281158282048414176124c4576124c46133ea565b601f82111561246e57805f5260205f20601f840160051c810160208510156136135750805b601f840160051c820191505b81811015613632575f815560010161361f565b5050505050565b81516001600160401b0381111561365257613652612c99565b613666816136608454613370565b846135ee565b602080601f831160018114613699575f84156136825750858301515b5f19600386901b1c1916600185901b178555611e2d565b5f85815260208120601f198616915b828110156136c7578886015182559484019460019091019084016136a8565b50858210156136e457878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b60e081525f61370660e083018a612e93565b6001600160a01b0389166020840152604083018890526060830187905282810360808401526137358187612e93565b905082810360a08401526137498186612e93565b9150508260c083015298975050505050505050565b634e487b7160e01b5f52602160045260245ffd5b5f815461377e81613370565b6001828116801561379657600181146137ab576137d7565b60ff19841687528215158302870194506137d7565b855f526020805f205f5b858110156137ce5781548a8201529084019082016137b5565b50505082870194505b5050505092915050565b5f6137f56137ef8387613772565b85613772565b8351613805818360208801612e71565b0195945050505050565b5f60018201613820576138206133ea565b5060010190565b5f826138355761383561352b565b50069056fea26469706673582212203227e5cac19bee7693df89c39f5a2182ac357fbac6b6e1c7b1adfab60d21d56764736f6c63430008180033000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002303200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405260043610610131575f3560e01c8063961b6aed116100a8578063ae06c1b71161006d578063ae06c1b71461034e578063b52e019f1461036d578063db079ebc1461038c578063f2fde38b146103ab578063f5a3a442146103ca578063fcf66664146103e9575f80fd5b8063961b6aed146102e057806399a5d747146102f3578063a001ecdd14610312578063a862c34b14610327578063a91db16b1461033a575f80fd5b8063576efc35116100f9578063576efc35146101f657806365a93b5614610215578063715018a61461026d5780637366f8ef146102815780638da5cb5b146102a457806393484daf146102c1575f80fd5b80630134edd614610135578063047086f214610156578063164e68de1461017557806332c5b4de146101945780634d2bf197146101be575b5f80fd5b348015610140575f80fd5b5061015461014f366004612d56565b610414565b005b348015610161575f80fd5b50610154610170366004612e11565b610878565b348015610180575f80fd5b5061015461018f366004612e56565b610c52565b34801561019f575f80fd5b506101a8610d99565b6040516101b59190612ebe565b60405180910390f35b3480156101c9575f80fd5b506101dd6101d8366004612e11565b610e25565b6040516101b59d9c9b9a99989796959493929190612ed0565b348015610201575f80fd5b50610154610210366004612f92565b61110f565b348015610220575f80fd5b5061025561022f366004612e11565b80516020818301810180516007825292820191909301209152546001600160a01b031681565b6040516001600160a01b0390911681526020016101b5565b348015610278575f80fd5b5061015461172b565b34801561028c575f80fd5b5061029660035481565b6040519081526020016101b5565b3480156102af575f80fd5b506001546001600160a01b0316610255565b3480156102cc575f80fd5b506101a86102db366004612e56565b61173e565b6101546102ee366004613071565b6117e7565b3480156102fe575f80fd5b5061029661030d36600461312b565b611c50565b34801561031d575f80fd5b5061029660025481565b610154610335366004613142565b611c88565b348015610345575f80fd5b506101a8611e35565b348015610359575f80fd5b5061015461036836600461312b565b611e42565b348015610378575f80fd5b506101546103873660046131bc565b611edd565b348015610397575f80fd5b506101a86103a6366004612e56565b611ff0565b3480156103b6575f80fd5b506101546103c5366004612e56565b612008565b3480156103d5575f80fd5b506101546103e4366004613248565b612042565b3480156103f4575f80fd5b50610296610403366004612e56565b60096020525f908152604090205481565b61041c6123b8565b5f8151116104715760405162461bcd60e51b815260206004820152601d60248201527f4d7573742063616e63656c206174206c65617374206f6e65206361726400000060448201526064015b60405180910390fd5b5f5b815181101561086b575f82828151811061048f5761048f613318565b602002602001015190505f6007826040516104aa919061332c565b908152604051908190036020019020546001600160a01b03169050806104e25760405162461bcd60e51b815260040161046890613347565b6001600160a01b038082165f908152600660209081526040808320815161018081018352815460ff811615158252610100900486169381019390935260018101549183019190915260028101546060830152600381015490931660808201526004830180549293919260a08401919061055a90613370565b80601f016020809104026020016040519081016040528092919081815260200182805461058690613370565b80156105d15780601f106105a8576101008083540402835291602001916105d1565b820191905f5260205f20905b8154815290600101906020018083116105b457829003601f168201915b505050505081526020016005820180546105ea90613370565b80601f016020809104026020016040519081016040528092919081815260200182805461061690613370565b80156106615780601f1061063857610100808354040283529160200191610661565b820191905f5260205f20905b81548152906001019060200180831161064457829003601f168201915b50505091835250506006820154602082015260078201546001600160a01b0390811660408301526008830154811660608301526009830154166080820152600a9091015460a09091015280519091506106cc5760405162461bcd60e51b8152600401610468906133a8565b60808101516001600160a01b031633148061070d57506001546001600160a01b03163314801561070d575060e081015161070a9063096601806133fe565b42115b6107295760405162461bcd60e51b815260040161046890613411565b6001600160a01b038083165f908152600660209081526040909120805460ff191681556008810180546001600160a01b0319163317905542600a90910155820151166107dd5760408082015190515f9133918381818185875af1925050503d805f81146107b1576040519150601f19603f3d011682016040523d82523d5f602084013e6107b6565b606091505b50509050806107d75760405162461bcd60e51b81526004016104689061346e565b50610803565b61080333826040015183602001516001600160a01b031661240f9092919063ffffffff16565b80608001516001600160a01b0316826001600160a01b03167f5afb313cb5bbcdcfd5b0665bc8c4d3afb9eb69992797d9726b4ea64760814209858460200151856040015142604051610858949392919061349a565b60405180910390a3505050600101610473565b5061087560015f55565b50565b6108806123b8565b5f600782604051610891919061332c565b908152604051908190036020019020546001600160a01b03169050806108c95760405162461bcd60e51b815260040161046890613347565b6001600160a01b038082165f908152600660209081526040808320815161018081018352815460ff811615158252610100900486169381019390935260018101549183019190915260028101546060830152600381015490931660808201526004830180549293919260a08401919061094190613370565b80601f016020809104026020016040519081016040528092919081815260200182805461096d90613370565b80156109b85780601f1061098f576101008083540402835291602001916109b8565b820191905f5260205f20905b81548152906001019060200180831161099b57829003601f168201915b505050505081526020016005820180546109d190613370565b80601f01602080910402602001604051908101604052809291908181526020018280546109fd90613370565b8015610a485780601f10610a1f57610100808354040283529160200191610a48565b820191905f5260205f20905b815481529060010190602001808311610a2b57829003601f168201915b50505091835250506006820154602082015260078201546001600160a01b0390811660408301526008830154811660608301526009830154166080820152600a9091015460a0909101528051909150610ab35760405162461bcd60e51b8152600401610468906133a8565b60808101516001600160a01b0316331480610af457506001546001600160a01b031633148015610af4575060e0810151610af19063096601806133fe565b42115b610b105760405162461bcd60e51b815260040161046890613411565b6001600160a01b038083165f908152600660209081526040909120805460ff191681556008810180546001600160a01b0319163317905542600a9091015582015116610bc45760408082015190515f9133918381818185875af1925050503d805f8114610b98576040519150601f19603f3d011682016040523d82523d5f602084013e610b9d565b606091505b5050905080610bbe5760405162461bcd60e51b81526004016104689061346e565b50610bea565b610bea33826040015183602001516001600160a01b031661240f9092919063ffffffff16565b80608001516001600160a01b0316826001600160a01b03167f5afb313cb5bbcdcfd5b0665bc8c4d3afb9eb69992797d9726b4ea64760814209858460200151856040015142604051610c3f949392919061349a565b60405180910390a3505061087560015f55565b610c5a612473565b6001600160a01b0381165f9081526009602052604090205480610cb55760405162461bcd60e51b81526020600482015260136024820152724e6f206665657320746f20776974686472617760681b6044820152606401610468565b6001600160a01b0382165f81815260096020526040812055610d3c576040515f90339083908381818185875af1925050503d805f8114610d10576040519150601f19603f3d011682016040523d82523d5f602084013e610d15565b606091505b5050905080610d365760405162461bcd60e51b81526004016104689061346e565b50610d50565b610d506001600160a01b038316338361240f565b6040805182815242602082015233916001600160a01b038516917fc7966d68b12e948d7c237e7d9137565fcd716dbc3d168b724fc57c3a92859b2c910160405180910390a35050565b60048054610da690613370565b80601f0160208091040260200160405190810160405280929190818152602001828054610dd290613370565b8015610e1d5780601f10610df457610100808354040283529160200191610e1d565b820191905f5260205f20905b815481529060010190602001808311610e0057829003601f168201915b505050505081565b5f805f805f6060805f805f805f8060078e604051610e43919061332c565b908152604051908190036020019020546001600160a01b0316955085610e7b5760405162461bcd60e51b815260040161046890613347565b6001600160a01b038087165f908152600660209081526040808320815161018081018352815460ff811615158252610100900486169381019390935260018101549183019190915260028101546060830152600381015490931660808201526004830180549293919260a084019190610ef390613370565b80601f0160208091040260200160405190810160405280929190818152602001828054610f1f90613370565b8015610f6a5780601f10610f4157610100808354040283529160200191610f6a565b820191905f5260205f20905b815481529060010190602001808311610f4d57829003601f168201915b50505050508152602001600582018054610f8390613370565b80601f0160208091040260200160405190810160405280929190818152602001828054610faf90613370565b8015610ffa5780601f10610fd157610100808354040283529160200191610ffa565b820191905f5260205f20905b815481529060010190602001808311610fdd57829003601f168201915b5050505050815260200160068201548152602001600782015f9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600882015f9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600982015f9054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600a820154815250509050805f015181602001518260400151836060015184608001518560a001518660c001518d8860e001518961010001518a61012001518b61014001518c61016001519d509d509d509d509d509d509d509d509d509d509d509d509d505091939597999b9d90929496989a9c50565b6111176123b8565b5f600785604051611128919061332c565b908152604051908190036020019020546001600160a01b03169050806111605760405162461bcd60e51b815260040161046890613347565b6001600160a01b0381165f9081526006602052604090205460ff166111975760405162461bcd60e51b8152600401610468906133a8565b6001600160a01b0384166111ed5760405162461bcd60e51b815260206004820152601d60248201527f43616e6e6f742072656465656d20746f207a65726f20616464726573730000006044820152606401610468565b5f85856040516020016112019291906134d1565b6040516020818303038152906040528051906020012090505f8160405160200161125791907f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b60408051601f19818403018152919052805160209091012090505f61127c82876124a0565b9050836001600160a01b0316816001600160a01b0316146112d35760405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606401610468565b6001600160a01b038085165f908152600660209081526040808320815161018081018352815460ff811615158252610100900486169381019390935260018101549183019190915260028101546060830152600381015490931660808201526004830180549293919260a08401919061134b90613370565b80601f016020809104026020016040519081016040528092919081815260200182805461137790613370565b80156113c25780601f10611399576101008083540402835291602001916113c2565b820191905f5260205f20905b8154815290600101906020018083116113a557829003601f168201915b505050505081526020016005820180546113db90613370565b80601f016020809104026020016040519081016040528092919081815260200182805461140790613370565b80156114525780601f1061142957610100808354040283529160200191611452565b820191905f5260205f20905b81548152906001019060200180831161143557829003601f168201915b50505091835250506006828101546020808401919091526007808501546001600160a01b0390811660408087019190915260088701548216606087015260098088015483166080880152600a9788015460a0909701969096528c82165f90815294909352918320805460ff1916815590810180548f84166001600160a01b0319918216179091559381018054928d16929094168217909355429290930191909155919250611500575f61152f565b5f60648360400151611512919061353f565b1161151e57600161152f565b6064826040015161152f919061353f565b60208301519091506001600160a01b031661166b5780156115eb575f876001600160a01b0316826040515f6040518083038185875af1925050503d805f8114611593576040519150601f19603f3d011682016040523d82523d5f602084013e611598565b606091505b50509050806115e95760405162461bcd60e51b815260206004820152601d60248201527f4661696c656420746f2073656e642045544820746f20706172746e65720000006044820152606401610468565b505b5f896001600160a01b03168284604001516116069190613552565b6040515f81818185875af1925050503d805f811461163f576040519150601f19603f3d011682016040523d82523d5f602084013e611644565b606091505b50509050806116655760405162461bcd60e51b81526004016104689061346e565b506116b3565b801561168a57602082015161168a906001600160a01b0316888361240f565b6116b38982846040015161169e9190613552565b60208501516001600160a01b0316919061240f565b866001600160a01b0316896001600160a01b0316876001600160a01b03167fa8aea98c2125c6a7d663e933034cbdcfc17683f069aeda216aae38f93790f98c8d866020015187604001514260405161170e949392919061349a565b60405180910390a450505050505061172560015f55565b50505050565b611733612473565b61173c5f6124ca565b565b6001600160a01b0381165f90815260086020526040902080546060919061176490613370565b80601f016020809104026020016040519081016040528092919081815260200182805461179090613370565b80156117db5780601f106117b2576101008083540402835291602001916117db565b820191905f5260205f20905b8154815290600101906020018083116117be57829003601f168201915b50505050509050919050565b866118345760405162461bcd60e51b815260206004820152601d60248201527f4d75737420637265617465206174206c65617374206f6e6520636172640000006044820152606401610468565b8685146118535760405162461bcd60e51b815260040161046890613565565b8683146118725760405162461bcd60e51b815260040161046890613565565b8681146118915760405162461bcd60e51b815260040161046890613565565b5f8080876001600160401b038111156118ac576118ac612c99565b6040519080825280602002602001820160405280156118d5578160200160208202803683370190505b5090505f5b888110156119d4575f8a8a838181106118f5576118f5613318565b90506020020135116119405760405162461bcd60e51b8152602060048201526014602482015273086c2dcdcdee840c8cae0dee6d2e84060408aa8960631b6044820152606401610468565b89898281811061195257611952613318565b905060200201358461196491906133fe565b93506119878a8a8381811061197b5761197b613318565b90506020020135611c50565b82828151811061199957611999613318565b6020026020010181815250508181815181106119b7576119b7613318565b6020026020010151836119ca91906133fe565b92506001016118da565b506119df82846133fe565b341015611a265760405162461bcd60e51b8152602060048201526015602482015274125b9cdd59999a58da595b9d08115512081cd95b9d605a1b6044820152606401610468565b5f80805260096020527fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b8054849290611a609084906133fe565b909155505f90505b8a811015611b8d57611b858c8c83818110611a8557611a85613318565b9050602002016020810190611a9a9190612e56565b5f8c8c85818110611aad57611aad613318565b90506020020135858581518110611ac657611ac6613318565b60200260200101518c8c87818110611ae057611ae0613318565b9050602002810190611af29190613595565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508e92508d9150899050818110611b3a57611b3a613318565b9050602002810190611b4c9190613595565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061251b92505050565b600101611a68565b505f611b9983856133fe565b611ba39034613552565b90508015611c42576040515f90339083908381818185875af1925050503d805f8114611bea576040519150601f19603f3d011682016040523d82523d5f602084013e611bef565b606091505b5050905080611c405760405162461bcd60e51b815260206004820152601b60248201527f4661696c656420746f2072657475726e206578636573732045544800000000006044820152606401610468565b505b505050505050505050505050565b5f8061271060025484611c6391906135d7565b611c6d919061353f565b90506001808211611c7e5780611c80565b815b949350505050565b5f8311611cce5760405162461bcd60e51b8152602060048201526014602482015273086c2dcdcdee840c8cae0dee6d2e84060408aa8960631b6044820152606401610468565b5f611cd884611c50565b9050611ce481856133fe565b341015611d2b5760405162461bcd60e51b8152602060048201526015602482015274125b9cdd59999a58da595b9d08115512081cd95b9d605a1b6044820152606401610468565b5f80805260096020527fec8156718a8372b1db44bb411437d0870f3e3790d4a08526d024ce1b0b668f6b8054839290611d659084906133fe565b90915550611d799050855f8684878761251b565b5f611d8482866133fe565b611d8e9034613552565b90508015611e2d576040515f90339083908381818185875af1925050503d805f8114611dd5576040519150601f19603f3d011682016040523d82523d5f602084013e611dda565b606091505b5050905080611e2b5760405162461bcd60e51b815260206004820152601b60248201527f4661696c656420746f2072657475726e206578636573732045544800000000006044820152606401610468565b505b505050505050565b60058054610da690613370565b611e4a612473565b60c8811115611e925760405162461bcd60e51b81526020600482015260146024820152734665652063616e6e6f742065786365656420322560601b6044820152606401610468565b60028054908290556040805182815260208101849052428183015290517f5d94a8aa43f58b2ea6ffdb6ec89bb71f9b57edb28d82934dac8d2dc6e52d18419181900360600190a15050565b6001600160a01b038416611f3e5760405162461bcd60e51b815260206004820152602260248201527f557365206465706f73697445544820666f72206e61746976652063757272656e604482015261637960f01b6064820152608401610468565b5f8311611f875760405162461bcd60e51b815260206004820152601760248201527643616e6e6f74206465706f736974203020746f6b656e7360481b6044820152606401610468565b5f611f9184611c50565b90505f611f9e82866133fe565b9050611fb56001600160a01b0387163330846128db565b6001600160a01b0386165f9081526009602052604081208054849290611fdc9084906133fe565b90915550611e2b905087878785888861251b565b60086020525f908152604090208054610da690613370565b612010612473565b6001600160a01b03811661203957604051631e4fbdf760e01b81525f6004820152602401610468565b610875816124ca565b6001600160a01b0387166120985760405162461bcd60e51b815260206004820152601a60248201527f5573652062756c6b4465706f73697445544820696e73746561640000000000006044820152606401610468565b876120e55760405162461bcd60e51b815260206004820152601d60248201527f4d75737420637265617465206174206c65617374206f6e6520636172640000006044820152606401610468565b8785146121045760405162461bcd60e51b815260040161046890613565565b8783146121235760405162461bcd60e51b815260040161046890613565565b8781146121425760405162461bcd60e51b815260040161046890613565565b5f8080876001600160401b0381111561215d5761215d612c99565b604051908082528060200260200182016040528015612186578160200160208202803683370190505b5090505f5b8881101561227c575f8a8a838181106121a6576121a6613318565b90506020020135116121f45760405162461bcd60e51b815260206004820152601760248201527643616e6e6f74206465706f736974203020746f6b656e7360481b6044820152606401610468565b89898281811061220657612206613318565b905060200201358461221891906133fe565b935061222f8a8a8381811061197b5761197b613318565b82828151811061224157612241613318565b60200260200101818152505081818151811061225f5761225f613318565b60200260200101518361227291906133fe565b925060010161218b565b505f61228883856133fe565b905061229f6001600160a01b038c163330846128db565b6001600160a01b038b165f90815260096020526040812080548592906122c69084906133fe565b909155505f90505b8c8110156123a8576123a08e8e838181106122eb576122eb613318565b90506020020160208101906123009190612e56565b8d8d8d8581811061231357612313613318565b9050602002013586858151811061232c5761232c613318565b60200260200101518d8d8781811061234657612346613318565b90506020028101906123589190613595565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152508f92508e9150899050818110611b3a57611b3a613318565b6001016122ce565b5050505050505050505050505050565b60025f54036124095760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610468565b60025f55565b6040516001600160a01b0383811660248301526044820183905261246e91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612914565b505050565b6001546001600160a01b0316331461173c5760405163118cdaa760e01b8152336004820152602401610468565b5f805f806124ae8686612980565b9250925092506124be82826129c9565b50909150505b92915050565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b6001600160a01b03861661257c5760405162461bcd60e51b815260206004820152602260248201527f43616e6e6f7420757365207a65726f206164647265737320617320736c6f7420604482015261125160f21b6064820152608401610468565b6001600160a01b0386165f908152600860205260409020805461262491906125a390613370565b80601f01602080910402602001604051908101604052809291908181526020018280546125cf90613370565b801561261a5780601f106125f15761010080835404028352916020019161261a565b820191905f5260205f20905b8154815290600101906020018083116125fd57829003601f168201915b5050505050511590565b6126675760405162461bcd60e51b815260206004820152601460248201527314db1bdd08125108185b1c9958591e481d5cd95960621b6044820152606401610468565b5f612670612a85565b905086600782604051612683919061332c565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039485161790559189165f9081526008909152206126c58282613639565b50604051806101800160405280600115158152602001876001600160a01b03168152602001868152602001858152602001336001600160a01b031681526020018481526020018381526020014281526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f6001600160a01b031681526020015f81525060065f896001600160a01b03166001600160a01b031681526020019081526020015f205f820151815f015f6101000a81548160ff0219169083151502179055506020820151815f0160016101000a8154816001600160a01b0302191690836001600160a01b0316021790555060408201518160010155606082015181600201556080820151816003015f6101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160040190816128099190613639565b5060c0820151600582019061281e9082613639565b5060e082015160068201556101008201516007820180546001600160a01b03199081166001600160a01b0393841617909155610120840151600884018054831691841691909117905561014084015160098401805490921690831617905561016090920151600a9091015560405133918916907fd2fcff1668b7c7615b3b77bc5ce8c16b211ba473fab592938b645eb5af6add96906128ca9085908b908b908b908b908b9042906136f4565b60405180910390a350505050505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526117259186918216906323b872dd9060840161243c565b5f8060205f8451602086015f885af180612933576040513d5f823e3d81fd5b50505f513d9150811561294a578060011415612957565b6001600160a01b0384163b155b1561172557604051635274afe760e01b81526001600160a01b0385166004820152602401610468565b5f805f83516041036129b7576020840151604085015160608601515f1a6129a988828585612ad5565b9550955095505050506129c2565b505081515f91506002905b9250925092565b5f8260038111156129dc576129dc61375e565b036129e5575050565b60018260038111156129f9576129f961375e565b03612a175760405163f645eedf60e01b815260040160405180910390fd5b6002826003811115612a2b57612a2b61375e565b03612a4c5760405163fce698f760e01b815260048101829052602401610468565b6003826003811115612a6057612a6061375e565b03612a81576040516335e2f38360e21b815260048101829052602401610468565b5050565b60605f60056004612a97600354612b9d565b604051602001612aa9939291906137e1565b60408051601f19818403018152919052600380549192505f612aca8361380f565b909155509092915050565b5f80807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115612b0e57505f91506003905082612b93565b604080515f808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015612b5f573d5f803e3d5ffd5b5050604051601f1901519150506001600160a01b038116612b8a57505f925060019150829050612b93565b92505f91508190505b9450945094915050565b6060815f03612bc35750506040805180820190915260018152600360fc1b602082015290565b815f5b8115612bec5780612bd68161380f565b9150612be59050600a8361353f565b9150612bc6565b5f816001600160401b03811115612c0557612c05612c99565b6040519080825280601f01601f191660200182016040528015612c2f576020820181803683370190505b5090505b8415611c8057612c44600183613552565b9150612c51600a86613827565b612c5c9060306133fe565b60f81b818381518110612c7157612c71613318565b60200101906001600160f81b03191690815f1a905350612c92600a8661353f565b9450612c33565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b0381118282101715612cd557612cd5612c99565b604052919050565b5f6001600160401b03831115612cf557612cf5612c99565b612d08601f8401601f1916602001612cad565b9050828152838383011115612d1b575f80fd5b828260208301375f602084830101529392505050565b5f82601f830112612d40575f80fd5b612d4f83833560208501612cdd565b9392505050565b5f6020808385031215612d67575f80fd5b82356001600160401b0380821115612d7d575f80fd5b818501915085601f830112612d90575f80fd5b813581811115612da257612da2612c99565b8060051b612db1858201612cad565b9182528381018501918581019089841115612dca575f80fd5b86860192505b83831015612e0457823585811115612de6575f80fd5b612df48b89838a0101612d31565b8352509186019190860190612dd0565b9998505050505050505050565b5f60208284031215612e21575f80fd5b81356001600160401b03811115612e36575f80fd5b611c8084828501612d31565b6001600160a01b0381168114610875575f80fd5b5f60208284031215612e66575f80fd5b8135612d4f81612e42565b5f5b83811015612e8b578181015183820152602001612e73565b50505f910152565b5f8151808452612eaa816020860160208601612e71565b601f01601f19169290920160200192915050565b602081525f612d4f6020830184612e93565b8d151581526001600160a01b038d81166020830152604082018d9052606082018c90528a1660808201525f6101a08060a0840152612f108184018c612e93565b905082810360c0840152612f24818b612e93565b915050612f3c60e08301896001600160a01b03169052565b86610100830152612f596101208301876001600160a01b03169052565b6001600160a01b0385166101408301526001600160a01b038416610160830152826101808301529e9d5050505050505050505050505050565b5f805f8060808587031215612fa5575f80fd5b84356001600160401b0380821115612fbb575f80fd5b612fc788838901612d31565b955060208701359150612fd982612e42565b90935060408601359080821115612fee575f80fd5b508501601f81018713612fff575f80fd5b61300e87823560208401612cdd565b925050606085013561301f81612e42565b939692955090935050565b5f8083601f84011261303a575f80fd5b5081356001600160401b03811115613050575f80fd5b6020830191508360208260051b850101111561306a575f80fd5b9250929050565b5f805f805f805f806080898b031215613088575f80fd5b88356001600160401b038082111561309e575f80fd5b6130aa8c838d0161302a565b909a50985060208b01359150808211156130c2575f80fd5b6130ce8c838d0161302a565b909850965060408b01359150808211156130e6575f80fd5b6130f28c838d0161302a565b909650945060608b013591508082111561310a575f80fd5b506131178b828c0161302a565b999c989b5096995094979396929594505050565b5f6020828403121561313b575f80fd5b5035919050565b5f805f8060808587031215613155575f80fd5b843561316081612e42565b93506020850135925060408501356001600160401b0380821115613182575f80fd5b61318e88838901612d31565b935060608701359150808211156131a3575f80fd5b506131b087828801612d31565b91505092959194509250565b5f805f805f60a086880312156131d0575f80fd5b85356131db81612e42565b945060208601356131eb81612e42565b93506040860135925060608601356001600160401b038082111561320d575f80fd5b61321989838a01612d31565b9350608088013591508082111561322e575f80fd5b5061323b88828901612d31565b9150509295509295909350565b5f805f805f805f805f60a08a8c031215613260575f80fd5b89356001600160401b0380821115613276575f80fd5b6132828d838e0161302a565b909b50995060208c0135915061329782612e42565b90975060408b013590808211156132ac575f80fd5b6132b88d838e0161302a565b909850965060608c01359150808211156132d0575f80fd5b6132dc8d838e0161302a565b909650945060808c01359150808211156132f4575f80fd5b506133018c828d0161302a565b915080935050809150509295985092959850929598565b634e487b7160e01b5f52603260045260245ffd5b5f825161333d818460208701612e71565b9190910192915050565b6020808252600f908201526e125b9d985b1a590818d85c99081251608a1b604082015260600190565b600181811c9082168061338457607f821691505b6020821081036133a257634e487b7160e01b5f52602260045260245ffd5b50919050565b60208082526022908201527f4361726420616c72656164792072656465656d6564206f722063616e63656c6c604082015261195960f21b606082015260800190565b634e487b7160e01b5f52601160045260245ffd5b808201808211156124c4576124c46133ea565b60208082526037908201527f4e6f7420617574686f72697a65643a206d7573742062652063726561746f722060408201527f6f72206f776e657220286966206162616e646f6e656429000000000000000000606082015260800190565b60208082526012908201527108cc2d2d8cac840e8de40e6cadcc8408aa8960731b604082015260600190565b608081525f6134ac6080830187612e93565b6001600160a01b03959095166020830152506040810192909252606090910152919050565b6b2932b232b2b69031b0b9321d60a11b81525f83516134f781600c850160208801612e71565b623a379d60e91b600c93909101928301525060609190911b6bffffffffffffffffffffffff1916600f820152602301919050565b634e487b7160e01b5f52601260045260245ffd5b5f8261354d5761354d61352b565b500490565b818103818111156124c4576124c46133ea565b602080825260169082015275082e4e4c2f2e640d8cadccee8d040dad2e6dac2e8c6d60531b604082015260600190565b5f808335601e198436030181126135aa575f80fd5b8301803591506001600160401b038211156135c3575f80fd5b60200191503681900382131561306a575f80fd5b80820281158282048414176124c4576124c46133ea565b601f82111561246e57805f5260205f20601f840160051c810160208510156136135750805b601f840160051c820191505b81811015613632575f815560010161361f565b5050505050565b81516001600160401b0381111561365257613652612c99565b613666816136608454613370565b846135ee565b602080601f831160018114613699575f84156136825750858301515b5f19600386901b1c1916600185901b178555611e2d565b5f85815260208120601f198616915b828110156136c7578886015182559484019460019091019084016136a8565b50858210156136e457878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b60e081525f61370660e083018a612e93565b6001600160a01b0389166020840152604083018890526060830187905282810360808401526137358187612e93565b905082810360a08401526137498186612e93565b9150508260c083015298975050505050505050565b634e487b7160e01b5f52602160045260245ffd5b5f815461377e81613370565b6001828116801561379657600181146137ab576137d7565b60ff19841687528215158302870194506137d7565b855f526020805f205f5b858110156137ce5781548a8201529084019082016137b5565b50505082870194505b5050505092915050565b5f6137f56137ef8387613772565b85613772565b8351613805818360208801612e71565b0195945050505050565b5f60018201613820576138206133ea565b5060010190565b5f826138355761383561352b565b50069056fea26469706673582212203227e5cac19bee7693df89c39f5a2182ac357fbac6b6e1c7b1adfab60d21d56764736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000002303200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013100000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _chainPrefix (string): 02
Arg [1] : _versionPrefix (string): 1
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [3] : 3032000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [5] : 3100000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 43.95% | $0.999803 | 101.005 | $100.99 | |
| ETH | 6.59% | $0.999916 | 15.15 | $15.15 | |
| ETH | 3.54% | $3,423.21 | 0.0023768 | $8.14 | |
| BASE | 44.42% | $0.99986 | 102.076 | $102.06 | |
| BASE | 0.77% | $3,402.68 | 0.00051812 | $1.76 | |
| BASE | 0.12% | $0.99844 | 0.2863 | $0.2858 | |
| POL | 0.37% | $0.999803 | 0.85 | $0.8498 | |
| BSC | 0.23% | $947.85 | 0.0005633 | $0.533923 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.