Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- LaunchWindowManager
- Optimization enabled
- false
- Compiler version
- v0.8.26+commit.8a97fa7a
- EVM Version
- Verified at
- 2026-10-11T05:21:36.785534Z
Constructor Arguments
000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f01058000000000000000000000000ede5501406c1e191f40a0145fa3d4881c18e458000000000000000000000000084bd7c30bec67cba9952cc07e3bf3a90180547db
Arg [0] (address) : 0xdd99adf15d84d425f02983e730b0db8e27f01058
Arg [1] (address) : 0xede5501406c1e191f40a0145fa3d4881c18e4580
Arg [2] (address) : 0x84bd7c30bec67cba9952cc07e3bf3a90180547db
contracts/launch/LaunchWindowManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {PulseBurnLaunch} from "./PulseBurnLaunch.sol";
/// @title LaunchWindowManager
/// @notice Owns the token through its ten-minute launch window with exactly the powers that
/// window needs, then offers ownership on to the timelock. Decision D3, 2026-09-24.
///
/// @dev WHY THIS EXISTS. `flagSnipers`, `clearSniper` and `liftLimitsEarly` matter only inside
/// the window, and only its owner can call them. The owner the launch hands to must
/// `acceptOwnership()` first (Ownable2Step), and a timelock with a 72-hour delay cannot
/// accept anything inside ten minutes - so with the timelock as the direct final owner,
/// the window's tools were unreachable exactly when they mattered.
///
/// Handing the token to an operator's EOA instead would reach them, and would also put
/// `setFeeRecipient`, `setFeeBps`, `setExempt` and `setPair` in that one key's hands
/// until the timelock took over three days later. So this contract sits in between with
/// a FIXED surface: the three window functions, for the operator only, and nothing else.
/// It cannot redirect fees, change them, exempt anyone, register a pair or renounce.
///
/// THE OPERATOR'S POWERS END ON THE CLOCK, not on anyone's action. All three tools work only
/// while the window is open: `flagSnipers` and `liftLimitsEarly` because the token itself
/// refuses them afterwards, `clearSniper` because this contract does. Nothing needs to be
/// cleared afterwards anyway - the token reads a sniper flag only inside the window, so a
/// flagged wallet can sell the moment the window ends, whether or not anyone acts.
///
/// After the window, anyone may offer ownership to the timelock - the operator is not a
/// dependency - and the timelock accepts through a scheduled operation. Until it does, this
/// contract owns the token and can do nothing with it at all.
contract LaunchWindowManager {
PulseBurnLaunch public immutable token;
address public immutable operator;
address public immutable timelock;
event Claimed(address indexed token);
event OfferedToTimelock(address indexed token, address indexed timelock);
error ZeroAddress();
error OnlyOperator();
error WindowStillOpen(uint64 endsAt);
error WindowClosed();
/// @param token_ The token this manages. At a real launch it does not exist yet: it is the
/// address the orchestrator's first CREATE will produce, fixed here so no other
/// contract can ever be claimed through this one.
constructor(PulseBurnLaunch token_, address operator_, address timelock_) {
if (address(token_) == address(0) || operator_ == address(0) || timelock_ == address(0)) {
revert ZeroAddress();
}
token = token_;
operator = operator_;
timelock = timelock_;
}
modifier onlyOperator() {
if (msg.sender != operator) revert OnlyOperator();
_;
}
/// @notice Accepts the ownership the launch offered. Permissionless: it can only move
/// ownership INTO this contract, whose powers are fixed. Reverts unless this
/// contract is the token's pending owner.
function claim() external {
token.acceptOwnership();
emit Claimed(address(token));
}
// --- the window's tools, and nothing else ---------------------------------------------------
function flagSnipers(address[] calldata accounts) external onlyOperator {
token.flagSnipers(accounts);
}
/// @dev Window-only, unlike the token's own `clearSniper`, so that every power this contract
/// holds ends when the window does. Nothing is lost: after the window a flag has no effect.
function clearSniper(address account) external onlyOperator {
if (!token.limitsActive()) revert WindowClosed();
token.clearSniper(account);
}
function liftLimitsEarly() external onlyOperator {
token.liftLimitsEarly();
}
// --- afterwards -------------------------------------------------------------------------
/// @notice Once the window has closed, offer ownership to the timelock. Permissionless, so
/// a lost operator key cannot strand the token here.
function offerToTimelock() external {
if (token.limitsActive()) revert WindowStillOpen(token.limitsEndAt());
token.transferOwnership(timelock);
emit OfferedToTimelock(address(token), timelock);
}
}
lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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 ERC-20
* applications.
*/
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}.
*
* Skips emitting an {Approval} event indicating an allowance update. This is not
* required by the ERC. See {xref-ERC20-_approve-address-address-uint256-bool-}[_approve].
*
* 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:
*
* ```solidity
* 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);
}
}
}
}
lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.20;
import {Ownable} from "./Ownable.sol";
/**
* @dev Contract module which provides access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This extension of the {Ownable} contract includes a two-step mechanism to transfer
* ownership, where the new owner must call {acceptOwnership} in order to replace the
* old one. This can help prevent common mistakes, such as transfers of ownership to
* incorrect accounts, or to contracts that are unable to interact with the
* permission system.
*
* The initial owner is specified at deployment time in the constructor for `Ownable`. This
* can later be changed with {transferOwnership} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*
* Setting `newOwner` to the zero address is allowed; this can be used to cancel an initiated ownership transfer.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() public virtual {
address sender = _msgSender();
if (pendingOwner() != sender) {
revert OwnableUnauthorizedAccount(sender);
}
_transferOwnership(sender);
}
}
contracts/launch/PulseBurnLaunch.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Ownable2Step} from "@openzeppelin/contracts/access/Ownable2Step.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/// @title PulseBurnLaunch
/// @notice Launch-guarded PBURN: fixed 21M cap, 0.3% fee-on-transfer, and anti-snipe
/// limits that **expire on a hard-coded clock and cannot be extended**.
///
/// @dev A SEPARATE CONTRACT FROM `contracts/token/PBURN.sol`, WHICH IS ALREADY DEPLOYED.
/// The live token has no trading gate, no limits and no sniper handling, is immutable,
/// and has renounced its roles to a timelock. Nothing here modifies it.
///
/// WHY EVERY RESTRICTION SUNSETS ON ONE IMMUTABLE TIMESTAMP
///
/// Anti-snipe protection and a honeypot are the same code with different lifetimes.
/// Max-transaction limits, wallet caps, buy/sell cooldowns, sniper flags and the
/// blacklist are *all* gated behind a single check - `block.timestamp < limitsEndAt` -
/// where `limitsEndAt` is written once, in `enableTrading`, and has no setter.
///
/// Consequences worth stating plainly, because they are the point:
///
/// - The owner cannot extend the window. There is no function that writes
/// `limitsEndAt` twice; `enableTrading` reverts if already called.
/// - After the window, `_update` has no path that can block or cap a transfer. Not
/// "the owner promises not to" - the branch does not execute.
/// - `flagSniper` is `onlyWhileLimited`, so it becomes permanently uncallable. A
/// flagged address is blocked from *selling during the window only*, which kills the
/// same-block flip without creating a wallet that can buy and never sell.
/// - Un-flagging is callable at any time, because a function that can only loosen
/// restrictions is not a risk.
///
/// That asymmetry is deliberate: every privileged function here can only reduce
/// restrictions or run out of time. A honeypot checker simulating a sell after
/// `limitsEndAt` gets a clean result, and the reason is structural rather than a
/// promise.
///
/// THE FEE IS NOT PART OF THE ANTI-SNIPE MACHINERY. 0.3% on transfers is the
/// protocol's documented mechanism, routed to a fee recipient that buys and burns. It
/// is capped at `MAX_FEE_BPS` and cannot be raised beyond it, so the "raise the tax to
/// 100% after launch" failure mode is unreachable.
contract PulseBurnLaunch is ERC20, Ownable2Step, ReentrancyGuard {
// --- supply -------------------------------------------------------------
/// @notice Minted once, in the constructor. There is no other mint path.
uint256 public constant MAX_SUPPLY = 21_000_000e18;
uint16 public constant BPS_DENOMINATOR = 10_000;
// --- fee ----------------------------------------------------------------
/// @notice Hard ceiling. `setFeeBps` cannot exceed this, so the fee can never be
/// raised to a level that blocks selling.
uint16 public constant MAX_FEE_BPS = 300; // 3%
uint16 public feeBps = 30; // 0.3%
address public feeRecipient;
// --- launch window ------------------------------------------------------
/// @notice How long the anti-snipe limits last. Compile-time constant, not a parameter.
uint64 public constant LIMIT_DURATION = 10 minutes;
/// @notice How long `flagSniper` remains callable. Never longer than LIMIT_DURATION.
uint64 public constant BLACKLIST_WINDOW = 10 minutes;
/// @notice Minimum cap sizes, so the owner cannot set limits so low that nobody can
/// trade at all. A 0-value max-transaction is a honeypot by another route.
uint256 public constant MIN_MAX_TX = MAX_SUPPLY / 1000; // 0.1%
uint256 public constant MIN_MAX_WALLET = MAX_SUPPLY / 500; // 0.2%
uint32 public constant TRADE_COOLDOWN = 30 seconds;
bool public tradingEnabled;
uint64 public launchBlock;
/// @notice Written exactly once, by `enableTrading`. No setter exists.
uint64 public limitsEndAt;
uint256 public maxTxAmount;
uint256 public maxWalletAmount;
// --- classification -----------------------------------------------------
mapping(address => bool) public isExempt; // fee AND limits
mapping(address => bool) public isPair;
mapping(address => bool) public isSniper;
mapping(address => uint64) public lastTradeAt;
// --- events -------------------------------------------------------------
event TradingEnabled(uint64 launchBlock, uint64 limitsEndAt, uint256 maxTx, uint256 maxWallet);
event LimitsLiftedEarly(uint64 at);
event PairSet(address indexed pair, bool isPair);
event ExemptSet(address indexed account, bool exempt);
event SniperFlagged(address indexed account);
event SniperCleared(address indexed account);
event FeeRecipientSet(address indexed previous, address indexed current);
event FeeBpsSet(uint16 previous, uint16 current);
// --- errors -------------------------------------------------------------
error TradingNotEnabled();
error TradingAlreadyEnabled();
error LimitWindowClosed();
error MaxTxExceeded(uint256 amount, uint256 limit);
error MaxWalletExceeded(uint256 balance, uint256 limit);
error CooldownActive(uint64 until);
error SniperCannotSellDuringWindow(address account);
error FeeTooHigh(uint16 requested, uint16 maximum);
error LimitTooLow(uint256 requested, uint256 minimum);
error ZeroAddress();
constructor(address initialOwner, address initialHolder, address feeRecipient_)
ERC20("PulseBurn", "PBURN")
Ownable(initialOwner)
{
if (initialOwner == address(0) || initialHolder == address(0) || feeRecipient_ == address(0)) {
revert ZeroAddress();
}
feeRecipient = feeRecipient_;
// Exempt the parties that must move tokens before trading opens, and the fee sink
// itself - taxing the fee recipient would double-charge every collection.
isExempt[initialOwner] = true;
isExempt[initialHolder] = true;
isExempt[feeRecipient_] = true;
isExempt[address(this)] = true;
_mint(initialHolder, MAX_SUPPLY);
}
// --- modifiers ----------------------------------------------------------
modifier onlyWhileLimited() {
if (!limitsActive()) revert LimitWindowClosed();
_;
}
// --- views --------------------------------------------------------------
/// @notice True only inside the launch window. Every restriction in this contract is
/// gated on this, so when it is false the token is a plain fee-on-transfer
/// ERC-20 with no owner-controlled transfer restrictions of any kind.
function limitsActive() public view returns (bool) {
return tradingEnabled && block.timestamp < limitsEndAt;
}
/// @notice Seconds until every restriction stops applying. Zero once they have.
/// Published so a holder can verify the sunset without reading the bytecode.
function secondsUntilUnrestricted() external view returns (uint64) {
if (!tradingEnabled) return LIMIT_DURATION;
if (block.timestamp >= limitsEndAt) return 0;
return limitsEndAt - uint64(block.timestamp);
}
// --- launch -------------------------------------------------------------
/// @notice Opens trading and starts the limit clock. Callable once, ever.
///
/// @dev The one-way door. `limitsEndAt` is written here and nowhere else, so the
/// window cannot be extended by any subsequent call - including by a new owner.
function enableTrading(uint256 maxTx_, uint256 maxWallet_) external onlyOwner {
if (tradingEnabled) revert TradingAlreadyEnabled();
if (maxTx_ < MIN_MAX_TX) revert LimitTooLow(maxTx_, MIN_MAX_TX);
if (maxWallet_ < MIN_MAX_WALLET) revert LimitTooLow(maxWallet_, MIN_MAX_WALLET);
tradingEnabled = true;
launchBlock = uint64(block.number);
limitsEndAt = uint64(block.timestamp) + LIMIT_DURATION;
maxTxAmount = maxTx_;
maxWalletAmount = maxWallet_;
emit TradingEnabled(launchBlock, limitsEndAt, maxTx_, maxWallet_);
}
/// @notice Ends the limit window immediately. Can only shorten it, never extend it.
function liftLimitsEarly() external onlyOwner onlyWhileLimited {
limitsEndAt = uint64(block.timestamp);
emit LimitsLiftedEarly(limitsEndAt);
}
// --- owner configuration ------------------------------------------------
function setPair(address pair, bool value) external onlyOwner {
if (pair == address(0)) revert ZeroAddress();
isPair[pair] = value;
emit PairSet(pair, value);
}
function setExempt(address account, bool value) external onlyOwner {
if (account == address(0)) revert ZeroAddress();
isExempt[account] = value;
emit ExemptSet(account, value);
}
function setFeeRecipient(address recipient) external onlyOwner {
if (recipient == address(0)) revert ZeroAddress();
address previous = feeRecipient;
feeRecipient = recipient;
isExempt[recipient] = true;
emit FeeRecipientSet(previous, recipient);
}
function setFeeBps(uint16 newFeeBps) external onlyOwner {
if (newFeeBps > MAX_FEE_BPS) revert FeeTooHigh(newFeeBps, MAX_FEE_BPS);
uint16 previous = feeBps;
feeBps = newFeeBps;
emit FeeBpsSet(previous, newFeeBps);
}
/// @dev Restricted to the launch window by `onlyWhileLimited`, so it stops working on
/// its own. Batched because snipers arrive together and each second matters.
function flagSnipers(address[] calldata accounts) external onlyOwner onlyWhileLimited {
for (uint256 i = 0; i < accounts.length; ++i) {
isSniper[accounts[i]] = true;
emit SniperFlagged(accounts[i]);
}
}
/// @dev Deliberately NOT window-restricted. This can only remove a restriction, and a
/// mistaken flag should be correctable for as long as the flag has any effect.
function clearSniper(address account) external onlyOwner {
isSniper[account] = false;
emit SniperCleared(account);
}
// --- transfer logic -----------------------------------------------------
function _update(address from, address to, uint256 value) internal override {
// Mint and burn bypass every check. Without this the constructor mint would be
// rejected for exceeding maxWallet before trading is even enabled.
if (from == address(0) || to == address(0)) {
super._update(from, to, value);
return;
}
bool exempt = isExempt[from] || isExempt[to];
if (!exempt) {
if (!tradingEnabled) revert TradingNotEnabled();
if (limitsActive()) _enforceLimits(from, to, value);
}
uint256 fee = exempt ? 0 : (value * feeBps) / BPS_DENOMINATOR;
if (fee > 0) {
super._update(from, feeRecipient, fee);
unchecked {
value -= fee;
}
}
super._update(from, to, value);
}
/// @dev Only reachable while `limitsActive()`. After the window this function is dead
/// code from the transfer path's point of view.
function _enforceLimits(address from, address to, uint256 value) private {
bool buying = isPair[from];
bool selling = isPair[to];
// Same-block-as-launch buyers are the bots this exists for. They are blocked from
// SELLING for the remainder of the window only - long enough to defeat the flip,
// short enough that no wallet is ever permanently trapped.
if (buying && uint64(block.number) == launchBlock) {
isSniper[to] = true;
emit SniperFlagged(to);
}
if (selling && isSniper[from]) revert SniperCannotSellDuringWindow(from);
if (value > maxTxAmount) revert MaxTxExceeded(value, maxTxAmount);
if (!selling) {
uint256 resulting = balanceOf(to) + value;
if (resulting > maxWalletAmount) revert MaxWalletExceeded(resulting, maxWalletAmount);
}
// Cooldown applies per wallet across BOTH pools. A sniper rate-limited on
// PBURN/pFLY must not be able to route around it through PBURN/pCOCK, so the
// timestamp is keyed on the trader and not on the pair.
if (buying || selling) {
address trader = buying ? to : from;
uint64 nextAllowed = lastTradeAt[trader] + TRADE_COOLDOWN;
if (lastTradeAt[trader] != 0 && block.timestamp < nextAllowed) {
revert CooldownActive(nextAllowed);
}
lastTradeAt[trader] = uint64(block.timestamp);
}
}
// --- burn ---------------------------------------------------------------
/// @notice Destroys supply outright. No privileged burn-from exists.
function burn(uint256 amount) external nonReentrant {
_burn(msg.sender, amount);
}
}
lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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 EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* 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;
}
}
lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
lib/openzeppelin-contracts/contracts/access/Ownable.sol
// 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);
}
}
lib/openzeppelin-contracts/contracts/utils/Context.sol
// 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;
}
}
lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.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 ERC-20 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);
}
lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC-20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-20 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 ERC-721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in ERC-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 ERC-1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC-1155 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);
}
Compiler Settings
{"viaIR":false,"remappings":["@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/","forge-std/=lib/forge-std/src/","ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/","erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/","halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/","openzeppelin-contracts/=lib/openzeppelin-contracts/"],"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode"]}},"optimizer":{"runs":200,"enabled":true},"metadata":{"useLiteralContent":false,"bytecodeHash":"ipfs","appendCBOR":true},"libraries":{},"evmVersion":"paris"}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"token_","internalType":"contract PulseBurnLaunch"},{"type":"address","name":"operator_","internalType":"address"},{"type":"address","name":"timelock_","internalType":"address"}]},{"type":"error","name":"OnlyOperator","inputs":[]},{"type":"error","name":"WindowClosed","inputs":[]},{"type":"error","name":"WindowStillOpen","inputs":[{"type":"uint64","name":"endsAt","internalType":"uint64"}]},{"type":"error","name":"ZeroAddress","inputs":[]},{"type":"event","name":"Claimed","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"OfferedToTimelock","inputs":[{"type":"address","name":"token","internalType":"address","indexed":true},{"type":"address","name":"timelock","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"clearSniper","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"flagSnipers","inputs":[{"type":"address[]","name":"accounts","internalType":"address[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"liftLimitsEarly","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"offerToTimelock","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"operator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"timelock","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract PulseBurnLaunch"}],"name":"token","inputs":[]}]
Contract Creation Code
0x60e060405234801561001057600080fd5b50604051610a76380380610a7683398101604081905261002f916100b1565b6001600160a01b038316158061004c57506001600160a01b038216155b8061005e57506001600160a01b038116155b1561007c5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b0392831660805290821660a0521660c0526100fe565b6001600160a01b03811681146100ae57600080fd5b50565b6000806000606084860312156100c657600080fd5b83516100d181610099565b60208501519093506100e281610099565b60408501519092506100f381610099565b809150509250925092565b60805160a05160c0516108e26101946000396000818160fa0152818161040e015261049d01526000818160b701528181610169015281816105e0015261069e01526000818161013c015281816101a901528181610265015281816102c60152818161034d01528181610436015281816104c20152818161050e0152818161058a0152818161062001526106f301526108e26000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063d33219b41161005b578063d33219b4146100f5578063db04427c1461011c578063f65562ad14610124578063fc0c546a1461013757600080fd5b806303b78b8b1461008d57806343ebe14e146100a25780634e71d92d146100aa578063570ca735146100b2575b600080fd5b6100a061009b36600461077c565b61015e565b005b6100a06102c4565b6100a061050c565b6100d97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b6100d97f000000000000000000000000000000000000000000000000000000000000000081565b6100a06105d5565b6100a061013236600461079e565b610693565b6100d97f000000000000000000000000000000000000000000000000000000000000000081565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101a7576040516327e1f1e560e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631cce34ee6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102299190610815565b61024657604051632f23cfcd60e01b815260040160405180910390fd5b6040516303b78b8b60e01b81526001600160a01b0382811660048301527f000000000000000000000000000000000000000000000000000000000000000016906303b78b8b90602401600060405180830381600087803b1580156102a957600080fd5b505af11580156102bd573d6000803e3d6000fd5b5050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631cce34ee6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610322573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103469190610815565b156103f7577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166397a601936040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cd9190610837565b60405163d62136e760e01b815267ffffffffffffffff909116600482015260240160405180910390fd5b60405163f2fde38b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660048301527f0000000000000000000000000000000000000000000000000000000000000000169063f2fde38b90602401600060405180830381600087803b15801561047a57600080fd5b505af115801561048e573d6000803e3d6000fd5b50506040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811693507f00000000000000000000000000000000000000000000000000000000000000001691507fa72ea8ff6f31ee48eb3eb0e455ad76361f6b590e413d6b264583eaeef8f22e6190600090a3565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561056757600080fd5b505af115801561057b573d6000803e3d6000fd5b50506040516001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692507fb449c24d261a59627b537c8c41c57ab559f4205c56bea745ff61c5521bece2149150600090a2565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461061e576040516327e1f1e560e01b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663db04427c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561067957600080fd5b505af115801561068d573d6000803e3d6000fd5b50505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146106dc576040516327e1f1e560e01b815260040160405180910390fd5b60405163f65562ad60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f65562ad9061072a9085908590600401610861565b600060405180830381600087803b15801561074457600080fd5b505af1158015610758573d6000803e3d6000fd5b505050505050565b80356001600160a01b038116811461077757600080fd5b919050565b60006020828403121561078e57600080fd5b61079782610760565b9392505050565b600080602083850312156107b157600080fd5b823567ffffffffffffffff8111156107c857600080fd5b8301601f810185136107d957600080fd5b803567ffffffffffffffff8111156107f057600080fd5b8560208260051b840101111561080557600080fd5b6020919091019590945092505050565b60006020828403121561082757600080fd5b8151801515811461079757600080fd5b60006020828403121561084957600080fd5b815167ffffffffffffffff8116811461079757600080fd5b6020808252810182905260008360408301825b858110156108a2576001600160a01b0361088d84610760565b16825260209283019290910190600101610874565b509594505050505056fea2646970667358221220e06cc2909d2357b37fd70c8fd99d06c0229c401414fde7bdfd9ce4c556a7a2ef64736f6c634300081a0033000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f01058000000000000000000000000ede5501406c1e191f40a0145fa3d4881c18e458000000000000000000000000084bd7c30bec67cba9952cc07e3bf3a90180547db
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106100885760003560e01c8063d33219b41161005b578063d33219b4146100f5578063db04427c1461011c578063f65562ad14610124578063fc0c546a1461013757600080fd5b806303b78b8b1461008d57806343ebe14e146100a25780634e71d92d146100aa578063570ca735146100b2575b600080fd5b6100a061009b36600461077c565b61015e565b005b6100a06102c4565b6100a061050c565b6100d97f000000000000000000000000ede5501406c1e191f40a0145fa3d4881c18e458081565b6040516001600160a01b03909116815260200160405180910390f35b6100d97f00000000000000000000000084bd7c30bec67cba9952cc07e3bf3a90180547db81565b6100a06105d5565b6100a061013236600461079e565b610693565b6100d97f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f0105881565b336001600160a01b037f000000000000000000000000ede5501406c1e191f40a0145fa3d4881c18e458016146101a7576040516327e1f1e560e01b815260040160405180910390fd5b7f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f010586001600160a01b0316631cce34ee6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102299190610815565b61024657604051632f23cfcd60e01b815260040160405180910390fd5b6040516303b78b8b60e01b81526001600160a01b0382811660048301527f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f0105816906303b78b8b90602401600060405180830381600087803b1580156102a957600080fd5b505af11580156102bd573d6000803e3d6000fd5b5050505050565b7f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f010586001600160a01b0316631cce34ee6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610322573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103469190610815565b156103f7577f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f010586001600160a01b03166397a601936040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103cd9190610837565b60405163d62136e760e01b815267ffffffffffffffff909116600482015260240160405180910390fd5b60405163f2fde38b60e01b81526001600160a01b037f00000000000000000000000084bd7c30bec67cba9952cc07e3bf3a90180547db811660048301527f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f01058169063f2fde38b90602401600060405180830381600087803b15801561047a57600080fd5b505af115801561048e573d6000803e3d6000fd5b50506040516001600160a01b037f00000000000000000000000084bd7c30bec67cba9952cc07e3bf3a90180547db811693507f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f010581691507fa72ea8ff6f31ee48eb3eb0e455ad76361f6b590e413d6b264583eaeef8f22e6190600090a3565b7f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f010586001600160a01b03166379ba50976040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561056757600080fd5b505af115801561057b573d6000803e3d6000fd5b50506040516001600160a01b037f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f010581692507fb449c24d261a59627b537c8c41c57ab559f4205c56bea745ff61c5521bece2149150600090a2565b336001600160a01b037f000000000000000000000000ede5501406c1e191f40a0145fa3d4881c18e4580161461061e576040516327e1f1e560e01b815260040160405180910390fd5b7f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f010586001600160a01b031663db04427c6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561067957600080fd5b505af115801561068d573d6000803e3d6000fd5b50505050565b336001600160a01b037f000000000000000000000000ede5501406c1e191f40a0145fa3d4881c18e458016146106dc576040516327e1f1e560e01b815260040160405180910390fd5b60405163f65562ad60e01b81526001600160a01b037f000000000000000000000000dd99adf15d84d425f02983e730b0db8e27f01058169063f65562ad9061072a9085908590600401610861565b600060405180830381600087803b15801561074457600080fd5b505af1158015610758573d6000803e3d6000fd5b505050505050565b80356001600160a01b038116811461077757600080fd5b919050565b60006020828403121561078e57600080fd5b61079782610760565b9392505050565b600080602083850312156107b157600080fd5b823567ffffffffffffffff8111156107c857600080fd5b8301601f810185136107d957600080fd5b803567ffffffffffffffff8111156107f057600080fd5b8560208260051b840101111561080557600080fd5b6020919091019590945092505050565b60006020828403121561082757600080fd5b8151801515811461079757600080fd5b60006020828403121561084957600080fd5b815167ffffffffffffffff8116811461079757600080fd5b6020808252810182905260008360408301825b858110156108a2576001600160a01b0361088d84610760565b16825260209283019290910190600101610874565b509594505050505056fea2646970667358221220e06cc2909d2357b37fd70c8fd99d06c0229c401414fde7bdfd9ce4c556a7a2ef64736f6c634300081a0033