Source Code
Latest 25 from a total of 1,907 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Claim Lot | 5395365 | 578 days ago | IN | 0.0005796 ETH | 0.0000021 | ||||
| Bid | 5395258 | 578 days ago | IN | 0 ETH | 0.00000053 | ||||
| Bid | 5395258 | 578 days ago | IN | 0 ETH | 0.00000056 | ||||
| Bid | 5395229 | 578 days ago | IN | 0 ETH | 0.00000123 | ||||
| Bid | 5395227 | 578 days ago | IN | 0 ETH | 0.00000123 | ||||
| Bid | 5395216 | 578 days ago | IN | 0 ETH | 0.00000122 | ||||
| Bid | 5395211 | 578 days ago | IN | 0 ETH | 0.00000103 | ||||
| Bid | 5395211 | 578 days ago | IN | 0 ETH | 0.00000123 | ||||
| Bid | 5395206 | 578 days ago | IN | 0 ETH | 0.0000011 | ||||
| Bid | 5395199 | 578 days ago | IN | 0 ETH | 0.0000012 | ||||
| Bid | 5395185 | 578 days ago | IN | 0 ETH | 0.00000142 | ||||
| Bid | 5395174 | 578 days ago | IN | 0 ETH | 0.00000126 | ||||
| Bid | 5395162 | 578 days ago | IN | 0 ETH | 0.00000108 | ||||
| Bid | 5395148 | 578 days ago | IN | 0 ETH | 0.00000125 | ||||
| Bid | 5395131 | 578 days ago | IN | 0 ETH | 0.00000108 | ||||
| Bid | 5395111 | 578 days ago | IN | 0 ETH | 0.00000146 | ||||
| Bid | 5395101 | 578 days ago | IN | 0 ETH | 0.00000111 | ||||
| Bid | 5395094 | 578 days ago | IN | 0 ETH | 0.00000125 | ||||
| Bid | 5395087 | 578 days ago | IN | 0 ETH | 0.00000137 | ||||
| Bid | 5395085 | 578 days ago | IN | 0 ETH | 0.00000145 | ||||
| Bid | 5395063 | 578 days ago | IN | 0 ETH | 0.00000103 | ||||
| Bid | 5395063 | 578 days ago | IN | 0 ETH | 0.00000127 | ||||
| Bid | 5395051 | 578 days ago | IN | 0 ETH | 0.00000122 | ||||
| Bid | 5395050 | 578 days ago | IN | 0 ETH | 0.00000121 | ||||
| Bid | 5395047 | 578 days ago | IN | 0 ETH | 0.00000122 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 5395365 | 578 days ago | 0.0005796 ETH | ||||
| 5225643 | 581 days ago | 0.0019908 ETH | ||||
| 5218184 | 582 days ago | 0.028 ETH | ||||
| 5218184 | 582 days ago | 0.028 ETH | ||||
| 5094796 | 584 days ago | 0.000966 ETH | ||||
| 5088327 | 585 days ago | 0.028 ETH | ||||
| 5088327 | 585 days ago | 0.028 ETH | ||||
| 5008558 | 586 days ago | 0.0014364 ETH | ||||
| 5000467 | 587 days ago | 0.028 ETH | ||||
| 5000467 | 587 days ago | 0.028 ETH | ||||
| 4919044 | 589 days ago | 0.000322 ETH | ||||
| 4905555 | 589 days ago | 0.028 ETH | ||||
| 4905555 | 589 days ago | 0.028 ETH | ||||
| 4872726 | 590 days ago | 0.0009884 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH | ||||
| 4862914 | 590 days ago | 0.028 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Auctioneer
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.20;
pragma experimental ABIEncoderV2;
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC20Permit } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { IWETH } from "./WETH9.sol";
import "./IAuctioneer.sol";
import { GBMath } from "./AuctionUtils.sol";
import { BlastYield } from "./BlastYield.sol";
import { IAuctioneerAuction } from "./AuctioneerAuction.sol";
// , , , *, , , , *, ,
// , , , , * * ,* , *,, , , .
// . . .* , ,,, * , * ,, ,, *
// , , , , , , ,,** * , * ,, , ,
// * * , ,,,*, * @ , ,, , ,,
// , , * * , ,, ,@,,,, ,, , , * ,
// , * * , , , **,,,@*,*, * *,, * , ,
// , , * , ,*,* ,* ,, , , * @/*/* ,, , , , , , ,
// , * * * * , ,,,, , */*@// * ,,, , , ,, ,
// * ,, ,, , , ,, ** ,/ (*@/(*,, , , , ,
// * *, * , , ,, , , *,,.. ./*/@///,*,,* *,, ,
// , ,*,,* , , ** , ,,,,,*,//(%@&((/,/,.*.*.* ., ., . .
// *, ., ., *,, ., ,* .***/(%@@/@(@@/(/**.*,*,,, . .. ..... . .
// ,,,... ,, * ** , *,,*,,**//@@*(/*@/ /@@//,,*,*, ,,
// *,* *, , , ,, * *,*,*((@@//,//*@/ (@@/*,, , ,
// , * ,* , ,, , *, ***/*@@*/* ***/,@//* *//(*@@** , ,
// , * * , ,,* *, * ,,@@*,*,,*,**,*@*/,* ,,,*//@@ ,,
// ,, ,,,, , , *, ,,,*,,,,@@,,***,,*,@**,*,**,/@@,*, , ,,
// ,* ,,, , , ,, , , , ,,,/*@@***,, @*,,,,*@@,/,*,,,,
// , *,, , , ** , , ,, ,, **,*@@,*/,@,, /@@*/** , ,
// * * *, ,, ,, ** * *,***@@ @*@@*/*,* , , ,
// , * ,, , , , , *, **,**%@&,,,*, , ,
// , *, ,, * , , *,,** ,,@,,, ,, ,
// *, ,* ,* *, ,* , , ,, ,,*,,*,,* @,** ,,
// * ** * * / , ,, , * ,@*, ,*, ,, , ,
// * ,, * ,, , , ** ,**,, , @ * ,
// ,*, * ** ,* ,, * ,, *, ,,@, ,,,* ,
// , /**, , * ,, , @ , , ,
// , /* * / * * * ,*,,, ,* @,, , , , ,
// , ,* ,,* *, , ** ,
// * , *, , ,, , , ,, , ,
// ,, , , , , *
// -- ARCH --
contract Auctioneer is AccessControl, ReentrancyGuard, AuctioneerEvents, BlastYield {
using GBMath for uint256;
using SafeERC20 for IERC20;
using EnumerableSet for EnumerableSet.UintSet;
IERC20 public VOUCHER;
IWETH public WETH;
address public treasury;
uint256 public treasuryCut;
address public deadAddress = 0x000000000000000000000000000000000000dEaD;
IAuctioneerAuction public auctioneerAuction;
mapping(uint256 => mapping(address => AuctionUser)) public auctionUsers;
mapping(address => EnumerableSet.UintSet) userParticipatedAuctions;
mapping(address => string) public userAlias;
mapping(string => address) public aliasUser;
mapping(address => bool) public mutedUsers;
bytes32 public constant MOD_ROLE = keccak256("MOD_ROLE");
bytes32 public constant CREATOR_ROLE = keccak256("CREATOR_ROLE");
bool public createAuctionRequiresRole = true;
EnumerableSet.UintSet activeLots;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor(IERC20 _voucher, IWETH _weth) {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(MOD_ROLE, msg.sender);
_grantRole(CREATOR_ROLE, msg.sender);
VOUCHER = _voucher;
WETH = _weth;
}
function link(address _auctioneerAuction) external onlyAdmin {
if (_auctioneerAuction == address(0)) revert ZeroAddress();
if (address(auctioneerAuction) != address(0)) revert AlreadyLinked();
auctioneerAuction = IAuctioneerAuction(_auctioneerAuction);
emit Linked(address(this), _auctioneerAuction);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
receive() external payable {}
modifier onlyAdmin() {
_checkRole(DEFAULT_ADMIN_ROLE);
_;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function initializeBlast() external onlyAdmin {
_initializeBlast();
}
function claimYieldAll(address _recipient, uint256 _minClaimRateBips) external onlyAdmin {
_claimYieldAll(_recipient, _minClaimRateBips);
}
function updateTreasury(address _treasury) external onlyAdmin {
if (_treasury == address(0)) revert ZeroAddress();
treasury = _treasury;
auctioneerAuction.updateTreasury(treasury);
emit UpdatedTreasury(_treasury);
}
function muteUser(address _user, bool _muted) external onlyRole(MOD_ROLE) {
mutedUsers[_user] = _muted;
aliasUser[userAlias[_user]] = address(0);
userAlias[_user] = "";
emit MutedUser(_user, _muted);
}
function setCreateAuctionRequiresRole(bool _required) external onlyAdmin {
createAuctionRequiresRole = _required;
emit UpdatedCreateAuctionRequiresRole(_required);
}
function updateTreasuryCut(uint256 _treasuryCut) external onlyAdmin {
if (_treasuryCut > 2000) revert Invalid();
treasuryCut = _treasuryCut;
emit UpdatedTreasuryCut(_treasuryCut);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function createAuction(AuctionParams memory _param) external nonReentrant returns (uint256 lot) {
if (treasury == address(0)) revert TreasuryNotSet();
if (createAuctionRequiresRole) {
_checkRole(CREATOR_ROLE);
}
uint256 wethAmount = 0;
for (uint8 i = 0; i < _param.tokens.length; i++) {
if (_param.tokens[i].token != address(0)) continue;
wethAmount += _param.tokens[i].amount;
}
if (wethAmount > 0) {
IERC20(address(WETH)).safeTransferFrom(msg.sender, address(this), wethAmount);
WETH.withdraw(wethAmount);
}
lot = auctioneerAuction.createAuction{ value: wethAmount }(msg.sender, _param, treasuryCut);
activeLots.add(lot);
emit AuctionCreated(msg.sender, lot);
}
function cancelAuction(uint256 _lot) external {
_cancelAuction(msg.sender, _lot);
activeLots.remove(_lot);
}
function bid(
uint256 _lot,
uint8 _rune,
string calldata _message,
uint256 _bidCount,
PaymentType _paymentType
) external payable nonReentrant {
_bid(_lot, _rune, _message, _bidCount, _paymentType);
userParticipatedAuctions[msg.sender].add(_lot);
}
function bidWithPermit(
uint256 _lot,
uint8 _rune,
string calldata _message,
uint256 _bidCount,
PaymentType _paymentType,
PermitData memory _permitData
) external payable nonReentrant {
_selfPermit(_permitData);
_bid(_lot, _rune, _message, _bidCount, _paymentType);
}
function selectRune(uint256 _lot, uint8 _rune, string calldata _message) external nonReentrant {
AuctionUser storage user = auctionUsers[_lot][msg.sender];
user.bids = auctioneerAuction.selectRune(_lot, user.bids, user.rune, _rune);
uint8 prevRune = user.rune;
user.rune = _rune;
emit SelectedRune(
_lot,
msg.sender,
mutedUsers[msg.sender] ? "" : _message,
userAlias[msg.sender],
_rune,
prevRune
);
}
function messageAuction(uint256 _lot, string memory _message) external nonReentrant {
if (mutedUsers[msg.sender]) revert Muted();
auctioneerAuction.validateAuctionRunning(_lot);
emit Messaged(_lot, msg.sender, _message, userAlias[msg.sender], auctionUsers[_lot][msg.sender].rune);
}
function finalizeAuction(uint256 _lot) external nonReentrant {
_finalizeAuction(_lot);
}
function claimLot(uint256 _lot, string calldata _message) external payable nonReentrant {
AuctionUser storage user = auctionUsers[_lot][msg.sender];
if (user.lotClaimed) revert UserAlreadyClaimedLot();
user.lotClaimed = true;
(
uint256 userShareOfPayment,
address creator,
uint256 _treasuryCut,
bool triggerFinalization
) = auctioneerAuction.claimLot(_lot, msg.sender, user.bids, user.rune);
_takeUserPayment(msg.sender, PaymentType.WALLET, userShareOfPayment, 0);
_transferRevenue(userShareOfPayment, creator, _treasuryCut);
userParticipatedAuctions[msg.sender].remove(_lot);
if (triggerFinalization) _finalizeAuction(_lot);
emit Claimed(_lot, msg.sender, mutedUsers[msg.sender] ? "" : _message, userAlias[msg.sender], user.rune);
}
function setAlias(string memory _alias) external nonReentrant {
if (mutedUsers[msg.sender]) revert Muted();
if (bytes(_alias).length < 3 || bytes(_alias).length > 9) revert InvalidAlias();
if (aliasUser[_alias] != address(0)) revert AliasTaken();
// Free previous alias
aliasUser[userAlias[msg.sender]] = address(0);
// Set new alias
userAlias[msg.sender] = _alias;
aliasUser[_alias] = msg.sender;
emit UpdatedAlias(msg.sender, _alias);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function _cancelAuction(address _canceller, uint256 _lot) internal {
auctioneerAuction.cancelAuction(_canceller, _lot, hasRole(DEFAULT_ADMIN_ROLE, _canceller));
emit AuctionCancelled(_canceller, _lot);
}
function _bid(
uint256 _lot,
uint8 _rune,
string calldata _message,
uint256 _bidCount,
PaymentType _paymentType
) internal {
if (_bidCount != 1) revert InvalidBidCount();
AuctionUser storage user = auctionUsers[_lot][msg.sender];
(uint256 userBidsAfterPenalty, uint256 auctionBid, uint256 bidCost) = auctioneerAuction.bid(
_lot,
IAuctioneerAuction.BidData({
user: msg.sender,
prevRune: user.rune,
newRune: _rune,
existingBidCount: user.bids,
arrivingBidCount: _bidCount,
paymentType: _paymentType
})
);
uint8 prevRune = user.rune;
user.rune = _rune;
user.bids = userBidsAfterPenalty + _bidCount;
_takeUserPayment(msg.sender, _paymentType, bidCost * _bidCount, _bidCount * 1e18);
emit Bid(
_lot,
msg.sender,
mutedUsers[msg.sender] ? "" : _message,
userAlias[msg.sender],
_rune,
prevRune,
auctionBid,
_bidCount,
block.timestamp
);
}
function _finalizeAuction(uint256 _lot) internal {
(bool triggerCancellation, uint256 revenue, address creator, uint256 _treasuryCut) = auctioneerAuction
.finalizeAuction(_lot);
if (triggerCancellation) {
_cancelAuction(creator, _lot);
}
_transferRevenue(revenue, creator, _treasuryCut);
activeLots.remove(_lot);
}
function _selfPermit(PermitData memory _permitData) internal {
IERC20Permit(_permitData.token).permit(
msg.sender,
address(this),
_permitData.value,
_permitData.deadline,
_permitData.v,
_permitData.r,
_permitData.s
);
}
function _takeUserPayment(
address _user,
PaymentType _paymentType,
uint256 _ethAmount,
uint256 _voucherAmount
) internal {
if (_paymentType == PaymentType.WALLET) {
if (msg.value != _ethAmount) revert IncorrectETHPaymentAmount();
} else {
if (msg.value != 0) revert SentETHButNotWalletPayment();
}
if (_paymentType == PaymentType.VOUCHER) {
VOUCHER.safeTransferFrom(_user, deadAddress, _voucherAmount);
}
}
function _transferRevenue(uint256 revenue, address creator, uint256 _treasuryCut) internal {
if (revenue == 0) return;
uint256 cut = revenue.scaleByBP(_treasuryCut);
(bool sent, ) = treasury.call{ value: cut }("");
if (!sent) revert ETHTransferFailed();
(sent, ) = payable(creator).call{ value: revenue - cut }("");
if (!sent) revert ETHTransferFailed();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function getAliasAndRune(uint256 _lot, address _user) external view returns (uint8 rune, string memory _alias) {
rune = auctionUsers[_lot][_user].rune;
_alias = userAlias[_user];
}
function getAuctionUser(uint256 _lot, address _user) external view returns (AuctionUser memory) {
return auctionUsers[_lot][_user];
}
function getUserParticipatedAuctions(address _user) public view returns (uint256[] memory lots) {
uint256 count = userParticipatedAuctions[_user].length();
lots = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
lots[i] = userParticipatedAuctions[_user].at(i);
}
}
function getActiveLots() external view returns (uint256[] memory lots) {
uint256 count = activeLots.length();
lots = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
lots[i] = activeLots.at(i);
}
}
function getUserLotInfos(uint256[] memory _lots, address _user) external view returns (UserLotInfo[] memory infos) {
infos = new UserLotInfo[](_lots.length);
uint256 lot;
for (uint256 i = 0; i < _lots.length; i++) {
lot = _lots[i];
Auction memory auction = auctioneerAuction.getAuction(lot);
uint256 runicLastBidderBonus = auctioneerAuction.runicLastBidderBonus();
AuctionUser memory user = auctionUsers[lot][_user];
bool auctionHasRunes = auction.runes.length > 0;
bool auctionHasBids = auction.bidData.bids > 0;
infos[i].lot = auction.lot;
infos[i].rune = user.rune;
// Bids
infos[i].bidCounts.user = user.bids;
infos[i].bidCounts.rune = !auctionHasRunes || user.rune == 0 ? 0 : auction.runes[user.rune].bids;
infos[i].bidCounts.auction = auction.bidData.bids;
// Winning bid
infos[i].isWinner =
user.bids > 0 &&
(auction.runes.length > 0 ? user.rune == auction.bidData.bidRune : _user == auction.bidData.bidUser);
infos[i].lotClaimed = user.lotClaimed;
// Share
bool isLastBidder = auction.bidData.bidUser == _user;
uint256 runicLastBidderBonusBids = isLastBidder && auctionHasRunes
? auction.runes[user.rune].bids.scaleByBP(runicLastBidderBonus)
: 0;
if (auctionHasBids && auctionHasRunes && auction.runes[user.rune].bids > 0) {
infos[i].shareOfLot =
((user.bids + runicLastBidderBonusBids) * 1e18) /
auction.runes[user.rune].bids.scaleByBP(10000 + runicLastBidderBonus);
} else if (auctionHasBids && !auctionHasRunes) {
infos[i].shareOfLot = 1e18;
} else {
infos[i].shareOfLot = 0;
}
infos[i].price = (auction.bidData.bid * infos[i].shareOfLot) / 1e18;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @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;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
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
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../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 An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev 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);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev 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);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that 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(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @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 v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.20;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { ERC20Burnable } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import { ERC20Pausable } from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol";
interface IWETH is IERC20 {
function withdraw(uint256 amount) external;
function deposit() external payable;
}
contract WETH9 is ERC20, ERC20Burnable, ERC20Pausable, Ownable {
constructor() ERC20("Wrapped Ether", "WETH") Ownable(msg.sender) {}
event Deposit(address indexed dst, uint256 amount);
event Withdrawal(address indexed src, uint256 amount);
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
function mint(address to, uint256 amount) external onlyOwner {
_mint(to, amount);
}
function _update(address from, address to, uint256 value) internal override(ERC20, ERC20Pausable) {
super._update(from, to, value);
}
function deposit() public payable {
_mint(msg.sender, msg.value);
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint256 amount) public {
require(balanceOf(msg.sender) >= amount);
_burn(msg.sender, amount);
payable(msg.sender).transfer(amount);
emit Withdrawal(msg.sender, amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
enum BidWindowType {
OPEN,
TIMED,
INFINITE
}
enum PaymentType {
WALLET,
VOUCHER
}
// Params
struct BidRune {
uint8 runeSymbol;
uint256 bids;
}
struct PermitData {
address token;
uint256 value;
uint256 deadline;
uint8 v;
bytes32 r;
bytes32 s;
}
// Alphabetical field ordering for json parsing
struct BidWindowParams {
uint256 duration;
uint256 timer;
BidWindowType windowType;
}
// Alphabetical field ordering for json parsing
struct TokenData {
uint256 amount;
address token;
}
// Alphabetical field ordering for json parsing
struct NftData {
uint256 id;
address nft;
}
// Alphabetical field ordering for json parsing
struct AuctionParams {
uint256 bidCost;
uint256 bidIncrement;
string name;
NftData[] nfts;
uint8[] runeSymbols;
uint256 startingBid;
TokenData[] tokens;
uint256 unlockTimestamp;
BidWindowParams[] windows;
}
// Storage
struct BidWindow {
BidWindowType windowType;
uint256 windowOpenTimestamp;
uint256 windowCloseTimestamp; // 0 for window that goes forever
uint256 timer; // 0 for no timer, >60 for other timers (1m / 2m / 5m)
}
struct AuctionLot {
uint256 estimatedValue; // Estimated value of the lot (1 ETH = 4000 USD)
TokenData[] tokens;
NftData[] nfts;
}
struct AuctionBidData {
uint256 revenue;
uint256 bid;
uint256 bidTimestamp;
uint256 nextBidBy;
address bidUser;
uint8 bidRune;
uint256 bids; // number of bids during auction
uint256 bidCost; // Frozen value to prevent updating bidCost from messing with revenue calculations
uint256 bidIncrement;
}
struct Auction {
address creator;
uint256 lot;
uint256 day;
string name;
uint256 unlockTimestamp;
BidRune[] runes;
BidWindow[] windows;
AuctionLot rewards;
AuctionBidData bidData;
uint256 treasuryCut;
bool finalized;
uint256 initialBlock;
}
struct AuctionUser {
uint256 bids;
uint8 rune; // indexed starting at 1 to check if rune has been set (defaults to 0)
bool lotClaimed;
}
// Returns
struct BidCounts {
uint256 user;
uint256 rune;
uint256 auction;
}
struct UserLotInfo {
uint256 lot;
uint8 rune;
// Bids
BidCounts bidCounts;
// Winning bid
bool isWinner;
bool lotClaimed;
uint256 shareOfLot;
uint256 price;
}
struct AuctionExt {
uint256 lot;
uint256 blockTimestamp;
bool isBiddingOpen;
bool isEnded;
uint256 activeWindow;
}
struct DailyAuctions {
uint256 day;
uint256[] lots;
}
error NotAuctioneer();
error NotAuctioneerAuction();
error AlreadyInitialized();
error TreasuryNotSet();
error Invalid();
error InvalidAuctionLot();
error InvalidWindowOrder();
error WindowTooShort();
error InvalidBidWindowCount();
error InvalidBidWindowTimer();
error LastWindowNotInfinite();
error MultipleInfiniteWindows();
error TooManyTokens();
error TooManyNFTs();
error NotEnoughETHToCoverLots();
error AuctionEnded();
error AuctionNotYetOpen();
error AuctionStillRunning();
error NoRewards();
error AuctionClosed();
error NotCancellable();
error TooSteep();
error ZeroAddress();
error AlreadyLinked();
error UnlockAlreadyPassed();
error BadDeposit();
error BadWithdrawal();
error InvalidAlias();
error AliasTaken();
error ETHTransferFailed();
error MustBidAtLeastOnce();
error NotWinner();
error UserAlreadyClaimedLot();
error InvalidBidCount();
error InvalidRune();
error InvalidRuneSymbol();
error InvalidRunesCount();
error DuplicateRuneSymbols();
error CantSwitchRune();
error CannotHaveNFTsWithRunes();
error IncorrectETHPaymentAmount();
error SentETHButNotWalletPayment();
error Muted();
error Unauthorized();
interface AuctioneerEvents {
// ADMIN
event Linked(address indexed _auctioneer, address _auctioneerAuction);
event Initialized();
event MutedUser(address indexed _user, bool _muted);
// CONSTS
event UpdatedTreasuryCut(uint256 _treasuryCut);
event UpdatedRuneSwitchPenalty(uint256 _penalty);
event UpdatedTreasury(address indexed _treasury);
event UpdatedAlias(address indexed _user, string _alias);
event UpdatedRunicLastBidderBonus(uint256 _bonus);
event UpdatedCreateAuctionRequiresRole(bool _required);
// AUCTION STATE
event AuctionCreated(address indexed _creator, uint256 indexed _lot);
event AuctionCancelled(address indexed _canceller, uint256 indexed _lot);
event AuctionFinalized(uint256 indexed _lot);
// USER INTERACTIONS
event Bid(
uint256 indexed _lot,
address indexed _user,
string _message,
string _alias,
uint8 _rune,
uint8 _prevRune,
uint256 _bid,
uint256 _bidCount,
uint256 _timestamp
);
event SelectedRune(
uint256 indexed _lot,
address indexed _user,
string _message,
string _alias,
uint8 _rune,
uint8 _prevRune
);
event Messaged(uint256 indexed _lot, address indexed _user, string _message, string _alias, uint8 _rune);
event Claimed(uint256 indexed _lot, address indexed _user, string _message, string _alias, uint8 _rune);
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.20;
import { Auction, AuctionParams, BidWindow, BidWindowType, BidRune, TokenData, NftData, AuctionNotYetOpen, AuctionEnded, AuctionStillRunning, NotWinner, ETHTransferFailed, IncorrectETHPaymentAmount, UnlockAlreadyPassed, TooManyTokens, TooManyNFTs, CannotHaveNFTsWithRunes, NoRewards, InvalidBidWindowCount, InvalidWindowOrder, LastWindowNotInfinite, MultipleInfiniteWindows, WindowTooShort, InvalidBidWindowTimer, InvalidRunesCount, InvalidRuneSymbol, DuplicateRuneSymbols } from "./IAuctioneer.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
// , , , *, , , , *, ,
// , , , , * * ,* , *,, , , .
// . . .* , ,,, * , * ,, ,, *
// , , , , , , ,,** * , * ,, , ,
// * * , ,,,*, * @ , ,, , ,,
// , , * * , ,, ,@,,,, ,, , , * ,
// , * * , , , **,,,@*,*, * *,, * , ,
// , , * , ,*,* ,* ,, , , * @/*/* ,, , , , , , ,
// , * * * * , ,,,, , */*@// * ,,, , , ,, ,
// * ,, ,, , , ,, ** ,/ (*@/(*,, , , , ,
// * *, * , , ,, , , *,,.. ./*/@///,*,,* *,, ,
// , ,*,,* , , ** , ,,,,,*,//(%@&((/,/,.*.*.* ., ., . .
// *, ., ., *,, ., ,* .***/(%@@/@(@@/(/**.*,*,,, . .. ..... . .
// ,,,... ,, * ** , *,,*,,**//@@*(/*@/ /@@//,,*,*, ,,
// *,* *, , , ,, * *,*,*((@@//,//*@/ (@@/*,, , ,
// , * ,* , ,, , *, ***/*@@*/* ***/,@//* *//(*@@** , ,
// , * * , ,,* *, * ,,@@*,*,,*,**,*@*/,* ,,,*//@@ ,,
// ,, ,,,, , , *, ,,,*,,,,@@,,***,,*,@**,*,**,/@@,*, , ,,
// ,* ,,, , , ,, , , , ,,,/*@@***,, @*,,,,*@@,/,*,,,,
// , *,, , , ** , , ,, ,, **,*@@,*/,@,, /@@*/** , ,
// * * *, ,, ,, ** * *,***@@ @*@@*/*,* , , ,
// , * ,, , , , , *, **,**%@&,,,*, , ,
// , *, ,, * , , *,,** ,,@,,, ,, ,
// *, ,* ,* *, ,* , , ,, ,,*,,*,,* @,** ,,
// * ** * * / , ,, , * ,@*, ,*, ,, , ,
// * ,, * ,, , , ** ,**,, , @ * ,
// ,*, * ** ,* ,, * ,, *, ,,@, ,,,* ,
// , /**, , * ,, , @ , , ,
// , /* * / * * * ,*,,, ,* @,, , , , ,
// , ,* ,,* *, , ** ,
// * , *, , ,, , , ,, , ,
// , , , , *
// -- ARCH --
library GBMath {
function transformDec(uint256 amount, uint8 from, uint8 to) internal pure returns (uint256) {
return (amount * 10 ** to) / 10 ** from;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function scaleByBP(uint256 amount, uint256 bp) internal pure returns (uint256) {
if (bp == 10000) return amount;
return (amount * bp) / 10000;
}
}
library AuctionViewUtils {
using GBMath for uint256;
function hasRunes(Auction storage auction) internal view returns (bool) {
return auction.runes.length > 0;
}
function activeWindow(Auction storage auction) internal view returns (uint256) {
// Before auction opens, active window is 0
// This case gets caught by first window
// Check if timestamp is before the end of each window, if it is, return that windows index
for (uint256 i = 0; i < auction.windows.length; i++) {
if (block.timestamp < auction.windows[i].windowCloseTimestamp) return i;
}
// Shouldn't ever get here, maybe in 10 years or so.
return auction.windows.length - 1;
}
// Recursive fetcher of next bid cutoff timestamp
// Open window or negative window will look to next window
// Timed or infinite window will give timestamp to exit
function getWindowNextBidBy(Auction storage auction, uint256 window) internal view returns (uint256) {
if (auction.windows[window].windowType == BidWindowType.OPEN) return getWindowNextBidBy(auction, window + 1);
// Timed or infinite window
// max(last bid timestamp, window open timestamp) + window timer
// A bid 5 seconds before window closes will be given the timer of the current window, even if it overflows into next window
return
GBMath.max(auction.bidData.bidTimestamp, auction.windows[window].windowOpenTimestamp) +
auction.windows[window].timer;
}
function getNextBidBy(Auction storage auction) internal view returns (uint256) {
return getWindowNextBidBy(auction, activeWindow(auction));
}
function isBiddingOpen(Auction storage auction) internal view returns (bool) {
// Early escape if the auction has been finalized
if (auction.finalized) return false;
// Early escape if auction not yet unlocked
if (block.timestamp < auction.unlockTimestamp) return false;
// Closed if nextBidBy is in future
return block.timestamp <= auction.bidData.nextBidBy;
}
function validateBiddingOpen(Auction storage auction) internal view {
if (!isBiddingOpen(auction)) {
if (block.timestamp <= auction.unlockTimestamp) revert AuctionNotYetOpen();
revert AuctionEnded();
}
}
function isEnded(Auction storage auction) internal view returns (bool) {
// Early escape if the auction has been finalized
if (auction.finalized) return true;
// Early escape if auction not yet unlocked
if (block.timestamp < auction.unlockTimestamp) return false;
// Closed if nextBidBy is in past
return block.timestamp > auction.bidData.nextBidBy;
}
function validateEnded(Auction storage auction) internal view {
if (!isEnded(auction)) revert AuctionStillRunning();
}
function validateWinner(Auction storage auction, address _user, uint8 _rune) internal view {
if (auction.runes.length > 0 ? auction.bidData.bidRune != _rune : auction.bidData.bidUser != _user)
revert NotWinner();
}
}
library AuctionMutateUtils {
using SafeERC20 for IERC20;
function addBidWindows(Auction storage auction, AuctionParams memory _params, uint256 _bonusTime) internal {
uint256 openTimestamp = _params.unlockTimestamp;
for (uint8 i = 0; i < _params.windows.length; i++) {
uint256 closeTimestamp = openTimestamp + _params.windows[i].duration;
if (_params.windows[i].windowType == BidWindowType.INFINITE) {
closeTimestamp = openTimestamp + 315600000; // 10 years, hah
}
uint256 timer = _params.windows[i].windowType == BidWindowType.OPEN
? 0
: _params.windows[i].timer + _bonusTime;
auction.windows.push(
BidWindow({
windowType: _params.windows[i].windowType,
windowOpenTimestamp: openTimestamp,
windowCloseTimestamp: closeTimestamp,
timer: timer
})
);
openTimestamp += _params.windows[i].duration;
}
}
function addRewards(Auction storage auction, AuctionParams memory params) internal {
for (uint8 i = 0; i < params.tokens.length; i++) {
auction.rewards.tokens.push(params.tokens[i]);
}
for (uint8 i = 0; i < params.nfts.length; i++) {
auction.rewards.nfts.push(params.nfts[i]);
}
}
function addRunes(Auction storage auction, AuctionParams memory params) internal {
if (params.runeSymbols.length == 0) return;
// Add empty rune (cannot be bid on), to offset array indices
auction.runes.push(BidRune({ runeSymbol: 0, bids: 0 }));
for (uint8 i = 0; i < params.runeSymbols.length; i++) {
auction.runes.push(BidRune({ runeSymbol: params.runeSymbols[i], bids: 0 }));
}
}
function _transferLotTokenTo(TokenData memory token, address to, uint256 userShareOfLot) internal {
if (token.token == address(0)) {
(bool sent, ) = to.call{ value: (token.amount * userShareOfLot) / 1e18 }("");
if (!sent) revert ETHTransferFailed();
} else {
// Transfer as default ERC20
IERC20(token.token).safeTransfer(to, (token.amount * userShareOfLot) / 1e18);
}
}
// Transfer lot (or partial lot) from AuctioneerAuction contract to user (to)
// Auction ETH / tokens / nfts sit in AuctioneerAuction contract during auction
function transferLotTo(Auction storage auction, address to, uint256 userShareOfLot) internal {
// Return lot tokens
for (uint8 i = 0; i < auction.rewards.tokens.length; i++) {
_transferLotTokenTo(auction.rewards.tokens[i], to, userShareOfLot);
}
// Transfer lot nfts
for (uint8 i = 0; i < auction.rewards.nfts.length; i++) {
IERC721(auction.rewards.nfts[i].nft).transferFrom(address(this), to, auction.rewards.nfts[i].id);
}
}
// Transfers lot from address (treasury) to AuctioneerAuction contract
// ETH should already be in the contract, validate that it has been received with msg.value check
function transferLotFrom(Auction storage auction, address from) internal {
// Transfer tokens from
for (uint8 i = 0; i < auction.rewards.tokens.length; i++) {
address token = auction.rewards.tokens[i].token;
if (token == address(0)) {
if (msg.value != auction.rewards.tokens[i].amount) revert IncorrectETHPaymentAmount();
} else {
IERC20(token).safeTransferFrom(from, address(this), auction.rewards.tokens[i].amount);
}
}
// Transfer nfts from
for (uint8 i = 0; i < auction.rewards.nfts.length; i++) {
IERC721(auction.rewards.nfts[i].nft).safeTransferFrom(from, address(this), auction.rewards.nfts[i].id);
}
}
}
library AuctionParamsUtils {
function validateUnlock(AuctionParams memory _params) internal view {
if (_params.unlockTimestamp < block.timestamp) revert UnlockAlreadyPassed();
}
function validateTokens(AuctionParams memory _params) internal pure {
if (_params.tokens.length > 4) revert TooManyTokens();
}
function validateNFTs(AuctionParams memory _params) internal pure {
if (_params.nfts.length > 4) revert TooManyNFTs();
if (_params.nfts.length > 0 && _params.runeSymbols.length > 0) revert CannotHaveNFTsWithRunes();
}
function validateAnyReward(AuctionParams memory _params) internal pure {
if (_params.nfts.length == 0 && _params.tokens.length == 0) revert NoRewards();
}
// YES I KNOW that this is inefficient, this is an owner facing function.
// Legibility and clarity > once daily gas price.
function validateBidWindows(AuctionParams memory _params) internal pure {
// VALIDATE: Acceptable number of bidding windows
if (_params.windows.length == 0 || _params.windows.length > 4) revert InvalidBidWindowCount();
// VALIDATE: Windows must flow from open -> timed -> infinite
BidWindowType runningType = BidWindowType.OPEN;
for (uint8 i = 0; i < _params.windows.length; i++) {
if (_params.windows[i].windowType < runningType) revert InvalidWindowOrder();
runningType = _params.windows[i].windowType;
}
// VALIDATE: Last window must be infinite window
if (_params.windows[_params.windows.length - 1].windowType != BidWindowType.INFINITE)
revert LastWindowNotInfinite();
// VALIDATE: Only one infinite window can exist
uint8 infCount = 0;
for (uint8 i = 0; i < _params.windows.length; i++) {
if (_params.windows[i].windowType == BidWindowType.INFINITE) infCount += 1;
}
if (infCount > 1) revert MultipleInfiniteWindows();
// VALIDATE: Windows must have a valid duration (if not infinite)
for (uint8 i = 0; i < _params.windows.length; i++) {
if (_params.windows[i].windowType != BidWindowType.INFINITE && _params.windows[i].duration < 1 hours)
revert WindowTooShort();
}
// VALIDATE: Timed windows must have a valid timer
for (uint8 i = 0; i < _params.windows.length; i++) {
// TIMED and INFINITE windows should have a timer >= 30 seconds
if (_params.windows[i].windowType != BidWindowType.OPEN && _params.windows[i].timer < 30 seconds)
revert InvalidBidWindowTimer();
// OPEN windows should have a timer of 0 (no timer)
if (_params.windows[i].windowType == BidWindowType.OPEN && _params.windows[i].timer != 0)
revert InvalidBidWindowTimer();
}
}
function validateRunes(AuctionParams memory _params) internal pure {
// Early escape if no runes
if (_params.runeSymbols.length == 0) return;
// VALIDATE: Number of runes
if (_params.runeSymbols.length == 1 || _params.runeSymbols.length > 5) revert InvalidRunesCount();
// VALIDATE: Rune symbols > 0 (account for empty rune at index 0)
for (uint8 i = 0; i < _params.runeSymbols.length; i++) {
if (_params.runeSymbols[i] == 0) revert InvalidRuneSymbol();
}
// VALIDATE: No duplicate symbols
// Example:
// Symbols = [0, 1, 2, 2]
// i = 0 - 2
// i = 0 :: j = 1 - 3
// i = 1 :: j = 2 - 3
// i = 2 :: j = 3
// checks: s[0]:s[1] ✔, s[0]:s[2] ✔, s[0]:s[3] ✔, s[1]:s[2] ✔, s[1]:s[3] ✔, s[2]:s[3] ✘
for (uint8 i = 0; i < _params.runeSymbols.length - 1; i++) {
for (uint8 j = i + 1; j < _params.runeSymbols.length; j++) {
if (_params.runeSymbols[i] == _params.runeSymbols[j]) revert DuplicateRuneSymbols();
}
}
}
// Wholistic validation
function validate(AuctionParams memory _params) internal view {
validateUnlock(_params);
validateTokens(_params);
validateNFTs(_params);
validateAnyReward(_params);
validateBidWindows(_params);
validateRunes(_params);
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.20;
enum YieldMode {
AUTOMATIC,
VOID,
CLAIMABLE
}
enum GasMode {
VOID,
CLAIMABLE
}
interface IBlast {
// configure
function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external;
function configure(YieldMode _yield, GasMode gasMode, address governor) external;
// base configuration options
function configureClaimableYield() external;
function configureClaimableYieldOnBehalf(address contractAddress) external;
function configureAutomaticYield() external;
function configureAutomaticYieldOnBehalf(address contractAddress) external;
function configureVoidYield() external;
function configureVoidYieldOnBehalf(address contractAddress) external;
function configureClaimableGas() external;
function configureClaimableGasOnBehalf(address contractAddress) external;
function configureVoidGas() external;
function configureVoidGasOnBehalf(address contractAddress) external;
function configureGovernor(address _governor) external;
function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external;
// claim yield
function claimYield(address contractAddress, address recipientOfYield, uint amount) external returns (uint);
function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint);
// claim gas
function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint);
function claimGasAtMinClaimRate(
address contractAddress,
address recipientOfGas,
uint minClaimRateBips
) external returns (uint);
function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint);
function claimGas(
address contractAddress,
address recipientOfGas,
uint gasToClaim,
uint gasSecondsToConsume
) external returns (uint);
// read functions
function readClaimableYield(address contractAddress) external view returns (uint);
function readYieldConfiguration(address contractAddress) external view returns (uint8);
function readGasParams(
address contractAddress
) external view returns (uint etherSeconds, uint etherBalance, uint lastUpdated, GasMode);
function isGovernor(address contractAddress) external view returns (bool);
function governorNotSet(address contractAddress) external view returns (bool);
function isAuthorized(address contractAddress) external view returns (bool);
}
contract BlastYield {
IBlast public BLAST;
event ClaimYieldAll(address indexed recipient, uint256 amountETH, uint256 amountGas);
function _initializeBlast() internal {
BLAST = IBlast(0x4300000000000000000000000000000000000002);
BLAST.configureClaimableYield();
BLAST.configureClaimableGas();
}
function _claimYieldAll(address _recipient, uint256 _minClaimRateBips) internal {
uint256 amountETH = BLAST.claimAllYield(address(this), _recipient);
uint256 amountGas = _minClaimRateBips == 0
? BLAST.claimMaxGas(address(this), _recipient)
: BLAST.claimGasAtMinClaimRate(address(this), _recipient, _minClaimRateBips);
emit ClaimYieldAll(_recipient, amountETH, amountGas);
}
}// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.20;
pragma experimental ABIEncoderV2;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import { SafeERC20, IERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Auction, AuctionParams, PaymentType, AuctioneerEvents, AuctionExt, NotAuctioneer, InvalidAuctionLot, InvalidRune, AuctionEnded, Invalid, NotCancellable, Unauthorized } from "./IAuctioneer.sol";
import { BlastYield } from "./BlastYield.sol";
import { GBMath, AuctionViewUtils, AuctionMutateUtils, AuctionParamsUtils } from "./AuctionUtils.sol";
// , , , *, , , , *, ,
// , , , , * * ,* , *,, , , .
// . . .* , ,,, * , * ,, ,, *
// , , , , , , ,,** * , * ,, , ,
// * * , ,,,*, * @ , ,, , ,,
// , , * * , ,, ,@,,,, ,, , , * ,
// , * * , , , **,,,@*,*, * *,, * , ,
// , , * , ,*,* ,* ,, , , * @/*/* ,, , , , , , ,
// , * * * * , ,,,, , */*@// * ,,, , , ,, ,
// * ,, ,, , , ,, ** ,/ (*@/(*,, , , , ,
// * *, * , , ,, , , *,,.. ./*/@///,*,,* *,, ,
// , ,*,,* , , ** , ,,,,,*,//(%@&((/,/,.*.*.* ., ., . .
// *, ., ., *,, ., ,* .***/(%@@/@(@@/(/**.*,*,,, . .. ..... . .
// ,,,... ,, * ** , *,,*,,**//@@*(/*@/ /@@//,,*,*, ,,
// *,* *, , , ,, * *,*,*((@@//,//*@/ (@@/*,, , ,
// , * ,* , ,, , *, ***/*@@*/* ***/,@//* *//(*@@** , ,
// , * * , ,,* *, * ,,@@*,*,,*,**,*@*/,* ,,,*//@@ ,,
// ,, ,,,, , , *, ,,,*,,,,@@,,***,,*,@**,*,**,/@@,*, , ,,
// ,* ,,, , , ,, , , , ,,,/*@@***,, @*,,,,*@@,/,*,,,,
// , *,, , , ** , , ,, ,, **,*@@,*/,@,, /@@*/** , ,
// * * *, ,, ,, ** * *,***@@ @*@@*/*,* , , ,
// , * ,, , , , , *, **,**%@&,,,*, , ,
// , *, ,, * , , *,,** ,,@,,, ,, ,
// *, ,* ,* *, ,* , , ,, ,,*,,*,,* @,** ,,
// * ** * * / , ,, , * ,@*, ,*, ,, , ,
// * ,, * ,, , , ** ,**,, , @ * ,
// ,*, * ** ,* ,, * ,, *, ,,@, ,,,* ,
// , /**, , * ,, , @ , , ,
// , /* * / * * * ,*,,, ,* @,, , , , ,
// , ,* ,,* *, , ** ,
// * , *, , ,, , , ,, , ,
// ,, , , , , *
// -- ARCH --
interface IAuctioneerAuction {
function runeSwitchPenalty() external view returns (uint256);
function runicLastBidderBonus() external view returns (uint256);
function updateTreasury(address _treasury) external;
function createAuction(
address _creator,
AuctionParams memory _params,
uint256 _treasuryCut
) external payable returns (uint256 lot);
function cancelAuction(address _creator, uint256 _lot, bool _isAdmin) external;
struct BidData {
address user;
uint8 prevRune;
uint8 newRune;
uint256 existingBidCount;
uint256 arrivingBidCount;
PaymentType paymentType;
}
function bid(
uint256 _lot,
BidData memory _data
) external returns (uint256 userBidsAfterPenalty, uint256 bid, uint256 bidCost);
function selectRune(uint256 _lot, uint256 _userBids, uint8 _prevRune, uint8 _rune) external returns (uint256);
function claimLot(
uint256 _lot,
address _user,
uint256 _userBids,
uint8 _userRune
) external returns (uint256 userShareOfPayment, address creator, uint256 treasuryCut, bool triggerFinalization);
function finalizeAuction(
uint256 _lot
) external returns (bool triggerCancellation, uint256 revenue, address creator, uint256 treasuryCut);
function validateAuctionRunning(uint256 _lot) external view;
function getAuction(uint256 _lot) external view returns (Auction memory auction);
}
contract AuctioneerAuction is
IAuctioneerAuction,
Ownable,
ReentrancyGuard,
AuctioneerEvents,
IERC721Receiver,
BlastYield
{
using GBMath for uint256;
using SafeERC20 for IERC20;
using AuctionParamsUtils for AuctionParams;
using AuctionViewUtils for Auction;
using AuctionMutateUtils for Auction;
using EnumerableSet for EnumerableSet.UintSet;
address public auctioneer;
address public treasury;
address public deadAddress = 0x000000000000000000000000000000000000dEaD;
uint256 public lotCount;
mapping(uint256 => Auction) public auctions;
uint256 public runeSwitchPenalty = 2000;
uint256 public onceTwiceBlastBonusTime = 9;
uint256 public runicLastBidderBonus = 2000;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor(address _auctioneer) Ownable(msg.sender) {
auctioneer = _auctioneer;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
receive() external payable {}
function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) {
return this.onERC721Received.selector;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
modifier onlyAuctioneer() {
if (msg.sender != auctioneer) revert NotAuctioneer();
_;
}
modifier validAuctionLot(uint256 _lot) {
if (_lot >= lotCount) revert InvalidAuctionLot();
_;
}
modifier validRune(uint256 _lot, uint8 _rune) {
if (auctions[_lot].runes.length > 0 && (_rune == 0 || _rune >= auctions[_lot].runes.length))
revert InvalidRune();
if (auctions[_lot].runes.length == 0 && _rune != 0) revert InvalidRune();
_;
}
function validateAuctionRunning(uint256 _lot) external view validAuctionLot(_lot) {
if (auctions[_lot].isEnded()) revert AuctionEnded();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function initializeBlast() external onlyOwner {
_initializeBlast();
}
function claimYieldAll(address _recipient, uint256 _minClaimRateBips) external onlyOwner {
_claimYieldAll(_recipient, _minClaimRateBips);
}
function updateTreasury(address _treasury) external onlyAuctioneer {
treasury = _treasury;
}
function updateRuneSwitchPenalty(uint256 _penalty) external onlyOwner {
if (_penalty > 10000) revert Invalid();
runeSwitchPenalty = _penalty;
emit UpdatedRuneSwitchPenalty(_penalty);
}
function updateRunicLastBidderBonus(uint256 _bonus) external onlyOwner {
if (_bonus > 5000) revert Invalid();
runicLastBidderBonus = _bonus;
emit UpdatedRunicLastBidderBonus(_bonus);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function createAuction(
address _creator,
AuctionParams memory _params,
uint256 _treasuryCut
) external payable onlyAuctioneer returns (uint256 lot) {
_params.validate();
lot = lotCount;
uint256 day = _params.unlockTimestamp / 1 days;
Auction storage auction = auctions[lotCount];
auction.creator = _creator;
auction.lot = lotCount;
auction.day = day;
auction.name = _params.name;
auction.treasuryCut = _treasuryCut;
auction.finalized = false;
auction.initialBlock = block.number;
auction.addRunes(_params);
auction.unlockTimestamp = _params.unlockTimestamp;
auction.addBidWindows(_params, onceTwiceBlastBonusTime);
auction.addRewards(_params);
auction.transferLotFrom(_creator);
auction.bidData.revenue = 0;
auction.bidData.bids = 0;
auction.bidData.bid = _params.startingBid;
auction.bidData.bidTimestamp = _params.unlockTimestamp;
auction.bidData.nextBidBy = auction.getNextBidBy();
auction.bidData.bidCost = _params.bidCost;
auction.bidData.bidIncrement = _params.bidIncrement;
lotCount++;
}
function cancelAuction(
address _canceller,
uint256 _lot,
bool _isAdmin
) external onlyAuctioneer validAuctionLot(_lot) {
Auction storage auction = auctions[_lot];
if (!_isAdmin && auction.creator != _canceller) revert Unauthorized();
if (auction.bidData.bids > 0 || auction.finalized) revert NotCancellable();
auction.transferLotTo(auction.creator, 1e18);
auction.finalized = true;
}
function bid(
uint256 _lot,
BidData memory _data
)
external
onlyAuctioneer
validAuctionLot(_lot)
validRune(_lot, _data.newRune)
returns (uint256 userBidsAfterPenalty, uint256 auctionBid, uint256 auctionBidCost)
{
Auction storage auction = auctions[_lot];
auction.validateBiddingOpen();
auction.bidData.bid += auction.bidData.bidIncrement * _data.arrivingBidCount;
auction.bidData.bids += _data.arrivingBidCount;
auction.bidData.bidUser = _data.user;
auction.bidData.bidTimestamp = block.timestamp;
auction.bidData.nextBidBy = auction.getNextBidBy();
if (_data.paymentType != PaymentType.VOUCHER) {
auction.bidData.revenue += auction.bidData.bidCost * _data.arrivingBidCount;
}
if (auction.runes.length > 0) {
auction.runes[_data.newRune].bids += _data.arrivingBidCount;
auction.bidData.bidRune = _data.newRune;
}
auctionBid = auction.bidData.bid;
auctionBidCost = auction.bidData.bidCost;
userBidsAfterPenalty = _switchRuneUpdateData(_lot, _data.existingBidCount, _data.prevRune, _data.newRune);
}
function selectRune(
uint256 _lot,
uint256 _userBids,
uint8 _prevRune,
uint8 _newRune
) external onlyAuctioneer validAuctionLot(_lot) validRune(_lot, _newRune) returns (uint256 userBidsAfterPenalty) {
if (auctions[_lot].isEnded()) revert AuctionEnded();
if (auctions[_lot].runes.length == 0) revert InvalidRune();
userBidsAfterPenalty = _switchRuneUpdateData(_lot, _userBids, _prevRune, _newRune);
}
function claimLot(
uint256 _lot,
address _user,
uint256 _userBids,
uint8 _userRune
)
external
onlyAuctioneer
validAuctionLot(_lot)
returns (uint256 userShareOfPayment, address creator, uint256 treasuryCut, bool triggerFinalization)
{
Auction storage auction = auctions[_lot];
auction.validateEnded();
auction.validateWinner(_user, _userRune);
bool auctionHasRunes = auction.runes.length > 0;
bool isLastBidder = auction.bidData.bidUser == _user;
uint256 userShareOfLot = 1e18;
if (auctionHasRunes) {
uint256 lastBidderBonusBids = isLastBidder
? auction.runes[_userRune].bids.scaleByBP(runicLastBidderBonus)
: 0;
userShareOfLot =
((_userBids + lastBidderBonusBids) * 1e18) /
auction.runes[_userRune].bids.scaleByBP(10000 + runicLastBidderBonus);
}
auction.transferLotTo(_user, userShareOfLot);
userShareOfPayment = (auction.bidData.bid * userShareOfLot) / 1e18;
creator = auction.creator;
treasuryCut = auction.treasuryCut;
triggerFinalization = !auction.finalized;
}
function finalizeAuction(
uint256 _lot
)
external
onlyAuctioneer
validAuctionLot(_lot)
returns (bool triggerCancellation, uint256 revenue, address creator, uint256 treasuryCut)
{
if (auctions[_lot].finalized) return (false, 0, auctions[_lot].creator, 0);
Auction storage auction = auctions[_lot];
auction.validateEnded();
// If auction ends with 0 bids, cancel it to recover the lot
if (auction.bidData.bids == 0) return (true, 0, auctions[_lot].creator, 0);
auction.finalized = true;
revenue = auction.bidData.revenue;
creator = auction.creator;
treasuryCut = auction.treasuryCut;
triggerCancellation = false;
emit AuctionFinalized(auction.lot);
}
function _switchRuneUpdateData(
uint256 _lot,
uint256 _userBids,
uint8 _prevRune,
uint8 _newRune
) internal returns (uint256 userBidsAfterPenalty) {
if (_userBids == 0) return _userBids;
if (_prevRune == _newRune) return _userBids;
userBidsAfterPenalty = _userBids < 4 ? _userBids : _userBids.scaleByBP(10000 - runeSwitchPenalty);
auctions[_lot].runes[_newRune].bids += userBidsAfterPenalty;
auctions[_lot].bidData.bids = auctions[_lot].bidData.bids + userBidsAfterPenalty - _userBids;
if (_prevRune != 0) {
auctions[_lot].runes[_prevRune].bids -= _userBids;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function getAuction(uint256 _lot) external view validAuctionLot(_lot) returns (Auction memory) {
return auctions[_lot];
}
// TODO: Get live auctions
// function getDailyAuctions(
// uint256 lookBackDays,
// uint256 lookForwardDays
// ) external view returns (DailyAuctions[] memory data) {
// uint256 currentDay = block.timestamp / 1 days;
// uint256[] memory dayLots;
// uint256 day = currentDay - lookBackDays;
// data = new DailyAuctions[](lookBackDays + 1 + lookForwardDays);
// for (uint256 dayIndex = 0; dayIndex < (lookBackDays + 1 + lookForwardDays); dayIndex++) {
// dayLots = auctionsOnDay[day].values();
// data[dayIndex].day = day;
// data[dayIndex].lots = new uint256[](dayLots.length);
// for (uint256 dayLotIndex = 0; dayLotIndex < dayLots.length; dayLotIndex++) {
// data[dayIndex].lots[dayLotIndex] = dayLots[dayLotIndex];
// }
// day++;
// }
// }
function getAuctionExt(
uint256 _lot
) external view validAuctionLot(_lot) returns (Auction memory auction, AuctionExt memory ext) {
auction = auctions[_lot];
ext = AuctionExt({
lot: auction.lot,
blockTimestamp: block.timestamp,
activeWindow: auctions[_lot].activeWindow(),
isBiddingOpen: auctions[_lot].isBiddingOpen(),
isEnded: auctions[_lot].isEnded()
});
}
function getAuctionExts(
uint256[] memory _lots
) external view returns (Auction[] memory auctionBases, AuctionExt[] memory auctionExts) {
auctionBases = new Auction[](_lots.length);
auctionExts = new AuctionExt[](_lots.length);
uint256 lot;
for (uint256 i = 0; i < _lots.length; i++) {
lot = _lots[i];
auctionBases[i] = auctions[lot];
auctionExts[i] = AuctionExt({
lot: lot,
blockTimestamp: block.timestamp,
activeWindow: auctions[lot].activeWindow(),
isBiddingOpen: auctions[lot].isBiddingOpen(),
isEnded: auctions[lot].isEnded()
});
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./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);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)
pragma solidity ^0.8.20;
import {ERC20} from "../ERC20.sol";
import {Context} from "../../../utils/Context.sol";
/**
* @dev Extension of {ERC20} that allows token holders to destroy both their own
* tokens and those that they have an allowance for, in a way that can be
* recognized off-chain (via event analysis).
*/
abstract contract ERC20Burnable is Context, ERC20 {
/**
* @dev Destroys a `value` amount of tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 value) public virtual {
_burn(_msgSender(), value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, deducting from
* the caller's allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `value`.
*/
function burnFrom(address account, uint256 value) public virtual {
_spendAllowance(account, _msgSender(), value);
_burn(account, value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Pausable.sol)
pragma solidity ^0.8.20;
import {ERC20} from "../ERC20.sol";
import {Pausable} from "../../../utils/Pausable.sol";
/**
* @dev ERC20 token with pausable token transfers, minting and burning.
*
* Useful for scenarios such as preventing trades until the end of an evaluation
* period, or having an emergency switch for freezing all token transfers in the
* event of a large bug.
*
* IMPORTANT: This contract does not include public pause and unpause functions. In
* addition to inheriting this contract, you must define both functions, invoking the
* {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
* access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
* make the contract pause mechanism of the contract unreachable, and thus unusable.
*/
abstract contract ERC20Pausable is ERC20, Pausable {
/**
* @dev See {ERC20-_update}.
*
* Requirements:
*
* - the contract must not be paused.
*/
function _update(address from, address to, uint256 value) internal virtual override whenNotPaused {
super._update(from, to, value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../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 address zero.
*
* 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 v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @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 v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
bool private _paused;
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
/**
* @dev The operation failed because the contract is paused.
*/
error EnforcedPause();
/**
* @dev The operation failed because the contract is not paused.
*/
error ExpectedPause();
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
_requireNotPaused();
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
_requirePaused();
_;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Throws if the contract is paused.
*/
function _requireNotPaused() internal view virtual {
if (paused()) {
revert EnforcedPause();
}
}
/**
* @dev Throws if the contract is not paused.
*/
function _requirePaused() internal view virtual {
if (!paused()) {
revert ExpectedPause();
}
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}{
"remappings": [
"@openzeppelin/=lib/openzeppelin-contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std/=lib/forge-std/src/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IERC20","name":"_voucher","type":"address"},{"internalType":"contract IWETH","name":"_weth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"AliasTaken","type":"error"},{"inputs":[],"name":"AlreadyLinked","type":"error"},{"inputs":[],"name":"ETHTransferFailed","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"IncorrectETHPaymentAmount","type":"error"},{"inputs":[],"name":"Invalid","type":"error"},{"inputs":[],"name":"InvalidAlias","type":"error"},{"inputs":[],"name":"InvalidBidCount","type":"error"},{"inputs":[],"name":"Muted","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SentETHButNotWalletPayment","type":"error"},{"inputs":[],"name":"TreasuryNotSet","type":"error"},{"inputs":[],"name":"UserAlreadyClaimedLot","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_canceller","type":"address"},{"indexed":true,"internalType":"uint256","name":"_lot","type":"uint256"}],"name":"AuctionCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_creator","type":"address"},{"indexed":true,"internalType":"uint256","name":"_lot","type":"uint256"}],"name":"AuctionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_lot","type":"uint256"}],"name":"AuctionFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_lot","type":"uint256"},{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"string","name":"_message","type":"string"},{"indexed":false,"internalType":"string","name":"_alias","type":"string"},{"indexed":false,"internalType":"uint8","name":"_rune","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"_prevRune","type":"uint8"},{"indexed":false,"internalType":"uint256","name":"_bid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_bidCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_timestamp","type":"uint256"}],"name":"Bid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amountETH","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountGas","type":"uint256"}],"name":"ClaimYieldAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_lot","type":"uint256"},{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"string","name":"_message","type":"string"},{"indexed":false,"internalType":"string","name":"_alias","type":"string"},{"indexed":false,"internalType":"uint8","name":"_rune","type":"uint8"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_auctioneer","type":"address"},{"indexed":false,"internalType":"address","name":"_auctioneerAuction","type":"address"}],"name":"Linked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_lot","type":"uint256"},{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"string","name":"_message","type":"string"},{"indexed":false,"internalType":"string","name":"_alias","type":"string"},{"indexed":false,"internalType":"uint8","name":"_rune","type":"uint8"}],"name":"Messaged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"bool","name":"_muted","type":"bool"}],"name":"MutedUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"_lot","type":"uint256"},{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"string","name":"_message","type":"string"},{"indexed":false,"internalType":"string","name":"_alias","type":"string"},{"indexed":false,"internalType":"uint8","name":"_rune","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"_prevRune","type":"uint8"}],"name":"SelectedRune","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"string","name":"_alias","type":"string"}],"name":"UpdatedAlias","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"_required","type":"bool"}],"name":"UpdatedCreateAuctionRequiresRole","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_penalty","type":"uint256"}],"name":"UpdatedRuneSwitchPenalty","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_bonus","type":"uint256"}],"name":"UpdatedRunicLastBidderBonus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_treasury","type":"address"}],"name":"UpdatedTreasury","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_treasuryCut","type":"uint256"}],"name":"UpdatedTreasuryCut","type":"event"},{"inputs":[],"name":"BLAST","outputs":[{"internalType":"contract IBlast","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CREATOR_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MOD_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOUCHER","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"aliasUser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"auctionUsers","outputs":[{"internalType":"uint256","name":"bids","type":"uint256"},{"internalType":"uint8","name":"rune","type":"uint8"},{"internalType":"bool","name":"lotClaimed","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"auctioneerAuction","outputs":[{"internalType":"contract IAuctioneerAuction","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lot","type":"uint256"},{"internalType":"uint8","name":"_rune","type":"uint8"},{"internalType":"string","name":"_message","type":"string"},{"internalType":"uint256","name":"_bidCount","type":"uint256"},{"internalType":"enum PaymentType","name":"_paymentType","type":"uint8"}],"name":"bid","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lot","type":"uint256"},{"internalType":"uint8","name":"_rune","type":"uint8"},{"internalType":"string","name":"_message","type":"string"},{"internalType":"uint256","name":"_bidCount","type":"uint256"},{"internalType":"enum PaymentType","name":"_paymentType","type":"uint8"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"value","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"}],"internalType":"struct PermitData","name":"_permitData","type":"tuple"}],"name":"bidWithPermit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lot","type":"uint256"}],"name":"cancelAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lot","type":"uint256"},{"internalType":"string","name":"_message","type":"string"}],"name":"claimLot","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_minClaimRateBips","type":"uint256"}],"name":"claimYieldAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"bidCost","type":"uint256"},{"internalType":"uint256","name":"bidIncrement","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"nft","type":"address"}],"internalType":"struct NftData[]","name":"nfts","type":"tuple[]"},{"internalType":"uint8[]","name":"runeSymbols","type":"uint8[]"},{"internalType":"uint256","name":"startingBid","type":"uint256"},{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"token","type":"address"}],"internalType":"struct TokenData[]","name":"tokens","type":"tuple[]"},{"internalType":"uint256","name":"unlockTimestamp","type":"uint256"},{"components":[{"internalType":"uint256","name":"duration","type":"uint256"},{"internalType":"uint256","name":"timer","type":"uint256"},{"internalType":"enum BidWindowType","name":"windowType","type":"uint8"}],"internalType":"struct BidWindowParams[]","name":"windows","type":"tuple[]"}],"internalType":"struct AuctionParams","name":"_param","type":"tuple"}],"name":"createAuction","outputs":[{"internalType":"uint256","name":"lot","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"createAuctionRequiresRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deadAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lot","type":"uint256"}],"name":"finalizeAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getActiveLots","outputs":[{"internalType":"uint256[]","name":"lots","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lot","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getAliasAndRune","outputs":[{"internalType":"uint8","name":"rune","type":"uint8"},{"internalType":"string","name":"_alias","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lot","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getAuctionUser","outputs":[{"components":[{"internalType":"uint256","name":"bids","type":"uint256"},{"internalType":"uint8","name":"rune","type":"uint8"},{"internalType":"bool","name":"lotClaimed","type":"bool"}],"internalType":"struct AuctionUser","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_lots","type":"uint256[]"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserLotInfos","outputs":[{"components":[{"internalType":"uint256","name":"lot","type":"uint256"},{"internalType":"uint8","name":"rune","type":"uint8"},{"components":[{"internalType":"uint256","name":"user","type":"uint256"},{"internalType":"uint256","name":"rune","type":"uint256"},{"internalType":"uint256","name":"auction","type":"uint256"}],"internalType":"struct BidCounts","name":"bidCounts","type":"tuple"},{"internalType":"bool","name":"isWinner","type":"bool"},{"internalType":"bool","name":"lotClaimed","type":"bool"},{"internalType":"uint256","name":"shareOfLot","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"}],"internalType":"struct UserLotInfo[]","name":"infos","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"getUserParticipatedAuctions","outputs":[{"internalType":"uint256[]","name":"lots","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initializeBlast","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_auctioneerAuction","type":"address"}],"name":"link","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lot","type":"uint256"},{"internalType":"string","name":"_message","type":"string"}],"name":"messageAuction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"bool","name":"_muted","type":"bool"}],"name":"muteUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mutedUsers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lot","type":"uint256"},{"internalType":"uint8","name":"_rune","type":"uint8"},{"internalType":"string","name":"_message","type":"string"}],"name":"selectRune","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_alias","type":"string"}],"name":"setAlias","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_required","type":"bool"}],"name":"setCreateAuctionRequiresRole","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":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"treasuryCut","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"updateTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_treasuryCut","type":"uint256"}],"name":"updateTreasuryCut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userAlias","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6080604052600780546001600160a01b03191661dead179055600e805460ff191660011790553480156200003257600080fd5b506040516200453e3803806200453e8339810160408190526200005591620001bb565b6001805562000066600033620000f3565b50620000937f950b8f2d7415defaee398bb4898e8e094a64c725873b81952b7ab9f08d70efb333620000f3565b50620000c07f828634d95e775031b9ff576b159a8509d3053581a8c9c4d7d86899e0afcd882f33620000f3565b50600380546001600160a01b039384166001600160a01b03199182161790915560048054929093169116179055620001fa565b6000828152602081815260408083206001600160a01b038516845290915281205460ff1662000198576000838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556200014f3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45060016200019c565b5060005b92915050565b6001600160a01b0381168114620001b857600080fd5b50565b60008060408385031215620001cf57600080fd5b8251620001dc81620001a2565b6020840151909250620001ef81620001a2565b809150509250929050565b614334806200020a6000396000f3fe6080604052600436106102555760003560e01c806391d1485411610139578063bf1a84dd116100b6578063db288f9f1161007a578063db288f9f146107de578063ddd0c960146107fe578063e803f8101461081e578063e808386314610888578063e932406f146108a8578063ec90dbc3146108dc57600080fd5b8063bf1a84dd146106ad578063c95a9139146106cd578063ce329ff3146106fb578063d547741f146107a9578063d8735768146107c957600080fd5b8063ad5c4648116100fd578063ad5c4648146105f1578063afaea6bd14610611578063afdeafb41461063e578063bd9ff32b1461066b578063be12d2ae1461069857600080fd5b806391d148541461053b57806396b5a7551461055b57806397d757761461057b578063a217fddf1461059b578063a6002132146105b057600080fd5b806346397a45116101d25780636a293d04116101965780636a293d041461047e578063746922d61461049e5780637f51bb1f146104b457806383c9d03f146104d45780638aeda25a146104e757806391a897121461051b57600080fd5b806346397a45146103eb5780634918cf6a1461040b578063561ce98c1461042b578063580664e71461043e57806361d027b31461045e57600080fd5b806327c8f8351161021957806327c8f83514610346578063283b914b1461037e5780632f2ff15d1461039157806336568abe146103b1578063406fcc63146103d157600080fd5b806301ffc9a71461026157806313ef73a31461029657806315ea9962146102b85780631ca339dd146102e6578063248a9ca31461031657600080fd5b3661025c57005b600080fd5b34801561026d57600080fd5b5061028161027c366004612c92565b6108fc565b60405190151581526020015b60405180910390f35b3480156102a257600080fd5b506102b66102b1366004612cbc565b610933565b005b3480156102c457600080fd5b506102d86102d336600461305f565b61099c565b60405190815260200161028d565b3480156102f257600080fd5b50610281610301366004613188565b600d6020526000908152604090205460ff1681565b34801561032257600080fd5b506102d8610331366004612cbc565b60009081526020819052604090206001015490565b34801561035257600080fd5b50600754610366906001600160a01b031681565b6040516001600160a01b03909116815260200161028d565b6102b661038c3660046131ed565b610bdb565b34801561039d57600080fd5b506102b66103ac366004613238565b610ddd565b3480156103bd57600080fd5b506102b66103cc366004613238565b610e08565b3480156103dd57600080fd5b50600e546102819060ff1681565b3480156103f757600080fd5b506102b6610406366004613276565b610e3b565b34801561041757600080fd5b50600354610366906001600160a01b031681565b6102b66104393660046132a2565b610e86565b34801561044a57600080fd5b50600854610366906001600160a01b031681565b34801561046a57600080fd5b50600554610366906001600160a01b031681565b34801561048a57600080fd5b506102b661049936600461338b565b610eb7565b3480156104aa57600080fd5b506102d860065481565b3480156104c057600080fd5b506102b66104cf366004613188565b61105a565b6102b66104e23660046133c7565b611138565b3480156104f357600080fd5b506102d87f828634d95e775031b9ff576b159a8509d3053581a8c9c4d7d86899e0afcd882f81565b34801561052757600080fd5b506102b6610536366004613188565b611179565b34801561054757600080fd5b50610281610556366004613238565b61122a565b34801561056757600080fd5b506102b6610576366004612cbc565b611253565b34801561058757600080fd5b50600254610366906001600160a01b031681565b3480156105a757600080fd5b506102d8600081565b3480156105bc57600080fd5b506103666105cb36600461338b565b8051602081830181018051600c825292820191909301209152546001600160a01b031681565b3480156105fd57600080fd5b50600454610366906001600160a01b031681565b34801561061d57600080fd5b5061063161062c36600461343e565b61126c565b60405161028d91906134e0565b34801561064a57600080fd5b5061065e610659366004613188565b611805565b60405161028d91906135e7565b34801561067757600080fd5b5061068b610686366004613188565b61189f565b60405161028d91906135fa565b3480156106a457600080fd5b506102b661196d565b3480156106b957600080fd5b506102b66106c836600461363e565b611981565b3480156106d957600080fd5b506106ed6106e8366004613238565b611b0c565b60405161028d929190613699565b34801561070757600080fd5b50610782610716366004613238565b604080516060808201835260008083526020808401829052928401819052948552600982528285206001600160a01b039490941685529281529281902081519283018252805483526001015460ff80821694840194909452610100900490921615159181019190915290565b604080518251815260208084015160ff16908201529181015115159082015260600161028d565b3480156107b557600080fd5b506102b66107c4366004613238565b611bd6565b3480156107d557600080fd5b5061068b611bfb565b3480156107ea57600080fd5b506102b66107f93660046136b5565b611c99565b34801561080a57600080fd5b506102b66108193660046136e3565b611d98565b34801561082a57600080fd5b50610869610839366004613238565b60096020908152600092835260408084209091529082529020805460019091015460ff8082169161010090041683565b6040805193845260ff909216602084015215159082015260600161028d565b34801561089457600080fd5b506102b66108a3366004612cbc565b611dac565b3480156108b457600080fd5b506102d87f950b8f2d7415defaee398bb4898e8e094a64c725873b81952b7ab9f08d70efb381565b3480156108e857600080fd5b506102b66108f736600461370f565b611dc6565b60006001600160e01b03198216637965db0b60e01b148061092d57506301ffc9a760e01b6001600160e01b03198316145b92915050565b61093d6000611ed0565b6107d081111561096057604051636dac6a0960e01b815260040160405180910390fd5b60068190556040518181527f80fcaeb6b7053a53b9ad01b2961d826e0461582d34e279c402b914f87b34c152906020015b60405180910390a150565b60006109a6611eda565b6005546001600160a01b03166109cf5760405163b2c4cce960e01b815260040160405180910390fd5b600e5460ff1615610a0357610a037f828634d95e775031b9ff576b159a8509d3053581a8c9c4d7d86899e0afcd882f611ed0565b6000805b8360c00151518160ff161015610a9a5760006001600160a01b03168460c001518260ff1681518110610a3b57610a3b613755565b6020026020010151602001516001600160a01b031603610a88578360c001518160ff1681518110610a6e57610a6e613755565b60200260200101516000015182610a859190613781565b91505b80610a9281613794565b915050610a07565b508015610b1657600454610ab9906001600160a01b0316333084611f04565b60048054604051632e1a7d4d60e01b81529182018390526001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610afd57600080fd5b505af1158015610b11573d6000803e3d6000fd5b505050505b60085460065460405163573e74d160e11b81526001600160a01b039092169163ae7ce9a2918491610b4e9133918991906004016138a1565b60206040518083038185885af1158015610b6c573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610b919190613985565b9150610b9e600f83611f5e565b50604051829033907f3249a06bd478adf780bb7930214ad005e9cfa517d63221c0b77f27199d1a58b390600090a350610bd660018055565b919050565b610be3611eda565b600083815260096020908152604080832033845290915290206001810154610100900460ff1615610c2757604051638a1ce94d60e01b815260040160405180910390fd5b60018101805461010061ff00198216179091556008548254604051633044143960e01b815260048101889052336024820152604481019190915260ff90921660648301526000918291829182916001600160a01b0316906330441439906084016080604051808303816000875af1158015610ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cca91906139b4565b9350935093509350610ce0336000866000611f71565b610ceb848484612006565b336000908152600a60205260409020610d049089612118565b508015610d1457610d1488612124565b336000818152600d602052604090205489907f7b0b98081002edd6afba673b65400fe98ed56ff907a5860e5b3c1ad702997b579060ff16610d8b5789898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610d9c92505050565b604051806020016040528060008152505b336000908152600b60205260409081902060018b01549151610dc2939260ff1690613ab6565b60405180910390a35050505050610dd860018055565b505050565b600082815260208190526040902060010154610df881611ed0565b610e0283836121ca565b50505050565b6001600160a01b0381163314610e315760405163334bd91960e11b815260040160405180910390fd5b610dd8828261225c565b610e456000611ed0565b600e805460ff19168215159081179091556040519081527f3fcd4dd73af3f4558ad8923f15846d2e59c211916f64fbec32ac7e5ed1128db290602001610991565b610e8e611eda565b610e97816122c7565b610ea5878787878787612360565b610eae60018055565b50505050505050565b610ebf611eda565b336000908152600d602052604090205460ff1615610ef057604051639b545b7360e01b815260040160405180910390fd5b600381511080610f01575060098151115b15610f1f5760405163071be59b60e01b815260040160405180910390fd5b60006001600160a01b0316600c82604051610f3a9190613aef565b908152604051908190036020019020546001600160a01b031614610f7157604051631af3778960e31b815260040160405180910390fd5b336000908152600b60205260408082209051600c91610f8f91613b0b565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039490941693909317909255336000908152600b90915220610fd58282613bc7565b5033600c82604051610fe79190613aef565b90815260405190819003602001812080546001600160a01b03939093166001600160a01b03199093169290921790915533907f90fd02fbcbd067a1c26b1397ddd9e406682052c502c5ee222e8b7b26035def25906110469084906135e7565b60405180910390a261105760018055565b50565b6110646000611ed0565b6001600160a01b03811661108b5760405163d92e233d60e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b03838116918217909255600854604051637f51bb1f60e01b8152600481019290925290911690637f51bb1f90602401600060405180830381600087803b1580156110e957600080fd5b505af11580156110fd573d6000803e3d6000fd5b50506040516001600160a01b03841692507fa6df481f77da1f4c92eb330341e03585d46106fcf522f8e6b6b2afbea56eefdc9150600090a250565b611140611eda565b61114e868686868686612360565b336000908152600a602052604090206111679087611f5e565b5061117160018055565b505050505050565b6111836000611ed0565b6001600160a01b0381166111aa5760405163d92e233d60e01b815260040160405180910390fd5b6008546001600160a01b0316156111d457604051635fb2b52360e11b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b03831690811790915560405190815230907f5febe1b9e375a634d9d565149e636879057714c557b8c78aab7cccae8cf48e489060200160405180910390a250565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b61125d3382612590565b611268600f82612118565b5050565b606082516001600160401b0381111561128757611287612cd5565b6040519080825280602002602001820160405280156112c057816020015b6112ad612c30565b8152602001906001900390816112a55790505b5090506000805b84518110156117fd578481815181106112e2576112e2613755565b60209081029190910101516008546040516378bd793560e01b8152600481018390529193506000916001600160a01b03909116906378bd793590602401600060405180830381865afa15801561133c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113649190810190613fa2565b90506000600860009054906101000a90046001600160a01b03166001600160a01b03166391c578756040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113df9190613985565b60008581526009602090815260408083206001600160a01b038b16845282529182902082516060810184528154815260019091015460ff80821683850152610100918290041615159382019390935260a0860151519286015160c001519186015189519495509093921515929115159189908890811061146157611461613755565b60200260200101516000018181525050826020015188878151811061148857611488613755565b60209081029190910181015160ff909216910152825188518990889081106114b2576114b2613755565b602090810291909101015160400151528115806114d45750602083015160ff16155b611506578460a00151836020015160ff16815181106114f5576114f5613755565b602002602001015160200151611509565b60005b88878151811061151b5761151b613755565b602002602001015160400151602001818152505084610100015160c0015188878151811061154b5761154b613755565b602090810291909101015160409081015101528251158015906115b0575060008560a00151511161159957846101000151608001516001600160a01b0316896001600160a01b0316146115b0565b84610100015160a0015160ff16836020015160ff16145b8887815181106115c2576115c2613755565b6020026020010151606001901515908115158152505082604001518887815181106115ef576115ef613755565b602090810291909101015190151560809182015261010086015101516001600160a01b038a811691161460008180156116255750835b61163057600061166b565b61166b868860a00151876020015160ff168151811061165157611651613755565b60200260200101516020015161265090919063ffffffff16565b90508280156116775750835b80156116ab575060008760a00151866020015160ff168151811061169d5761169d613755565b602002602001015160200151115b1561172c576116dc6116bf87612710613781565b8860a00151876020015160ff168151811061165157611651613755565b85516116e9908390613781565b6116fb90670de0b6b3a76400006140eb565b6117059190614102565b8a898151811061171757611717613755565b602002602001015160a001818152505061177c565b828015611737575083155b1561175757670de0b6b3a76400008a898151811061171757611717613755565b60008a898151811061176b5761176b613755565b602002602001015160a00181815250505b670de0b6b3a76400008a898151811061179757611797613755565b602002602001015160a00151886101000151602001516117b791906140eb565b6117c19190614102565b8a89815181106117d3576117d3613755565b602002602001015160c00181815250505050505050505080806117f590614124565b9150506112c7565b505092915050565b600b602052600090815260409020805461181e906139ff565b80601f016020809104026020016040519081016040528092919081815260200182805461184a906139ff565b80156118975780601f1061186c57610100808354040283529160200191611897565b820191906000526020600020905b81548152906001019060200180831161187a57829003601f168201915b505050505081565b6001600160a01b0381166000908152600a60205260408120606091906118c490612679565b9050806001600160401b038111156118de576118de612cd5565b604051908082528060200260200182016040528015611907578160200160208202803683370190505b50915060005b81811015611966576001600160a01b0384166000908152600a602052604090206119379082612683565b83828151811061194957611949613755565b60209081029190910101528061195e81614124565b91505061190d565b5050919050565b6119776000611ed0565b61197f61268f565b565b611989611eda565b600084815260096020908152604080832033845290915290819020600854815460018301549351633f83441560e01b815260048101899052602481019190915260ff9384166044820152928616606484015290916001600160a01b0390911690633f834415906084016020604051808303816000875af1158015611a11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a359190613985565b815560018101805460ff86811660ff19831617909255336000818152600d602052604090205491831692909188917fe887c12401d1218764994b5ed2143e6d0c23ab88b3d47e18a99ed4164b8e2c649116611ac65786868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611ad792505050565b604051806020016040528060008152505b336000908152600b6020526040908190209051611af99291908b90889061413d565b60405180910390a35050610e0260018055565b60008281526009602090815260408083206001600160a01b0385168452825280832060010154600b909252909120805460ff9092169160609190611b4f906139ff565b80601f0160208091040260200160405190810160405280929190818152602001828054611b7b906139ff565b8015611bc85780601f10611b9d57610100808354040283529160200191611bc8565b820191906000526020600020905b815481529060010190602001808311611bab57829003601f168201915b505050505090509250929050565b600082815260208190526040902060010154611bf181611ed0565b610e02838361225c565b60606000611c09600f612679565b9050806001600160401b03811115611c2357611c23612cd5565b604051908082528060200260200182016040528015611c4c578160200160208202803683370190505b50915060005b81811015611c9457611c65600f82612683565b838281518110611c7757611c77613755565b602090810291909101015280611c8c81614124565b915050611c52565b505090565b7f950b8f2d7415defaee398bb4898e8e094a64c725873b81952b7ab9f08d70efb3611cc381611ed0565b6001600160a01b0383166000908152600d60209081526040808320805460ff1916861515179055600b9091528082209051600c91611d0091613b0b565b908152604080516020928190038301812080546001600160a01b0319166001600160a01b03958616179055828101825260008082529387168452600b90925290912090611d4d9082613bc7565b50826001600160a01b03167ff43f03272568f314d919decd0ce22ee579a44c1754101b036edee97edb067cdf83604051611d8b911515815260200190565b60405180910390a2505050565b611da26000611ed0565b611268828261275e565b611db4611eda565b611dbd81612124565b61105760018055565b611dce611eda565b336000908152600d602052604090205460ff1615611dff57604051639b545b7360e01b815260040160405180910390fd5b6008546040516357a9855560e01b8152600481018490526001600160a01b03909116906357a985559060240160006040518083038186803b158015611e4357600080fd5b505afa158015611e57573d6000803e3d6000fd5b5050336000818152600b6020908152604080832088845260098352818420858552909252918290206001015491519294508693507f513343dc7568bca122edc0a7dff37f2707f3df31d4e985c69cef736af6d18edd92611ebf9287929160ff90911690613ab6565b60405180910390a361126860018055565b6110578133612924565b600260015403611efd57604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610e02908590612962565b6000611f6a83836129c5565b9392505050565b6000836001811115611f8557611f85613835565b03611faf57813414611faa57604051634e03ebdd60e01b815260040160405180910390fd5b611fce565b3415611fce57604051630cd5039560e21b815260040160405180910390fd5b6001836001811115611fe257611fe2613835565b03610e0257600754600354610e02916001600160a01b039182169187911684611f04565b8260000361201357505050565b600061201f8483612650565b6005546040519192506000916001600160a01b039091169083908381818185875af1925050503d8060008114612071576040519150601f19603f3d011682016040523d82523d6000602084013e612076565b606091505b50509050806120985760405163b12d13eb60e01b815260040160405180910390fd5b6001600160a01b0384166120ac8387614180565b604051600081818185875af1925050503d80600081146120e8576040519150601f19603f3d011682016040523d82523d6000602084013e6120ed565b606091505b505080915050806121115760405163b12d13eb60e01b815260040160405180910390fd5b5050505050565b6000611f6a8383612a0c565b60085460405163e808386360e01b8152600481018390526000918291829182916001600160a01b039091169063e8083863906024016080604051808303816000875af1158015612178573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061219c9190614193565b935093509350935083156121b4576121b48286612590565b6121bf838383612006565b611171600f86612118565b60006121d6838361122a565b612254576000838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561220c3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161092d565b50600061092d565b6000612268838361122a565b15612254576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161092d565b805160208201516040808401516060850151608086015160a0870151935163d505accf60e01b81523360048201523060248201526044810195909552606485019290925260ff16608484015260a483015260c48201526001600160a01b039091169063d505accf9060e401600060405180830381600087803b15801561234c57600080fd5b505af1158015612111573d6000803e3d6000fd5b816001146123815760405163e318e67360e01b815260040160405180910390fd5b600086815260096020908152604080832033808552908352818420600854835160c08101855292835260018083015460ff90811696850196909652948b169383019390935280546060830152608082018790529392839283926001600160a01b039091169163466f174a918d9160a08201908a9081111561240457612404613835565b8152506040518363ffffffff1660e01b81526004016124249291906141dc565b6060604051808303816000875af1158015612443573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124679190614247565b60018701805460ff8e811660ff1983161790925593965091945092501661248e8785613781565b85556124b6338761249f8a866140eb565b6124b18b670de0b6b3a76400006140eb565b611f71565b336000818152600d60205260409020548c907fc5658d374977ba82a6583515e5a13a9345ae28df457a0b8447642110684245389060ff1661252d578b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061253e92505050565b604051806020016040528060008152505b600b6000336001600160a01b03166001600160a01b031681526020019081526020016000208e86898e4260405161257b9796959493929190614275565b60405180910390a35050505050505050505050565b6008546001600160a01b031663dca80c1983836125ae60008361122a565b6040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915215156044820152606401600060405180830381600087803b1580156125fe57600080fd5b505af1158015612612573d6000803e3d6000fd5b50506040518392506001600160a01b03851691507f018b64b6242d32aa550e95d78985b938d71af5b3f10827b0683f55da1639304890600090a35050565b6000816127100361266257508161092d565b61271061266f83856140eb565b611f6a9190614102565b600061092d825490565b6000611f6a8383612aff565b600280546001600160a01b0319166002604360981b019081179091556040805163784c3b3d60e11b8152905163f098767a9160048082019260009290919082900301818387803b1580156126e257600080fd5b505af11580156126f6573d6000803e3d6000fd5b50505050600260009054906101000a90046001600160a01b03166001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561274a57600080fd5b505af1158015610e02573d6000803e3d6000fd5b60025460405163430021db60e11b81523060048201526001600160a01b038481166024830152600092169063860043b6906044016020604051808303816000875af11580156127b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d59190613985565b90506000821561286157600254604051630951888f60e01b81523060048201526001600160a01b0386811660248301526044820186905290911690630951888f906064016020604051808303816000875af1158015612838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061285c9190613985565b6128d7565b60025460405163662aa11d60e01b81523060048201526001600160a01b0386811660248301529091169063662aa11d906044016020604051808303816000875af11580156128b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d79190613985565b60408051848152602081018390529192506001600160a01b038616917f19f76cb54ee84067ebfd4c9afacfcc412d9e2e1d9026f4ce6f2ec7764f16e1b7910160405180910390a250505050565b61292e828261122a565b6112685760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044015b60405180910390fd5b60006129776001600160a01b03841683612b29565b9050805160001415801561299c57508080602001905181019061299a91906142cb565b155b15610dd857604051635274afe760e01b81526001600160a01b0384166004820152602401612959565b60008181526001830160205260408120546122545750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561092d565b60008181526001830160205260408120548015612af5576000612a30600183614180565b8554909150600090612a4490600190614180565b9050808214612aa9576000866000018281548110612a6457612a64613755565b9060005260206000200154905080876000018481548110612a8757612a87613755565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612aba57612aba6142e8565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061092d565b600091505061092d565b6000826000018281548110612b1657612b16613755565b9060005260206000200154905092915050565b6060611f6a8383600084600080856001600160a01b03168486604051612b4f9190613aef565b60006040518083038185875af1925050503d8060008114612b8c576040519150601f19603f3d011682016040523d82523d6000602084013e612b91565b606091505b5091509150612ba1868383612bab565b9695505050505050565b606082612bc057612bbb82612c07565b611f6a565b8151158015612bd757506001600160a01b0384163b155b15612c0057604051639996b31560e01b81526001600160a01b0385166004820152602401612959565b5080611f6a565b805115612c175780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040518060e0016040528060008152602001600060ff168152602001612c7060405180606001604052806000815260200160008152602001600081525090565b8152600060208201819052604082018190526060820181905260809091015290565b600060208284031215612ca457600080fd5b81356001600160e01b031981168114611f6a57600080fd5b600060208284031215612cce57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612d0d57612d0d612cd5565b60405290565b604051606081016001600160401b0381118282101715612d0d57612d0d612cd5565b60405161012081016001600160401b0381118282101715612d0d57612d0d612cd5565b60405160c081016001600160401b0381118282101715612d0d57612d0d612cd5565b604051608081016001600160401b0381118282101715612d0d57612d0d612cd5565b60405161018081016001600160401b0381118282101715612d0d57612d0d612cd5565b604051601f8201601f191681016001600160401b0381118282101715612de757612de7612cd5565b604052919050565b60006001600160401b03821115612e0857612e08612cd5565b50601f01601f191660200190565b600082601f830112612e2757600080fd5b8135612e3a612e3582612def565b612dbf565b818152846020838601011115612e4f57600080fd5b816020850160208301376000918101602001919091529392505050565b60006001600160401b03821115612e8557612e85612cd5565b5060051b60200190565b6001600160a01b038116811461105757600080fd5b8035610bd681612e8f565b600082601f830112612ec057600080fd5b81356020612ed0612e3583612e6c565b82815260069290921b84018101918181019086841115612eef57600080fd5b8286015b84811015612f375760408189031215612f0c5760008081fd5b612f14612ceb565b8135815284820135612f2581612e8f565b81860152835291830191604001612ef3565b509695505050505050565b60ff8116811461105757600080fd5b600082601f830112612f6257600080fd5b81356020612f72612e3583612e6c565b82815260059290921b84018101918181019086841115612f9157600080fd5b8286015b84811015612f37578035612fa881612f42565b8352918301918301612f95565b6003811061105757600080fd5b600082601f830112612fd357600080fd5b81356020612fe3612e3583612e6c565b8281526060928302850182019282820191908785111561300257600080fd5b8387015b858110156130525781818a03121561301e5760008081fd5b613026612d13565b81358152858201358682015260408083013561304181612fb5565b908201528452928401928101613006565b5090979650505050505050565b60006020828403121561307157600080fd5b81356001600160401b038082111561308857600080fd5b90830190610120828603121561309d57600080fd5b6130a5612d35565b82358152602083013560208201526040830135828111156130c557600080fd5b6130d187828601612e16565b6040830152506060830135828111156130e957600080fd5b6130f587828601612eaf565b60608301525060808301358281111561310d57600080fd5b61311987828601612f51565b60808301525060a083013560a082015260c08301358281111561313b57600080fd5b61314787828601612eaf565b60c08301525060e083013560e0820152610100808401358381111561316b57600080fd5b61317788828701612fc2565b918301919091525095945050505050565b60006020828403121561319a57600080fd5b8135611f6a81612e8f565b60008083601f8401126131b757600080fd5b5081356001600160401b038111156131ce57600080fd5b6020830191508360208285010111156131e657600080fd5b9250929050565b60008060006040848603121561320257600080fd5b8335925060208401356001600160401b0381111561321f57600080fd5b61322b868287016131a5565b9497909650939450505050565b6000806040838503121561324b57600080fd5b82359150602083013561325d81612e8f565b809150509250929050565b801515811461105757600080fd5b60006020828403121561328857600080fd5b8135611f6a81613268565b803560028110610bd657600080fd5b60008060008060008060008789036101608112156132bf57600080fd5b8835975060208901356132d181612f42565b965060408901356001600160401b038111156132ec57600080fd5b6132f88b828c016131a5565b9097509550506060890135935061331160808a01613293565b925060c0609f198201121561332557600080fd5b5061332e612d58565b60a089013561333c81612e8f565b815260c0890135602082015260e0890135604082015261010089013561336181612f42565b606082015261012089013560808201526101409098013560a0890152509497939650919490939192565b60006020828403121561339d57600080fd5b81356001600160401b038111156133b357600080fd5b6133bf84828501612e16565b949350505050565b60008060008060008060a087890312156133e057600080fd5b8635955060208701356133f281612f42565b945060408701356001600160401b0381111561340d57600080fd5b61341989828a016131a5565b9095509350506060870135915061343260808801613293565b90509295509295509295565b6000806040838503121561345157600080fd5b82356001600160401b0381111561346757600080fd5b8301601f8101851361347857600080fd5b80356020613488612e3583612e6c565b82815260059290921b830181019181810190888411156134a757600080fd5b938201935b838510156134c5578435825293820193908201906134ac565b95506134d49050868201612ea4565b93505050509250929050565b602080825282518282018190526000919060409081850190868401855b8281101561358a578151805185528681015160ff1687860152858101518051878701528088015160608088019190915290870151608080880191909152908201519060a061354e8189018415159052565b90830151915060c0906135648883018415159052565b83015160e0880152909101516101008601525061012090930192908501906001016134fd565b5091979650505050505050565b60005b838110156135b257818101518382015260200161359a565b50506000910152565b600081518084526135d3816020860160208601613597565b601f01601f19169290920160200192915050565b602081526000611f6a60208301846135bb565b6020808252825182820181905260009190848201906040850190845b8181101561363257835183529284019291840191600101613616565b50909695505050505050565b6000806000806060858703121561365457600080fd5b84359350602085013561366681612f42565b925060408501356001600160401b0381111561368157600080fd5b61368d878288016131a5565b95989497509550505050565b60ff831681526040602082015260006133bf60408301846135bb565b600080604083850312156136c857600080fd5b82356136d381612e8f565b9150602083013561325d81613268565b600080604083850312156136f657600080fd5b823561370181612e8f565b946020939093013593505050565b6000806040838503121561372257600080fd5b8235915060208301356001600160401b0381111561373f57600080fd5b61374b85828601612e16565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561092d5761092d61376b565b600060ff821660ff81036137aa576137aa61376b565b60010192915050565b600081518084526020808501945080840160005b838110156137f7578151805188528301516001600160a01b031683880152604090960195908201906001016137c7565b509495945050505050565b600081518084526020808501945080840160005b838110156137f757815160ff1687529582019590820190600101613816565b634e487b7160e01b600052602160045260246000fd5b600081518084526020808501945080840160005b838110156137f7578151805188528381015184890152604090810151906003821061388c5761388c613835565b8801526060909601959082019060010161385f565b60018060a01b0384168152606060208201528251606082015260208301516080820152600060408401516101208060a08501526138e26101808501836135bb565b91506060860151605f19808685030160c087015261390084836137b3565b935060808801519150808685030160e087015261391d8483613802565b935060a08801519150610100828188015260c0890151925081878603018488015261394885846137b3565b945060e08901516101408801528089015193505080868503016101608701525050613973828261384b565b92505050826040830152949350505050565b60006020828403121561399757600080fd5b5051919050565b8051610bd681612e8f565b8051610bd681613268565b600080600080608085870312156139ca57600080fd5b8451935060208501516139dc81612e8f565b6040860151606087015191945092506139f481613268565b939692955090935050565b600181811c90821680613a1357607f821691505b602082108103613a3357634e487b7160e01b600052602260045260246000fd5b50919050565b60008154613a46816139ff565b808552602060018381168015613a635760018114613a7d57613aab565b60ff1985168884015283151560051b880183019550613aab565b866000528260002060005b85811015613aa35781548a8201860152908301908401613a88565b890184019650505b505050505092915050565b606081526000613ac960608301866135bb565b8281036020840152613adb8186613a39565b91505060ff83166040830152949350505050565b60008251613b01818460208701613597565b9190910192915050565b6000808354613b19816139ff565b60018281168015613b315760018114613b4657613b75565b60ff1984168752821515830287019450613b75565b8760005260208060002060005b85811015613b6c5781548a820152908401908201613b53565b50505082870194505b50929695505050505050565b601f821115610dd857600081815260208120601f850160051c81016020861015613ba85750805b601f850160051c820191505b8181101561117157828155600101613bb4565b81516001600160401b03811115613be057613be0612cd5565b613bf481613bee84546139ff565b84613b81565b602080601f831160018114613c295760008415613c115750858301515b600019600386901b1c1916600185901b178555611171565b600085815260208120601f198616915b82811015613c5857888601518255948401946001909101908401613c39565b5085821015613c765787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600082601f830112613c9757600080fd5b8151613ca5612e3582612def565b818152846020838601011115613cba57600080fd5b6133bf826020830160208701613597565b8051610bd681612f42565b600082601f830112613ce757600080fd5b81516020613cf7612e3583612e6c565b82815260069290921b84018101918181019086841115613d1657600080fd5b8286015b84811015612f375760408189031215613d335760008081fd5b613d3b612ceb565b8151613d4681612f42565b81528185015185820152835291830191604001613d1a565b600082601f830112613d6f57600080fd5b81516020613d7f612e3583612e6c565b82815260079290921b84018101918181019086841115613d9e57600080fd5b8286015b84811015612f375760808189031215613dbb5760008081fd5b613dc3612d7a565b8151613dce81612fb5565b815281850151858201526040808301519082015260608083015190820152835291830191608001613da2565b6000613e08612e3584612e6c565b8381529050602080820190600685901b840186811115613e2757600080fd5b845b81811015613e6d5760408189031215613e425760008081fd5b613e4a612ceb565b8151815283820151613e5b81612e8f565b81850152845292820192604001613e29565b505050509392505050565b600060608284031215613e8a57600080fd5b613e92612d13565b90508151815260208201516001600160401b0380821115613eb257600080fd5b818401915084601f830112613ec657600080fd5b613ed585835160208501613dfa565b60208401526040840151915080821115613eee57600080fd5b508201601f81018413613f0057600080fd5b613f0f84825160208401613dfa565b60408301525092915050565b60006101208284031215613f2e57600080fd5b613f36612d35565b905081518152602082015160208201526040820151604082015260608201516060820152613f666080830161399e565b6080820152613f7760a08301613ccb565b60a082015260c082015160c082015260e082015160e082015261010080830151818301525092915050565b600060208284031215613fb457600080fd5b81516001600160401b0380821115613fcb57600080fd5b908301906102808286031215613fe057600080fd5b613fe8612d9c565b613ff18361399e565b8152602083015160208201526040830151604082015260608301518281111561401957600080fd5b61402587828601613c86565b6060830152506080830151608082015260a08301518281111561404757600080fd5b61405387828601613cd6565b60a08301525060c08301518281111561406b57600080fd5b61407787828601613d5e565b60c08301525060e08301518281111561408f57600080fd5b61409b87828601613e78565b60e08301525061010091506140b286838501613f1b565b828201526102208301516101208201526140cf61024084016139a9565b6101408201526102609290920151610160830152509392505050565b808202811582820484141761092d5761092d61376b565b60008261411f57634e487b7160e01b600052601260045260246000fd5b500490565b6000600182016141365761413661376b565b5060010190565b60808152600061415060808301876135bb565b82810360208401526141628187613a39565b91505060ff8416604083015260ff8316606083015295945050505050565b8181038181111561092d5761092d61376b565b600080600080608085870312156141a957600080fd5b84516141b481613268565b6020860151604087015191955093506141cc81612e8f565b6060959095015193969295505050565b600060e08201905083825260018060a01b03835116602083015260ff602084015116604083015260ff604084015116606083015260608301516080830152608083015160a083015260a08301516002811061423957614239613835565b8060c0840152509392505050565b60008060006060848603121561425c57600080fd5b8351925060208401519150604084015190509250925092565b60e08152600061428860e083018a6135bb565b828103602084015261429a818a613a39565b60ff988916604085015296909716606083015250608081019390935260a083019190915260c0909101529392505050565b6000602082840312156142dd57600080fd5b8151611f6a81613268565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220200ad70d4fd2ddb153d0e00798665187ce2e63a1d345ea8ba27d1b2e871fafdc64736f6c634300081400330000000000000000000000008f2505e4cb1aa4e2b763de8d7fe5519dd757186b0000000000000000000000004300000000000000000000000000000000000004
Deployed Bytecode
0x6080604052600436106102555760003560e01c806391d1485411610139578063bf1a84dd116100b6578063db288f9f1161007a578063db288f9f146107de578063ddd0c960146107fe578063e803f8101461081e578063e808386314610888578063e932406f146108a8578063ec90dbc3146108dc57600080fd5b8063bf1a84dd146106ad578063c95a9139146106cd578063ce329ff3146106fb578063d547741f146107a9578063d8735768146107c957600080fd5b8063ad5c4648116100fd578063ad5c4648146105f1578063afaea6bd14610611578063afdeafb41461063e578063bd9ff32b1461066b578063be12d2ae1461069857600080fd5b806391d148541461053b57806396b5a7551461055b57806397d757761461057b578063a217fddf1461059b578063a6002132146105b057600080fd5b806346397a45116101d25780636a293d04116101965780636a293d041461047e578063746922d61461049e5780637f51bb1f146104b457806383c9d03f146104d45780638aeda25a146104e757806391a897121461051b57600080fd5b806346397a45146103eb5780634918cf6a1461040b578063561ce98c1461042b578063580664e71461043e57806361d027b31461045e57600080fd5b806327c8f8351161021957806327c8f83514610346578063283b914b1461037e5780632f2ff15d1461039157806336568abe146103b1578063406fcc63146103d157600080fd5b806301ffc9a71461026157806313ef73a31461029657806315ea9962146102b85780631ca339dd146102e6578063248a9ca31461031657600080fd5b3661025c57005b600080fd5b34801561026d57600080fd5b5061028161027c366004612c92565b6108fc565b60405190151581526020015b60405180910390f35b3480156102a257600080fd5b506102b66102b1366004612cbc565b610933565b005b3480156102c457600080fd5b506102d86102d336600461305f565b61099c565b60405190815260200161028d565b3480156102f257600080fd5b50610281610301366004613188565b600d6020526000908152604090205460ff1681565b34801561032257600080fd5b506102d8610331366004612cbc565b60009081526020819052604090206001015490565b34801561035257600080fd5b50600754610366906001600160a01b031681565b6040516001600160a01b03909116815260200161028d565b6102b661038c3660046131ed565b610bdb565b34801561039d57600080fd5b506102b66103ac366004613238565b610ddd565b3480156103bd57600080fd5b506102b66103cc366004613238565b610e08565b3480156103dd57600080fd5b50600e546102819060ff1681565b3480156103f757600080fd5b506102b6610406366004613276565b610e3b565b34801561041757600080fd5b50600354610366906001600160a01b031681565b6102b66104393660046132a2565b610e86565b34801561044a57600080fd5b50600854610366906001600160a01b031681565b34801561046a57600080fd5b50600554610366906001600160a01b031681565b34801561048a57600080fd5b506102b661049936600461338b565b610eb7565b3480156104aa57600080fd5b506102d860065481565b3480156104c057600080fd5b506102b66104cf366004613188565b61105a565b6102b66104e23660046133c7565b611138565b3480156104f357600080fd5b506102d87f828634d95e775031b9ff576b159a8509d3053581a8c9c4d7d86899e0afcd882f81565b34801561052757600080fd5b506102b6610536366004613188565b611179565b34801561054757600080fd5b50610281610556366004613238565b61122a565b34801561056757600080fd5b506102b6610576366004612cbc565b611253565b34801561058757600080fd5b50600254610366906001600160a01b031681565b3480156105a757600080fd5b506102d8600081565b3480156105bc57600080fd5b506103666105cb36600461338b565b8051602081830181018051600c825292820191909301209152546001600160a01b031681565b3480156105fd57600080fd5b50600454610366906001600160a01b031681565b34801561061d57600080fd5b5061063161062c36600461343e565b61126c565b60405161028d91906134e0565b34801561064a57600080fd5b5061065e610659366004613188565b611805565b60405161028d91906135e7565b34801561067757600080fd5b5061068b610686366004613188565b61189f565b60405161028d91906135fa565b3480156106a457600080fd5b506102b661196d565b3480156106b957600080fd5b506102b66106c836600461363e565b611981565b3480156106d957600080fd5b506106ed6106e8366004613238565b611b0c565b60405161028d929190613699565b34801561070757600080fd5b50610782610716366004613238565b604080516060808201835260008083526020808401829052928401819052948552600982528285206001600160a01b039490941685529281529281902081519283018252805483526001015460ff80821694840194909452610100900490921615159181019190915290565b604080518251815260208084015160ff16908201529181015115159082015260600161028d565b3480156107b557600080fd5b506102b66107c4366004613238565b611bd6565b3480156107d557600080fd5b5061068b611bfb565b3480156107ea57600080fd5b506102b66107f93660046136b5565b611c99565b34801561080a57600080fd5b506102b66108193660046136e3565b611d98565b34801561082a57600080fd5b50610869610839366004613238565b60096020908152600092835260408084209091529082529020805460019091015460ff8082169161010090041683565b6040805193845260ff909216602084015215159082015260600161028d565b34801561089457600080fd5b506102b66108a3366004612cbc565b611dac565b3480156108b457600080fd5b506102d87f950b8f2d7415defaee398bb4898e8e094a64c725873b81952b7ab9f08d70efb381565b3480156108e857600080fd5b506102b66108f736600461370f565b611dc6565b60006001600160e01b03198216637965db0b60e01b148061092d57506301ffc9a760e01b6001600160e01b03198316145b92915050565b61093d6000611ed0565b6107d081111561096057604051636dac6a0960e01b815260040160405180910390fd5b60068190556040518181527f80fcaeb6b7053a53b9ad01b2961d826e0461582d34e279c402b914f87b34c152906020015b60405180910390a150565b60006109a6611eda565b6005546001600160a01b03166109cf5760405163b2c4cce960e01b815260040160405180910390fd5b600e5460ff1615610a0357610a037f828634d95e775031b9ff576b159a8509d3053581a8c9c4d7d86899e0afcd882f611ed0565b6000805b8360c00151518160ff161015610a9a5760006001600160a01b03168460c001518260ff1681518110610a3b57610a3b613755565b6020026020010151602001516001600160a01b031603610a88578360c001518160ff1681518110610a6e57610a6e613755565b60200260200101516000015182610a859190613781565b91505b80610a9281613794565b915050610a07565b508015610b1657600454610ab9906001600160a01b0316333084611f04565b60048054604051632e1a7d4d60e01b81529182018390526001600160a01b031690632e1a7d4d90602401600060405180830381600087803b158015610afd57600080fd5b505af1158015610b11573d6000803e3d6000fd5b505050505b60085460065460405163573e74d160e11b81526001600160a01b039092169163ae7ce9a2918491610b4e9133918991906004016138a1565b60206040518083038185885af1158015610b6c573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610b919190613985565b9150610b9e600f83611f5e565b50604051829033907f3249a06bd478adf780bb7930214ad005e9cfa517d63221c0b77f27199d1a58b390600090a350610bd660018055565b919050565b610be3611eda565b600083815260096020908152604080832033845290915290206001810154610100900460ff1615610c2757604051638a1ce94d60e01b815260040160405180910390fd5b60018101805461010061ff00198216179091556008548254604051633044143960e01b815260048101889052336024820152604481019190915260ff90921660648301526000918291829182916001600160a01b0316906330441439906084016080604051808303816000875af1158015610ca6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cca91906139b4565b9350935093509350610ce0336000866000611f71565b610ceb848484612006565b336000908152600a60205260409020610d049089612118565b508015610d1457610d1488612124565b336000818152600d602052604090205489907f7b0b98081002edd6afba673b65400fe98ed56ff907a5860e5b3c1ad702997b579060ff16610d8b5789898080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610d9c92505050565b604051806020016040528060008152505b336000908152600b60205260409081902060018b01549151610dc2939260ff1690613ab6565b60405180910390a35050505050610dd860018055565b505050565b600082815260208190526040902060010154610df881611ed0565b610e0283836121ca565b50505050565b6001600160a01b0381163314610e315760405163334bd91960e11b815260040160405180910390fd5b610dd8828261225c565b610e456000611ed0565b600e805460ff19168215159081179091556040519081527f3fcd4dd73af3f4558ad8923f15846d2e59c211916f64fbec32ac7e5ed1128db290602001610991565b610e8e611eda565b610e97816122c7565b610ea5878787878787612360565b610eae60018055565b50505050505050565b610ebf611eda565b336000908152600d602052604090205460ff1615610ef057604051639b545b7360e01b815260040160405180910390fd5b600381511080610f01575060098151115b15610f1f5760405163071be59b60e01b815260040160405180910390fd5b60006001600160a01b0316600c82604051610f3a9190613aef565b908152604051908190036020019020546001600160a01b031614610f7157604051631af3778960e31b815260040160405180910390fd5b336000908152600b60205260408082209051600c91610f8f91613b0b565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039490941693909317909255336000908152600b90915220610fd58282613bc7565b5033600c82604051610fe79190613aef565b90815260405190819003602001812080546001600160a01b03939093166001600160a01b03199093169290921790915533907f90fd02fbcbd067a1c26b1397ddd9e406682052c502c5ee222e8b7b26035def25906110469084906135e7565b60405180910390a261105760018055565b50565b6110646000611ed0565b6001600160a01b03811661108b5760405163d92e233d60e01b815260040160405180910390fd5b600580546001600160a01b0319166001600160a01b03838116918217909255600854604051637f51bb1f60e01b8152600481019290925290911690637f51bb1f90602401600060405180830381600087803b1580156110e957600080fd5b505af11580156110fd573d6000803e3d6000fd5b50506040516001600160a01b03841692507fa6df481f77da1f4c92eb330341e03585d46106fcf522f8e6b6b2afbea56eefdc9150600090a250565b611140611eda565b61114e868686868686612360565b336000908152600a602052604090206111679087611f5e565b5061117160018055565b505050505050565b6111836000611ed0565b6001600160a01b0381166111aa5760405163d92e233d60e01b815260040160405180910390fd5b6008546001600160a01b0316156111d457604051635fb2b52360e11b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b03831690811790915560405190815230907f5febe1b9e375a634d9d565149e636879057714c557b8c78aab7cccae8cf48e489060200160405180910390a250565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b61125d3382612590565b611268600f82612118565b5050565b606082516001600160401b0381111561128757611287612cd5565b6040519080825280602002602001820160405280156112c057816020015b6112ad612c30565b8152602001906001900390816112a55790505b5090506000805b84518110156117fd578481815181106112e2576112e2613755565b60209081029190910101516008546040516378bd793560e01b8152600481018390529193506000916001600160a01b03909116906378bd793590602401600060405180830381865afa15801561133c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113649190810190613fa2565b90506000600860009054906101000a90046001600160a01b03166001600160a01b03166391c578756040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113df9190613985565b60008581526009602090815260408083206001600160a01b038b16845282529182902082516060810184528154815260019091015460ff80821683850152610100918290041615159382019390935260a0860151519286015160c001519186015189519495509093921515929115159189908890811061146157611461613755565b60200260200101516000018181525050826020015188878151811061148857611488613755565b60209081029190910181015160ff909216910152825188518990889081106114b2576114b2613755565b602090810291909101015160400151528115806114d45750602083015160ff16155b611506578460a00151836020015160ff16815181106114f5576114f5613755565b602002602001015160200151611509565b60005b88878151811061151b5761151b613755565b602002602001015160400151602001818152505084610100015160c0015188878151811061154b5761154b613755565b602090810291909101015160409081015101528251158015906115b0575060008560a00151511161159957846101000151608001516001600160a01b0316896001600160a01b0316146115b0565b84610100015160a0015160ff16836020015160ff16145b8887815181106115c2576115c2613755565b6020026020010151606001901515908115158152505082604001518887815181106115ef576115ef613755565b602090810291909101015190151560809182015261010086015101516001600160a01b038a811691161460008180156116255750835b61163057600061166b565b61166b868860a00151876020015160ff168151811061165157611651613755565b60200260200101516020015161265090919063ffffffff16565b90508280156116775750835b80156116ab575060008760a00151866020015160ff168151811061169d5761169d613755565b602002602001015160200151115b1561172c576116dc6116bf87612710613781565b8860a00151876020015160ff168151811061165157611651613755565b85516116e9908390613781565b6116fb90670de0b6b3a76400006140eb565b6117059190614102565b8a898151811061171757611717613755565b602002602001015160a001818152505061177c565b828015611737575083155b1561175757670de0b6b3a76400008a898151811061171757611717613755565b60008a898151811061176b5761176b613755565b602002602001015160a00181815250505b670de0b6b3a76400008a898151811061179757611797613755565b602002602001015160a00151886101000151602001516117b791906140eb565b6117c19190614102565b8a89815181106117d3576117d3613755565b602002602001015160c00181815250505050505050505080806117f590614124565b9150506112c7565b505092915050565b600b602052600090815260409020805461181e906139ff565b80601f016020809104026020016040519081016040528092919081815260200182805461184a906139ff565b80156118975780601f1061186c57610100808354040283529160200191611897565b820191906000526020600020905b81548152906001019060200180831161187a57829003601f168201915b505050505081565b6001600160a01b0381166000908152600a60205260408120606091906118c490612679565b9050806001600160401b038111156118de576118de612cd5565b604051908082528060200260200182016040528015611907578160200160208202803683370190505b50915060005b81811015611966576001600160a01b0384166000908152600a602052604090206119379082612683565b83828151811061194957611949613755565b60209081029190910101528061195e81614124565b91505061190d565b5050919050565b6119776000611ed0565b61197f61268f565b565b611989611eda565b600084815260096020908152604080832033845290915290819020600854815460018301549351633f83441560e01b815260048101899052602481019190915260ff9384166044820152928616606484015290916001600160a01b0390911690633f834415906084016020604051808303816000875af1158015611a11573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a359190613985565b815560018101805460ff86811660ff19831617909255336000818152600d602052604090205491831692909188917fe887c12401d1218764994b5ed2143e6d0c23ab88b3d47e18a99ed4164b8e2c649116611ac65786868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611ad792505050565b604051806020016040528060008152505b336000908152600b6020526040908190209051611af99291908b90889061413d565b60405180910390a35050610e0260018055565b60008281526009602090815260408083206001600160a01b0385168452825280832060010154600b909252909120805460ff9092169160609190611b4f906139ff565b80601f0160208091040260200160405190810160405280929190818152602001828054611b7b906139ff565b8015611bc85780601f10611b9d57610100808354040283529160200191611bc8565b820191906000526020600020905b815481529060010190602001808311611bab57829003601f168201915b505050505090509250929050565b600082815260208190526040902060010154611bf181611ed0565b610e02838361225c565b60606000611c09600f612679565b9050806001600160401b03811115611c2357611c23612cd5565b604051908082528060200260200182016040528015611c4c578160200160208202803683370190505b50915060005b81811015611c9457611c65600f82612683565b838281518110611c7757611c77613755565b602090810291909101015280611c8c81614124565b915050611c52565b505090565b7f950b8f2d7415defaee398bb4898e8e094a64c725873b81952b7ab9f08d70efb3611cc381611ed0565b6001600160a01b0383166000908152600d60209081526040808320805460ff1916861515179055600b9091528082209051600c91611d0091613b0b565b908152604080516020928190038301812080546001600160a01b0319166001600160a01b03958616179055828101825260008082529387168452600b90925290912090611d4d9082613bc7565b50826001600160a01b03167ff43f03272568f314d919decd0ce22ee579a44c1754101b036edee97edb067cdf83604051611d8b911515815260200190565b60405180910390a2505050565b611da26000611ed0565b611268828261275e565b611db4611eda565b611dbd81612124565b61105760018055565b611dce611eda565b336000908152600d602052604090205460ff1615611dff57604051639b545b7360e01b815260040160405180910390fd5b6008546040516357a9855560e01b8152600481018490526001600160a01b03909116906357a985559060240160006040518083038186803b158015611e4357600080fd5b505afa158015611e57573d6000803e3d6000fd5b5050336000818152600b6020908152604080832088845260098352818420858552909252918290206001015491519294508693507f513343dc7568bca122edc0a7dff37f2707f3df31d4e985c69cef736af6d18edd92611ebf9287929160ff90911690613ab6565b60405180910390a361126860018055565b6110578133612924565b600260015403611efd57604051633ee5aeb560e01b815260040160405180910390fd5b6002600155565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052610e02908590612962565b6000611f6a83836129c5565b9392505050565b6000836001811115611f8557611f85613835565b03611faf57813414611faa57604051634e03ebdd60e01b815260040160405180910390fd5b611fce565b3415611fce57604051630cd5039560e21b815260040160405180910390fd5b6001836001811115611fe257611fe2613835565b03610e0257600754600354610e02916001600160a01b039182169187911684611f04565b8260000361201357505050565b600061201f8483612650565b6005546040519192506000916001600160a01b039091169083908381818185875af1925050503d8060008114612071576040519150601f19603f3d011682016040523d82523d6000602084013e612076565b606091505b50509050806120985760405163b12d13eb60e01b815260040160405180910390fd5b6001600160a01b0384166120ac8387614180565b604051600081818185875af1925050503d80600081146120e8576040519150601f19603f3d011682016040523d82523d6000602084013e6120ed565b606091505b505080915050806121115760405163b12d13eb60e01b815260040160405180910390fd5b5050505050565b6000611f6a8383612a0c565b60085460405163e808386360e01b8152600481018390526000918291829182916001600160a01b039091169063e8083863906024016080604051808303816000875af1158015612178573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061219c9190614193565b935093509350935083156121b4576121b48286612590565b6121bf838383612006565b611171600f86612118565b60006121d6838361122a565b612254576000838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561220c3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161092d565b50600061092d565b6000612268838361122a565b15612254576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161092d565b805160208201516040808401516060850151608086015160a0870151935163d505accf60e01b81523360048201523060248201526044810195909552606485019290925260ff16608484015260a483015260c48201526001600160a01b039091169063d505accf9060e401600060405180830381600087803b15801561234c57600080fd5b505af1158015612111573d6000803e3d6000fd5b816001146123815760405163e318e67360e01b815260040160405180910390fd5b600086815260096020908152604080832033808552908352818420600854835160c08101855292835260018083015460ff90811696850196909652948b169383019390935280546060830152608082018790529392839283926001600160a01b039091169163466f174a918d9160a08201908a9081111561240457612404613835565b8152506040518363ffffffff1660e01b81526004016124249291906141dc565b6060604051808303816000875af1158015612443573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124679190614247565b60018701805460ff8e811660ff1983161790925593965091945092501661248e8785613781565b85556124b6338761249f8a866140eb565b6124b18b670de0b6b3a76400006140eb565b611f71565b336000818152600d60205260409020548c907fc5658d374977ba82a6583515e5a13a9345ae28df457a0b8447642110684245389060ff1661252d578b8b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061253e92505050565b604051806020016040528060008152505b600b6000336001600160a01b03166001600160a01b031681526020019081526020016000208e86898e4260405161257b9796959493929190614275565b60405180910390a35050505050505050505050565b6008546001600160a01b031663dca80c1983836125ae60008361122a565b6040516001600160e01b031960e086901b1681526001600160a01b039093166004840152602483019190915215156044820152606401600060405180830381600087803b1580156125fe57600080fd5b505af1158015612612573d6000803e3d6000fd5b50506040518392506001600160a01b03851691507f018b64b6242d32aa550e95d78985b938d71af5b3f10827b0683f55da1639304890600090a35050565b6000816127100361266257508161092d565b61271061266f83856140eb565b611f6a9190614102565b600061092d825490565b6000611f6a8383612aff565b600280546001600160a01b0319166002604360981b019081179091556040805163784c3b3d60e11b8152905163f098767a9160048082019260009290919082900301818387803b1580156126e257600080fd5b505af11580156126f6573d6000803e3d6000fd5b50505050600260009054906101000a90046001600160a01b03166001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561274a57600080fd5b505af1158015610e02573d6000803e3d6000fd5b60025460405163430021db60e11b81523060048201526001600160a01b038481166024830152600092169063860043b6906044016020604051808303816000875af11580156127b1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d59190613985565b90506000821561286157600254604051630951888f60e01b81523060048201526001600160a01b0386811660248301526044820186905290911690630951888f906064016020604051808303816000875af1158015612838573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061285c9190613985565b6128d7565b60025460405163662aa11d60e01b81523060048201526001600160a01b0386811660248301529091169063662aa11d906044016020604051808303816000875af11580156128b3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128d79190613985565b60408051848152602081018390529192506001600160a01b038616917f19f76cb54ee84067ebfd4c9afacfcc412d9e2e1d9026f4ce6f2ec7764f16e1b7910160405180910390a250505050565b61292e828261122a565b6112685760405163e2517d3f60e01b81526001600160a01b0382166004820152602481018390526044015b60405180910390fd5b60006129776001600160a01b03841683612b29565b9050805160001415801561299c57508080602001905181019061299a91906142cb565b155b15610dd857604051635274afe760e01b81526001600160a01b0384166004820152602401612959565b60008181526001830160205260408120546122545750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561092d565b60008181526001830160205260408120548015612af5576000612a30600183614180565b8554909150600090612a4490600190614180565b9050808214612aa9576000866000018281548110612a6457612a64613755565b9060005260206000200154905080876000018481548110612a8757612a87613755565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612aba57612aba6142e8565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061092d565b600091505061092d565b6000826000018281548110612b1657612b16613755565b9060005260206000200154905092915050565b6060611f6a8383600084600080856001600160a01b03168486604051612b4f9190613aef565b60006040518083038185875af1925050503d8060008114612b8c576040519150601f19603f3d011682016040523d82523d6000602084013e612b91565b606091505b5091509150612ba1868383612bab565b9695505050505050565b606082612bc057612bbb82612c07565b611f6a565b8151158015612bd757506001600160a01b0384163b155b15612c0057604051639996b31560e01b81526001600160a01b0385166004820152602401612959565b5080611f6a565b805115612c175780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b6040518060e0016040528060008152602001600060ff168152602001612c7060405180606001604052806000815260200160008152602001600081525090565b8152600060208201819052604082018190526060820181905260809091015290565b600060208284031215612ca457600080fd5b81356001600160e01b031981168114611f6a57600080fd5b600060208284031215612cce57600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715612d0d57612d0d612cd5565b60405290565b604051606081016001600160401b0381118282101715612d0d57612d0d612cd5565b60405161012081016001600160401b0381118282101715612d0d57612d0d612cd5565b60405160c081016001600160401b0381118282101715612d0d57612d0d612cd5565b604051608081016001600160401b0381118282101715612d0d57612d0d612cd5565b60405161018081016001600160401b0381118282101715612d0d57612d0d612cd5565b604051601f8201601f191681016001600160401b0381118282101715612de757612de7612cd5565b604052919050565b60006001600160401b03821115612e0857612e08612cd5565b50601f01601f191660200190565b600082601f830112612e2757600080fd5b8135612e3a612e3582612def565b612dbf565b818152846020838601011115612e4f57600080fd5b816020850160208301376000918101602001919091529392505050565b60006001600160401b03821115612e8557612e85612cd5565b5060051b60200190565b6001600160a01b038116811461105757600080fd5b8035610bd681612e8f565b600082601f830112612ec057600080fd5b81356020612ed0612e3583612e6c565b82815260069290921b84018101918181019086841115612eef57600080fd5b8286015b84811015612f375760408189031215612f0c5760008081fd5b612f14612ceb565b8135815284820135612f2581612e8f565b81860152835291830191604001612ef3565b509695505050505050565b60ff8116811461105757600080fd5b600082601f830112612f6257600080fd5b81356020612f72612e3583612e6c565b82815260059290921b84018101918181019086841115612f9157600080fd5b8286015b84811015612f37578035612fa881612f42565b8352918301918301612f95565b6003811061105757600080fd5b600082601f830112612fd357600080fd5b81356020612fe3612e3583612e6c565b8281526060928302850182019282820191908785111561300257600080fd5b8387015b858110156130525781818a03121561301e5760008081fd5b613026612d13565b81358152858201358682015260408083013561304181612fb5565b908201528452928401928101613006565b5090979650505050505050565b60006020828403121561307157600080fd5b81356001600160401b038082111561308857600080fd5b90830190610120828603121561309d57600080fd5b6130a5612d35565b82358152602083013560208201526040830135828111156130c557600080fd5b6130d187828601612e16565b6040830152506060830135828111156130e957600080fd5b6130f587828601612eaf565b60608301525060808301358281111561310d57600080fd5b61311987828601612f51565b60808301525060a083013560a082015260c08301358281111561313b57600080fd5b61314787828601612eaf565b60c08301525060e083013560e0820152610100808401358381111561316b57600080fd5b61317788828701612fc2565b918301919091525095945050505050565b60006020828403121561319a57600080fd5b8135611f6a81612e8f565b60008083601f8401126131b757600080fd5b5081356001600160401b038111156131ce57600080fd5b6020830191508360208285010111156131e657600080fd5b9250929050565b60008060006040848603121561320257600080fd5b8335925060208401356001600160401b0381111561321f57600080fd5b61322b868287016131a5565b9497909650939450505050565b6000806040838503121561324b57600080fd5b82359150602083013561325d81612e8f565b809150509250929050565b801515811461105757600080fd5b60006020828403121561328857600080fd5b8135611f6a81613268565b803560028110610bd657600080fd5b60008060008060008060008789036101608112156132bf57600080fd5b8835975060208901356132d181612f42565b965060408901356001600160401b038111156132ec57600080fd5b6132f88b828c016131a5565b9097509550506060890135935061331160808a01613293565b925060c0609f198201121561332557600080fd5b5061332e612d58565b60a089013561333c81612e8f565b815260c0890135602082015260e0890135604082015261010089013561336181612f42565b606082015261012089013560808201526101409098013560a0890152509497939650919490939192565b60006020828403121561339d57600080fd5b81356001600160401b038111156133b357600080fd5b6133bf84828501612e16565b949350505050565b60008060008060008060a087890312156133e057600080fd5b8635955060208701356133f281612f42565b945060408701356001600160401b0381111561340d57600080fd5b61341989828a016131a5565b9095509350506060870135915061343260808801613293565b90509295509295509295565b6000806040838503121561345157600080fd5b82356001600160401b0381111561346757600080fd5b8301601f8101851361347857600080fd5b80356020613488612e3583612e6c565b82815260059290921b830181019181810190888411156134a757600080fd5b938201935b838510156134c5578435825293820193908201906134ac565b95506134d49050868201612ea4565b93505050509250929050565b602080825282518282018190526000919060409081850190868401855b8281101561358a578151805185528681015160ff1687860152858101518051878701528088015160608088019190915290870151608080880191909152908201519060a061354e8189018415159052565b90830151915060c0906135648883018415159052565b83015160e0880152909101516101008601525061012090930192908501906001016134fd565b5091979650505050505050565b60005b838110156135b257818101518382015260200161359a565b50506000910152565b600081518084526135d3816020860160208601613597565b601f01601f19169290920160200192915050565b602081526000611f6a60208301846135bb565b6020808252825182820181905260009190848201906040850190845b8181101561363257835183529284019291840191600101613616565b50909695505050505050565b6000806000806060858703121561365457600080fd5b84359350602085013561366681612f42565b925060408501356001600160401b0381111561368157600080fd5b61368d878288016131a5565b95989497509550505050565b60ff831681526040602082015260006133bf60408301846135bb565b600080604083850312156136c857600080fd5b82356136d381612e8f565b9150602083013561325d81613268565b600080604083850312156136f657600080fd5b823561370181612e8f565b946020939093013593505050565b6000806040838503121561372257600080fd5b8235915060208301356001600160401b0381111561373f57600080fd5b61374b85828601612e16565b9150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561092d5761092d61376b565b600060ff821660ff81036137aa576137aa61376b565b60010192915050565b600081518084526020808501945080840160005b838110156137f7578151805188528301516001600160a01b031683880152604090960195908201906001016137c7565b509495945050505050565b600081518084526020808501945080840160005b838110156137f757815160ff1687529582019590820190600101613816565b634e487b7160e01b600052602160045260246000fd5b600081518084526020808501945080840160005b838110156137f7578151805188528381015184890152604090810151906003821061388c5761388c613835565b8801526060909601959082019060010161385f565b60018060a01b0384168152606060208201528251606082015260208301516080820152600060408401516101208060a08501526138e26101808501836135bb565b91506060860151605f19808685030160c087015261390084836137b3565b935060808801519150808685030160e087015261391d8483613802565b935060a08801519150610100828188015260c0890151925081878603018488015261394885846137b3565b945060e08901516101408801528089015193505080868503016101608701525050613973828261384b565b92505050826040830152949350505050565b60006020828403121561399757600080fd5b5051919050565b8051610bd681612e8f565b8051610bd681613268565b600080600080608085870312156139ca57600080fd5b8451935060208501516139dc81612e8f565b6040860151606087015191945092506139f481613268565b939692955090935050565b600181811c90821680613a1357607f821691505b602082108103613a3357634e487b7160e01b600052602260045260246000fd5b50919050565b60008154613a46816139ff565b808552602060018381168015613a635760018114613a7d57613aab565b60ff1985168884015283151560051b880183019550613aab565b866000528260002060005b85811015613aa35781548a8201860152908301908401613a88565b890184019650505b505050505092915050565b606081526000613ac960608301866135bb565b8281036020840152613adb8186613a39565b91505060ff83166040830152949350505050565b60008251613b01818460208701613597565b9190910192915050565b6000808354613b19816139ff565b60018281168015613b315760018114613b4657613b75565b60ff1984168752821515830287019450613b75565b8760005260208060002060005b85811015613b6c5781548a820152908401908201613b53565b50505082870194505b50929695505050505050565b601f821115610dd857600081815260208120601f850160051c81016020861015613ba85750805b601f850160051c820191505b8181101561117157828155600101613bb4565b81516001600160401b03811115613be057613be0612cd5565b613bf481613bee84546139ff565b84613b81565b602080601f831160018114613c295760008415613c115750858301515b600019600386901b1c1916600185901b178555611171565b600085815260208120601f198616915b82811015613c5857888601518255948401946001909101908401613c39565b5085821015613c765787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600082601f830112613c9757600080fd5b8151613ca5612e3582612def565b818152846020838601011115613cba57600080fd5b6133bf826020830160208701613597565b8051610bd681612f42565b600082601f830112613ce757600080fd5b81516020613cf7612e3583612e6c565b82815260069290921b84018101918181019086841115613d1657600080fd5b8286015b84811015612f375760408189031215613d335760008081fd5b613d3b612ceb565b8151613d4681612f42565b81528185015185820152835291830191604001613d1a565b600082601f830112613d6f57600080fd5b81516020613d7f612e3583612e6c565b82815260079290921b84018101918181019086841115613d9e57600080fd5b8286015b84811015612f375760808189031215613dbb5760008081fd5b613dc3612d7a565b8151613dce81612fb5565b815281850151858201526040808301519082015260608083015190820152835291830191608001613da2565b6000613e08612e3584612e6c565b8381529050602080820190600685901b840186811115613e2757600080fd5b845b81811015613e6d5760408189031215613e425760008081fd5b613e4a612ceb565b8151815283820151613e5b81612e8f565b81850152845292820192604001613e29565b505050509392505050565b600060608284031215613e8a57600080fd5b613e92612d13565b90508151815260208201516001600160401b0380821115613eb257600080fd5b818401915084601f830112613ec657600080fd5b613ed585835160208501613dfa565b60208401526040840151915080821115613eee57600080fd5b508201601f81018413613f0057600080fd5b613f0f84825160208401613dfa565b60408301525092915050565b60006101208284031215613f2e57600080fd5b613f36612d35565b905081518152602082015160208201526040820151604082015260608201516060820152613f666080830161399e565b6080820152613f7760a08301613ccb565b60a082015260c082015160c082015260e082015160e082015261010080830151818301525092915050565b600060208284031215613fb457600080fd5b81516001600160401b0380821115613fcb57600080fd5b908301906102808286031215613fe057600080fd5b613fe8612d9c565b613ff18361399e565b8152602083015160208201526040830151604082015260608301518281111561401957600080fd5b61402587828601613c86565b6060830152506080830151608082015260a08301518281111561404757600080fd5b61405387828601613cd6565b60a08301525060c08301518281111561406b57600080fd5b61407787828601613d5e565b60c08301525060e08301518281111561408f57600080fd5b61409b87828601613e78565b60e08301525061010091506140b286838501613f1b565b828201526102208301516101208201526140cf61024084016139a9565b6101408201526102609290920151610160830152509392505050565b808202811582820484141761092d5761092d61376b565b60008261411f57634e487b7160e01b600052601260045260246000fd5b500490565b6000600182016141365761413661376b565b5060010190565b60808152600061415060808301876135bb565b82810360208401526141628187613a39565b91505060ff8416604083015260ff8316606083015295945050505050565b8181038181111561092d5761092d61376b565b600080600080608085870312156141a957600080fd5b84516141b481613268565b6020860151604087015191955093506141cc81612e8f565b6060959095015193969295505050565b600060e08201905083825260018060a01b03835116602083015260ff602084015116604083015260ff604084015116606083015260608301516080830152608083015160a083015260a08301516002811061423957614239613835565b8060c0840152509392505050565b60008060006060848603121561425c57600080fd5b8351925060208401519150604084015190509250925092565b60e08152600061428860e083018a6135bb565b828103602084015261429a818a613a39565b60ff988916604085015296909716606083015250608081019390935260a083019190915260c0909101529392505050565b6000602082840312156142dd57600080fd5b8151611f6a81613268565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220200ad70d4fd2ddb153d0e00798665187ce2e63a1d345ea8ba27d1b2e871fafdc64736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008f2505e4cb1aa4e2b763de8d7fe5519dd757186b0000000000000000000000004300000000000000000000000000000000000004
-----Decoded View---------------
Arg [0] : _voucher (address): 0x8f2505e4cb1aa4E2B763de8D7Fe5519dd757186B
Arg [1] : _weth (address): 0x4300000000000000000000000000000000000004
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000008f2505e4cb1aa4e2b763de8d7fe5519dd757186b
Arg [1] : 0000000000000000000000004300000000000000000000000000000000000004
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.