Source Code
Multichain Info
N/A
Latest 25 from a total of 500 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Transfer Ownersh... | 24728176 | 113 days ago | IN | 0 APE | 0.00076356 | ||||
| Transfer Ownersh... | 24727492 | 113 days ago | IN | 0 APE | 0.00076356 | ||||
| Claim Refund All | 24698652 | 114 days ago | IN | 0 APE | 0.00085662 | ||||
| Rescue ERC20 | 24698263 | 114 days ago | IN | 0 APE | 0.00694986 | ||||
| Request Winner V... | 24697874 | 114 days ago | IN | 0 APE | 0.00933981 | ||||
| Set VRNG Fee | 24697718 | 114 days ago | IN | 0 APE | 0.00069573 | ||||
| Admin Finalize R... | 24696894 | 114 days ago | IN | 0 APE | 0.00941887 | ||||
| Admin Finalize R... | 24696874 | 114 days ago | IN | 0 APE | 0.00941887 | ||||
| Set VRNG Fee | 24696760 | 114 days ago | IN | 0 APE | 0.00064489 | ||||
| Admin Finalize R... | 24696684 | 114 days ago | IN | 0 APE | 0.00114573 | ||||
| Enter Raffle Wit... | 24696516 | 114 days ago | IN | 0 APE | 0.01642463 | ||||
| Enter Raffle Wit... | 24696460 | 114 days ago | IN | 0 APE | 0.00235395 | ||||
| Enter Raffle Wit... | 24696429 | 114 days ago | IN | 0 APE | 0.00385713 | ||||
| Enter Raffle Wit... | 24696290 | 114 days ago | IN | 0 APE | 0.00159941 | ||||
| Withdraw Proceed... | 24695775 | 114 days ago | IN | 0 APE | 0.00151804 | ||||
| Enter Raffle | 24695454 | 114 days ago | IN | 0 APE | 0.00079508 | ||||
| Claim Refund | 24653511 | 115 days ago | IN | 0 APE | 0.00085685 | ||||
| Claim Refund | 24653502 | 115 days ago | IN | 0 APE | 0.00085655 | ||||
| Claim Refund All | 24653410 | 115 days ago | IN | 0 APE | 0.00085662 | ||||
| Claim Refund All | 24609635 | 117 days ago | IN | 0 APE | 0.00085662 | ||||
| Claim Refund All | 24609622 | 117 days ago | IN | 0 APE | 0.00160343 | ||||
| Claim Refund All | 24608168 | 117 days ago | IN | 0 APE | 0.00085662 | ||||
| Enter Raffle Wit... | 24608152 | 117 days ago | IN | 0 APE | 0.00223193 | ||||
| Claim Refund All | 24608117 | 117 days ago | IN | 0 APE | 0.00160343 | ||||
| Transfer Ownersh... | 24608035 | 117 days ago | IN | 0 APE | 0.00076356 |
Latest 15 internal transactions
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 24696516 | 114 days ago | 0.01 APE | ||||
| 24578127 | 117 days ago | 0.01 APE | ||||
| 24571391 | 117 days ago | 0.01 APE | ||||
| 23868633 | 130 days ago | 0.01 APE | ||||
| 23867738 | 130 days ago | 0.01 APE | ||||
| 23867368 | 130 days ago | 0.01 APE | ||||
| 23857493 | 130 days ago | 0.01 APE | ||||
| 23657852 | 133 days ago | 0.01 APE | ||||
| 23656088 | 133 days ago | 0.01 APE | ||||
| 23581954 | 135 days ago | 0.01 APE | ||||
| 23580677 | 135 days ago | 0.01 APE | ||||
| 23579798 | 135 days ago | 0.01 APE | ||||
| 23578197 | 135 days ago | 0.01 APE | ||||
| 23577149 | 135 days ago | 0.02 APE | ||||
| 23549775 | 135 days ago | 0.01 APE |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
GeezRaffle
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 1 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import "@openzeppelin/contracts/utils/Address.sol";
interface IVRNGRouter {
function requestRandomNumberWithTraceId(uint256 traceId) external payable returns (uint256 requestId);
}
interface IVRFSystemCallback {
function randomNumberCallback(uint256 requestId, uint256 randomNumber) external;
}
interface IBurnableERC1155 is IERC1155 {
function burn(address from, uint256 id, uint256 amount) external;
}
/**
* @title GeezRaffle - Modified for Dual Entry Mode (Burn OR ERC20) with Auto Winner Selection
* @dev Raffle system supporting EITHER Geez token burning OR ERC20 payment per raffle
*
* MODIFICATION: Raffles can now be configured to accept EITHER:
* - Geez Nutz burning (traditional mode)
* - ERC20 token payment (e.g., Pnutz)
* The mode is determined by whether paymentToken is set at creation
*
* AUTO WINNER SELECTION: Contract automatically attempts to finalize when raffle becomes full
*/
contract GeezRaffle is Ownable, ReentrancyGuard, IERC721Receiver, IERC1155Receiver, ERC165, IVRFSystemCallback {
using SafeERC20 for IERC20;
using Address for address;
// Custom errors
error InvalidRaffleId();
error RaffleCanceledError();
error RaffleNotOpen();
error RafflePausedError();
error RandomnessPending();
error TokenNotAccepted();
error InvalidAmount();
error MaxBurnExceeded();
error TooManyEntrants();
error NotReadyToFinalize();
error UnauthorizedCaller();
error InvalidState();
error BadRecipient();
error WrongEntryMode();
// Geez Nutz ERC1155
IBurnableERC1155 public immutable geezToken;
// VRNG Router
IVRNGRouter public immutable vrngRouter;
// Constants
uint256 public constant VRNG_TIMEOUT = 2 hours;
uint256 public constant DEFAULT_MAX_ENTRANTS = 500;
uint256 public constant MAX_ENTRANTS_BOUND = 1000;
uint256 public constant MIN_FINALIZATION_DELAY = 5 minutes;
uint256 public constant MAX_ACCEPTED_TOKEN_IDS = 8;
uint256 public constant REFUND_BATCH_SIZE = 50;
uint256 public raffleCounter;
bool public isSelfBurnAllowed;
uint256 public vrngFeeWei;
// NEW: Auto-finalization settings
bool public autoFinalizationEnabled = true;
uint256 public vrngFeeBuffer; // Extra ETH buffer for VRNG fees
struct Raffle {
// Prize info (on-chain NFTs)
address prizeNFT;
uint256 prizeTokenId;
uint256 prizeAmount;
bool prizeIs1155;
// ERC20 prize support
bool prizeIsERC20;
address prizeERC20Token;
uint256 prizeERC20Amount;
// External prize info
bool prizeIsExternal;
bool externalDelivered;
uint256 externalChainId;
address externalPrizeCollection;
address externalCustodian;
// Raffle meta
address creator;
uint256 maxBurn; // MODIFIED: Now represents max entries regardless of type
uint256 burned; // MODIFIED: Now represents total entries regardless of type
bool isOpen;
bool isPaused;
bool isCanceled;
bool prizeWithdrawnIfCanceled;
uint256 maxEntrants;
uint256 createdAt;
// Entries
address[] entrants;
uint256[] acceptedTokenIds; // Only used for burn mode
uint256[] usedTokenIds; // Only used for burn mode
// MODIFIED: Entry mode configuration
address paymentToken; // If set, use ERC20 mode; if address(0), use burn mode
uint256 pricePerEntry; // Price per entry in ERC20 mode
uint256 proceedsAccrued; // Total ERC20 collected
// Winner and VRNG state
address winner;
bool awaitingRandomness;
uint256 vrngRequestId;
uint256 vrngRequestTimestamp;
// Winner selection optimization
uint256[] cumulativeWeights;
uint256 totalWeight;
bool weightsCalculated;
// Storage management
bool storageCanBePruned;
uint256 refundProgress;
bool burnFailed;
// NEW: Auto-finalization tracking
bool autoFinalized;
}
mapping(uint256 => Raffle) public raffles;
// Mappings moved outside struct for gas efficiency
mapping(uint256 => mapping(address => uint256)) public raffleEntries;
mapping(uint256 => mapping(uint256 => bool)) public raffleTokenIdAllowed; // Only for burn mode
mapping(uint256 => mapping(uint256 => bool)) private _tokenIdUsed; // Only for burn mode
// VRNG request tracking
mapping(uint256 => uint256) public vrngRequestToRaffle;
// Escrow mappings
mapping(uint256 => mapping(address => mapping(uint256 => uint256))) private _escrow; // Only for burn mode
mapping(uint256 => mapping(uint256 => uint256)) private _escrowTotals; // Only for burn mode
mapping(uint256 => mapping(address => uint256)) private _erc20Paid; // Only for ERC20 mode
// Anti-griefing protection
mapping(uint256 => uint256) public lastFinalizationAttempt;
// Events
event RaffleCreated(uint256 indexed raffleId, address indexed creator, address indexed prizeNFT, uint256 prizeTokenId, bool prizeIs1155, uint256 prizeAmount, uint256 maxBurn, uint256[] acceptedTokenIds, uint256 maxEntrants);
event ERC20RaffleCreated(uint256 indexed raffleId, address indexed creator, address indexed prizeToken, uint256 prizeAmount, uint256 maxBurn, uint256[] acceptedTokenIds, uint256 maxEntrants);
event RaffleEntered(uint256 indexed raffleId, address indexed user, uint256 tokenId, uint256 amount);
event RaffleEnteredBatch(uint256 indexed raffleId, address indexed user, uint256[] tokenIds, uint256[] amounts);
event RafflePurchased(uint256 indexed raffleId, address indexed user, address paymentToken, uint256 entries, uint256 cost);
event RaffleEnteredWithPermit(uint256 indexed raffleId, address indexed user, address paymentToken, uint256 entries, uint256 cost);
event RaffleWinner(uint256 indexed raffleId, address indexed winner);
event RafflePaused(uint256 indexed raffleId);
event RaffleUnpaused(uint256 indexed raffleId);
event RaffleCanceled(uint256 indexed raffleId, bool autoRefundEnabled);
event PrizeWithdrawn(uint256 indexed raffleId);
event RefundIssued(uint256 indexed raffleId, address indexed user, uint256 amount1155);
event TokenRefundIssued(uint256 indexed raffleId, address indexed user, address token, uint256 amountToken);
event BatchRefundProcessed(uint256 indexed raffleId, uint256 start, uint256 end, uint256 usersProcessed);
event RaffleClosed(uint256 indexed raffleId);
event ExternalPrizeAnnounced(uint256 indexed raffleId, address indexed winner, uint256 externalChainId, address externalPrizeCollection, uint256 prizeTokenId, bool prizeIs1155, uint256 prizeAmount);
event ExternalPrizeDeliveryMarked(uint256 indexed raffleId, address indexed by, bytes32 externalTxHash);
event ExternalCustodianUpdated(uint256 indexed raffleId, address indexed newCustodian);
event VRNGRequested(uint256 indexed raffleId, uint256 indexed requestId, uint256 traceId);
event VRNGFulfilled(uint256 indexed raffleId, uint256 indexed requestId, uint256 randomNumber);
event VRNGFeeSet(uint256 feeWei);
event PaymentConfigSet(uint256 indexed raffleId, address token, uint256 pricePerEntry);
event ReadyToFinalize(uint256 indexed raffleId);
event FinalizeRequested(uint256 indexed raffleId, address indexed finalizer);
event EmergencyCancel(uint256 indexed raffleId);
event RaffleDeleted(uint256 indexed raffleId, address indexed creator);
event WeightsCalculated(uint256 indexed raffleId, uint256 totalWeight);
event StoragePruned(uint256 indexed raffleId, uint256 itemsCleared);
event ProceedsWithdrawn(uint256 indexed raffleId, address indexed token, address indexed to, uint256 amount);
event BurnValidationSet(bool isSelfBurnAllowed);
event GeezSwept(uint256 indexed raffleId, address indexed to, uint256[] tokenIds, uint256[] amounts);
// NEW: Auto-finalization events
event AutoFinalizationEnabled(bool enabled);
event AutoFinalizationAttempted(uint256 indexed raffleId, bool success, string reason);
event VRNGFeesFunded(address indexed funder, uint256 amount);
event VRNGFeeBufferSet(uint256 newBuffer);
constructor(address _geezToken, address _vrngRouter) {
if (_geezToken == address(0)) revert InvalidState();
if (_vrngRouter == address(0)) revert InvalidState();
if (!_geezToken.isContract()) revert InvalidState();
if (!_vrngRouter.isContract()) revert InvalidState();
geezToken = IBurnableERC1155(_geezToken);
vrngRouter = IVRNGRouter(_vrngRouter);
_validateBurnInterface();
}
function _validateBurnInterface() internal {
try geezToken.burn(address(this), 0, 0) {
isSelfBurnAllowed = true;
} catch {
isSelfBurnAllowed = false;
}
emit BurnValidationSet(isSelfBurnAllowed);
}
function setBurnValidation(bool _isSelfBurnAllowed) external onlyOwner {
isSelfBurnAllowed = _isSelfBurnAllowed;
emit BurnValidationSet(_isSelfBurnAllowed);
}
function setVRNGFee(uint256 feeWei) external onlyOwner {
vrngFeeWei = feeWei;
emit VRNGFeeSet(feeWei);
}
// NEW: Auto-finalization management functions
function setAutoFinalization(bool enabled) external onlyOwner {
autoFinalizationEnabled = enabled;
emit AutoFinalizationEnabled(enabled);
}
function setVRNGFeeBuffer(uint256 buffer) external onlyOwner {
vrngFeeBuffer = buffer;
emit VRNGFeeBufferSet(buffer);
}
function fundVRNGFees() external payable {
if (msg.value == 0) revert InvalidAmount();
emit VRNGFeesFunded(msg.sender, msg.value);
}
function withdrawExcessETH(uint256 amount) external onlyOwner {
if (amount == 0) revert InvalidAmount();
uint256 contractBalance = address(this).balance;
uint256 reservedForVRNG = vrngFeeWei + vrngFeeBuffer;
if (contractBalance < reservedForVRNG + amount) revert InvalidAmount();
(bool success, ) = payable(owner()).call{value: amount}("");
if (!success) revert InvalidState();
}
// NEW: Auto-finalization logic
function _tryAutoFinalize(uint256 raffleId) internal {
if (!autoFinalizationEnabled) {
emit ReadyToFinalize(raffleId);
return;
}
Raffle storage r = raffles[raffleId];
// Check if already auto-finalized
if (r.autoFinalized) return;
// Check basic conditions
if (!r.isOpen || r.isCanceled || r.awaitingRandomness) {
emit AutoFinalizationAttempted(raffleId, false, "Invalid state");
return;
}
// Check if we have enough ETH for VRNG fee
uint256 contractBalance = address(this).balance;
if (vrngFeeWei > 0 && contractBalance < vrngFeeWei) {
emit AutoFinalizationAttempted(raffleId, false, "Insufficient VRNG fees");
emit ReadyToFinalize(raffleId);
return;
}
// Check finalization delay
uint256 lastAttempt = lastFinalizationAttempt[raffleId];
if (lastAttempt > 0 && block.timestamp < lastAttempt + MIN_FINALIZATION_DELAY) {
emit AutoFinalizationAttempted(raffleId, false, "Finalization delay not met");
return;
}
// Mark as auto-finalized to prevent re-entry
r.autoFinalized = true;
lastFinalizationAttempt[raffleId] = block.timestamp;
try this._internalAutoFinalize(raffleId) {
emit AutoFinalizationAttempted(raffleId, true, "Success");
} catch Error(string memory reason) {
r.autoFinalized = false; // Reset flag on failure
emit AutoFinalizationAttempted(raffleId, false, reason);
emit ReadyToFinalize(raffleId);
} catch {
r.autoFinalized = false; // Reset flag on failure
emit AutoFinalizationAttempted(raffleId, false, "Unknown error");
emit ReadyToFinalize(raffleId);
}
}
// NEW: Internal auto-finalization function (external for try/catch)
function _internalAutoFinalize(uint256 raffleId) external {
if (msg.sender != address(this)) revert UnauthorizedCaller();
_calculateWeights(raffleId);
_finalize(raffleId, vrngFeeWei);
emit FinalizeRequested(raffleId, address(this));
}
function _defaultIds() internal pure returns (uint256[] memory ids) {
ids = new uint256[](2);
ids[0] = 0;
ids[1] = 1;
}
function randomNumberCallback(uint256 requestId, uint256 randomNumber) external override nonReentrant {
if (msg.sender != address(vrngRouter)) revert UnauthorizedCaller();
uint256 raffleId = vrngRequestToRaffle[requestId];
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
if (!r.awaitingRandomness) revert InvalidState();
if (r.vrngRequestId != requestId) revert InvalidState();
r.awaitingRandomness = false;
delete vrngRequestToRaffle[requestId];
emit VRNGFulfilled(raffleId, requestId, randomNumber);
_completeFinalization(raffleId, randomNumber);
}
function requestWinnerVRNG(uint256 raffleId) external payable nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
if (!r.isOpen || r.isCanceled || r.awaitingRandomness) revert InvalidState();
if (r.burned != r.maxBurn || r.entrants.length == 0) revert NotReadyToFinalize();
if (vrngFeeWei > 0 && msg.value != vrngFeeWei) revert InvalidAmount();
if (vrngFeeWei == 0 && msg.value != 0) revert InvalidAmount();
uint256 lastAttempt = lastFinalizationAttempt[raffleId];
if (lastAttempt > 0 && block.timestamp < lastAttempt + MIN_FINALIZATION_DELAY) {
revert InvalidState();
}
lastFinalizationAttempt[raffleId] = block.timestamp;
_calculateWeights(raffleId);
_finalize(raffleId, msg.value);
emit FinalizeRequested(raffleId, msg.sender);
}
// MODIFIED: Now includes payment token option at creation
function createRaffle(
address prizeNFT,
uint256 prizeTokenId,
uint256 maxBurn
) external onlyOwner returns (uint256) {
uint256[] memory defaultTokenIds = _defaultIds();
return _createRaffleERC721(prizeNFT, prizeTokenId, maxBurn, defaultTokenIds, DEFAULT_MAX_ENTRANTS, address(0), 0);
}
// MODIFIED: Added payment token parameters
function createRaffleERC721(
address prizeNFT,
uint256 prizeTokenId,
uint256 maxBurn,
uint256[] memory acceptedTokenIds,
uint256 maxEntrants
) external onlyOwner returns (uint256) {
return _createRaffleERC721(prizeNFT, prizeTokenId, maxBurn, acceptedTokenIds, maxEntrants, address(0), 0);
}
// ADDED: New function to create ERC721 raffle with ERC20 payment
function createRaffleERC721WithPayment(
address prizeNFT,
uint256 prizeTokenId,
uint256 maxEntries,
address paymentToken,
uint256 pricePerEntry,
uint256 maxEntrants
) external onlyOwner returns (uint256) {
return _createRaffleERC721(prizeNFT, prizeTokenId, maxEntries, new uint256[](0), maxEntrants, paymentToken, pricePerEntry);
}
// MODIFIED: Added payment token parameters
function createRaffleERC1155(
address prizeNFT,
uint256 prizeTokenId,
uint256 prizeAmount,
uint256 maxBurn,
uint256[] memory acceptedTokenIds,
uint256 maxEntrants
) external onlyOwner returns (uint256) {
if (prizeNFT == address(0)) revert InvalidState();
if (!prizeNFT.isContract()) revert InvalidState();
if (prizeAmount == 0) revert InvalidAmount();
if (maxBurn == 0) revert InvalidAmount();
if (maxEntrants == 0 || maxEntrants > MAX_ENTRANTS_BOUND) revert InvalidState();
IERC1155(prizeNFT).safeTransferFrom(msg.sender, address(this), prizeTokenId, prizeAmount, "");
uint256 raffleId = ++raffleCounter;
Raffle storage raffle = raffles[raffleId];
raffle.prizeNFT = prizeNFT;
raffle.prizeTokenId = prizeTokenId;
raffle.prizeAmount = prizeAmount;
raffle.prizeIs1155 = true;
raffle.creator = msg.sender;
raffle.maxBurn = maxBurn;
raffle.maxEntrants = maxEntrants;
raffle.isOpen = true;
raffle.createdAt = block.timestamp;
// Only set accepted token IDs if in burn mode
if (acceptedTokenIds.length > 0) {
if (acceptedTokenIds.length > MAX_ACCEPTED_TOKEN_IDS) revert InvalidState();
_setAcceptedTokenIds(raffleId, acceptedTokenIds);
}
emit RaffleCreated(raffleId, msg.sender, prizeNFT, prizeTokenId, true, prizeAmount, maxBurn, acceptedTokenIds, maxEntrants);
return raffleId;
}
// ADDED: New function to create ERC1155 raffle with ERC20 payment
function createRaffleERC1155WithPayment(
address prizeNFT,
uint256 prizeTokenId,
uint256 prizeAmount,
uint256 maxEntries,
address paymentToken,
uint256 pricePerEntry,
uint256 maxEntrants
) external onlyOwner returns (uint256) {
if (prizeNFT == address(0)) revert InvalidState();
if (!prizeNFT.isContract()) revert InvalidState();
if (prizeAmount == 0) revert InvalidAmount();
if (maxEntries == 0) revert InvalidAmount();
if (paymentToken == address(0)) revert InvalidState();
if (!paymentToken.isContract()) revert InvalidState();
if (pricePerEntry == 0) revert InvalidAmount();
if (maxEntrants == 0 || maxEntrants > MAX_ENTRANTS_BOUND) revert InvalidState();
IERC1155(prizeNFT).safeTransferFrom(msg.sender, address(this), prizeTokenId, prizeAmount, "");
uint256 raffleId = ++raffleCounter;
Raffle storage raffle = raffles[raffleId];
raffle.prizeNFT = prizeNFT;
raffle.prizeTokenId = prizeTokenId;
raffle.prizeAmount = prizeAmount;
raffle.prizeIs1155 = true;
raffle.creator = msg.sender;
raffle.maxBurn = maxEntries;
raffle.maxEntrants = maxEntrants;
raffle.isOpen = true;
raffle.createdAt = block.timestamp;
raffle.paymentToken = paymentToken;
raffle.pricePerEntry = pricePerEntry;
emit RaffleCreated(raffleId, msg.sender, prizeNFT, prizeTokenId, true, prizeAmount, maxEntries, new uint256[](0), maxEntrants);
return raffleId;
}
function createRaffleExternalPrize(
uint256 externalChainId,
address externalPrizeCollection,
uint256 prizeTokenId,
bool prizeIs1155,
uint256 prizeAmount,
uint256 maxBurn,
uint256[] memory acceptedTokenIds,
address externalCustodian,
uint256 maxEntrants
) external onlyOwner returns (uint256) {
if (externalChainId == 0) revert InvalidState();
if (externalPrizeCollection == address(0)) revert InvalidState();
if (prizeAmount == 0) revert InvalidAmount();
if (maxBurn == 0) revert InvalidAmount();
if (externalCustodian == address(0)) revert InvalidState();
if (maxEntrants == 0 || maxEntrants > MAX_ENTRANTS_BOUND) revert InvalidState();
uint256 raffleId = ++raffleCounter;
Raffle storage raffle = raffles[raffleId];
raffle.prizeIsExternal = true;
raffle.externalChainId = externalChainId;
raffle.externalPrizeCollection = externalPrizeCollection;
raffle.prizeTokenId = prizeTokenId;
raffle.prizeIs1155 = prizeIs1155;
raffle.prizeAmount = prizeAmount;
raffle.externalCustodian = externalCustodian;
raffle.creator = msg.sender;
raffle.maxBurn = maxBurn;
raffle.maxEntrants = maxEntrants;
raffle.isOpen = true;
raffle.createdAt = block.timestamp;
// Only set accepted token IDs if in burn mode
if (acceptedTokenIds.length > 0) {
if (acceptedTokenIds.length > MAX_ACCEPTED_TOKEN_IDS) revert InvalidState();
_setAcceptedTokenIds(raffleId, acceptedTokenIds);
}
emit RaffleCreated(raffleId, msg.sender, address(0), prizeTokenId, prizeIs1155, prizeAmount, maxBurn, acceptedTokenIds, maxEntrants);
return raffleId;
}
// ADDED: External prize with ERC20 payment
function createRaffleExternalPrizeWithPayment(
uint256 externalChainId,
address externalPrizeCollection,
uint256 prizeTokenId,
bool prizeIs1155,
uint256 prizeAmount,
uint256 maxEntries,
address paymentToken,
uint256 pricePerEntry,
address externalCustodian,
uint256 maxEntrants
) external onlyOwner returns (uint256) {
if (externalChainId == 0) revert InvalidState();
if (externalPrizeCollection == address(0)) revert InvalidState();
if (prizeAmount == 0) revert InvalidAmount();
if (maxEntries == 0) revert InvalidAmount();
if (paymentToken == address(0)) revert InvalidState();
if (!paymentToken.isContract()) revert InvalidState();
if (pricePerEntry == 0) revert InvalidAmount();
if (externalCustodian == address(0)) revert InvalidState();
if (maxEntrants == 0 || maxEntrants > MAX_ENTRANTS_BOUND) revert InvalidState();
uint256 raffleId = ++raffleCounter;
Raffle storage raffle = raffles[raffleId];
raffle.prizeIsExternal = true;
raffle.externalChainId = externalChainId;
raffle.externalPrizeCollection = externalPrizeCollection;
raffle.prizeTokenId = prizeTokenId;
raffle.prizeIs1155 = prizeIs1155;
raffle.prizeAmount = prizeAmount;
raffle.externalCustodian = externalCustodian;
raffle.creator = msg.sender;
raffle.maxBurn = maxEntries;
raffle.maxEntrants = maxEntrants;
raffle.isOpen = true;
raffle.createdAt = block.timestamp;
raffle.paymentToken = paymentToken;
raffle.pricePerEntry = pricePerEntry;
emit RaffleCreated(raffleId, msg.sender, address(0), prizeTokenId, prizeIs1155, prizeAmount, maxEntries, new uint256[](0), maxEntrants);
return raffleId;
}
function createRaffleERC20(
address prizeToken,
uint256 prizeAmount,
uint256 maxBurn,
uint256[] memory acceptedTokenIds,
uint256 maxEntrants
) external onlyOwner returns (uint256) {
if (prizeToken == address(0)) revert InvalidState();
if (!prizeToken.isContract()) revert InvalidState();
if (prizeAmount == 0) revert InvalidAmount();
if (maxBurn == 0) revert InvalidAmount();
if (maxEntrants == 0 || maxEntrants > MAX_ENTRANTS_BOUND) revert InvalidState();
IERC20(prizeToken).safeTransferFrom(msg.sender, address(this), prizeAmount);
uint256 raffleId = ++raffleCounter;
Raffle storage raffle = raffles[raffleId];
raffle.prizeIsERC20 = true;
raffle.prizeERC20Token = prizeToken;
raffle.prizeERC20Amount = prizeAmount;
raffle.creator = msg.sender;
raffle.maxBurn = maxBurn;
raffle.maxEntrants = maxEntrants;
raffle.isOpen = true;
raffle.createdAt = block.timestamp;
// Only set accepted token IDs if in burn mode
if (acceptedTokenIds.length > 0) {
if (acceptedTokenIds.length > MAX_ACCEPTED_TOKEN_IDS) revert InvalidState();
_setAcceptedTokenIds(raffleId, acceptedTokenIds);
}
emit ERC20RaffleCreated(raffleId, msg.sender, prizeToken, prizeAmount, maxBurn, acceptedTokenIds, maxEntrants);
return raffleId;
}
// ADDED: ERC20 prize with ERC20 payment
function createRaffleERC20WithPayment(
address prizeToken,
uint256 prizeAmount,
uint256 maxEntries,
address paymentToken,
uint256 pricePerEntry,
uint256 maxEntrants
) external onlyOwner returns (uint256) {
if (prizeToken == address(0)) revert InvalidState();
if (!prizeToken.isContract()) revert InvalidState();
if (prizeAmount == 0) revert InvalidAmount();
if (maxEntries == 0) revert InvalidAmount();
if (paymentToken == address(0)) revert InvalidState();
if (!paymentToken.isContract()) revert InvalidState();
if (pricePerEntry == 0) revert InvalidAmount();
if (maxEntrants == 0 || maxEntrants > MAX_ENTRANTS_BOUND) revert InvalidState();
IERC20(prizeToken).safeTransferFrom(msg.sender, address(this), prizeAmount);
uint256 raffleId = ++raffleCounter;
Raffle storage raffle = raffles[raffleId];
raffle.prizeIsERC20 = true;
raffle.prizeERC20Token = prizeToken;
raffle.prizeERC20Amount = prizeAmount;
raffle.creator = msg.sender;
raffle.maxBurn = maxEntries;
raffle.maxEntrants = maxEntrants;
raffle.isOpen = true;
raffle.createdAt = block.timestamp;
raffle.paymentToken = paymentToken;
raffle.pricePerEntry = pricePerEntry;
emit ERC20RaffleCreated(raffleId, msg.sender, prizeToken, prizeAmount, maxEntries, new uint256[](0), maxEntrants);
return raffleId;
}
// MODIFIED: Internal function now accepts payment parameters
function _createRaffleERC721(
address prizeNFT,
uint256 prizeTokenId,
uint256 maxBurn,
uint256[] memory acceptedTokenIds,
uint256 maxEntrants,
address paymentToken,
uint256 pricePerEntry
) internal returns (uint256) {
if (prizeNFT == address(0)) revert InvalidState();
if (!prizeNFT.isContract()) revert InvalidState();
if (maxBurn == 0) revert InvalidAmount();
if (maxEntrants == 0 || maxEntrants > MAX_ENTRANTS_BOUND) revert InvalidState();
// MODIFIED: Validate based on mode
if (paymentToken != address(0)) {
// ERC20 mode
if (!paymentToken.isContract()) revert InvalidState();
if (pricePerEntry == 0) revert InvalidAmount();
} else {
// Burn mode - need accepted token IDs
if (acceptedTokenIds.length == 0 || acceptedTokenIds.length > MAX_ACCEPTED_TOKEN_IDS) revert InvalidState();
}
IERC721(prizeNFT).safeTransferFrom(msg.sender, address(this), prizeTokenId);
uint256 raffleId = ++raffleCounter;
Raffle storage r = raffles[raffleId];
r.prizeNFT = prizeNFT;
r.prizeTokenId = prizeTokenId;
r.prizeAmount = 1;
r.prizeIs1155 = false;
r.creator = msg.sender;
r.maxBurn = maxBurn;
r.maxEntrants = maxEntrants;
r.isOpen = true;
r.createdAt = block.timestamp;
r.paymentToken = paymentToken;
r.pricePerEntry = pricePerEntry;
// Only set accepted token IDs if in burn mode
if (paymentToken == address(0) && acceptedTokenIds.length > 0) {
_setAcceptedTokenIds(raffleId, acceptedTokenIds);
}
emit RaffleCreated(raffleId, msg.sender, prizeNFT, prizeTokenId, false, 1, maxBurn, acceptedTokenIds, maxEntrants);
return raffleId;
}
function _setAcceptedTokenIds(uint256 raffleId, uint256[] memory acceptedTokenIds) internal {
uint256 tokenCount = acceptedTokenIds.length;
for (uint256 i = 0; i < tokenCount;) {
uint256 tokenId = acceptedTokenIds[i];
if (!raffleTokenIdAllowed[raffleId][tokenId]) {
raffleTokenIdAllowed[raffleId][tokenId] = true;
raffles[raffleId].acceptedTokenIds.push(tokenId);
}
unchecked { ++i; }
}
}
// MODIFIED: Check entry mode and try auto-finalize
function enterRaffle(uint256 raffleId, uint256 tokenId, uint256 amount) external nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
// MODIFIED: Must be in burn mode
if (raffle.paymentToken != address(0)) revert WrongEntryMode();
_enterRaffleInternal(raffleId, tokenId, amount);
_markTokenIdUsed(raffleId, tokenId);
emit RaffleEntered(raffleId, msg.sender, tokenId, amount);
// NEW: Try auto-finalize if raffle is full
if (raffle.burned == raffle.maxBurn) {
_tryAutoFinalize(raffleId);
}
}
// MODIFIED: Try auto-finalize when full
function enterRaffleWithToken(uint256 raffleId, uint256 entries) external nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
// MODIFIED: Must be in ERC20 mode
if (raffle.paymentToken == address(0)) revert WrongEntryMode();
if (raffle.isCanceled) revert RaffleCanceledError();
if (!raffle.isOpen) revert RaffleNotOpen();
if (raffle.isPaused) revert RafflePausedError();
if (raffle.awaitingRandomness) revert RandomnessPending();
if (entries == 0) revert InvalidAmount();
if (raffle.burned + entries > raffle.maxBurn) revert MaxBurnExceeded();
bool isNewEntrant = raffleEntries[raffleId][msg.sender] == 0;
if (isNewEntrant && raffle.entrants.length >= raffle.maxEntrants) {
revert TooManyEntrants();
}
uint256 cost = entries * raffle.pricePerEntry;
IERC20(raffle.paymentToken).safeTransferFrom(msg.sender, address(this), cost);
_erc20Paid[raffleId][msg.sender] += cost;
raffle.proceedsAccrued += cost;
if (isNewEntrant) {
raffle.entrants.push(msg.sender);
}
raffleEntries[raffleId][msg.sender] += entries;
raffle.burned += entries;
emit RafflePurchased(raffleId, msg.sender, raffle.paymentToken, entries, cost);
// NEW: Try auto-finalize if raffle is full
if (raffle.burned == raffle.maxBurn) {
_tryAutoFinalize(raffleId);
}
}
function enterRaffleWithTokenPermit(
uint256 raffleId,
uint256 entries,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
// MODIFIED: Must be in ERC20 mode
if (raffle.paymentToken == address(0)) revert WrongEntryMode();
// Validate that the payment token supports permits
// This will revert if the token doesn't implement IERC20Permit
try IERC20Permit(raffle.paymentToken).DOMAIN_SEPARATOR() returns (bytes32) {
// Token supports permits, continue
} catch {
revert InvalidState(); // Token doesn't support permits
}
if (raffle.isCanceled) revert RaffleCanceledError();
if (!raffle.isOpen) revert RaffleNotOpen();
if (raffle.isPaused) revert RafflePausedError();
if (raffle.awaitingRandomness) revert RandomnessPending();
if (entries == 0) revert InvalidAmount();
if (raffle.burned + entries > raffle.maxBurn) revert MaxBurnExceeded();
bool isNewEntrant = raffleEntries[raffleId][msg.sender] == 0;
if (isNewEntrant && raffle.entrants.length >= raffle.maxEntrants) {
revert TooManyEntrants();
}
uint256 cost = entries * raffle.pricePerEntry;
IERC20Permit(raffle.paymentToken).permit(
msg.sender,
address(this),
cost,
deadline,
v,
r,
s
);
IERC20(raffle.paymentToken).safeTransferFrom(msg.sender, address(this), cost);
_erc20Paid[raffleId][msg.sender] += cost;
raffle.proceedsAccrued += cost;
if (isNewEntrant) {
raffle.entrants.push(msg.sender);
}
raffleEntries[raffleId][msg.sender] += entries;
raffle.burned += entries;
emit RaffleEnteredWithPermit(raffleId, msg.sender, raffle.paymentToken, entries, cost);
// NEW: Try auto-finalize if raffle is full
if (raffle.burned == raffle.maxBurn) {
_tryAutoFinalize(raffleId);
}
}
function _enterRaffleInternal(uint256 raffleId, uint256 tokenId, uint256 amount) internal {
Raffle storage raffle = raffles[raffleId];
if (raffle.isCanceled) revert RaffleCanceledError();
if (!raffle.isOpen) revert RaffleNotOpen();
if (raffle.isPaused) revert RafflePausedError();
if (raffle.awaitingRandomness) revert RandomnessPending();
if (!raffleTokenIdAllowed[raffleId][tokenId]) revert TokenNotAccepted();
if (amount == 0) revert InvalidAmount();
if (raffle.burned + amount > raffle.maxBurn) revert MaxBurnExceeded();
bool isNewEntrant = raffleEntries[raffleId][msg.sender] == 0;
if (isNewEntrant && raffle.entrants.length >= raffle.maxEntrants) {
revert TooManyEntrants();
}
geezToken.safeTransferFrom(msg.sender, address(this), tokenId, amount, "");
_escrow[raffleId][msg.sender][tokenId] += amount;
_escrowTotals[raffleId][tokenId] += amount;
if (isNewEntrant) {
raffle.entrants.push(msg.sender);
}
raffleEntries[raffleId][msg.sender] += amount;
raffle.burned += amount;
}
function _markTokenIdUsed(uint256 raffleId, uint256 tokenId) internal {
if (!_tokenIdUsed[raffleId][tokenId]) {
_tokenIdUsed[raffleId][tokenId] = true;
raffles[raffleId].usedTokenIds.push(tokenId);
}
}
function _calculateWeights(uint256 raffleId) internal {
Raffle storage r = raffles[raffleId];
if (r.weightsCalculated) return;
uint256 entrantCount = r.entrants.length;
r.cumulativeWeights = new uint256[](entrantCount);
uint256 cumulativeWeight = 0;
for (uint256 i = 0; i < entrantCount;) {
address entrant = r.entrants[i];
uint256 userEntries = raffleEntries[raffleId][entrant];
cumulativeWeight += userEntries;
r.cumulativeWeights[i] = cumulativeWeight;
unchecked { ++i; }
}
r.totalWeight = cumulativeWeight;
r.weightsCalculated = true;
emit WeightsCalculated(raffleId, cumulativeWeight);
}
function _finalize(uint256 raffleId, uint256 vrngFee) internal {
Raffle storage r = raffles[raffleId];
if (!r.isOpen) revert RaffleNotOpen();
if (r.entrants.length == 0) revert InvalidState();
if (r.awaitingRandomness) revert RandomnessPending();
r.awaitingRandomness = true;
r.vrngRequestTimestamp = block.timestamp;
uint256 requestId = vrngRouter.requestRandomNumberWithTraceId{value: vrngFee}(raffleId);
if (requestId == 0) revert InvalidState();
r.vrngRequestId = requestId;
vrngRequestToRaffle[requestId] = raffleId;
emit VRNGRequested(raffleId, requestId, raffleId);
}
function _completeFinalization(uint256 raffleId, uint256 randomNumber) internal {
Raffle storage r = raffles[raffleId];
if (!r.weightsCalculated) revert InvalidState();
if (r.totalWeight == 0) revert InvalidState();
uint256 winningNumber = randomNumber % r.totalWeight;
address winner = _findWinnerBinarySearch(raffleId, winningNumber);
if (winner == address(0)) revert InvalidState();
r.winner = winner;
_transferPrize(raffleId, winner);
emit RaffleWinner(raffleId, winner);
// MODIFIED: Only burn if in burn mode and burning is allowed
if (r.paymentToken == address(0) && isSelfBurnAllowed) {
_burnEscrowedTokens(raffleId);
}
_cleanupStorage(raffleId);
r.storageCanBePruned = true;
r.isOpen = false;
emit RaffleClosed(raffleId);
}
function _findWinnerBinarySearch(uint256 raffleId, uint256 target) internal view returns (address) {
Raffle storage r = raffles[raffleId];
uint256 left = 0;
uint256 right = r.cumulativeWeights.length;
while (left < right) {
uint256 mid = left + (right - left) / 2;
if (r.cumulativeWeights[mid] <= target) {
left = mid + 1;
} else {
right = mid;
}
}
return left < r.entrants.length ? r.entrants[left] : address(0);
}
function _transferPrize(uint256 raffleId, address winner) internal {
Raffle storage r = raffles[raffleId];
if (r.prizeIsERC20) {
IERC20(r.prizeERC20Token).safeTransfer(winner, r.prizeERC20Amount);
r.prizeERC20Amount = 0;
} else if (r.prizeIsExternal) {
emit ExternalPrizeAnnounced(
raffleId,
winner,
r.externalChainId,
r.externalPrizeCollection,
r.prizeTokenId,
r.prizeIs1155,
r.prizeAmount
);
} else {
if (r.prizeIs1155) {
IERC1155(r.prizeNFT).safeTransferFrom(address(this), winner, r.prizeTokenId, r.prizeAmount, "");
} else {
IERC721(r.prizeNFT).safeTransferFrom(address(this), winner, r.prizeTokenId);
}
}
}
function _burnEscrowedTokens(uint256 raffleId) internal {
Raffle storage r = raffles[raffleId];
uint256 usedTokenCount = r.usedTokenIds.length;
for (uint256 i = 0; i < usedTokenCount;) {
uint256 tokenId = r.usedTokenIds[i];
uint256 totalAmount = _escrowTotals[raffleId][tokenId];
if (totalAmount > 0) {
try geezToken.burn(address(this), tokenId, totalAmount) {
delete _escrowTotals[raffleId][tokenId];
} catch {
r.burnFailed = true;
}
}
unchecked { ++i; }
}
}
function _cleanupStorage(uint256 raffleId) internal {
Raffle storage r = raffles[raffleId];
uint256 entrantCount = r.entrants.length;
for (uint256 i = 0; i < entrantCount;) {
address entrant = r.entrants[i];
delete raffleEntries[raffleId][entrant];
delete _erc20Paid[raffleId][entrant];
// Only cleanup escrow if in burn mode
if (r.paymentToken == address(0)) {
uint256 usedTokenCount = r.usedTokenIds.length;
for (uint256 j = 0; j < usedTokenCount;) {
delete _escrow[raffleId][entrant][r.usedTokenIds[j]];
unchecked { ++j; }
}
}
unchecked { ++i; }
}
}
function adminFinalizeRaffle(uint256 raffleId) external payable onlyOwner nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (!raffle.isOpen) revert RaffleNotOpen();
if (raffle.entrants.length == 0) revert InvalidState();
if (raffle.awaitingRandomness) revert RandomnessPending();
if (raffle.burned != raffle.maxBurn) revert NotReadyToFinalize();
if (vrngFeeWei > 0 && msg.value != vrngFeeWei) revert InvalidAmount();
if (vrngFeeWei == 0 && msg.value != 0) revert InvalidAmount();
uint256 lastAttempt = lastFinalizationAttempt[raffleId];
if (lastAttempt > 0 && block.timestamp < lastAttempt + MIN_FINALIZATION_DELAY) {
revert InvalidState();
}
lastFinalizationAttempt[raffleId] = block.timestamp;
_calculateWeights(raffleId);
_finalize(raffleId, msg.value);
}
function pauseRaffle(uint256 raffleId) external onlyOwner {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (!raffle.isOpen) revert RaffleNotOpen();
if (raffle.isPaused) revert InvalidState();
raffle.isPaused = true;
emit RafflePaused(raffleId);
}
function unpauseRaffle(uint256 raffleId) external onlyOwner {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (!raffle.isOpen) revert RaffleNotOpen();
if (!raffle.isPaused) revert InvalidState();
raffle.isPaused = false;
emit RaffleUnpaused(raffleId);
}
function cancelRaffle(uint256 raffleId) external onlyOwner nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (!raffle.isOpen) revert RaffleNotOpen();
if (raffle.isCanceled) revert InvalidState();
raffle.isCanceled = true;
raffle.isOpen = false;
raffle.storageCanBePruned = true;
if (raffle.awaitingRandomness) {
raffle.awaitingRandomness = false;
delete vrngRequestToRaffle[raffle.vrngRequestId];
}
emit RaffleCanceled(raffleId, false);
}
function processRefunds(
uint256 raffleId,
uint256 start,
uint256 end
) external onlyOwner nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
if (!r.isCanceled) revert InvalidState();
uint256 entrantCount = r.entrants.length;
if (end > entrantCount) end = entrantCount;
if (start >= end) revert InvalidState();
if (end - start > REFUND_BATCH_SIZE) revert InvalidState();
uint256 processed = 0;
for (uint256 i = start; i < end;) {
_refundSingle(raffleId, r.entrants[i]);
unchecked {
++processed;
++i;
}
}
if (end > r.refundProgress) {
r.refundProgress = end;
}
emit BatchRefundProcessed(raffleId, start, end, processed);
}
function processRefundsFor(
uint256 raffleId,
address[] calldata users
) external onlyOwner nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
if (!r.isCanceled) revert InvalidState();
if (users.length > REFUND_BATCH_SIZE) revert InvalidState();
uint256 userCount = users.length;
for (uint256 i = 0; i < userCount;) {
_refundSingle(raffleId, users[i]);
unchecked { ++i; }
}
// Check if all refunds are complete after processing
bool allRefundsComplete = true;
// MODIFIED: Check based on entry mode
if (r.paymentToken == address(0)) {
// Burn mode - check escrow totals
uint256 usedTokenCount = r.usedTokenIds.length;
for (uint256 i = 0; i < usedTokenCount;) {
if (_escrowTotals[raffleId][r.usedTokenIds[i]] > 0) {
allRefundsComplete = false;
break;
}
unchecked { ++i; }
}
} else {
// ERC20 mode - check proceeds
if (r.proceedsAccrued > 0) {
allRefundsComplete = false;
}
}
if (allRefundsComplete) {
r.refundProgress = r.entrants.length;
}
emit BatchRefundProcessed(raffleId, 0, userCount, userCount);
}
// MODIFIED: Handle both burn and ERC20 refunds
function _refundSingle(uint256 raffleId, address user) internal {
Raffle storage r = raffles[raffleId];
if (r.paymentToken == address(0)) {
// Burn mode refunds
uint256 tokenRefund = 0;
uint256 nonZeroCount = 0;
uint256[] memory ids = r.usedTokenIds;
uint256 usedTokenCount = ids.length;
// First pass: count non-zero amounts
for (uint256 j = 0; j < usedTokenCount;) {
uint256 amount = _escrow[raffleId][user][ids[j]];
if (amount > 0) {
tokenRefund += amount;
unchecked { ++nonZeroCount; }
}
unchecked { ++j; }
}
if (tokenRefund > 0) {
uint256[] memory refundIds = new uint256[](nonZeroCount);
uint256[] memory refundAmounts = new uint256[](nonZeroCount);
uint256 index = 0;
for (uint256 j = 0; j < usedTokenCount;) {
uint256 tokenId = ids[j];
uint256 amount = _escrow[raffleId][user][tokenId];
if (amount > 0) {
refundIds[index] = tokenId;
refundAmounts[index] = amount;
delete _escrow[raffleId][user][tokenId];
_escrowTotals[raffleId][tokenId] -= amount;
unchecked { ++index; }
}
unchecked { ++j; }
}
if (nonZeroCount == 1) {
geezToken.safeTransferFrom(address(this), user, refundIds[0], refundAmounts[0], "");
} else {
geezToken.safeBatchTransferFrom(address(this), user, refundIds, refundAmounts, "");
}
emit RefundIssued(raffleId, user, tokenRefund);
}
} else {
// ERC20 mode refunds
uint256 paidAmount = _erc20Paid[raffleId][user];
if (paidAmount > 0) {
delete _erc20Paid[raffleId][user];
r.proceedsAccrued -= paidAmount;
IERC20(r.paymentToken).safeTransfer(user, paidAmount);
emit TokenRefundIssued(raffleId, user, r.paymentToken, paidAmount);
}
}
}
function deleteRaffle(uint256 raffleId) external onlyOwner nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (raffle.burned != 0) revert InvalidState();
if (raffle.entrants.length != 0) revert InvalidState();
if (raffle.proceedsAccrued != 0) revert InvalidState();
if (raffle.winner != address(0)) revert InvalidState();
if (raffle.awaitingRandomness) revert InvalidState();
if (raffle.isCanceled) revert InvalidState();
address creator = raffle.creator;
if (!raffle.prizeIsExternal) {
if (raffle.prizeIsERC20) {
IERC20(raffle.prizeERC20Token).safeTransfer(creator, raffle.prizeERC20Amount);
} else if (raffle.prizeIs1155) {
IERC1155(raffle.prizeNFT).safeTransferFrom(address(this), creator, raffle.prizeTokenId, raffle.prizeAmount, "");
} else {
IERC721(raffle.prizeNFT).safeTransferFrom(address(this), creator, raffle.prizeTokenId);
}
}
if (raffle.vrngRequestId != 0) {
delete vrngRequestToRaffle[raffle.vrngRequestId];
}
uint256 acceptedCount = raffle.acceptedTokenIds.length;
for (uint256 i = 0; i < acceptedCount;) {
delete raffleTokenIdAllowed[raffleId][raffle.acceptedTokenIds[i]];
unchecked { ++i; }
}
delete raffles[raffleId];
emit RaffleDeleted(raffleId, creator);
}
function adminWithdrawPrizeNFT(uint256 raffleId) external onlyOwner nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (!raffle.isCanceled) revert InvalidState();
if (raffle.prizeIsExternal) revert InvalidState();
if (raffle.prizeWithdrawnIfCanceled) revert InvalidState();
raffle.prizeWithdrawnIfCanceled = true;
if (raffle.prizeIsERC20) {
IERC20(raffle.prizeERC20Token).safeTransfer(owner(), raffle.prizeERC20Amount);
raffle.prizeERC20Amount = 0;
} else if (raffle.prizeIs1155) {
IERC1155(raffle.prizeNFT).safeTransferFrom(address(this), owner(), raffle.prizeTokenId, raffle.prizeAmount, "");
} else {
IERC721(raffle.prizeNFT).safeTransferFrom(address(this), owner(), raffle.prizeTokenId);
}
emit PrizeWithdrawn(raffleId);
}
function withdrawProceeds(uint256 raffleId, address to) external onlyOwner nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (raffle.isOpen) revert InvalidState();
if (raffle.isCanceled) revert InvalidState();
if (raffle.paymentToken == address(0)) revert InvalidState();
if (raffle.proceedsAccrued == 0) revert InvalidAmount();
if (to == address(0)) revert BadRecipient();
uint256 amount = raffle.proceedsAccrued;
raffle.proceedsAccrued = 0;
IERC20(raffle.paymentToken).safeTransfer(to, amount);
emit ProceedsWithdrawn(raffleId, raffle.paymentToken, to, amount);
}
function markExternalPrizeDelivered(uint256 raffleId, bytes32 externalTxHash) external nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (msg.sender != owner() && msg.sender != raffle.externalCustodian) revert UnauthorizedCaller();
if (!raffle.prizeIsExternal) revert InvalidState();
if (raffle.isOpen) revert InvalidState();
if (raffle.externalDelivered) revert InvalidState();
raffle.externalDelivered = true;
emit ExternalPrizeDeliveryMarked(raffleId, msg.sender, externalTxHash);
}
function setExternalCustodian(uint256 raffleId, address newCustodian) external onlyOwner {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
if (newCustodian == address(0)) revert BadRecipient();
Raffle storage raffle = raffles[raffleId];
if (!raffle.prizeIsExternal) revert InvalidState();
if (!raffle.isOpen && raffle.externalDelivered) revert InvalidState();
raffle.externalCustodian = newCustodian;
emit ExternalCustodianUpdated(raffleId, newCustodian);
}
function rescueETH(address to) external onlyOwner nonReentrant {
if (to == address(0)) revert BadRecipient();
(bool ok,) = payable(to).call{value: address(this).balance}("");
if (!ok) revert InvalidState();
}
function rescueERC20(address token, address to, uint256 amount) external onlyOwner nonReentrant {
if (to == address(0)) revert BadRecipient();
if (amount == 0) revert InvalidAmount();
uint256 contractBalance = IERC20(token).balanceOf(address(this));
if (amount > contractBalance) revert InvalidAmount();
uint256 protectedAmount = _calculateProtectedTokenAmount(token);
if (contractBalance < protectedAmount + amount) revert InvalidState();
IERC20(token).safeTransfer(to, amount);
}
function _calculateProtectedTokenAmount(address token) internal view returns (uint256) {
uint256 protected = 0;
for (uint256 id = 1; id <= raffleCounter;) {
Raffle storage r = raffles[id];
if (r.creator == address(0)) {
unchecked { ++id; }
continue;
}
if (r.paymentToken == token && (r.isOpen || r.proceedsAccrued > 0)) {
protected += r.proceedsAccrued;
}
if (r.prizeIsERC20 && r.prizeERC20Token == token && (!r.isCanceled || !r.prizeWithdrawnIfCanceled)) {
protected += r.prizeERC20Amount;
}
unchecked { ++id; }
}
return protected;
}
// MODIFIED: Handle both modes
function claimRefund(uint256 raffleId, uint256[] memory tokenIds) external nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (!raffle.isCanceled) revert InvalidState();
if (raffle.paymentToken == address(0)) {
// Burn mode - refund specific tokens
_refundSpecificTokens(raffleId, msg.sender, tokenIds);
} else {
// ERC20 mode - refund payment
uint256 paidAmount = _erc20Paid[raffleId][msg.sender];
if (paidAmount > 0) {
delete _erc20Paid[raffleId][msg.sender];
raffle.proceedsAccrued -= paidAmount;
IERC20(raffle.paymentToken).safeTransfer(msg.sender, paidAmount);
emit TokenRefundIssued(raffleId, msg.sender, raffle.paymentToken, paidAmount);
}
}
}
function claimRefundAll(uint256 raffleId) external nonReentrant {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage raffle = raffles[raffleId];
if (!raffle.isCanceled) revert InvalidState();
_refundSingle(raffleId, msg.sender);
}
function _refundSpecificTokens(uint256 raffleId, address user, uint256[] memory tokenIds) internal {
uint256 tokenRefund = 0;
uint256 nonZeroCount = 0;
uint256 tokenCount = tokenIds.length;
for (uint256 i = 0; i < tokenCount;) {
uint256 amount = _escrow[raffleId][user][tokenIds[i]];
if (amount > 0) {
tokenRefund += amount;
unchecked { ++nonZeroCount; }
}
unchecked { ++i; }
}
if (tokenRefund > 0) {
uint256[] memory refundIds = new uint256[](nonZeroCount);
uint256[] memory refundAmounts = new uint256[](nonZeroCount);
uint256 index = 0;
for (uint256 i = 0; i < tokenCount;) {
uint256 tokenId = tokenIds[i];
uint256 amount = _escrow[raffleId][user][tokenId];
if (amount > 0) {
refundIds[index] = tokenId;
refundAmounts[index] = amount;
delete _escrow[raffleId][user][tokenId];
_escrowTotals[raffleId][tokenId] -= amount;
unchecked { ++index; }
}
unchecked { ++i; }
}
if (nonZeroCount == 1) {
geezToken.safeTransferFrom(address(this), user, refundIds[0], refundAmounts[0], "");
} else {
geezToken.safeBatchTransferFrom(address(this), user, refundIds, refundAmounts, "");
}
emit RefundIssued(raffleId, user, tokenRefund);
}
}
// View functions remain unchanged
function isReadyToFinalize(uint256 raffleId) external view returns (bool) {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
return r.isOpen && !r.isCanceled && !r.awaitingRandomness &&
r.burned == r.maxBurn && r.entrants.length > 0;
}
function getRaffleStats(uint256 raffleId) external view returns (
address prizeNFT,
uint256 prizeTokenId,
address creator,
uint256 maxBurn,
uint256 burned,
bool isOpen,
bool isPaused,
bool isCanceled,
uint256 entrantsCount,
bool awaitingRandomness,
uint256 maxEntrants
) {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
return (
r.prizeNFT,
r.prizeTokenId,
r.creator,
r.maxBurn,
r.burned,
r.isOpen,
r.isPaused,
r.isCanceled,
r.entrants.length,
r.awaitingRandomness,
r.maxEntrants
);
}
function getRaffleDetails(uint256 raffleId) external view returns (
bool prizeIs1155,
uint256 prizeAmount,
uint256[] memory acceptedTokenIds,
bool prizeIsExternal,
uint256 externalChainId,
address externalPrizeCollection,
address externalCustodian,
bool externalDelivered
) {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
return (
r.prizeIs1155,
r.prizeAmount,
r.acceptedTokenIds,
r.prizeIsExternal,
r.externalChainId,
r.externalPrizeCollection,
r.externalCustodian,
r.externalDelivered
);
}
function getPaymentConfig(uint256 raffleId) external view returns (
address paymentToken,
uint256 pricePerEntry,
uint256 proceedsAccrued
) {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
return (
r.paymentToken,
r.pricePerEntry,
r.proceedsAccrued
);
}
function getWinnerInfo(uint256 raffleId) external view returns (
address winner,
uint256 vrngRequestId,
bool awaitingRandomness,
uint256 vrngRequestTimestamp
) {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
return (
r.winner,
r.vrngRequestId,
r.awaitingRandomness,
r.vrngRequestTimestamp
);
}
function getUserEntries(uint256 raffleId, address user) external view returns (uint256) {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
return raffleEntries[raffleId][user];
}
function getRaffleEntrants(uint256 raffleId) external view returns (address[] memory) {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
return raffles[raffleId].entrants;
}
function getUsedTokenIds(uint256 raffleId) external view returns (uint256[] memory) {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
return raffles[raffleId].usedTokenIds;
}
function getRefundStatus(uint256 raffleId, address user) external view returns (
uint256 tokenRefundAvailable,
uint256 erc20RefundAvailable,
bool hasRefundableTokens,
bool hasRefundableERC20
) {
if (raffleId == 0 || raffleId > raffleCounter) revert InvalidRaffleId();
Raffle storage r = raffles[raffleId];
if (r.paymentToken == address(0)) {
// Burn mode
uint256 usedTokenCount = r.usedTokenIds.length;
for (uint256 i = 0; i < usedTokenCount;) {
tokenRefundAvailable += _escrow[raffleId][user][r.usedTokenIds[i]];
unchecked { ++i; }
}
hasRefundableTokens = tokenRefundAvailable > 0;
} else {
// ERC20 mode
erc20RefundAvailable = _erc20Paid[raffleId][user];
hasRefundableERC20 = erc20RefundAvailable > 0;
}
}
// NEW: Auto-finalization view functions
function getAutoFinalizationConfig() external view returns (
bool enabled,
uint256 buffer
) {
return (autoFinalizationEnabled, vrngFeeBuffer);
}
function getVRNGFeeStatus() external view returns (
uint256 fee,
uint256 balance,
uint256 buffer,
bool hasEnough
) {
balance = address(this).balance;
hasEnough = vrngFeeWei == 0 || balance >= vrngFeeWei;
fee = vrngFeeWei;
buffer = vrngFeeBuffer;
}
function getVRNGRouter() external view returns (address) {
return address(vrngRouter);
}
function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
return IERC721Receiver.onERC721Received.selector;
}
function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure override returns (bytes4) {
return IERC1155Receiver.onERC1155Received.selector;
}
function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) external pure override returns (bytes4) {
return IERC1155Receiver.onERC1155BatchReceived.selector;
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC721Receiver).interfaceId ||
interfaceId == type(IERC1155Receiver).interfaceId ||
super.supportsInterface(interfaceId);
}
receive() external payable {
if (msg.sender != address(vrngRouter)) {
// Allow funding for VRNG fees from anyone
emit VRNGFeesFunded(msg.sender, msg.value);
}
}
fallback() external payable {
revert BadRecipient();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC1155 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-1155[EIP].
*
* _Available since v3.1._
*/
interface IERC1155 is IERC165 {
/**
* @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
*/
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
/**
* @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
* transfers.
*/
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] values
);
/**
* @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `approved`.
*/
event ApprovalForAll(address indexed account, address indexed operator, bool approved);
/**
* @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
*
* If an {URI} event was emitted for `id`, the standard
* https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
* returned by {IERC1155MetadataURI-uri}.
*/
event URI(string value, uint256 indexed id);
/**
* @dev Returns the amount of tokens of token type `id` owned by `account`.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function balanceOf(address account, uint256 id) external view returns (uint256);
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
*
* Requirements:
*
* - `accounts` and `ids` must have the same length.
*/
function balanceOfBatch(
address[] calldata accounts,
uint256[] calldata ids
) external view returns (uint256[] memory);
/**
* @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
*
* Emits an {ApprovalForAll} event.
*
* Requirements:
*
* - `operator` cannot be the caller.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address account, address operator) external view returns (bool);
/**
* @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
*
* Emits a {TransferSingle} event.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
* - `from` must have a balance of tokens of type `id` of at least `amount`.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
* acceptance magic value.
*/
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
*
* Emits a {TransferBatch} event.
*
* Requirements:
*
* - `ids` and `amounts` must have the same length.
* - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
* acceptance magic value.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
* Revert on invalid signature.
*/
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"optimizer": {
"enabled": true,
"runs": 1
},
"viaIR": true,
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_geezToken","type":"address"},{"internalType":"address","name":"_vrngRouter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadRecipient","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidRaffleId","type":"error"},{"inputs":[],"name":"InvalidState","type":"error"},{"inputs":[],"name":"MaxBurnExceeded","type":"error"},{"inputs":[],"name":"NotReadyToFinalize","type":"error"},{"inputs":[],"name":"RaffleCanceledError","type":"error"},{"inputs":[],"name":"RaffleNotOpen","type":"error"},{"inputs":[],"name":"RafflePausedError","type":"error"},{"inputs":[],"name":"RandomnessPending","type":"error"},{"inputs":[],"name":"TokenNotAccepted","type":"error"},{"inputs":[],"name":"TooManyEntrants","type":"error"},{"inputs":[],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"WrongEntryMode","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"},{"indexed":false,"internalType":"string","name":"reason","type":"string"}],"name":"AutoFinalizationAttempted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"AutoFinalizationEnabled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"start","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"end","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"usersProcessed","type":"uint256"}],"name":"BatchRefundProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isSelfBurnAllowed","type":"bool"}],"name":"BurnValidationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"address","name":"prizeToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxBurn","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"acceptedTokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"ERC20RaffleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"EmergencyCancel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"newCustodian","type":"address"}],"name":"ExternalCustodianUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"externalChainId","type":"uint256"},{"indexed":false,"internalType":"address","name":"externalPrizeCollection","type":"address"},{"indexed":false,"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"prizeIs1155","type":"bool"},{"indexed":false,"internalType":"uint256","name":"prizeAmount","type":"uint256"}],"name":"ExternalPrizeAnnounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"by","type":"address"},{"indexed":false,"internalType":"bytes32","name":"externalTxHash","type":"bytes32"}],"name":"ExternalPrizeDeliveryMarked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"finalizer","type":"address"}],"name":"FinalizeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"GeezSwept","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"pricePerEntry","type":"uint256"}],"name":"PaymentConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"PrizeWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ProceedsWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"autoRefundEnabled","type":"bool"}],"name":"RaffleCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"RaffleClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":true,"internalType":"address","name":"prizeNFT","type":"address"},{"indexed":false,"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"prizeIs1155","type":"bool"},{"indexed":false,"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"maxBurn","type":"uint256"},{"indexed":false,"internalType":"uint256[]","name":"acceptedTokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"RaffleCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"creator","type":"address"}],"name":"RaffleDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RaffleEntered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"RaffleEnteredBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"paymentToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"entries","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"}],"name":"RaffleEnteredWithPermit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"RafflePaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"paymentToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"entries","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cost","type":"uint256"}],"name":"RafflePurchased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"RaffleUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"winner","type":"address"}],"name":"RaffleWinner","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"ReadyToFinalize","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount1155","type":"uint256"}],"name":"RefundIssued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"itemsCleared","type":"uint256"}],"name":"StoragePruned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountToken","type":"uint256"}],"name":"TokenRefundIssued","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newBuffer","type":"uint256"}],"name":"VRNGFeeBufferSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"feeWei","type":"uint256"}],"name":"VRNGFeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"funder","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VRNGFeesFunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomNumber","type":"uint256"}],"name":"VRNGFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"traceId","type":"uint256"}],"name":"VRNGRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"raffleId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalWeight","type":"uint256"}],"name":"WeightsCalculated","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"DEFAULT_MAX_ENTRANTS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ACCEPTED_TOKEN_IDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ENTRANTS_BOUND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_FINALIZATION_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REFUND_BATCH_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VRNG_TIMEOUT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"_internalAutoFinalize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"adminFinalizeRaffle","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"adminWithdrawPrizeNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"autoFinalizationEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"cancelRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"claimRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"claimRefundAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"prizeNFT","type":"address"},{"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"internalType":"uint256","name":"maxBurn","type":"uint256"}],"name":"createRaffle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"prizeNFT","type":"address"},{"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"internalType":"uint256","name":"maxBurn","type":"uint256"},{"internalType":"uint256[]","name":"acceptedTokenIds","type":"uint256[]"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"createRaffleERC1155","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"prizeNFT","type":"address"},{"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"internalType":"uint256","name":"maxEntries","type":"uint256"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"pricePerEntry","type":"uint256"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"createRaffleERC1155WithPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"prizeToken","type":"address"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"internalType":"uint256","name":"maxBurn","type":"uint256"},{"internalType":"uint256[]","name":"acceptedTokenIds","type":"uint256[]"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"createRaffleERC20","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"prizeToken","type":"address"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"internalType":"uint256","name":"maxEntries","type":"uint256"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"pricePerEntry","type":"uint256"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"createRaffleERC20WithPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"prizeNFT","type":"address"},{"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"internalType":"uint256","name":"maxBurn","type":"uint256"},{"internalType":"uint256[]","name":"acceptedTokenIds","type":"uint256[]"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"createRaffleERC721","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"prizeNFT","type":"address"},{"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"internalType":"uint256","name":"maxEntries","type":"uint256"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"pricePerEntry","type":"uint256"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"createRaffleERC721WithPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"externalChainId","type":"uint256"},{"internalType":"address","name":"externalPrizeCollection","type":"address"},{"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"internalType":"bool","name":"prizeIs1155","type":"bool"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"internalType":"uint256","name":"maxBurn","type":"uint256"},{"internalType":"uint256[]","name":"acceptedTokenIds","type":"uint256[]"},{"internalType":"address","name":"externalCustodian","type":"address"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"createRaffleExternalPrize","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"externalChainId","type":"uint256"},{"internalType":"address","name":"externalPrizeCollection","type":"address"},{"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"internalType":"bool","name":"prizeIs1155","type":"bool"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"internalType":"uint256","name":"maxEntries","type":"uint256"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"pricePerEntry","type":"uint256"},{"internalType":"address","name":"externalCustodian","type":"address"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"name":"createRaffleExternalPrizeWithPayment","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"deleteRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"enterRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"uint256","name":"entries","type":"uint256"}],"name":"enterRaffleWithToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"uint256","name":"entries","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"enterRaffleWithTokenPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fundVRNGFees","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"geezToken","outputs":[{"internalType":"contract IBurnableERC1155","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAutoFinalizationConfig","outputs":[{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint256","name":"buffer","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getPaymentConfig","outputs":[{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"pricePerEntry","type":"uint256"},{"internalType":"uint256","name":"proceedsAccrued","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getRaffleDetails","outputs":[{"internalType":"bool","name":"prizeIs1155","type":"bool"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"internalType":"uint256[]","name":"acceptedTokenIds","type":"uint256[]"},{"internalType":"bool","name":"prizeIsExternal","type":"bool"},{"internalType":"uint256","name":"externalChainId","type":"uint256"},{"internalType":"address","name":"externalPrizeCollection","type":"address"},{"internalType":"address","name":"externalCustodian","type":"address"},{"internalType":"bool","name":"externalDelivered","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getRaffleEntrants","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getRaffleStats","outputs":[{"internalType":"address","name":"prizeNFT","type":"address"},{"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"maxBurn","type":"uint256"},{"internalType":"uint256","name":"burned","type":"uint256"},{"internalType":"bool","name":"isOpen","type":"bool"},{"internalType":"bool","name":"isPaused","type":"bool"},{"internalType":"bool","name":"isCanceled","type":"bool"},{"internalType":"uint256","name":"entrantsCount","type":"uint256"},{"internalType":"bool","name":"awaitingRandomness","type":"bool"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getRefundStatus","outputs":[{"internalType":"uint256","name":"tokenRefundAvailable","type":"uint256"},{"internalType":"uint256","name":"erc20RefundAvailable","type":"uint256"},{"internalType":"bool","name":"hasRefundableTokens","type":"bool"},{"internalType":"bool","name":"hasRefundableERC20","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getUsedTokenIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"getUserEntries","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVRNGFeeStatus","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"buffer","type":"uint256"},{"internalType":"bool","name":"hasEnough","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getVRNGRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"getWinnerInfo","outputs":[{"internalType":"address","name":"winner","type":"address"},{"internalType":"uint256","name":"vrngRequestId","type":"uint256"},{"internalType":"bool","name":"awaitingRandomness","type":"bool"},{"internalType":"uint256","name":"vrngRequestTimestamp","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"isReadyToFinalize","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isSelfBurnAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lastFinalizationAttempt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"bytes32","name":"externalTxHash","type":"bytes32"}],"name":"markExternalPrizeDelivered","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"pauseRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"processRefunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"address[]","name":"users","type":"address[]"}],"name":"processRefundsFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"raffleCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"raffleEntries","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"raffleTokenIdAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"raffles","outputs":[{"internalType":"address","name":"prizeNFT","type":"address"},{"internalType":"uint256","name":"prizeTokenId","type":"uint256"},{"internalType":"uint256","name":"prizeAmount","type":"uint256"},{"internalType":"bool","name":"prizeIs1155","type":"bool"},{"internalType":"bool","name":"prizeIsERC20","type":"bool"},{"internalType":"address","name":"prizeERC20Token","type":"address"},{"internalType":"uint256","name":"prizeERC20Amount","type":"uint256"},{"internalType":"bool","name":"prizeIsExternal","type":"bool"},{"internalType":"bool","name":"externalDelivered","type":"bool"},{"internalType":"uint256","name":"externalChainId","type":"uint256"},{"internalType":"address","name":"externalPrizeCollection","type":"address"},{"internalType":"address","name":"externalCustodian","type":"address"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"maxBurn","type":"uint256"},{"internalType":"uint256","name":"burned","type":"uint256"},{"internalType":"bool","name":"isOpen","type":"bool"},{"internalType":"bool","name":"isPaused","type":"bool"},{"internalType":"bool","name":"isCanceled","type":"bool"},{"internalType":"bool","name":"prizeWithdrawnIfCanceled","type":"bool"},{"internalType":"uint256","name":"maxEntrants","type":"uint256"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"pricePerEntry","type":"uint256"},{"internalType":"uint256","name":"proceedsAccrued","type":"uint256"},{"internalType":"address","name":"winner","type":"address"},{"internalType":"bool","name":"awaitingRandomness","type":"bool"},{"internalType":"uint256","name":"vrngRequestId","type":"uint256"},{"internalType":"uint256","name":"vrngRequestTimestamp","type":"uint256"},{"internalType":"uint256","name":"totalWeight","type":"uint256"},{"internalType":"bool","name":"weightsCalculated","type":"bool"},{"internalType":"bool","name":"storageCanBePruned","type":"bool"},{"internalType":"uint256","name":"refundProgress","type":"uint256"},{"internalType":"bool","name":"burnFailed","type":"bool"},{"internalType":"bool","name":"autoFinalized","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"requestId","type":"uint256"},{"internalType":"uint256","name":"randomNumber","type":"uint256"}],"name":"randomNumberCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"requestWinnerVRNG","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"rescueETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setAutoFinalization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_isSelfBurnAllowed","type":"bool"}],"name":"setBurnValidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"address","name":"newCustodian","type":"address"}],"name":"setExternalCustodian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"feeWei","type":"uint256"}],"name":"setVRNGFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"buffer","type":"uint256"}],"name":"setVRNGFeeBuffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"}],"name":"unpauseRaffle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vrngFeeBuffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vrngFeeWei","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"vrngRequestToRaffle","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vrngRouter","outputs":[{"internalType":"contract IVRNGRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawExcessETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"raffleId","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawProceeds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60c080604052346101f65760006040826160e0803803809161002182856101fb565b8339810103126101f357610040602061003984610234565b9301610234565b8154336001600160a01b031982168117845560405194916001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08580a360018080556005805460ff191690911790556001600160a01b0381169182156101d5576001600160a01b0381169182156101e4573b156101d5573b156101c6578160805260a052803b156101c25782606481848094637a94c56560e11b83523060048401528160248401528160448401525af191826101b2575b50506101a05760ff19600354166003555b7fefc59f9df31916aa38fd5ec9fd6105fa15a7ba2ea46ecbf27993bccf5721ed7d602060ff600354166040519015158152a1604051615e979081610249823960805181818161056401528181611d5e0152818161409a01528181614152015281816145160152818161586b015261592f015260a051818181602a01528181610c35015281816119ef01526151650152f35b600160ff19600354161760035561010f565b816101bc916101fb565b386100fe565b5080fd5b63baf3f0f760e01b8352600483fd5b63baf3f0f760e01b8452600484fd5b63baf3f0f760e01b8552600485fd5b80fd5b600080fd5b601f909101601f19168101906001600160401b0382119082101761021e57604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b03821682036101f65756fe610220806040526004361015610076575b503615610028576333d1661360e11b60005260046000fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316330361005a57005b604051348152600080516020615d6283398151915260203392a2005b600090813560e01c90816301ffc9a71461491957508063023ea0b2146148d057806302753713146147f757806304824e70146147915780630a27a7091461473a5780630a722b381461442d5780630dbdf70a146144105780631288608914610c1f57806312911a3d146143f2578063150b7a021461439b578063151e44cb14613fc25780631b6d1b7314613ea15780631b70e79c14613e3a57806321f29f5b14613d7657806325af3e8614613d165780632c920f1b14613ae35780632fd50375146138ed578063341e0c851461381957806334408093146136da578063357adca21461367a5780633df2cf3a1461361f5780634144d833146135d8578063432329a414613410578063442133ab146133ed578063448b0cd4146133d15780634615b9b5146133265780634646e090146132d8578063539cd3e51461324f5780635d4bc0ce14612f5c5780635eaee86d14612ec15780635fba317114612dc557806364aa48da14612ccd57806366c74034146129965780636b1da364146129235780636b7739171461275f578063715018a61461271757806373b6dfe214612542578063744792681461238e578063884464121461237257806389b9d593146121d95780638ae20021146120225780638da5cb5b14611ffb5780638f561acc146119d6578063930f20fd146119ac57806394be8c9814611989578063983b1f1c1461183b578063a080dffe14611773578063a323800c14611749578063a7cccdaf146116ee578063a8bad83a146116d1578063aeff22a114611693578063b2118a8d14611479578063b50dbedf14611212578063b8fde8f214611098578063bb5d241514611066578063bc197c8114610fcd578063bc25d6e314610ea8578063c064a2b314610cf4578063c2f306a514610cd6578063c622969814610c64578063ca606c7514610c1f578063cc1970c114610c02578063d1cfcd0d14610b2e578063d3f643bf14610ae0578063d83decfd14610ac2578063dbd8788614610aa5578063de078b7414610922578063e7b1de4214610593578063ebcdb4571461054e578063ecf9961c14610524578063f23a6e61146104c9578063f2e42fd3146104585763f2fde38b036100105734610455576020366003190112610455576103bb614986565b6103c3614f25565b6001600160a01b031680156104015781546001600160a01b03198116821783556001600160a01b0316600080516020615e228339815191528380a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b80fd5b5034610455576040366003190112610455576004359061047661499c565b91801580156104be575b6104af579060409181526008602052209060018060a01b03166000526020526020604060002054604051908152f35b63f3bf62c360e01b8252600482fd5b506002548111610480565b50346104555760a0366003190112610455576104e3614986565b506104ec61499c565b506084356001600160401b0381116105205761050c9036906004016149cc565b505060405163f23a6e6160e01b8152602090f35b5080fd5b5034610455578060031936011261045557604060ff60055416600654825191151582526020820152f35b50346104555780600319360112610455576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b50346104555760c0366003190112610455576004356024356064359060ff821680920361091e576105c2614ecf565b82158015610913575b6109045782845260076020526040842090601282019260018060a01b0384541680156108f557604051633644e51560e01b8152602081600481855afa90816108c6575b506106225763baf3f0f760e01b8752600487fd5b600c84015460ff8160101c166108b75760ff8116156108a85760081c60ff1661089a5760ff601585015460a01c1661088b57821561087c57600b84019461066a848754614c9b565b94600a81019586541061086d57878952600860209081526040808b2033600090815292529020541593848061085b575b61084c579089949392916106b2601383015488614df7565b93803b156108485760e48792604051988993849263d505accf60e01b84523360048501523060248501528960448501526044356064850152608484015260843560a484015260a43560c48401525af1938a851561083c578a9561081d575b507fd9055e1350232d8f60c534c2cff1e8ec585535179ef5b4827e22f911d5281ba294955061074a84303360018060a01b038754166157c5565b858b52600e60205260408b2060018060a01b0333166000526020526040600020610775858254614c9b565b905560148201610786858254614c9b565b9055610809575b5083895260086020526040892060018060a01b03331660005260205260406000206107b9868254614c9b565b90556107c6858854614c9b565b96879055546040513395909283926107e892906001600160a01b031684614bd2565b0390a354146107fa575b506001805580f35b61080390615336565b386107f2565b61081790600f339101614e45565b3861078d565b61082b9195508092966149f9565b610838578388938a610710565b8880fd5b604051903d90823e3d90fd5b8680fd5b63ead7562d60e01b8a5260048afd5b50600f820154600d830154111561069a565b63f4ff27fb60e01b8952600489fd5b63162908e360e11b8752600487fd5b63319b714360e01b8752600487fd5b629d9e8560e31b8752600487fd5b63ee0eb16d60e01b8852600488fd5b630bb8def160e21b8852600488fd5b6020813d6020116108ed575b816108df602093836149f9565b81010312610838575161060e565b3d91506108d2565b638ceccfff60e01b8752600487fd5b63f3bf62c360e01b8452600484fd5b5060025483116105cb565b8380fd5b5060203660031901126104555760043561093a614f25565b610942614ecf565b80158015610a9a575b6104af5780825260076020526040822060ff600c8201541615610a8b57600f81015415610a7c5760ff601582015460a01c16610a6d57600a600b82015491015403610a5e5760045480159081159081610a53575b50610a445780610a3b575b610a2c57808252600f60205260408220548015159081610a02575b506109f357806109ec918352600f6020524260408420556109e581614f7d565b34906150f4565b6001805580f35b63baf3f0f760e01b8252600482fd5b905061012c8101809111610a18574210386109c5565b634e487b7160e01b83526011600452602483fd5b63162908e360e11b8252600482fd5b503415156109aa565b63162908e360e11b8352600483fd5b90503414153861099f565b634ef0cb9960e01b8252600482fd5b63319b714360e01b8352600483fd5b63baf3f0f760e01b8352600483fd5b63ee0eb16d60e01b8352600483fd5b50600254811161094b565b503461045557806003193601126104555760206040516101f48152f35b50346104555780600319360112610455576020600454604051908152f35b5034610455576020366003190112610455577f3f4696a39500bc65c1c5aa43d74bec8ee234f19fe464577f7ef872bb274833446020600435610b20614f25565b80600655604051908152a180f35b50346104555760203660031901126104555760043580158015610bf7575b6104af5781604091610160935260076020522060018060a01b038154169060018101549060018060a01b0360098201541660ff600a830154600b840154600c85015491600f86015494600d85601589015460a01c1697015497604051998a5260208a0152604089015260608801526080870152818116151560a0870152818160081c16151560c087015260101c16151560e08501526101008401521515610120830152610140820152f35b506002548111610b4c565b5034610455578060031936011261045557602060405161012c8152f35b50346104555780600319360112610455576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b5034610455576020366003190112610455576004359081158015610ccb575b610cbc57604091815260076020522060018060a01b03601282015416610cb86014601384015493015460405193849384614bd2565b0390f35b63f3bf62c360e01b8152600490fd5b506002548211610c83565b50346104555780600319360112610455576020600254604051908152f35b5034610455576040366003190112610455576004356024356001600160401b038111610ea457610d28903690600401614ba2565b9190610d32614f25565b610d3a614ecf565b81158015610e99575b6109045781845260076020526040842060ff600c82015460101c1615610e8a5760328411610e8a57845b84811015610da057600581901b830135906001600160a01b038216820361084857610d9a600192866157ed565b01610d6d565b50601281015460019492506001600160a01b0316610e645760118101805490865b828110610e12575b50505090606091600080516020615de283398151915293945b610e02575b50604051908582528060208301526040820152a26001805580f35b601b600f82015491015538610de7565b858852600d60205260408820610e288284614c6d565b90549060031b1c89526020526040882054610e4557600101610dc1565b50869550829150600080516020615de283398151915290506060610dc9565b9081600080516020615de283398151915293946014606094015415610de2575085610de2565b63baf3f0f760e01b8552600485fd5b506002548211610d43565b8280fd5b503461045557610eb7366149b2565b610ebf614f25565b610ec7614ecf565b8083158015610fc2575b610fb35783855260076020526040852060ff600c82015460101c1615610f9c57600f8101928354809111610fab575b5081841015610f9c576032610f158584614c2f565b11610f9c57859284905b838210610f6c5750509181600080516020615de28339815191529492601b6060950180548211610f64575b505060405192835260208301526040820152a26001805580f35b558038610f4a565b909360018091610f93610f7f8886614c6d565b848060a01b0391549060031b1c168a6157ed565b01940190610f1f565b63baf3f0f760e01b8652600486fd5b915038610f00565b63f3bf62c360e01b8552600485fd5b506002548411610ed1565b50346104555760a036600319011261045557610fe7614986565b50610ff061499c565b506044356001600160401b03811161052057611010903690600401614ba2565b50506064356001600160401b03811161052057611031903690600401614ba2565b50506084356001600160401b038111610520576110529036906004016149cc565b505060405163bc197c8160e01b8152602090f35b50346104555760ff604060209261107c36614af8565b9082526009855282822090825284522054166040519015158152f35b5034610455576110a736614b5c565b6110b394939194614f25565b6001600160a01b0386169485156111e957863b156111e9578415611203578215611203576001600160a01b038416156111e957833b156111e957801561120357811580156111f8575b6111e957916111de60209892600080516020615da2833981519152946111248830338c6157c5565b6013611131600254614ca8565b9a8b988960025589885260078e5261115d60408920926003840161010061ff0019825416178155614e86565b600482018b90556009820180546001600160a01b03199081163317909155600a8301889055600d8301869055600c8301805460ff1916600117905542600e8401556012830180549091166001600160a01b03929092169190911790550155604051936111c98b866149f9565b84526000368137604051938493339885614ead565b0390a4604051908152f35b63baf3f0f760e01b8852600488fd5b506103e882116110fc565b63162908e360e11b8852600488fd5b50346104555761122136614b5c565b9261122e95949295614f25565b6020956040519261123f88856149f9565b88845260003681376001600160a01b038716968715611415573b1561145057821561146a578515801561145f575b611450576001600160a01b03821615918261142457803b15611415578115611406575b873b156113f757604051632142170760e11b81528a81806112b68a303360048501614dd5565b0381838d5af180156113fb576113e2575b509288996113b593600080516020615d828339815191529693601360079c99976112f2600254614ca8565b9d8e9b8c6002558c87525260408520908d60018060a01b0319835416178255896001830155600160028301556003820160ff1981541690556009820160018060a01b03331660018060a01b031982541617905586600a8301558c600d830155600c8201600160ff1982541617905542600e830155601282019060018060a01b031660018060a01b03198254161790550155806113d8575b6113c9575b6040519485528a85015260016040850152606084015260c0608084015260c0830190614ac4565b9360a08201528033940390a4604051908152f35b6113d38388615735565b61138e565b5082511515611389565b6113ed8b80926149f9565b6113f757386112c7565b8980fd5b6040513d8d823e3d90fd5b63162908e360e11b8a5260048afd5b63baf3f0f760e01b8a5260048afd5b84518015908115611445575b50156112905763baf3f0f760e01b8a5260048afd5b600891501138611430565b63baf3f0f760e01b8952600489fd5b506103e8861161126d565b63162908e360e11b8952600489fd5b503461045557606036600319011261045557611493614986565b9061149c61499c565b91604435906114a9614f25565b6114b1614ecf565b6001600160a01b03841615611684578115610a44576040516370a0823160e01b81523060048201526001600160a01b03919091169390602081602481885afa908115611679578491611642575b508083116116335783836001600254905b8181111561153157505061152291614c9b565b11610a7c576109ec9293615687565b808852600760205260408820600981015492935090916001600160a01b0316156116295760128101546001600160a01b031689148061160e575b6115f8575b60038101548960ff8260081c1691826115e2575b5050806115b7575b61159e575b50600101905b859161150f565b6001919360046115b092015490614c9b565b9290611591565b50600c81015460ff8160101c16159081156115d3575b5061158c565b60ff915060181c1615386115cd565b60101c6001600160a01b03161490508938611584565b9261160890601485015490614c9b565b92611570565b5060ff600c820154168061156b57506014810154151561156b565b5060010190611597565b63162908e360e11b8452600484fd5b90506020813d602011611671575b8161165d602093836149f9565b8101031261166c5751386114fe565b600080fd5b3d9150611650565b6040513d86823e3d90fd5b6333d1661360e11b8352600483fd5b50806003193601126104555734156116c257604051348152600080516020615d6283398151915260203392a280f35b63162908e360e11b8152600490fd5b503461045557806003193601126104555760206040516103e88152f35b50346104555760203660031901126104555760043561170b614ecf565b8015801561173e575b6104af57808252600760205260ff600c60408420015460101c16156109f3576109ec9033906157ed565b506002548111611714565b50346104555760203660031901126104555760406020916004358152600b83522054604051908152f35b5034610455576020366003190112610455576004359081158015611830575b610cbc57604091815260076020522060ff60038201541660028201549160ff600582015460068301549260018060a01b036007820154166118076117e5601060018060a01b036008860154169401614d4f565b6040519889981515895260208901526101006040890152610100880190614ac4565b9484841615156060880152608087015260a086015260c085015260081c16151560e08301520390f35b506002548211611792565b50346104555761184a36614b0e565b6118579593929195614f25565b6001600160a01b03851693841561196f57853b1561196f5783156116c25782156116c2578115801561197e575b61196f57611894843033886157c5565b61189f600254614ca8565b958660025586825260076020526118ca60408320916003830161010061ff0019825416178155614e86565b600481018590556009810180546001600160a01b03191633179055600a8101849055600d8101839055600c8101805460ff1916600117905542600e90910155865180611939575b505060209585926111de600080516020615da283398151915293604051938493339885614ead565b60081061196f57508585926111de600080516020615da28339815191529361196360209a87615735565b93505092819750611911565b63baf3f0f760e01b8152600490fd5b506103e88211611884565b5034610455578060031936011261045557602060ff600354166040519015158152f35b50346104555760203660031901126104555760406020916004358152600f83522054604051908152f35b5034610455576119e536614af8565b6119ed614ecf565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163303611fec57818352600b60205260408320549182158015611fe1575b61090457828452600760205260408420601581019081549060ff8260a01c1615611fd25760168491015403610f9c5760ff60a01b19169055808452600b602052836040812055827f63c6ab7b3ed733d226f47ccf6994f0ca68bde6721dcae5c7b741d744d9b5577b6020604051858152a381835260076020526040832090601a82019060ff82541615610e8a576019830154908115610f9c57068385526007602052604085208591601882018054915b828510611f6f57505050600f019081548110600014611f6757611b0691614c6d565b905460039190911b1c6001600160a01b03165b6001600160a01b038116908115610f9c578590601585018360018060a01b0319825416179055858252600760205260408220600381018488825460ff8160081c16600014611e255750509054600490920180549093611b87939192509060101c6001600160a01b0316615687565b555b837fb4d601e7092e672cbffcd1512cc6592c35b9947e1ebfeea7647231887a5224478680a360128201546001600160a01b03161580611e19575b611cf9575b828452600760205260408420600f81018054916012810191875b848110611c2f57855461ff001916610100178655600c8701805460ff1916905588887f2a7d48246875b5f17dc9944def25fc8fe90e524ca2165e290ffdc0e44a0bf8b68280a26001805580f35b611c398183614c6d565b9054898b52600860209081526040808d2060039490941b9290921c6001600160a01b0390811660008181529483528385208e90558c8e52600e8352838e20818652909252919092208b905585541615611c96575b50600101611be2565b601184018054916001600160a01b03168b5b8b8d858310611cbb575050505050611c8d565b906001929152600c6020528d60408082206000908682526020522090611ce18387614c6d565b90549060031b1c90526020528d604081205501611ca8565b828452600760205260408420601181019081549186805b848110611d21575050505050611bc8565b611d2b8184614c6d565b90549060031b1c888352600d60205260408320818452602052604083205480611d5c575b5089925050600101611d10565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b15611e1557611db38592918392604051978880948193637a94c56560e11b8352893060048501614bd2565b03925af19384611e00575b505060019215600014611de35750601c8401805460ff1916831790555b889138611d4f565b888a52600d60205260408a20908a52602052886040812055611ddb565b81611e0a916149f9565b6113f7578938611dbe565b8480fd5b5060ff60035416611bc3565b600585015492969195919260ff1615611ea5575050508160a09160067fe9321bc2ec3549bcfe86623e2e466c29cd13e86670241465ec76939e5ece47a194015491600180851b0360078201541691600260ff60018401549254169201549260405194855260208501526040840152151560608301526080820152a3611b89565b91955092935060ff16159050611f2e5781546001830154600290930154906001600160a01b0316803b15611e1557611ef89385809460405196879586948593637921219560e11b85523060048601614d9c565b03925af18015611f2357611f0e575b5050611b89565b81611f18916149f9565b611e15578438611f07565b6040513d84823e3d90fd5b6001808060a01b03835416920154823b1561091e57611ef892849283604051809681958294632142170760e11b84523060048501614dd5565b505083611b19565b909193611f88611f7f8287614c2f565b60011c82614c9b565b9082611f948386614c6d565b905460039190911b1c11611fcb575060018101809111611fb757935b9190611ae4565b634e487b7160e01b89526011600452602489fd5b9450611fb0565b63baf3f0f760e01b8752600487fd5b506002548311611a34565b635c427cd960e01b8352600483fd5b5034610455578060031936011261045557546040516001600160a01b039091168152602090f35b50346104555761203136614b0e565b9193929061203d614f25565b6001600160a01b038416938415611fd2573b15610f9c5784156121ca57821580156121bf575b610f9c57805180159081156121b4575b50610f9c57833b156121a557604051632142170760e11b815286818061209e86303360048501614dd5565b038183895af180156121a957612190575b50602095916113b5600080516020615d82833981519152926120d2600254614ca8565b600281815581875260078b526040872080546001600160a01b03199081168b178255600180830188905592820183905560038201805460ff19908116909155600983018054831633179055600a83018d9055600d83018b9055600c8301805490911690931790925542600e8201556012810180549092166001600160a01b0389161790915560130186905581519098899690916113c9576040519485528a85015260016040850152606084015260c0608084015260c0830190614ac4565b61219b8780926149f9565b6121a557386120af565b8580fd5b6040513d89823e3d90fd5b600891501138612073565b506103e88311612063565b63162908e360e11b8652600486fd5b5034610455576121e836614af8565b6121f0614ecf565b81158015612367575b612358578183526007602052604083206012810180549092906001600160a01b0316801561234957600c83015460ff8160101c1661233a5760ff81161561232b5760081c60ff1661231d5760ff601584015460a01c1661230e5781156121ca57600b830193612269838654614c9b565b93600a8101948554106122ff57868852600860209081526040808a2033600090815292529020541580806122ed575b6122de5791817fff2a02174867ec97730bdb6670a03e2dc11c034323ab0e03142d3a6aeb6993a69361074a6122d360138c9896015489614df7565b8095309033906157c5565b63ead7562d60e01b8952600489fd5b50600f820154600d8301541115612298565b63f4ff27fb60e01b8852600488fd5b63319b714360e01b8652600486fd5b629d9e8560e31b8652600486fd5b63ee0eb16d60e01b8752600487fd5b630bb8def160e21b8752600487fd5b638ceccfff60e01b8652600486fd5b63f3bf62c360e01b8352600483fd5b5060025482116121f9565b5034610455578060031936011261045557602060405160328152f35b5034610455576020366003190112610455576004356123ab614f25565b6123b3614ecf565b80158015612537575b6104af57808252600760205260408220600c8101805460ff8160101c1615610e8a5760ff600584015416610e8a5760ff8160181c16610e8a5763ff0000001916630100000017905560038101805484929190600881901c60ff1615612472575054825460049290920180549092612445926001600160a01b039182169160109190911c16615687565b555b7fa239896844a2f9e1e391fef736d650713e4e95cc542a49fb562dfd461b20a0318280a26001805580f35b60ff161590506124f1578054825460018301546002909301546001600160a01b0391821692909116803b15611e15576124c69385809460405196879586948593637921219560e11b85523060048601614d9c565b03925af18015611f23576124dc575b5050612447565b816124e6916149f9565b6105205781386124d5565b80548254600192909201546001600160a01b039182169290911690823b1561091e576124c692849283604051809681958294632142170760e11b84523060048501614dd5565b5060025481116123bc565b503461045557610120366003190112610455576004359061256161499c565b9060443561256d614ab5565b6084359460a43560c4356001600160401b0381116121a557612593903690600401614a49565b9060e4359260018060a01b0384168094036108485761010435936125b5614f25565b81156111e9576001600160a01b038916156111e95789156112035782156112035780156111e9578415801561270c575b6111e9576125f4600254614ca8565b98896002558989526007602052604089209260058401600160ff198254161790556006840155600783019060018060a01b031660018060a01b031982541617905586600183015561265486600384019060ff801983541691151516179055565b600282018a90556008820180546001600160a01b0319908116909217905560098201805490911633179055600a8101829055600d8101849055600c8101805460ff1916600117905542600e909101558151806126d4575b50926111de600080516020615d8283398151915293602099938996604051958695339a87614d1e565b600810610f9c57926111de600080516020615d82833981519152938389966126ff60209c9689615735565b93965093995093506126ab565b506103e885116125e5565b5034610455578060031936011261045557612730614f25565b80546001600160a01b03198116825581906001600160a01b0316600080516020615e228339815191528280a380f35b50346104555760e036600319011261045557612779614986565b6024356084356001600160a01b0381169060643590604435908381036108485760a43560c435916127a8614f25565b6001600160a01b038816978815611415573b1561145057831561146a57841561146a578515611450573b156111e95780156112035781158015612918575b6111e957863b1561290957604051637921219560e11b8152888180612811878b303360048601614d9c565b0381838c5af1801561290d576128f4575b50916111de60139796959492602099600080516020615d828339815191529561284c600254614ca8565b600281815581845260078e52604080852080546001600160a01b03199081168f17825560018083018f90559382018a905560038201805460ff199081168617909155600983018054831633179055600a83018c9055600d8301899055600c8301805490911690941790935542600e820155601281018054909316909b1790915598909b0155955189966128df8c836149f9565b81526000368137604051948594339986614ce9565b6128ff8980926149f9565b6129095738612822565b8780fd5b6040513d8b823e3d90fd5b506103e882116127e6565b5034610455576020366003190112610455576004358015801561298b575b6104af578160409160809352600760205220601581015460ff60176016840154930154916040519360018060a01b0382168552602085015260a01c16151560408301526060820152f35b506002548111612941565b5034610455576020366003190112610455576004356129b3614f25565b6129bb614ecf565b80158015612cc2575b6104af5780825260076020526040822090600b820154610a7c57600f820154610a7c576014820154610a7c5760158201546001600160a01b038116612cb35760a01c60ff16610a7c5760ff600c83015460101c16610a7c5760018060a01b036009830154169160ff60058201541615612bb9575b806016601092015480612ba6575b5001805490845b828110612b6f57505050808352600760205282601c6040822082815582600182015582600282015582600382015582600482015582600582015582600682015582600782015582600882015582600982015582600a82015582600b82015582600c82015582600d82015582600e820155600f8101805484825580612b55575b5050612ada60108201614e21565b612ae660118201614e21565b826012820155826013820155826014820155826015820155826016820155826017820155612b1660188201614e21565b82601982015582601a82015582601b82015501557f8cdff5921279206684dbbd35fbeaef8aaff873c39399773df75ce32a75218e8f8380a36001805580f35b612b689185526020852090810190614e0a565b3880612acc565b600190848752600960205260408720612b888285614c6d565b90549060031b1c88526020526040872060ff19815416905501612a4d565b8552600b60205284604081205538612a46565b60038101805460ff8160081c16600014612bf6575054600482015460109291612bef91908690851c6001600160a01b0316615687565b9050612a38565b60ff16159050612c735780546001820154600283015486926001600160a01b03169190823b1561091e57612c4592849283604051809681958294637921219560e11b84528d3060048601614d9c565b03925af18015611f2357612c5e575b5050601090612bef565b81612c68916149f9565b61091e578338612c54565b8054600182015485916001600160a01b0316803b15610ea457604051632142170760e11b81529183918391829084908290612c45908c3060048501614dd5565b63baf3f0f760e01b8452600484fd5b5060025481116129c4565b503461045557604036600319011261045557600435612cea61499c565b90612cf3614f25565b612cfb614ecf565b80158015612dba575b6123585780835260076020526040832090600c82015460ff8116610e8a5760101c60ff16612cb3576012820180546001600160a01b0316928315610f9c5760140193845493841561087c576001600160a01b038216958615612dab57856020937f467267afbc5bfc89ff052b40651c068e07799972abce91b6457016d2b126a99195938a612d929455615687565b546040519485526001600160a01b031693a46001805580f35b6333d1661360e11b8852600488fd5b506002548111612d04565b503461045557602036600319011261045557600435612de2614f25565b612dea614ecf565b80158015612eb6575b6104af57808252600760205260408220600c8101805460ff811615612ea75760ff8160101c16610e8a5762ff00ff191662010000179055601a8101805461ff001916610100179055601581018054919060a083901c60ff16612e84575b5050507fa02141afc19f84c375c9c5757d4c36e47857bf58d1b0f85f9a491bada681bbcb6020604051848152a26001805580f35b60169260ff60a01b1916905501548252600b602052816040812055388080612e50565b63ee0eb16d60e01b8552600485fd5b506002548111612df3565b503461045557602036600319011261045557600435612ede614f25565b80158015612f51575b6104af578082526007602052600c6040832001805460ff811615612f425760ff8160081c16612cb35761ff0019166101001790557f59ae418981ae00500624dca49fa8395d59a12e54cc5af94604258b6402cfb0048280a280f35b63ee0eb16d60e01b8452600484fd5b506002548111612ee7565b50346104555760203660031901126104555760409060043581526007602052206102005260018060a01b036102005154166001610200510154610100526002610200510154610140526003610200510154600461020051015460ff6005610200510154600661020051015460018060a01b0360076102005101541660018060a01b0360086102005101541660018060a01b0360096102005101541690600a61020051015492600b6102005101549487600c61020051015497600d6102005101549a600e6102005101549c60018060a01b036012610200510154169e6013610200510154608052601461020051015460c05260156102005101546101e05260166102005101546101c05260176102005101546101a052601961020051015461018052601a61020051015461016052601b61020051015461012052601c61020051015460e05260405160a05260a0515261010051602060a051015261014051604060a05101528381161515606060a0510152838160081c161515608060a051015260018060a01b039060101c1660a08051015260c060a0510152818116151560e060a051015260081c16151561010060a051015261012060a051015261014060a051015261016060a051015261018060a05101526101a060a05101526101c060a051015281811615156101e060a0510152818160081c16151561020060a0510152818160101c16151561022060a051015260181c16151561024060a051015261026060a051015261028060a05101526102a060a05101526080516102c060a051015260c0516102e060a051015260018060a01b036101e0511661030060a051015260ff6101e05160a01c16151561032060a05101526101c05161034060a05101526101a05161036060a05101526101805161038060a051015260ff610160511615156103a060a051015260ff6101605160081c1615156103c060a0510152610120516103e060a051015260ff60e05116151561040060a051015260ff60e05160081c16151561042060a051015261044060a051f35b50346104555760203660031901126104555760043561326c614f25565b801580156132cd575b6104af578082526007602052600c6040832001805460ff811615612f425760ff8160081c1615612cb35761ff00191690557f88d20d5ea9eaba2406719d2e3e97a5ba16fb0748f87067b5d315ffa7ed7a01018280a280f35b506002548111613275565b5034610455576020366003190112610455577f8b18b05e90c984f3b4e04de16c3b33b6613d924dffaa2d583180e0a984c495286020600435613318614f25565b80600455604051908152a180f35b503461045557602036600319011261045557600435801580156133c6575b6104af5781604091602093526007835220600c8101549060ff821691826133b7575b50816133a4575b81613392575b81613384575b506040519015158152f35b600f91500154151538613379565b600b810154600a820154149150613373565b601581015460a01c60ff1615915061336d565b60101c60ff1615915038613366565b506002548111613344565b5034610455578060031936011261045557602060405160088152f35b5034610455578060031936011261045557602060ff600554166040519015158152f35b50346104555760c03660031901126104555761342a614986565b60643591906024356044356084356001600160401b038111611e1557613454903690600401614a49565b60a43590613460614f25565b6001600160a01b038516948515611fd2573b15610f9c5782156121ca5786156121ca57811580156135cd575b610f9c57843b156121a557604051637921219560e11b81528681806134b78789303360048601614d9c565b0381838a5af180156121a9579087916135b8575b50506134d8600254614ca8565b95866002558681526007602052604081208660018060a01b031982541617815585600182015584600282015560038101600160ff198254161790556009810160018060a01b03331660018060a01b031982541617905588600a82015583600d820155600c8101600160ff19825416179055600e42910155815180613580575b50509585926111de600080516020615d8283398151915293602099604051948594339986614ce9565b60081061196f57509585926111de600080516020615d8283398151915293896135ab60209b88615735565b9399509350819450613557565b816135c2916149f9565b6121a55785386134cb565b506103e8821161348c565b50346104555760403660031901126104555760406135f461499c565b9160043581526008602052209060018060a01b03166000526020526020604060002054604051908152f35b5034610455576020366003190112610455576004358015801561366f575b6104af57601160408361365b93610cb8955260076020522001614d4f565b604051918291602083526020830190614ac4565b50600254811161363d565b5034610455576020366003190112610455577fefc59f9df31916aa38fd5ec9fd6105fa15a7ba2ea46ecbf27993bccf5721ed7d60206136b7614aa6565b6136bf614f25565b151560ff196003541660ff821617600355604051908152a180f35b506020366003190112610455576004356136f2614ecf565b8015801561380e575b6104af57808252600760205260408220600c81015460ff811615908115613800575b5080156137ef575b610a7c57600b810154600a82015414908115916137e2575b50610a5e57600454801590811590816137d7575b50610a4457806137ce575b610a2c57808252600f602052604082205480151590816137b8575b506109f357808252600f60205242604083205561379381614f7d565b61379d34826150f4565b3390600080516020615e028339815191528380a36001805580f35b905061012c8101809111610a1857421038613777565b5034151561375c565b905034141538613751565b600f91500154153861373d565b5060ff601582015460a01c16613725565b60ff915060101c163861371d565b5060025481116136fb565b503461045557602036600319011261045557600435801580156138e2575b6104af5781526007602052600f6040822001604051908160208254918281520190819285526020852090855b8181106138c357505050826138799103836149f9565b604051928392602084019060208552518091526040840192915b8181106138a1575050500390f35b82516001600160a01b0316845285945060209384019390920191600101613893565b82546001600160a01b0316845260209093019260019283019201613863565b506002548111613837565b503461045557610140366003190112610455576004359061390c61499c565b60443590613918614ab5565b9160843560a4359160c43560018060a01b0381169788820361290957610104356001600160a01b0381169960e43592918b90036113f757610124359361395c614f25565b8215613ac5576001600160a01b03891615613ac5578615613ad4578715613ad4578115613ac5573b15611415578215611406578a156114155783158015613aba575b611415576002546139ae90614ca8565b9a8b9889600255898c52600760205260408c20936005850160ff19815416600117905560068501556007840190600160a01b6001900316600160a01b6001900319825416179055856001840155896003840190613a16919060ff801983541691151516179055565b600283018790556008830180546001600160a01b03199081169092179055600983018054821633179055600a8301889055600d8301859055600c8301805460ff1916600117905542600e840155601283018054909116909117905560130155604051613a836020826149f9565b87815260003681376040519485943398613a9d9587614d1e565b03600080516020615d8283398151915291a4604051908152602090f35b506103e8841161399e565b63baf3f0f760e01b8b5260048bfd5b63162908e360e11b8b5260048bfd5b503461045557606036600319011261045557613afd614986565b6044359190602435613b0d614f25565b606092604051613b1d85826149f9565b60028152601f19850136602083013781613b36826156c1565b52805160011015613d0257600160408201526001600160a01b038416938415610a7c573b156109f3578515610a2c57816109f35760009581518015908115613cf7575b50611fd257843b1561084857604051632142170760e11b815296808880613ba588303360048501614dd5565b0381838a5af1978815613cea57602098613cbf575b5050600080516020615d8283398151915291613c9991613bdb600254614ca8565b600281815581875260078b526040872080546001600160a01b03199081168b17825560018083018b905592820183905560038201805460ff19908116909155600983018054831633179055600a83018690556101f4600d840155600c8301805490911690931790925542600e8201556012810180549092166001600160a01b038916179091556013018690558251909889969091613cb0575b6040519788528a8801526001604088015286015260c0608086015260c0850190614ac4565b926101f460a08201528033940390a4604051908152f35b613cba8488615735565b613c74565b613c9992945090613ce081600080516020615d8283398151915295936149f9565b9391819350613bba565b50604051903d90823e3d90fd5b600891501138613b79565b634e487b7160e01b82526032600452602482fd5b5034610455576020366003190112610455577f93357458538ed084eb6df13ca0871aec371e75476b600c54d197320f860e9e446020613d53614aa6565b613d5b614f25565b151560ff196005541660ff821617600555604051908152a180f35b503461045557604036600319011261045557600435613d9361499c565b613d9b614f25565b81158015613e2f575b612358576001600160a01b031690811561168457808352600760205260408320600581015460ff811615610e8a5760ff600c83015416159081613e21575b50612cb35760080180546001600160a01b031916831790557f875c3a0cb9d5fbd474450607d9085f95ff59c5f49af9d25fa6ad5990105c6f918380a380f35b60ff915060081c1638613de2565b506002548211613da4565b503461045557602036600319011261045557600435613e57614f25565b8015610a2c5747613e7682613e7160045460065490614c9b565b614c9b565b11610a2c57815482918291829182916001600160a01b03165af1613e98614bf0565b501561196f5780f35b50346104555760403660031901126104555760043590613ebf61499c565b81908190818086158015613fb7575b6104af5786825260076020526040822060128101549091906001600160a01b0316613f85575060110190815491819360018060a01b0316975b838510613f3757505050505060809350821515905b60405193845260208401521515604083015215156060820152f35b9091929396613f7a600191838652600c60205260408087206000908d825260205220613f638b87614c6d565b90549060031b1c8752602052604086205490614c9b565b970193929190613f07565b94505060409192506080958152600e602052209060018060a01b03166000526020526040600020549081151591613f1c565b506002548711613ece565b503461045557604036600319011261045557600435906024356001600160401b03811161052057613ff7903690600401614a49565b91614000614ecf565b80158015614390575b6104af5780825260076020526040822060ff600c82015460101c1615610a7c576012810180546001600160a01b03166142dd57505082518291903383805b838110614289575084614063575b505050505090506001805580f35b61406c81614cb7565b9261407682614cb7565b928790885b8381106141d357505050508596506001909593949514600014614150577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316916140d7906140d0906156c1565b51916156c1565b51823b1561091e5761410492849283604051809681958294637921219560e11b8452333060048601614d9c565b03925af18015611f235761413b575b50505b604051918252600080516020615d2283398151915260203393a3803880808080614055565b81614145916149f9565b610ea4578238614113565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169190823b1561091e576141a892849283604051809681958294631759616b60e11b84523330600486016156e2565b03925af18015611f23576141be575b5050614116565b816141c8916149f9565b610ea45782386141b7565b6141dd818c6156ce565b51888b52600c6020526040808c2060009085825260205220818c526020528a6040812054918a898b85614219575b50505050505060010161407b565b938361427a938761423f8c60409660019c9e9a99614239838f9e9c6156ce565b526156ce565b52808352600c602052838084206000908c82526020522082845260205282848120558252600d60205282822090825260205220918254614c2f565b90550192908a388a898b61420b565b848752600c6020526040808820600090858252602052206142aa828a6156ce565b5188526020526040872054806142c4575b50600101614047565b6142d46001929397918392614c9b565b960191906142bb565b828452600e602090815260408086203360009081529252902054939450908361430a575b505050506109ec565b600080516020615dc283398151915291601461438492858852600e6020526040882060018060a01b033316600052602052876040600020550161434e868254614c2f565b9055805461436890869033906001600160a01b0316615687565b546040513395909283929091906001600160a01b031683614c52565b0390a338808080614301565b506002548111614009565b5034610455576080366003190112610455576143b5614986565b506143be61499c565b506064356001600160401b038111610520576143de9036906004016149cc565b5050604051630a85bd0160e11b8152602090f35b50346104555780600319360112610455576020600654604051908152f35b50346104555780600319360112610455576020604051611c208152f35b50346104555761443c366149b2565b90614445614ecf565b8215801561472f575b6109045782845260076020526040842060128101549092906001600160a01b031661472057838552600760205260408520600c81015460ff8160101c1661233a5760ff81161561232b5760081c60ff1661231d5760ff601582015460a01c1661230e5784865260096020526040862083875260205260ff604087205416156147115781156121ca57600b8101906144e6838354614c9b565b600a8201541061470257858752600860209081526040808920338a529091528720541580806146f0575b6146e1577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b1561083857886040518092637921219560e11b82528183816145688b8d303360048601614d9c565b03925af1801561290d576146cd575b50868852600c6020526040882060018060a01b0333166000526020526040600020858952602052604088206145ad858254614c9b565b9055868852600d60205260408820858952602052604088206145d0858254614c9b565b90556146b9575b5084865260086020526040862060018060a01b0333166000526020526040600020614603838254614c9b565b9055614610828254614c9b565b9055838552600a6020526040852082865260205260ff6040862054161561467b575b6040519182526020820152827feb79e1c4c2e9267b8cc3b7b7df468f4a50a3fb1c8093d604f2c281ebdf2ae82960403393a3600a600b820154910154146107fa57506001805580f35b838552600a6020526040852082865260205260408520600160ff1982541617905583855260076020526146b4826011604088200161525a565b614632565b6146c790600f339101614e45565b386145d7565b886146da919992996149f9565b9638614577565b63ead7562d60e01b8852600488fd5b50600f820154600d8301541115614510565b63f4ff27fb60e01b8752600487fd5b63e51cf7bf60e01b8652600486fd5b638ceccfff60e01b8552600485fd5b50600254831161444e565b5034610455576020366003190112610455576004353033036147825761475f81614f7d565b61476b600454826150f4565b3090600080516020615e028339815191528380a380f35b635c427cd960e01b8252600482fd5b5034610455576020366003190112610455576147ab614986565b6147b3614f25565b6147bb614ecf565b6001600160a01b031680156147e857818080809347905af16147db614bf0565b501561196f576001805580f35b6333d1661360e11b8252600482fd5b503461045557604036600319011261045557600435614814614ecf565b801580156148c5575b6104af5780825260076020526040822082546001600160a01b0316331415806148ae575b611fec57600581019081549060ff821615610e8a57600c015460ff16612cb35760ff8160081c16612cb3576101009061ff0019161790556040519060243582527f2d667ad442cc5f473a053638a3dd16af33d42b9363dbee8c915a0e0f8327fa0a60203393a36001805580f35b5060088101546001600160a01b0316331415614841565b50600254811161481d565b5034610455578060031936011261045557600454608090801547811561490e575b600654906040519384526020840152604083015215156060820152f35b8281101591506148f1565b9050346105205760203660031901126105205760043563ffffffff60e01b8116809103610ea45760209250630a85bd0160e11b8114908115614975575b8115614964575b5015158152f35b6301ffc9a760e01b1490503861495d565b630271189760e51b81149150614956565b600435906001600160a01b038216820361166c57565b602435906001600160a01b038216820361166c57565b606090600319011261166c57600435906024359060443590565b9181601f8401121561166c578235916001600160401b03831161166c576020838186019501011161166c57565b601f909101601f19168101906001600160401b03821190821017614a1c57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111614a1c5760051b60200190565b9080601f8301121561166c578135614a6081614a32565b92614a6e60405194856149f9565b81845260208085019260051b82010192831161166c57602001905b828210614a965750505090565b8135815260209182019101614a89565b60043590811515820361166c57565b60643590811515820361166c57565b906020808351928381520192019060005b818110614ae25750505090565b8251845260209384019390920191600101614ad5565b604090600319011261166c576004359060243590565b9060a060031983011261166c576004356001600160a01b038116810361166c57916024359160443591606435906001600160401b03821161166c57614b5591600401614a49565b9060843590565b60c090600319011261166c576004356001600160a01b038116810361166c579060243590604435906064356001600160a01b038116810361166c57906084359060a43590565b9181601f8401121561166c578235916001600160401b03831161166c576020808501948460051b01011161166c57565b604091949392606082019560018060a01b0316825260208201520152565b3d15614c2a573d906001600160401b038211614a1c5760405191614c1e601f8201601f1916602001846149f9565b82523d6000602084013e565b606090565b91908203918211614c3c57565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b039091168152602081019190915260400190565b8054821015614c855760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b91908201809211614c3c57565b6000198114614c3c5760010190565b90614cc182614a32565b614cce60405191826149f9565b8281528092614cdf601f1991614a32565b0190602036910137565b9594939092614d199260a0948852600160208901526040880152606087015260c0608087015260c0860190614ac4565b930152565b9695949192614d199360a095928952151560208901526040880152606087015260c0608087015260c0860190614ac4565b906040519182815491828252602082019060005260206000209260005b818110614d83575050614d81925003836149f9565b565b8454835260019485019487945060209093019201614d6c565b6001600160a01b039182168152911660208201526040810191909152606081019190915260a06080820181905260009082015260c00190565b6001600160a01b03918216815291166020820152604081019190915260600190565b81810292918115918404141715614c3c57565b818110614e15575050565b60008155600101614e0a565b80546000825580614e30575050565b614d8191600052602060002090810190614e0a565b8054600160401b811015614a1c57614e6291600182018155614c6d565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b949392606092614d199287526020870152608060408701526080860190614ac4565b600260015414614ee0576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b6000546001600160a01b03163303614f3957565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b8060005260076020526040600020601a810160ff8154166150ef57600f8201918254614fa881614cb7565b805160188401916001600160401b038211614a1c57600160401b8211614a1c5760209083548385558084106150d2575b50969392960186600052602060002060005b8381106150be575050505060009485925b8284106150455750505050601901829055805460ff191660011790556040519081527f3678327a1697b2c81faff80acadd724ab2cd2928955cda6532904fa6950929a590602090a2565b9091929561508d600191604061505b8a86614c6d565b858060a01b0391549060031b1c168b600052600860205281600020600091868060a01b03168252602052205490614c9b565b966150b58861509c8387614c6d565b90919082549060031b91821b91600019901b1916179055565b01929190614ffb565b825181830155602090920191600101614fea565b6150e9908560005284846000209182019101614e0a565b38614fd8565b505050565b806000526007602052604060002060ff600c820154161561524957600f810154156151e757601581019283549060ff8260a01c166152385760ff60a01b19909116600160a01b179093554260178201556040516371c8a23960e11b81526004810183905292602090849060249082907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af192831561522c576000936151f8575b5082156151e75760168391015581600052600b602052806040600020557fc794a0c14d8a263cb588cdbe9d8440fe3dc0604231e2bd9230c307ebd2089cd26020604051838152a3565b63baf3f0f760e01b60005260046000fd5b90926020823d602011615224575b81615213602093836149f9565b81010312610455575051913861519e565b3d9150615206565b6040513d6000823e3d90fd5b63319b714360e01b60005260046000fd5b63ee0eb16d60e01b60005260046000fd5b80549190600160401b831015614a1c578261509c916001614d8195018155614c6d565b600060443d106152e4576040513d600319016004823e8051916001600160401b0383113d6024850111176152ef578183018051909390916001600160401b0383116152e7573d840160031901858401602001116152e757506152e4929101602001906149f9565b90565b949350505050565b92915050565b919082519283825260005b848110615321575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201615300565b60055460ff60009116156156735781815260076020526040812090601c82019182549060ff8260081c1661566c57600c8101549060ff82161591821561565e575b50811561564c575b5061560a57476004548015159182615600575b50506155a457838252600f6020526040822054801515908161558e575b5061553f5761ff001916610100178255828152600f60205260408120429055303b1561045557604051630a27a70960e01b81526004810184905290808260248183305af1918261552f575b50906154f45760018160033d116154e4575b6308c379a01461547a575b61542057505050565b600080516020615d428339815191529161ff0019815416905582600080516020615e42833981519152608060405184815260406020820152600d60408201526c2ab735b737bbb71032b93937b960991b6060820152a280a2565b61548261527d565b8061548e575b50615417565b905083600080516020615e428339815191526154c8849361ff001987541687556040519182918783526040602084015260408301906152f5565b0390a283600080516020615d428339815191528380a238615488565b50600482803e815160e01c61540c565b5050600080516020615e428339815191526080604051600181526040602082015260076040820152665375636365737360c81b6060820152a2565b81615539916149f9565b386153fa565b50600080516020615e42833981519152915060809060405190815260406020820152601a604082015279119a5b985b1a5e985d1a5bdb8819195b185e481b9bdd081b595d60321b6060820152a2565b905061012c8101809111610a18574210386153af565b50600080516020615d42833981519152915082600080516020615e428339815191526080604051848152604060208201526016604082015275496e73756666696369656e742056524e47206665657360501b6060820152a280a2565b1090503880615392565b50600080516020615e42833981519152915060809060405190815260406020820152600d60408201526c496e76616c696420737461746560981b6060820152a2565b60ff91506015015460a01c163861537f565b60101c60ff16915038615377565b5050505050565b80600080516020615d4283398151915291a2565b6156bc614d8193926156ae60405194859263a9059cbb60e01b602085015260248401614c52565b03601f1981018452836149f9565b615b8f565b805115614c855760200190565b8051821015614c855760209160051b010190565b9261571690615724936020969360018060a01b0316865260018060a01b03168686015260a0604086015260a0850190614ac4565b908382036060850152614ac4565b906080818303910152600081520190565b81519160005b8381106157485750505050565b80615755600192846156ce565b5184600052600960205260406000208160005260205260ff6040600020541615615781575b500161573b565b6157bf9085600052600960205260406000208160005260205260406000208460ff19825416179055856000526007602052601060406000200161525a565b3861577a565b906156bc906156ae614d81956040519586936323b872dd60e01b602086015260248501614dd5565b6000818152600760205260408120601281018054919492916001600160a01b0316615ad7575080936158226011839201614d4f565b90815190835b828110615a7a57508661583f575b50505050505050565b61584881614cb7565b9161585282614cb7565b938590865b8381106159c0575050505060010361592d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906158a8906158a1906156c1565b51926156c1565b5191813b1561091e579183916158d79383604051809681958294637921219560e11b84528b3060048601614d9c565b03925af18015611f2357615918575b50506020600080516020615d22833981519152915b6040519485526001600160a01b031693a338808080808080615836565b6159238280926149f9565b61045557806158e6565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b1561091e579183916159859383604051809681958294631759616b60e11b84528b30600486016156e2565b03925af18015611f235791600080516020615d2283398151915293916020936159b0575b50506158fb565b816159ba916149f9565b386159a9565b6159ca81836156ce565b518a8952600c60209081526040808b206001600160a01b038d168c528252808b20838c529091528920549081615a05575b5050600101615857565b936001929491828493615a18848c6156ce565b5281615a24848d6156ce565b528d8c52600c60205260408c208d858060a01b03168d5260205260408c20818d526020528b60408120558d8c52600d60205260408c20908c52602052615a6f60408c20918254614c2f565b9055019290386159fb565b868552600c602090815260408087206001600160a01b03891688529091528520615aa482866156ce565b518652602052604085205480615abe575b50600101615828565b615ace6001929399918392614c9b565b98019190615ab5565b838252600e602090815260408084206001600160a01b03861685529091528220549294929182615b0a575b505050505050565b600080516020615dc283398151915293818660149352600e6020526040812060018060a01b0389168252602052604081205501615b48838254614c2f565b90558054615b6290839087906001600160a01b0316615687565b546040516001600160a01b039586169590928392615b81921683614c52565b0390a3388080808080615b02565b604080519092615bf4926001600160a01b0316906000908190615bb287866149f9565b602085527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564602086015260208151910182855af1615bee614bf0565b91615c84565b8051908115918215615c61575b505015615c0b5750565b5162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b819250906020918101031261166c5760200151801515810361166c573880615c01565b91929015615ce65750815115615c98575090565b3b15615ca15790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015615cf95750805190602001fd5b60405162461bcd60e51b815260206004820152908190615d1d9060248301906152f5565b0390fdfe7a482fdeb6bc9a1376f597068a214a7a39472bb2eff1b8cad21ba04f49ddca1b161be6479c47fe24a981165d1f4e37d9aee92fd6e6ef9b7cc418b862a961daf9c191099af2d2d1ec29ee63d6aaca4d0929807d3ae0ecdf72fe9073259685a8c29f686c1df8255b6aed5bb3791b218d49d0b23693116ed00d223dad05b9ba3cfc0bad0577cd8deb0fddfdca96bf4af8cfa4e13d4a109268718e1a95cb6582e8cf3e1757f494d1d3006a4f2ffe0ca12a60ba0638aa77cdd4cb69ad2fcbef9d5f1850c1f3ceae08077b76738a3be24875df98d239b0189963f38a29b3001922739a58cc6d5c90cacccf3ad59213f8ecaed268bea9172b66b7da53fac93ca7e3228d8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05a5357b9d51b1546187ecefb786bbac0929f2f83c03e3df378362014f4df3a07a26469706673582212202febf7ed4b748d9e35dd81059a4f91277c9bf036d260a58c2a616bae4667c55a64736f6c634300081c0033000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a0000000000000000000000005f78f2e450c82c782a26c713a4413f5ba2aaa0c3
Deployed Bytecode
0x610220806040526004361015610076575b503615610028576333d1661360e11b60005260046000fd5b7f0000000000000000000000005f78f2e450c82c782a26c713a4413f5ba2aaa0c36001600160a01b0316330361005a57005b604051348152600080516020615d6283398151915260203392a2005b600090813560e01c90816301ffc9a71461491957508063023ea0b2146148d057806302753713146147f757806304824e70146147915780630a27a7091461473a5780630a722b381461442d5780630dbdf70a146144105780631288608914610c1f57806312911a3d146143f2578063150b7a021461439b578063151e44cb14613fc25780631b6d1b7314613ea15780631b70e79c14613e3a57806321f29f5b14613d7657806325af3e8614613d165780632c920f1b14613ae35780632fd50375146138ed578063341e0c851461381957806334408093146136da578063357adca21461367a5780633df2cf3a1461361f5780634144d833146135d8578063432329a414613410578063442133ab146133ed578063448b0cd4146133d15780634615b9b5146133265780634646e090146132d8578063539cd3e51461324f5780635d4bc0ce14612f5c5780635eaee86d14612ec15780635fba317114612dc557806364aa48da14612ccd57806366c74034146129965780636b1da364146129235780636b7739171461275f578063715018a61461271757806373b6dfe214612542578063744792681461238e578063884464121461237257806389b9d593146121d95780638ae20021146120225780638da5cb5b14611ffb5780638f561acc146119d6578063930f20fd146119ac57806394be8c9814611989578063983b1f1c1461183b578063a080dffe14611773578063a323800c14611749578063a7cccdaf146116ee578063a8bad83a146116d1578063aeff22a114611693578063b2118a8d14611479578063b50dbedf14611212578063b8fde8f214611098578063bb5d241514611066578063bc197c8114610fcd578063bc25d6e314610ea8578063c064a2b314610cf4578063c2f306a514610cd6578063c622969814610c64578063ca606c7514610c1f578063cc1970c114610c02578063d1cfcd0d14610b2e578063d3f643bf14610ae0578063d83decfd14610ac2578063dbd8788614610aa5578063de078b7414610922578063e7b1de4214610593578063ebcdb4571461054e578063ecf9961c14610524578063f23a6e61146104c9578063f2e42fd3146104585763f2fde38b036100105734610455576020366003190112610455576103bb614986565b6103c3614f25565b6001600160a01b031680156104015781546001600160a01b03198116821783556001600160a01b0316600080516020615e228339815191528380a380f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b80fd5b5034610455576040366003190112610455576004359061047661499c565b91801580156104be575b6104af579060409181526008602052209060018060a01b03166000526020526020604060002054604051908152f35b63f3bf62c360e01b8252600482fd5b506002548111610480565b50346104555760a0366003190112610455576104e3614986565b506104ec61499c565b506084356001600160401b0381116105205761050c9036906004016149cc565b505060405163f23a6e6160e01b8152602090f35b5080fd5b5034610455578060031936011261045557604060ff60055416600654825191151582526020820152f35b50346104555780600319360112610455576040517f000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a6001600160a01b03168152602090f35b50346104555760c0366003190112610455576004356024356064359060ff821680920361091e576105c2614ecf565b82158015610913575b6109045782845260076020526040842090601282019260018060a01b0384541680156108f557604051633644e51560e01b8152602081600481855afa90816108c6575b506106225763baf3f0f760e01b8752600487fd5b600c84015460ff8160101c166108b75760ff8116156108a85760081c60ff1661089a5760ff601585015460a01c1661088b57821561087c57600b84019461066a848754614c9b565b94600a81019586541061086d57878952600860209081526040808b2033600090815292529020541593848061085b575b61084c579089949392916106b2601383015488614df7565b93803b156108485760e48792604051988993849263d505accf60e01b84523360048501523060248501528960448501526044356064850152608484015260843560a484015260a43560c48401525af1938a851561083c578a9561081d575b507fd9055e1350232d8f60c534c2cff1e8ec585535179ef5b4827e22f911d5281ba294955061074a84303360018060a01b038754166157c5565b858b52600e60205260408b2060018060a01b0333166000526020526040600020610775858254614c9b565b905560148201610786858254614c9b565b9055610809575b5083895260086020526040892060018060a01b03331660005260205260406000206107b9868254614c9b565b90556107c6858854614c9b565b96879055546040513395909283926107e892906001600160a01b031684614bd2565b0390a354146107fa575b506001805580f35b61080390615336565b386107f2565b61081790600f339101614e45565b3861078d565b61082b9195508092966149f9565b610838578388938a610710565b8880fd5b604051903d90823e3d90fd5b8680fd5b63ead7562d60e01b8a5260048afd5b50600f820154600d830154111561069a565b63f4ff27fb60e01b8952600489fd5b63162908e360e11b8752600487fd5b63319b714360e01b8752600487fd5b629d9e8560e31b8752600487fd5b63ee0eb16d60e01b8852600488fd5b630bb8def160e21b8852600488fd5b6020813d6020116108ed575b816108df602093836149f9565b81010312610838575161060e565b3d91506108d2565b638ceccfff60e01b8752600487fd5b63f3bf62c360e01b8452600484fd5b5060025483116105cb565b8380fd5b5060203660031901126104555760043561093a614f25565b610942614ecf565b80158015610a9a575b6104af5780825260076020526040822060ff600c8201541615610a8b57600f81015415610a7c5760ff601582015460a01c16610a6d57600a600b82015491015403610a5e5760045480159081159081610a53575b50610a445780610a3b575b610a2c57808252600f60205260408220548015159081610a02575b506109f357806109ec918352600f6020524260408420556109e581614f7d565b34906150f4565b6001805580f35b63baf3f0f760e01b8252600482fd5b905061012c8101809111610a18574210386109c5565b634e487b7160e01b83526011600452602483fd5b63162908e360e11b8252600482fd5b503415156109aa565b63162908e360e11b8352600483fd5b90503414153861099f565b634ef0cb9960e01b8252600482fd5b63319b714360e01b8352600483fd5b63baf3f0f760e01b8352600483fd5b63ee0eb16d60e01b8352600483fd5b50600254811161094b565b503461045557806003193601126104555760206040516101f48152f35b50346104555780600319360112610455576020600454604051908152f35b5034610455576020366003190112610455577f3f4696a39500bc65c1c5aa43d74bec8ee234f19fe464577f7ef872bb274833446020600435610b20614f25565b80600655604051908152a180f35b50346104555760203660031901126104555760043580158015610bf7575b6104af5781604091610160935260076020522060018060a01b038154169060018101549060018060a01b0360098201541660ff600a830154600b840154600c85015491600f86015494600d85601589015460a01c1697015497604051998a5260208a0152604089015260608801526080870152818116151560a0870152818160081c16151560c087015260101c16151560e08501526101008401521515610120830152610140820152f35b506002548111610b4c565b5034610455578060031936011261045557602060405161012c8152f35b50346104555780600319360112610455576040517f0000000000000000000000005f78f2e450c82c782a26c713a4413f5ba2aaa0c36001600160a01b03168152602090f35b5034610455576020366003190112610455576004359081158015610ccb575b610cbc57604091815260076020522060018060a01b03601282015416610cb86014601384015493015460405193849384614bd2565b0390f35b63f3bf62c360e01b8152600490fd5b506002548211610c83565b50346104555780600319360112610455576020600254604051908152f35b5034610455576040366003190112610455576004356024356001600160401b038111610ea457610d28903690600401614ba2565b9190610d32614f25565b610d3a614ecf565b81158015610e99575b6109045781845260076020526040842060ff600c82015460101c1615610e8a5760328411610e8a57845b84811015610da057600581901b830135906001600160a01b038216820361084857610d9a600192866157ed565b01610d6d565b50601281015460019492506001600160a01b0316610e645760118101805490865b828110610e12575b50505090606091600080516020615de283398151915293945b610e02575b50604051908582528060208301526040820152a26001805580f35b601b600f82015491015538610de7565b858852600d60205260408820610e288284614c6d565b90549060031b1c89526020526040882054610e4557600101610dc1565b50869550829150600080516020615de283398151915290506060610dc9565b9081600080516020615de283398151915293946014606094015415610de2575085610de2565b63baf3f0f760e01b8552600485fd5b506002548211610d43565b8280fd5b503461045557610eb7366149b2565b610ebf614f25565b610ec7614ecf565b8083158015610fc2575b610fb35783855260076020526040852060ff600c82015460101c1615610f9c57600f8101928354809111610fab575b5081841015610f9c576032610f158584614c2f565b11610f9c57859284905b838210610f6c5750509181600080516020615de28339815191529492601b6060950180548211610f64575b505060405192835260208301526040820152a26001805580f35b558038610f4a565b909360018091610f93610f7f8886614c6d565b848060a01b0391549060031b1c168a6157ed565b01940190610f1f565b63baf3f0f760e01b8652600486fd5b915038610f00565b63f3bf62c360e01b8552600485fd5b506002548411610ed1565b50346104555760a036600319011261045557610fe7614986565b50610ff061499c565b506044356001600160401b03811161052057611010903690600401614ba2565b50506064356001600160401b03811161052057611031903690600401614ba2565b50506084356001600160401b038111610520576110529036906004016149cc565b505060405163bc197c8160e01b8152602090f35b50346104555760ff604060209261107c36614af8565b9082526009855282822090825284522054166040519015158152f35b5034610455576110a736614b5c565b6110b394939194614f25565b6001600160a01b0386169485156111e957863b156111e9578415611203578215611203576001600160a01b038416156111e957833b156111e957801561120357811580156111f8575b6111e957916111de60209892600080516020615da2833981519152946111248830338c6157c5565b6013611131600254614ca8565b9a8b988960025589885260078e5261115d60408920926003840161010061ff0019825416178155614e86565b600482018b90556009820180546001600160a01b03199081163317909155600a8301889055600d8301869055600c8301805460ff1916600117905542600e8401556012830180549091166001600160a01b03929092169190911790550155604051936111c98b866149f9565b84526000368137604051938493339885614ead565b0390a4604051908152f35b63baf3f0f760e01b8852600488fd5b506103e882116110fc565b63162908e360e11b8852600488fd5b50346104555761122136614b5c565b9261122e95949295614f25565b6020956040519261123f88856149f9565b88845260003681376001600160a01b038716968715611415573b1561145057821561146a578515801561145f575b611450576001600160a01b03821615918261142457803b15611415578115611406575b873b156113f757604051632142170760e11b81528a81806112b68a303360048501614dd5565b0381838d5af180156113fb576113e2575b509288996113b593600080516020615d828339815191529693601360079c99976112f2600254614ca8565b9d8e9b8c6002558c87525260408520908d60018060a01b0319835416178255896001830155600160028301556003820160ff1981541690556009820160018060a01b03331660018060a01b031982541617905586600a8301558c600d830155600c8201600160ff1982541617905542600e830155601282019060018060a01b031660018060a01b03198254161790550155806113d8575b6113c9575b6040519485528a85015260016040850152606084015260c0608084015260c0830190614ac4565b9360a08201528033940390a4604051908152f35b6113d38388615735565b61138e565b5082511515611389565b6113ed8b80926149f9565b6113f757386112c7565b8980fd5b6040513d8d823e3d90fd5b63162908e360e11b8a5260048afd5b63baf3f0f760e01b8a5260048afd5b84518015908115611445575b50156112905763baf3f0f760e01b8a5260048afd5b600891501138611430565b63baf3f0f760e01b8952600489fd5b506103e8861161126d565b63162908e360e11b8952600489fd5b503461045557606036600319011261045557611493614986565b9061149c61499c565b91604435906114a9614f25565b6114b1614ecf565b6001600160a01b03841615611684578115610a44576040516370a0823160e01b81523060048201526001600160a01b03919091169390602081602481885afa908115611679578491611642575b508083116116335783836001600254905b8181111561153157505061152291614c9b565b11610a7c576109ec9293615687565b808852600760205260408820600981015492935090916001600160a01b0316156116295760128101546001600160a01b031689148061160e575b6115f8575b60038101548960ff8260081c1691826115e2575b5050806115b7575b61159e575b50600101905b859161150f565b6001919360046115b092015490614c9b565b9290611591565b50600c81015460ff8160101c16159081156115d3575b5061158c565b60ff915060181c1615386115cd565b60101c6001600160a01b03161490508938611584565b9261160890601485015490614c9b565b92611570565b5060ff600c820154168061156b57506014810154151561156b565b5060010190611597565b63162908e360e11b8452600484fd5b90506020813d602011611671575b8161165d602093836149f9565b8101031261166c5751386114fe565b600080fd5b3d9150611650565b6040513d86823e3d90fd5b6333d1661360e11b8352600483fd5b50806003193601126104555734156116c257604051348152600080516020615d6283398151915260203392a280f35b63162908e360e11b8152600490fd5b503461045557806003193601126104555760206040516103e88152f35b50346104555760203660031901126104555760043561170b614ecf565b8015801561173e575b6104af57808252600760205260ff600c60408420015460101c16156109f3576109ec9033906157ed565b506002548111611714565b50346104555760203660031901126104555760406020916004358152600b83522054604051908152f35b5034610455576020366003190112610455576004359081158015611830575b610cbc57604091815260076020522060ff60038201541660028201549160ff600582015460068301549260018060a01b036007820154166118076117e5601060018060a01b036008860154169401614d4f565b6040519889981515895260208901526101006040890152610100880190614ac4565b9484841615156060880152608087015260a086015260c085015260081c16151560e08301520390f35b506002548211611792565b50346104555761184a36614b0e565b6118579593929195614f25565b6001600160a01b03851693841561196f57853b1561196f5783156116c25782156116c2578115801561197e575b61196f57611894843033886157c5565b61189f600254614ca8565b958660025586825260076020526118ca60408320916003830161010061ff0019825416178155614e86565b600481018590556009810180546001600160a01b03191633179055600a8101849055600d8101839055600c8101805460ff1916600117905542600e90910155865180611939575b505060209585926111de600080516020615da283398151915293604051938493339885614ead565b60081061196f57508585926111de600080516020615da28339815191529361196360209a87615735565b93505092819750611911565b63baf3f0f760e01b8152600490fd5b506103e88211611884565b5034610455578060031936011261045557602060ff600354166040519015158152f35b50346104555760203660031901126104555760406020916004358152600f83522054604051908152f35b5034610455576119e536614af8565b6119ed614ecf565b7f0000000000000000000000005f78f2e450c82c782a26c713a4413f5ba2aaa0c36001600160a01b03163303611fec57818352600b60205260408320549182158015611fe1575b61090457828452600760205260408420601581019081549060ff8260a01c1615611fd25760168491015403610f9c5760ff60a01b19169055808452600b602052836040812055827f63c6ab7b3ed733d226f47ccf6994f0ca68bde6721dcae5c7b741d744d9b5577b6020604051858152a381835260076020526040832090601a82019060ff82541615610e8a576019830154908115610f9c57068385526007602052604085208591601882018054915b828510611f6f57505050600f019081548110600014611f6757611b0691614c6d565b905460039190911b1c6001600160a01b03165b6001600160a01b038116908115610f9c578590601585018360018060a01b0319825416179055858252600760205260408220600381018488825460ff8160081c16600014611e255750509054600490920180549093611b87939192509060101c6001600160a01b0316615687565b555b837fb4d601e7092e672cbffcd1512cc6592c35b9947e1ebfeea7647231887a5224478680a360128201546001600160a01b03161580611e19575b611cf9575b828452600760205260408420600f81018054916012810191875b848110611c2f57855461ff001916610100178655600c8701805460ff1916905588887f2a7d48246875b5f17dc9944def25fc8fe90e524ca2165e290ffdc0e44a0bf8b68280a26001805580f35b611c398183614c6d565b9054898b52600860209081526040808d2060039490941b9290921c6001600160a01b0390811660008181529483528385208e90558c8e52600e8352838e20818652909252919092208b905585541615611c96575b50600101611be2565b601184018054916001600160a01b03168b5b8b8d858310611cbb575050505050611c8d565b906001929152600c6020528d60408082206000908682526020522090611ce18387614c6d565b90549060031b1c90526020528d604081205501611ca8565b828452600760205260408420601181019081549186805b848110611d21575050505050611bc8565b611d2b8184614c6d565b90549060031b1c888352600d60205260408320818452602052604083205480611d5c575b5089925050600101611d10565b7f000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a6001600160a01b0316803b15611e1557611db38592918392604051978880948193637a94c56560e11b8352893060048501614bd2565b03925af19384611e00575b505060019215600014611de35750601c8401805460ff1916831790555b889138611d4f565b888a52600d60205260408a20908a52602052886040812055611ddb565b81611e0a916149f9565b6113f7578938611dbe565b8480fd5b5060ff60035416611bc3565b600585015492969195919260ff1615611ea5575050508160a09160067fe9321bc2ec3549bcfe86623e2e466c29cd13e86670241465ec76939e5ece47a194015491600180851b0360078201541691600260ff60018401549254169201549260405194855260208501526040840152151560608301526080820152a3611b89565b91955092935060ff16159050611f2e5781546001830154600290930154906001600160a01b0316803b15611e1557611ef89385809460405196879586948593637921219560e11b85523060048601614d9c565b03925af18015611f2357611f0e575b5050611b89565b81611f18916149f9565b611e15578438611f07565b6040513d84823e3d90fd5b6001808060a01b03835416920154823b1561091e57611ef892849283604051809681958294632142170760e11b84523060048501614dd5565b505083611b19565b909193611f88611f7f8287614c2f565b60011c82614c9b565b9082611f948386614c6d565b905460039190911b1c11611fcb575060018101809111611fb757935b9190611ae4565b634e487b7160e01b89526011600452602489fd5b9450611fb0565b63baf3f0f760e01b8752600487fd5b506002548311611a34565b635c427cd960e01b8352600483fd5b5034610455578060031936011261045557546040516001600160a01b039091168152602090f35b50346104555761203136614b0e565b9193929061203d614f25565b6001600160a01b038416938415611fd2573b15610f9c5784156121ca57821580156121bf575b610f9c57805180159081156121b4575b50610f9c57833b156121a557604051632142170760e11b815286818061209e86303360048501614dd5565b038183895af180156121a957612190575b50602095916113b5600080516020615d82833981519152926120d2600254614ca8565b600281815581875260078b526040872080546001600160a01b03199081168b178255600180830188905592820183905560038201805460ff19908116909155600983018054831633179055600a83018d9055600d83018b9055600c8301805490911690931790925542600e8201556012810180549092166001600160a01b0389161790915560130186905581519098899690916113c9576040519485528a85015260016040850152606084015260c0608084015260c0830190614ac4565b61219b8780926149f9565b6121a557386120af565b8580fd5b6040513d89823e3d90fd5b600891501138612073565b506103e88311612063565b63162908e360e11b8652600486fd5b5034610455576121e836614af8565b6121f0614ecf565b81158015612367575b612358578183526007602052604083206012810180549092906001600160a01b0316801561234957600c83015460ff8160101c1661233a5760ff81161561232b5760081c60ff1661231d5760ff601584015460a01c1661230e5781156121ca57600b830193612269838654614c9b565b93600a8101948554106122ff57868852600860209081526040808a2033600090815292529020541580806122ed575b6122de5791817fff2a02174867ec97730bdb6670a03e2dc11c034323ab0e03142d3a6aeb6993a69361074a6122d360138c9896015489614df7565b8095309033906157c5565b63ead7562d60e01b8952600489fd5b50600f820154600d8301541115612298565b63f4ff27fb60e01b8852600488fd5b63319b714360e01b8652600486fd5b629d9e8560e31b8652600486fd5b63ee0eb16d60e01b8752600487fd5b630bb8def160e21b8752600487fd5b638ceccfff60e01b8652600486fd5b63f3bf62c360e01b8352600483fd5b5060025482116121f9565b5034610455578060031936011261045557602060405160328152f35b5034610455576020366003190112610455576004356123ab614f25565b6123b3614ecf565b80158015612537575b6104af57808252600760205260408220600c8101805460ff8160101c1615610e8a5760ff600584015416610e8a5760ff8160181c16610e8a5763ff0000001916630100000017905560038101805484929190600881901c60ff1615612472575054825460049290920180549092612445926001600160a01b039182169160109190911c16615687565b555b7fa239896844a2f9e1e391fef736d650713e4e95cc542a49fb562dfd461b20a0318280a26001805580f35b60ff161590506124f1578054825460018301546002909301546001600160a01b0391821692909116803b15611e15576124c69385809460405196879586948593637921219560e11b85523060048601614d9c565b03925af18015611f23576124dc575b5050612447565b816124e6916149f9565b6105205781386124d5565b80548254600192909201546001600160a01b039182169290911690823b1561091e576124c692849283604051809681958294632142170760e11b84523060048501614dd5565b5060025481116123bc565b503461045557610120366003190112610455576004359061256161499c565b9060443561256d614ab5565b6084359460a43560c4356001600160401b0381116121a557612593903690600401614a49565b9060e4359260018060a01b0384168094036108485761010435936125b5614f25565b81156111e9576001600160a01b038916156111e95789156112035782156112035780156111e9578415801561270c575b6111e9576125f4600254614ca8565b98896002558989526007602052604089209260058401600160ff198254161790556006840155600783019060018060a01b031660018060a01b031982541617905586600183015561265486600384019060ff801983541691151516179055565b600282018a90556008820180546001600160a01b0319908116909217905560098201805490911633179055600a8101829055600d8101849055600c8101805460ff1916600117905542600e909101558151806126d4575b50926111de600080516020615d8283398151915293602099938996604051958695339a87614d1e565b600810610f9c57926111de600080516020615d82833981519152938389966126ff60209c9689615735565b93965093995093506126ab565b506103e885116125e5565b5034610455578060031936011261045557612730614f25565b80546001600160a01b03198116825581906001600160a01b0316600080516020615e228339815191528280a380f35b50346104555760e036600319011261045557612779614986565b6024356084356001600160a01b0381169060643590604435908381036108485760a43560c435916127a8614f25565b6001600160a01b038816978815611415573b1561145057831561146a57841561146a578515611450573b156111e95780156112035781158015612918575b6111e957863b1561290957604051637921219560e11b8152888180612811878b303360048601614d9c565b0381838c5af1801561290d576128f4575b50916111de60139796959492602099600080516020615d828339815191529561284c600254614ca8565b600281815581845260078e52604080852080546001600160a01b03199081168f17825560018083018f90559382018a905560038201805460ff199081168617909155600983018054831633179055600a83018c9055600d8301899055600c8301805490911690941790935542600e820155601281018054909316909b1790915598909b0155955189966128df8c836149f9565b81526000368137604051948594339986614ce9565b6128ff8980926149f9565b6129095738612822565b8780fd5b6040513d8b823e3d90fd5b506103e882116127e6565b5034610455576020366003190112610455576004358015801561298b575b6104af578160409160809352600760205220601581015460ff60176016840154930154916040519360018060a01b0382168552602085015260a01c16151560408301526060820152f35b506002548111612941565b5034610455576020366003190112610455576004356129b3614f25565b6129bb614ecf565b80158015612cc2575b6104af5780825260076020526040822090600b820154610a7c57600f820154610a7c576014820154610a7c5760158201546001600160a01b038116612cb35760a01c60ff16610a7c5760ff600c83015460101c16610a7c5760018060a01b036009830154169160ff60058201541615612bb9575b806016601092015480612ba6575b5001805490845b828110612b6f57505050808352600760205282601c6040822082815582600182015582600282015582600382015582600482015582600582015582600682015582600782015582600882015582600982015582600a82015582600b82015582600c82015582600d82015582600e820155600f8101805484825580612b55575b5050612ada60108201614e21565b612ae660118201614e21565b826012820155826013820155826014820155826015820155826016820155826017820155612b1660188201614e21565b82601982015582601a82015582601b82015501557f8cdff5921279206684dbbd35fbeaef8aaff873c39399773df75ce32a75218e8f8380a36001805580f35b612b689185526020852090810190614e0a565b3880612acc565b600190848752600960205260408720612b888285614c6d565b90549060031b1c88526020526040872060ff19815416905501612a4d565b8552600b60205284604081205538612a46565b60038101805460ff8160081c16600014612bf6575054600482015460109291612bef91908690851c6001600160a01b0316615687565b9050612a38565b60ff16159050612c735780546001820154600283015486926001600160a01b03169190823b1561091e57612c4592849283604051809681958294637921219560e11b84528d3060048601614d9c565b03925af18015611f2357612c5e575b5050601090612bef565b81612c68916149f9565b61091e578338612c54565b8054600182015485916001600160a01b0316803b15610ea457604051632142170760e11b81529183918391829084908290612c45908c3060048501614dd5565b63baf3f0f760e01b8452600484fd5b5060025481116129c4565b503461045557604036600319011261045557600435612cea61499c565b90612cf3614f25565b612cfb614ecf565b80158015612dba575b6123585780835260076020526040832090600c82015460ff8116610e8a5760101c60ff16612cb3576012820180546001600160a01b0316928315610f9c5760140193845493841561087c576001600160a01b038216958615612dab57856020937f467267afbc5bfc89ff052b40651c068e07799972abce91b6457016d2b126a99195938a612d929455615687565b546040519485526001600160a01b031693a46001805580f35b6333d1661360e11b8852600488fd5b506002548111612d04565b503461045557602036600319011261045557600435612de2614f25565b612dea614ecf565b80158015612eb6575b6104af57808252600760205260408220600c8101805460ff811615612ea75760ff8160101c16610e8a5762ff00ff191662010000179055601a8101805461ff001916610100179055601581018054919060a083901c60ff16612e84575b5050507fa02141afc19f84c375c9c5757d4c36e47857bf58d1b0f85f9a491bada681bbcb6020604051848152a26001805580f35b60169260ff60a01b1916905501548252600b602052816040812055388080612e50565b63ee0eb16d60e01b8552600485fd5b506002548111612df3565b503461045557602036600319011261045557600435612ede614f25565b80158015612f51575b6104af578082526007602052600c6040832001805460ff811615612f425760ff8160081c16612cb35761ff0019166101001790557f59ae418981ae00500624dca49fa8395d59a12e54cc5af94604258b6402cfb0048280a280f35b63ee0eb16d60e01b8452600484fd5b506002548111612ee7565b50346104555760203660031901126104555760409060043581526007602052206102005260018060a01b036102005154166001610200510154610100526002610200510154610140526003610200510154600461020051015460ff6005610200510154600661020051015460018060a01b0360076102005101541660018060a01b0360086102005101541660018060a01b0360096102005101541690600a61020051015492600b6102005101549487600c61020051015497600d6102005101549a600e6102005101549c60018060a01b036012610200510154169e6013610200510154608052601461020051015460c05260156102005101546101e05260166102005101546101c05260176102005101546101a052601961020051015461018052601a61020051015461016052601b61020051015461012052601c61020051015460e05260405160a05260a0515261010051602060a051015261014051604060a05101528381161515606060a0510152838160081c161515608060a051015260018060a01b039060101c1660a08051015260c060a0510152818116151560e060a051015260081c16151561010060a051015261012060a051015261014060a051015261016060a051015261018060a05101526101a060a05101526101c060a051015281811615156101e060a0510152818160081c16151561020060a0510152818160101c16151561022060a051015260181c16151561024060a051015261026060a051015261028060a05101526102a060a05101526080516102c060a051015260c0516102e060a051015260018060a01b036101e0511661030060a051015260ff6101e05160a01c16151561032060a05101526101c05161034060a05101526101a05161036060a05101526101805161038060a051015260ff610160511615156103a060a051015260ff6101605160081c1615156103c060a0510152610120516103e060a051015260ff60e05116151561040060a051015260ff60e05160081c16151561042060a051015261044060a051f35b50346104555760203660031901126104555760043561326c614f25565b801580156132cd575b6104af578082526007602052600c6040832001805460ff811615612f425760ff8160081c1615612cb35761ff00191690557f88d20d5ea9eaba2406719d2e3e97a5ba16fb0748f87067b5d315ffa7ed7a01018280a280f35b506002548111613275565b5034610455576020366003190112610455577f8b18b05e90c984f3b4e04de16c3b33b6613d924dffaa2d583180e0a984c495286020600435613318614f25565b80600455604051908152a180f35b503461045557602036600319011261045557600435801580156133c6575b6104af5781604091602093526007835220600c8101549060ff821691826133b7575b50816133a4575b81613392575b81613384575b506040519015158152f35b600f91500154151538613379565b600b810154600a820154149150613373565b601581015460a01c60ff1615915061336d565b60101c60ff1615915038613366565b506002548111613344565b5034610455578060031936011261045557602060405160088152f35b5034610455578060031936011261045557602060ff600554166040519015158152f35b50346104555760c03660031901126104555761342a614986565b60643591906024356044356084356001600160401b038111611e1557613454903690600401614a49565b60a43590613460614f25565b6001600160a01b038516948515611fd2573b15610f9c5782156121ca5786156121ca57811580156135cd575b610f9c57843b156121a557604051637921219560e11b81528681806134b78789303360048601614d9c565b0381838a5af180156121a9579087916135b8575b50506134d8600254614ca8565b95866002558681526007602052604081208660018060a01b031982541617815585600182015584600282015560038101600160ff198254161790556009810160018060a01b03331660018060a01b031982541617905588600a82015583600d820155600c8101600160ff19825416179055600e42910155815180613580575b50509585926111de600080516020615d8283398151915293602099604051948594339986614ce9565b60081061196f57509585926111de600080516020615d8283398151915293896135ab60209b88615735565b9399509350819450613557565b816135c2916149f9565b6121a55785386134cb565b506103e8821161348c565b50346104555760403660031901126104555760406135f461499c565b9160043581526008602052209060018060a01b03166000526020526020604060002054604051908152f35b5034610455576020366003190112610455576004358015801561366f575b6104af57601160408361365b93610cb8955260076020522001614d4f565b604051918291602083526020830190614ac4565b50600254811161363d565b5034610455576020366003190112610455577fefc59f9df31916aa38fd5ec9fd6105fa15a7ba2ea46ecbf27993bccf5721ed7d60206136b7614aa6565b6136bf614f25565b151560ff196003541660ff821617600355604051908152a180f35b506020366003190112610455576004356136f2614ecf565b8015801561380e575b6104af57808252600760205260408220600c81015460ff811615908115613800575b5080156137ef575b610a7c57600b810154600a82015414908115916137e2575b50610a5e57600454801590811590816137d7575b50610a4457806137ce575b610a2c57808252600f602052604082205480151590816137b8575b506109f357808252600f60205242604083205561379381614f7d565b61379d34826150f4565b3390600080516020615e028339815191528380a36001805580f35b905061012c8101809111610a1857421038613777565b5034151561375c565b905034141538613751565b600f91500154153861373d565b5060ff601582015460a01c16613725565b60ff915060101c163861371d565b5060025481116136fb565b503461045557602036600319011261045557600435801580156138e2575b6104af5781526007602052600f6040822001604051908160208254918281520190819285526020852090855b8181106138c357505050826138799103836149f9565b604051928392602084019060208552518091526040840192915b8181106138a1575050500390f35b82516001600160a01b0316845285945060209384019390920191600101613893565b82546001600160a01b0316845260209093019260019283019201613863565b506002548111613837565b503461045557610140366003190112610455576004359061390c61499c565b60443590613918614ab5565b9160843560a4359160c43560018060a01b0381169788820361290957610104356001600160a01b0381169960e43592918b90036113f757610124359361395c614f25565b8215613ac5576001600160a01b03891615613ac5578615613ad4578715613ad4578115613ac5573b15611415578215611406578a156114155783158015613aba575b611415576002546139ae90614ca8565b9a8b9889600255898c52600760205260408c20936005850160ff19815416600117905560068501556007840190600160a01b6001900316600160a01b6001900319825416179055856001840155896003840190613a16919060ff801983541691151516179055565b600283018790556008830180546001600160a01b03199081169092179055600983018054821633179055600a8301889055600d8301859055600c8301805460ff1916600117905542600e840155601283018054909116909117905560130155604051613a836020826149f9565b87815260003681376040519485943398613a9d9587614d1e565b03600080516020615d8283398151915291a4604051908152602090f35b506103e8841161399e565b63baf3f0f760e01b8b5260048bfd5b63162908e360e11b8b5260048bfd5b503461045557606036600319011261045557613afd614986565b6044359190602435613b0d614f25565b606092604051613b1d85826149f9565b60028152601f19850136602083013781613b36826156c1565b52805160011015613d0257600160408201526001600160a01b038416938415610a7c573b156109f3578515610a2c57816109f35760009581518015908115613cf7575b50611fd257843b1561084857604051632142170760e11b815296808880613ba588303360048501614dd5565b0381838a5af1978815613cea57602098613cbf575b5050600080516020615d8283398151915291613c9991613bdb600254614ca8565b600281815581875260078b526040872080546001600160a01b03199081168b17825560018083018b905592820183905560038201805460ff19908116909155600983018054831633179055600a83018690556101f4600d840155600c8301805490911690931790925542600e8201556012810180549092166001600160a01b038916179091556013018690558251909889969091613cb0575b6040519788528a8801526001604088015286015260c0608086015260c0850190614ac4565b926101f460a08201528033940390a4604051908152f35b613cba8488615735565b613c74565b613c9992945090613ce081600080516020615d8283398151915295936149f9565b9391819350613bba565b50604051903d90823e3d90fd5b600891501138613b79565b634e487b7160e01b82526032600452602482fd5b5034610455576020366003190112610455577f93357458538ed084eb6df13ca0871aec371e75476b600c54d197320f860e9e446020613d53614aa6565b613d5b614f25565b151560ff196005541660ff821617600555604051908152a180f35b503461045557604036600319011261045557600435613d9361499c565b613d9b614f25565b81158015613e2f575b612358576001600160a01b031690811561168457808352600760205260408320600581015460ff811615610e8a5760ff600c83015416159081613e21575b50612cb35760080180546001600160a01b031916831790557f875c3a0cb9d5fbd474450607d9085f95ff59c5f49af9d25fa6ad5990105c6f918380a380f35b60ff915060081c1638613de2565b506002548211613da4565b503461045557602036600319011261045557600435613e57614f25565b8015610a2c5747613e7682613e7160045460065490614c9b565b614c9b565b11610a2c57815482918291829182916001600160a01b03165af1613e98614bf0565b501561196f5780f35b50346104555760403660031901126104555760043590613ebf61499c565b81908190818086158015613fb7575b6104af5786825260076020526040822060128101549091906001600160a01b0316613f85575060110190815491819360018060a01b0316975b838510613f3757505050505060809350821515905b60405193845260208401521515604083015215156060820152f35b9091929396613f7a600191838652600c60205260408087206000908d825260205220613f638b87614c6d565b90549060031b1c8752602052604086205490614c9b565b970193929190613f07565b94505060409192506080958152600e602052209060018060a01b03166000526020526040600020549081151591613f1c565b506002548711613ece565b503461045557604036600319011261045557600435906024356001600160401b03811161052057613ff7903690600401614a49565b91614000614ecf565b80158015614390575b6104af5780825260076020526040822060ff600c82015460101c1615610a7c576012810180546001600160a01b03166142dd57505082518291903383805b838110614289575084614063575b505050505090506001805580f35b61406c81614cb7565b9261407682614cb7565b928790885b8381106141d357505050508596506001909593949514600014614150577f000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a6001600160a01b0316916140d7906140d0906156c1565b51916156c1565b51823b1561091e5761410492849283604051809681958294637921219560e11b8452333060048601614d9c565b03925af18015611f235761413b575b50505b604051918252600080516020615d2283398151915260203393a3803880808080614055565b81614145916149f9565b610ea4578238614113565b7f000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a6001600160a01b03169190823b1561091e576141a892849283604051809681958294631759616b60e11b84523330600486016156e2565b03925af18015611f23576141be575b5050614116565b816141c8916149f9565b610ea45782386141b7565b6141dd818c6156ce565b51888b52600c6020526040808c2060009085825260205220818c526020528a6040812054918a898b85614219575b50505050505060010161407b565b938361427a938761423f8c60409660019c9e9a99614239838f9e9c6156ce565b526156ce565b52808352600c602052838084206000908c82526020522082845260205282848120558252600d60205282822090825260205220918254614c2f565b90550192908a388a898b61420b565b848752600c6020526040808820600090858252602052206142aa828a6156ce565b5188526020526040872054806142c4575b50600101614047565b6142d46001929397918392614c9b565b960191906142bb565b828452600e602090815260408086203360009081529252902054939450908361430a575b505050506109ec565b600080516020615dc283398151915291601461438492858852600e6020526040882060018060a01b033316600052602052876040600020550161434e868254614c2f565b9055805461436890869033906001600160a01b0316615687565b546040513395909283929091906001600160a01b031683614c52565b0390a338808080614301565b506002548111614009565b5034610455576080366003190112610455576143b5614986565b506143be61499c565b506064356001600160401b038111610520576143de9036906004016149cc565b5050604051630a85bd0160e11b8152602090f35b50346104555780600319360112610455576020600654604051908152f35b50346104555780600319360112610455576020604051611c208152f35b50346104555761443c366149b2565b90614445614ecf565b8215801561472f575b6109045782845260076020526040842060128101549092906001600160a01b031661472057838552600760205260408520600c81015460ff8160101c1661233a5760ff81161561232b5760081c60ff1661231d5760ff601582015460a01c1661230e5784865260096020526040862083875260205260ff604087205416156147115781156121ca57600b8101906144e6838354614c9b565b600a8201541061470257858752600860209081526040808920338a529091528720541580806146f0575b6146e1577f000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a6001600160a01b0316803b1561083857886040518092637921219560e11b82528183816145688b8d303360048601614d9c565b03925af1801561290d576146cd575b50868852600c6020526040882060018060a01b0333166000526020526040600020858952602052604088206145ad858254614c9b565b9055868852600d60205260408820858952602052604088206145d0858254614c9b565b90556146b9575b5084865260086020526040862060018060a01b0333166000526020526040600020614603838254614c9b565b9055614610828254614c9b565b9055838552600a6020526040852082865260205260ff6040862054161561467b575b6040519182526020820152827feb79e1c4c2e9267b8cc3b7b7df468f4a50a3fb1c8093d604f2c281ebdf2ae82960403393a3600a600b820154910154146107fa57506001805580f35b838552600a6020526040852082865260205260408520600160ff1982541617905583855260076020526146b4826011604088200161525a565b614632565b6146c790600f339101614e45565b386145d7565b886146da919992996149f9565b9638614577565b63ead7562d60e01b8852600488fd5b50600f820154600d8301541115614510565b63f4ff27fb60e01b8752600487fd5b63e51cf7bf60e01b8652600486fd5b638ceccfff60e01b8552600485fd5b50600254831161444e565b5034610455576020366003190112610455576004353033036147825761475f81614f7d565b61476b600454826150f4565b3090600080516020615e028339815191528380a380f35b635c427cd960e01b8252600482fd5b5034610455576020366003190112610455576147ab614986565b6147b3614f25565b6147bb614ecf565b6001600160a01b031680156147e857818080809347905af16147db614bf0565b501561196f576001805580f35b6333d1661360e11b8252600482fd5b503461045557604036600319011261045557600435614814614ecf565b801580156148c5575b6104af5780825260076020526040822082546001600160a01b0316331415806148ae575b611fec57600581019081549060ff821615610e8a57600c015460ff16612cb35760ff8160081c16612cb3576101009061ff0019161790556040519060243582527f2d667ad442cc5f473a053638a3dd16af33d42b9363dbee8c915a0e0f8327fa0a60203393a36001805580f35b5060088101546001600160a01b0316331415614841565b50600254811161481d565b5034610455578060031936011261045557600454608090801547811561490e575b600654906040519384526020840152604083015215156060820152f35b8281101591506148f1565b9050346105205760203660031901126105205760043563ffffffff60e01b8116809103610ea45760209250630a85bd0160e11b8114908115614975575b8115614964575b5015158152f35b6301ffc9a760e01b1490503861495d565b630271189760e51b81149150614956565b600435906001600160a01b038216820361166c57565b602435906001600160a01b038216820361166c57565b606090600319011261166c57600435906024359060443590565b9181601f8401121561166c578235916001600160401b03831161166c576020838186019501011161166c57565b601f909101601f19168101906001600160401b03821190821017614a1c57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160401b038111614a1c5760051b60200190565b9080601f8301121561166c578135614a6081614a32565b92614a6e60405194856149f9565b81845260208085019260051b82010192831161166c57602001905b828210614a965750505090565b8135815260209182019101614a89565b60043590811515820361166c57565b60643590811515820361166c57565b906020808351928381520192019060005b818110614ae25750505090565b8251845260209384019390920191600101614ad5565b604090600319011261166c576004359060243590565b9060a060031983011261166c576004356001600160a01b038116810361166c57916024359160443591606435906001600160401b03821161166c57614b5591600401614a49565b9060843590565b60c090600319011261166c576004356001600160a01b038116810361166c579060243590604435906064356001600160a01b038116810361166c57906084359060a43590565b9181601f8401121561166c578235916001600160401b03831161166c576020808501948460051b01011161166c57565b604091949392606082019560018060a01b0316825260208201520152565b3d15614c2a573d906001600160401b038211614a1c5760405191614c1e601f8201601f1916602001846149f9565b82523d6000602084013e565b606090565b91908203918211614c3c57565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b039091168152602081019190915260400190565b8054821015614c855760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b91908201809211614c3c57565b6000198114614c3c5760010190565b90614cc182614a32565b614cce60405191826149f9565b8281528092614cdf601f1991614a32565b0190602036910137565b9594939092614d199260a0948852600160208901526040880152606087015260c0608087015260c0860190614ac4565b930152565b9695949192614d199360a095928952151560208901526040880152606087015260c0608087015260c0860190614ac4565b906040519182815491828252602082019060005260206000209260005b818110614d83575050614d81925003836149f9565b565b8454835260019485019487945060209093019201614d6c565b6001600160a01b039182168152911660208201526040810191909152606081019190915260a06080820181905260009082015260c00190565b6001600160a01b03918216815291166020820152604081019190915260600190565b81810292918115918404141715614c3c57565b818110614e15575050565b60008155600101614e0a565b80546000825580614e30575050565b614d8191600052602060002090810190614e0a565b8054600160401b811015614a1c57614e6291600182018155614c6d565b81546001600160a01b0393841660039290921b91821b9390911b1916919091179055565b805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b949392606092614d199287526020870152608060408701526080860190614ac4565b600260015414614ee0576002600155565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b6000546001600160a01b03163303614f3957565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b8060005260076020526040600020601a810160ff8154166150ef57600f8201918254614fa881614cb7565b805160188401916001600160401b038211614a1c57600160401b8211614a1c5760209083548385558084106150d2575b50969392960186600052602060002060005b8381106150be575050505060009485925b8284106150455750505050601901829055805460ff191660011790556040519081527f3678327a1697b2c81faff80acadd724ab2cd2928955cda6532904fa6950929a590602090a2565b9091929561508d600191604061505b8a86614c6d565b858060a01b0391549060031b1c168b600052600860205281600020600091868060a01b03168252602052205490614c9b565b966150b58861509c8387614c6d565b90919082549060031b91821b91600019901b1916179055565b01929190614ffb565b825181830155602090920191600101614fea565b6150e9908560005284846000209182019101614e0a565b38614fd8565b505050565b806000526007602052604060002060ff600c820154161561524957600f810154156151e757601581019283549060ff8260a01c166152385760ff60a01b19909116600160a01b179093554260178201556040516371c8a23960e11b81526004810183905292602090849060249082907f0000000000000000000000005f78f2e450c82c782a26c713a4413f5ba2aaa0c36001600160a01b03165af192831561522c576000936151f8575b5082156151e75760168391015581600052600b602052806040600020557fc794a0c14d8a263cb588cdbe9d8440fe3dc0604231e2bd9230c307ebd2089cd26020604051838152a3565b63baf3f0f760e01b60005260046000fd5b90926020823d602011615224575b81615213602093836149f9565b81010312610455575051913861519e565b3d9150615206565b6040513d6000823e3d90fd5b63319b714360e01b60005260046000fd5b63ee0eb16d60e01b60005260046000fd5b80549190600160401b831015614a1c578261509c916001614d8195018155614c6d565b600060443d106152e4576040513d600319016004823e8051916001600160401b0383113d6024850111176152ef578183018051909390916001600160401b0383116152e7573d840160031901858401602001116152e757506152e4929101602001906149f9565b90565b949350505050565b92915050565b919082519283825260005b848110615321575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201615300565b60055460ff60009116156156735781815260076020526040812090601c82019182549060ff8260081c1661566c57600c8101549060ff82161591821561565e575b50811561564c575b5061560a57476004548015159182615600575b50506155a457838252600f6020526040822054801515908161558e575b5061553f5761ff001916610100178255828152600f60205260408120429055303b1561045557604051630a27a70960e01b81526004810184905290808260248183305af1918261552f575b50906154f45760018160033d116154e4575b6308c379a01461547a575b61542057505050565b600080516020615d428339815191529161ff0019815416905582600080516020615e42833981519152608060405184815260406020820152600d60408201526c2ab735b737bbb71032b93937b960991b6060820152a280a2565b61548261527d565b8061548e575b50615417565b905083600080516020615e428339815191526154c8849361ff001987541687556040519182918783526040602084015260408301906152f5565b0390a283600080516020615d428339815191528380a238615488565b50600482803e815160e01c61540c565b5050600080516020615e428339815191526080604051600181526040602082015260076040820152665375636365737360c81b6060820152a2565b81615539916149f9565b386153fa565b50600080516020615e42833981519152915060809060405190815260406020820152601a604082015279119a5b985b1a5e985d1a5bdb8819195b185e481b9bdd081b595d60321b6060820152a2565b905061012c8101809111610a18574210386153af565b50600080516020615d42833981519152915082600080516020615e428339815191526080604051848152604060208201526016604082015275496e73756666696369656e742056524e47206665657360501b6060820152a280a2565b1090503880615392565b50600080516020615e42833981519152915060809060405190815260406020820152600d60408201526c496e76616c696420737461746560981b6060820152a2565b60ff91506015015460a01c163861537f565b60101c60ff16915038615377565b5050505050565b80600080516020615d4283398151915291a2565b6156bc614d8193926156ae60405194859263a9059cbb60e01b602085015260248401614c52565b03601f1981018452836149f9565b615b8f565b805115614c855760200190565b8051821015614c855760209160051b010190565b9261571690615724936020969360018060a01b0316865260018060a01b03168686015260a0604086015260a0850190614ac4565b908382036060850152614ac4565b906080818303910152600081520190565b81519160005b8381106157485750505050565b80615755600192846156ce565b5184600052600960205260406000208160005260205260ff6040600020541615615781575b500161573b565b6157bf9085600052600960205260406000208160005260205260406000208460ff19825416179055856000526007602052601060406000200161525a565b3861577a565b906156bc906156ae614d81956040519586936323b872dd60e01b602086015260248501614dd5565b6000818152600760205260408120601281018054919492916001600160a01b0316615ad7575080936158226011839201614d4f565b90815190835b828110615a7a57508661583f575b50505050505050565b61584881614cb7565b9161585282614cb7565b938590865b8381106159c0575050505060010361592d577f000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a6001600160a01b0316906158a8906158a1906156c1565b51926156c1565b5191813b1561091e579183916158d79383604051809681958294637921219560e11b84528b3060048601614d9c565b03925af18015611f2357615918575b50506020600080516020615d22833981519152915b6040519485526001600160a01b031693a338808080808080615836565b6159238280926149f9565b61045557806158e6565b7f000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a6001600160a01b031690813b1561091e579183916159859383604051809681958294631759616b60e11b84528b30600486016156e2565b03925af18015611f235791600080516020615d2283398151915293916020936159b0575b50506158fb565b816159ba916149f9565b386159a9565b6159ca81836156ce565b518a8952600c60209081526040808b206001600160a01b038d168c528252808b20838c529091528920549081615a05575b5050600101615857565b936001929491828493615a18848c6156ce565b5281615a24848d6156ce565b528d8c52600c60205260408c208d858060a01b03168d5260205260408c20818d526020528b60408120558d8c52600d60205260408c20908c52602052615a6f60408c20918254614c2f565b9055019290386159fb565b868552600c602090815260408087206001600160a01b03891688529091528520615aa482866156ce565b518652602052604085205480615abe575b50600101615828565b615ace6001929399918392614c9b565b98019190615ab5565b838252600e602090815260408084206001600160a01b03861685529091528220549294929182615b0a575b505050505050565b600080516020615dc283398151915293818660149352600e6020526040812060018060a01b0389168252602052604081205501615b48838254614c2f565b90558054615b6290839087906001600160a01b0316615687565b546040516001600160a01b039586169590928392615b81921683614c52565b0390a3388080808080615b02565b604080519092615bf4926001600160a01b0316906000908190615bb287866149f9565b602085527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564602086015260208151910182855af1615bee614bf0565b91615c84565b8051908115918215615c61575b505015615c0b5750565b5162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608490fd5b819250906020918101031261166c5760200151801515810361166c573880615c01565b91929015615ce65750815115615c98575090565b3b15615ca15790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b825190915015615cf95750805190602001fd5b60405162461bcd60e51b815260206004820152908190615d1d9060248301906152f5565b0390fdfe7a482fdeb6bc9a1376f597068a214a7a39472bb2eff1b8cad21ba04f49ddca1b161be6479c47fe24a981165d1f4e37d9aee92fd6e6ef9b7cc418b862a961daf9c191099af2d2d1ec29ee63d6aaca4d0929807d3ae0ecdf72fe9073259685a8c29f686c1df8255b6aed5bb3791b218d49d0b23693116ed00d223dad05b9ba3cfc0bad0577cd8deb0fddfdca96bf4af8cfa4e13d4a109268718e1a95cb6582e8cf3e1757f494d1d3006a4f2ffe0ca12a60ba0638aa77cdd4cb69ad2fcbef9d5f1850c1f3ceae08077b76738a3be24875df98d239b0189963f38a29b3001922739a58cc6d5c90cacccf3ad59213f8ecaed268bea9172b66b7da53fac93ca7e3228d8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05a5357b9d51b1546187ecefb786bbac0929f2f83c03e3df378362014f4df3a07a26469706673582212202febf7ed4b748d9e35dd81059a4f91277c9bf036d260a58c2a616bae4667c55a64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a0000000000000000000000005f78f2e450c82c782a26c713a4413f5ba2aaa0c3
-----Decoded View---------------
Arg [0] : _geezToken (address): 0x892AFc232b0741c4eEbAfea2e982ef842ECEc14A
Arg [1] : _vrngRouter (address): 0x5F78F2e450C82C782a26C713a4413f5Ba2aaa0c3
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000892afc232b0741c4eebafea2e982ef842ecec14a
Arg [1] : 0000000000000000000000005f78f2e450c82c782a26c713a4413f5ba2aaa0c3
Loading...
Loading
Loading...
Loading
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.