Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- SunPLSOracleV2
- Optimization enabled
- true
- Compiler version
- v0.8.20+commit.a1b79de6
- Optimization runs
- 200
- EVM Version
- shanghai
- Verified at
- 2026-03-12T00:46:16.181846Z
Constructor Arguments
000000000000000000000000ca46e01f4bf6938e8d8b8d22a570ffe96e9f0b19000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2700000000000000000000000004b37fa64a8d73a37d636608e5f6f8e5ce1541aa
Arg [0] (address) : 0xca46e01f4bf6938e8d8b8d22a570ffe96e9f0b19
Arg [1] (address) : 0xa1077a294dde1b09bb078844df40758a5d0f9a27
Arg [2] (address) : 0x04b37fa64a8d73a37d636608e5f6f8e5ce1541aa
SunPulse_Oracle.sol
// SPDX-License-Identifier: CC-BY-NC-SA-4.0
pragma solidity ^0.8.20;
/**
* ╔══════════════════════════════════════════════════════════════════════╗
* ║ SunPLS Oracle v1.2 — ELITE TEAM6 ║
* ║ Single-Pair TWAP Oracle for PulseChain ║
* ║ ║
* ║ Reads SunPLS/WPLS pair from PulseX ║
* ║ ║
* ║ PRICE DIRECTION: WPLS per SunPLS (1e18 scale) ║
* ║ Example: 100_000e18 = 1 SunPLS costs 100,000 PLS ║
* ║ This matches Controller's R (also WPLS per SunPLS) ║
* ║ ε = |P - R| / R is meaningful only when P and R share units ║
* ║ ║
* ║ UNISWAP V2 CUMULATIVE PRICE DIRECTION: ║
* ║ price0Cumulative = token1/token0 (in Q112 fixed point) ║
* ║ price1Cumulative = token0/token1 (in Q112 fixed point) ║
* ║ When wplsIsToken0: we want WPLS/SunPLS = token0/token1 ║
* ║ → use price1CumulativeLast ║
* ║ When wplsIsToken1: we want WPLS/SunPLS = token1/token0 ║
* ║ → use price0CumulativeLast ║
* ║ ║
* ║ ANTI-MANIPULATION: ║
* ║ • TWAP (60s window) for manipulation resistance ║
* ║ • Creeping: deviations >5% require 3 confirmations + 10% step ║
* ║ • Candidate tolerance band: rolling TWAP windows naturally produce ║
* ║ slightly different values each call. Confirmations now accumulate║
* ║ if the new reading is within 1% of pendingPrice, preventing ║
* ║ legitimate large moves from stalling indefinitely. ║
* ║ • Flash loan defense: MIN_TWAP_INTERVAL between updates ║
* ║ • Bootstrap from live reserves (no magic number starting price) ║
* ║ ║
* ║ CHANGELOG v1.2: ║
* ║ • Fixed creeping confirmation stall on large legitimate moves. ║
* ║ Previously: confirmations required newPrice == pendingPrice ║
* ║ (exact equality). Rolling TWAP windows produce fractionally ║
* ║ different values each call (e.g. 40.1e18, 40.2e18, 40.15e18), ║
* ║ causing confirmations to reset to 1 on every call. A sustained ║
* ║ PLS pump could leave the oracle permanently stuck tracking a ║
* ║ stale price, forcing indefinite Controller Mode B/C degradation. ║
* ║ Fix: CANDIDATE_TOLERANCE_BPS = 100 (1%) tolerance band. Any ║
* ║ new TWAP reading within 1% of pendingPrice counts as the same ║
* ║ candidate and increments confirmations. Genuine reversals (>1% ║
* ║ away from pendingPrice) still reset the counter. pendingPrice ║
* ║ updates to the latest reading within the band so it tracks the ║
* ║ rolling TWAP accurately. ║
* ║ ║
* ║ CHANGELOG v1.1: ║
* ║ • Split lastUpdateTimestamp (call gate) from lastPriceTimestamp ║
* ║ (when lastPrice last actually changed). isHealthy() and peek() ║
* ║ now use lastPriceTimestamp so health/staleness signals are ║
* ║ accurate even during creep confirmation accumulation. ║
* ║ ║
* ║ Dev: ELITE TEAM6 ║
* ║ License: CC-BY-NC-SA-4.0 | Immutable After Launch ║
* ╚══════════════════════════════════════════════════════════════════════╝
*
* ═══════════════════════════════════════════════════════════════════════
* CREEPING MECHANISM — HOW IT WORKS
* ═══════════════════════════════════════════════════════════════════════
*
* Small moves (≤5%): accepted immediately every call.
*
* Large moves (>5%): require confirmation before creeping:
*
* 1. First reading above threshold → pendingPrice = newPrice, confirmations = 1
* 2. Subsequent readings within 1% of pendingPrice → confirmations++
* pendingPrice updates to latest reading (tracks rolling TWAP)
* 3. Reading >1% away from pendingPrice → genuine reversal detected,
* pendingPrice = newPrice, confirmations = 1 (fresh start)
* 4. Once confirmations >= MAX_CONFIRMATIONS (3):
* → creep lastPrice by CREEP_STEP_BPS (10%) toward pendingPrice
* → reset confirmation state
* → repeat until lastPrice converges to pendingPrice
*
* Example — PLS pumps 40%:
* Call 1: TWAP = 140e18. Deviation 40% > 5%. pending=140e18, conf=1
* Call 2: TWAP = 140.2e18. Within 1% of 140e18. pending=140.2e18, conf=2
* Call 3: TWAP = 139.9e18. Within 1% of 140.2e18. pending=139.9e18, conf=3
* → Creep: lastPrice moves 10% toward 139.9e18
* Repeat until converged. Total time: ~(40/10) × 3 × 60s = ~12 minutes.
*
* ═══════════════════════════════════════════════════════════════════════
*/
interface IUniswapV2Pair {
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint256);
function price1CumulativeLast() external view returns (uint256);
}
contract SunPLSOracleV2 {
// ─────────────────────────────────────────────────────────────────────
// Immutables
// ─────────────────────────────────────────────────────────────────────
IUniswapV2Pair public immutable pair;
address public immutable wpls;
address public immutable sunpls;
/// @notice True if WPLS is token0. Determines which accumulator to use.
bool public immutable wplsIsToken0;
// ─────────────────────────────────────────────────────────────────────
// Constants
// ─────────────────────────────────────────────────────────────────────
uint256 public constant PRECISION = 1e18;
/// @notice Instant-accept threshold: deviations ≤ 5% accepted immediately
uint256 public constant MAX_DEVIATION_BPS = 500;
/// @notice Minimum seconds between oracle calls — flash loan defense
uint256 public constant MIN_TWAP_INTERVAL = 60;
/// @notice Oracle considered unhealthy if lastPrice not changed within this window
uint256 public constant MAX_PRICE_AGE = 300;
/// @notice Confirmations before a large deviation is accepted (via creep)
uint8 private constant MAX_CONFIRMATIONS = 3;
/// @notice Each creep step moves 10% toward the confirmed price
uint16 private constant CREEP_STEP_BPS = 1000;
/// @notice v1.2: Tolerance band for creep candidate matching.
/// Rolling TWAP windows naturally produce fractionally different
/// values each call. A new reading within 1% of pendingPrice
/// is treated as the same candidate and increments confirmations.
/// Genuine reversals (deviation > 1% from pendingPrice) reset.
uint16 private constant CANDIDATE_TOLERANCE_BPS = 100;
// ─────────────────────────────────────────────────────────────────────
// State
// ─────────────────────────────────────────────────────────────────────
/// @notice Last accepted price in WPLS per SunPLS (1e18 scale)
uint256 public lastPrice;
/// @notice Timestamp of last oracle CALL (used as rate-limit gate).
/// Advanced on every _updateIfNeeded() invocation regardless
/// of whether lastPrice changed. Do not use for staleness checks.
uint256 public lastUpdateTimestamp;
/// @notice Timestamp of last actual lastPrice CHANGE (accepted or creep step).
/// Used by isHealthy() and peek() for accurate staleness signals.
/// Only advances when lastPrice is written.
uint256 public lastPriceTimestamp;
/// @notice Cumulative price snapshot for TWAP (Q112 scale)
uint256 private priceCumulativeLast;
/// @notice Pair's blockTimestamp at last TWAP snapshot (seconds, wraps at uint32 max)
uint32 private blockTimestampLast;
/// @notice Price awaiting creep confirmation (tracks latest reading in the band)
uint256 private pendingPrice;
/// @notice Confirmations accumulated for pendingPrice
uint8 private confirmations;
// ─────────────────────────────────────────────────────────────────────
// Events
// ─────────────────────────────────────────────────────────────────────
event PriceUpdated(uint256 price, uint256 timestamp, bool creeping);
// ─────────────────────────────────────────────────────────────────────
// Constructor
// ─────────────────────────────────────────────────────────────────────
/**
* @param _pair PulseX SunPLS/WPLS pair — must have liquidity at deploy
* @param _wpls WPLS token address
* @param _sunpls SunPLS token address
*
* @dev Bootstraps lastPrice from live reserves so the oracle starts
* at the real market price. The pool must be seeded before this
* contract is deployed.
*/
constructor(address _pair, address _wpls, address _sunpls) {
require(
_pair != address(0) &&
_wpls != address(0) &&
_sunpls != address(0),
"Zero address"
);
pair = IUniswapV2Pair(_pair);
wpls = _wpls;
sunpls = _sunpls;
// Verify both tokens are in the pair
address t0 = IUniswapV2Pair(_pair).token0();
address t1 = IUniswapV2Pair(_pair).token1();
bool _wplsIsToken0 = (t0 == _wpls);
require(_wplsIsToken0 || t1 == _wpls, "Pair missing WPLS");
require(t0 == _sunpls || t1 == _sunpls, "Pair missing SunPLS");
wplsIsToken0 = _wplsIsToken0;
// Seed cumulative accumulator
(, , uint32 ts) = IUniswapV2Pair(_pair).getReserves();
blockTimestampLast = ts;
priceCumulativeLast = _wplsIsToken0
? IUniswapV2Pair(_pair).price1CumulativeLast()
: IUniswapV2Pair(_pair).price0CumulativeLast();
// Bootstrap from live spot price — pool must have liquidity
(uint112 r0, uint112 r1,) = IUniswapV2Pair(_pair).getReserves();
require(r0 > 0 && r1 > 0, "Pool has no liquidity at deploy");
uint256 initialPrice = _wplsIsToken0
? (uint256(r0) * PRECISION) / uint256(r1)
: (uint256(r1) * PRECISION) / uint256(r0);
require(initialPrice > 0, "Zero initial price");
lastPrice = initialPrice;
lastUpdateTimestamp = block.timestamp;
lastPriceTimestamp = block.timestamp;
}
// ─────────────────────────────────────────────────────────────────────
// External interface — Controller + Vault compatible
// ─────────────────────────────────────────────────────────────────────
/**
* @notice Update oracle and return current price.
* Called by Controller each epoch and Vault on mint/liquidate.
*/
function update() external returns (uint256 price, uint256 timestamp) {
return _updateIfNeeded();
}
/**
* @notice Read current price without mutating state.
* Returns lastPriceTimestamp — the time lastPrice last changed.
* Vault uses this for staleness: block.timestamp - ts <= MAX_ORACLE_STALENESS.
* Using lastPriceTimestamp here (not lastUpdateTimestamp) ensures the vault's
* staleness check reflects actual price age, not just last call time.
*/
function peek() external view returns (uint256 price, uint256 timestamp) {
return (lastPrice, lastPriceTimestamp);
}
/**
* @notice True if lastPrice has changed within 2 × MAX_PRICE_AGE.
* Uses lastPriceTimestamp so health accurately reflects price
* freshness, not just whether update() was recently called.
*/
function isHealthy() external view returns (bool) {
return (block.timestamp - lastPriceTimestamp) < (MAX_PRICE_AGE * 2);
}
// ─────────────────────────────────────────────────────────────────────
// Internal — update logic
// ─────────────────────────────────────────────────────────────────────
function _updateIfNeeded() internal returns (uint256, uint256) {
// Rate-limit gate: MIN_TWAP_INTERVAL between oracle calls.
// Uses lastUpdateTimestamp (call time) not lastPriceTimestamp (price time)
// so the gate works regardless of whether the last call changed the price.
if (block.timestamp - lastUpdateTimestamp < MIN_TWAP_INTERVAL) {
return (lastPrice, lastPriceTimestamp);
}
(uint112 r0, uint112 r1, uint32 tsPair) = pair.getReserves();
require(r0 > 0 && r1 > 0, "No liquidity");
uint32 elapsed = uint32(block.timestamp) - blockTimestampLast;
uint256 newPrice;
if (elapsed < MIN_TWAP_INTERVAL) {
newPrice = _spotPrice(r0, r1);
} else {
newPrice = _twapPrice(r0, r1, tsPair, elapsed);
}
// Advance call gate timestamp BEFORE applying creep so the rate-limit
// applies even if _applyCreepingOrAccept doesn't change lastPrice.
lastUpdateTimestamp = block.timestamp;
_applyCreepingOrAccept(newPrice);
return (lastPrice, lastPriceTimestamp);
}
/**
* @dev Spot price: WPLS per SunPLS from current reserves.
*/
function _spotPrice(uint112 r0, uint112 r1) internal view returns (uint256) {
return wplsIsToken0
? (uint256(r0) * PRECISION) / uint256(r1)
: (uint256(r1) * PRECISION) / uint256(r0);
}
/**
* @dev TWAP price: WPLS per SunPLS from cumulative accumulators.
*/
function _twapPrice(
uint112 r0,
uint112 r1,
uint32 tsPair,
uint32 elapsed
) internal returns (uint256) {
uint256 cumulative = wplsIsToken0
? pair.price1CumulativeLast()
: pair.price0CumulativeLast();
unchecked {
uint32 gapSinceSync = uint32(block.timestamp) - tsPair;
if (gapSinceSync > 0) {
uint256 instantQ112 = wplsIsToken0
? (uint256(r0) << 112) / uint256(r1)
: (uint256(r1) << 112) / uint256(r0);
cumulative += instantQ112 * gapSinceSync;
}
}
uint256 diff = cumulative - priceCumulativeLast;
uint256 twap = (diff * PRECISION) / (uint256(elapsed) << 112);
priceCumulativeLast = cumulative;
blockTimestampLast = uint32(block.timestamp);
return twap;
}
/**
* @dev Accept price immediately if deviation ≤ MAX_DEVIATION_BPS.
* For larger moves: accumulate MAX_CONFIRMATIONS using a tolerance
* band, then creep CREEP_STEP_BPS (10%) toward the confirmed price.
*
* v1.2 CHANGE — candidate matching:
* Old: confirmations++ only if newPrice == pendingPrice (exact).
* New: confirmations++ if newPrice is within CANDIDATE_TOLERANCE_BPS
* (1%) of pendingPrice. pendingPrice updates to newPrice so it
* tracks the rolling TWAP within the band.
*
* Why: TWAP windows roll forward each call, producing slightly
* different values (e.g. 140.1e18 vs 140.2e18) even for a sustained
* price. Exact equality never accumulates. The 1% band is tight enough
* to reject genuine reversals while wide enough to absorb TWAP drift.
*
* lastPriceTimestamp is ONLY updated when lastPrice actually changes.
* lastUpdateTimestamp is updated by _updateIfNeeded() before this call.
*/
function _applyCreepingOrAccept(uint256 newPrice) internal {
if (lastPrice == 0) {
lastPrice = newPrice;
lastPriceTimestamp = block.timestamp;
emit PriceUpdated(newPrice, block.timestamp, false);
return;
}
uint256 diff = newPrice > lastPrice ? newPrice - lastPrice : lastPrice - newPrice;
uint256 deviationBps = (diff * 10_000) / lastPrice;
if (deviationBps <= MAX_DEVIATION_BPS) {
// Small move — accept immediately, clear pending state
lastPrice = newPrice;
lastPriceTimestamp = block.timestamp;
confirmations = 0;
pendingPrice = 0;
emit PriceUpdated(newPrice, block.timestamp, false);
return;
}
// Large move — check if newPrice is within tolerance band of pendingPrice
// v1.2: tolerance band replaces exact equality check
bool sameCandidate = false;
if (pendingPrice > 0) {
uint256 candidateDiff = newPrice > pendingPrice
? newPrice - pendingPrice
: pendingPrice - newPrice;
sameCandidate = (candidateDiff * 10_000) / pendingPrice <= CANDIDATE_TOLERANCE_BPS;
}
if (sameCandidate) {
// Within 1% of current candidate — count as confirmation.
// Update pendingPrice to latest reading so it tracks TWAP drift.
pendingPrice = newPrice;
confirmations++;
} else {
// Genuine new candidate (reversal or first reading) — reset
pendingPrice = newPrice;
confirmations = 1;
}
if (confirmations >= MAX_CONFIRMATIONS) {
// Creep 10% toward confirmed price
uint256 step = pendingPrice > lastPrice
? ((pendingPrice - lastPrice) * CREEP_STEP_BPS) / 10_000
: ((lastPrice - pendingPrice) * CREEP_STEP_BPS) / 10_000;
lastPrice = pendingPrice > lastPrice
? lastPrice + step
: lastPrice - step;
// Price changed — update price timestamp
lastPriceTimestamp = block.timestamp;
confirmations = 0;
pendingPrice = 0;
emit PriceUpdated(lastPrice, block.timestamp, true);
}
// NOTE: lastUpdateTimestamp already advanced in _updateIfNeeded().
// We do NOT touch it here. During confirmation accumulation, lastPrice
// is unchanged and lastPriceTimestamp correctly remains stale.
}
// ─────────────────────────────────────────────────────────────────────
// View helpers
// ─────────────────────────────────────────────────────────────────────
/// @notice Current spot price from reserves (no state change).
function getSpotPrice() external view returns (uint256) {
(uint112 r0, uint112 r1,) = pair.getReserves();
if (r0 == 0 || r1 == 0) return lastPrice;
return _spotPrice(r0, r1);
}
/// @notice Oracle configuration for on-chain verification.
function getConfig()
external
view
returns (
address pairAddress,
address wplsAddress,
address sunplsAddress,
bool wplsIsToken0Flag,
uint256 maxDeviationBps,
uint256 minTwapInterval,
uint256 maxPriceAge,
uint256 candidateToleranceBps
)
{
return (
address(pair),
wpls,
sunpls,
wplsIsToken0,
MAX_DEVIATION_BPS,
MIN_TWAP_INTERVAL,
MAX_PRICE_AGE,
CANDIDATE_TOLERANCE_BPS
);
}
/// @notice Creeping state for dashboards and monitoring.
function getCreepingState()
external
view
returns (
uint256 pending,
uint8 confirmCount,
bool isCreeping
)
{
return (pendingPrice, confirmations, pendingPrice > 0);
}
}
Compiler Settings
{"remappings":[],"optimizer":{"runs":200,"enabled":true},"metadata":{"bytecodeHash":"ipfs"},"libraries":{},"evmVersion":"shanghai","compilationTarget":{"SunPulse_Oracle.sol":"SunPLSOracleV2"}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_pair","internalType":"address"},{"type":"address","name":"_wpls","internalType":"address"},{"type":"address","name":"_sunpls","internalType":"address"}]},{"type":"event","name":"PriceUpdated","inputs":[{"type":"uint256","name":"price","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"bool","name":"creeping","internalType":"bool","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_DEVIATION_BPS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_PRICE_AGE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MIN_TWAP_INTERVAL","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"pairAddress","internalType":"address"},{"type":"address","name":"wplsAddress","internalType":"address"},{"type":"address","name":"sunplsAddress","internalType":"address"},{"type":"bool","name":"wplsIsToken0Flag","internalType":"bool"},{"type":"uint256","name":"maxDeviationBps","internalType":"uint256"},{"type":"uint256","name":"minTwapInterval","internalType":"uint256"},{"type":"uint256","name":"maxPriceAge","internalType":"uint256"},{"type":"uint256","name":"candidateToleranceBps","internalType":"uint256"}],"name":"getConfig","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"pending","internalType":"uint256"},{"type":"uint8","name":"confirmCount","internalType":"uint8"},{"type":"bool","name":"isCreeping","internalType":"bool"}],"name":"getCreepingState","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getSpotPrice","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isHealthy","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastPrice","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastPriceTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastUpdateTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IUniswapV2Pair"}],"name":"pair","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"peek","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"sunpls","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"name":"update","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"wpls","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"wplsIsToken0","inputs":[]}]
Contract Creation Code
0x61010060405234801562000011575f80fd5b506040516200140d3803806200140d8339810160408190526200003491620005b2565b6001600160a01b038316158015906200005557506001600160a01b03821615155b80156200006a57506001600160a01b03811615155b620000ab5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b60448201526064015b60405180910390fd5b6001600160a01b03808416608081905283821660a05290821660c05260408051630dfe168160e01b815290515f9291630dfe16819160048083019260209291908290030181865afa15801562000103573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620001299190620005f9565b90505f846001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000169573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906200018f9190620005f9565b90506001600160a01b03828116908516148080620001be5750846001600160a01b0316826001600160a01b0316145b620002005760405162461bcd60e51b815260206004820152601160248201527050616972206d697373696e672057504c5360781b6044820152606401620000a2565b836001600160a01b0316836001600160a01b03161480620002325750836001600160a01b0316826001600160a01b0316145b620002805760405162461bcd60e51b815260206004820152601360248201527f50616972206d697373696e672053756e504c53000000000000000000000000006044820152606401620000a2565b80151560e0811515815250505f866001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015620002ca573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620002f0919062000633565b6004805463ffffffff191663ffffffff831617905592508391506200037a905057866001600160a01b0316635909c0d56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156200034e573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000374919062000685565b620003dd565b866001600160a01b0316635a3d54936040518163ffffffff1660e01b8152600401602060405180830381865afa158015620003b7573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190620003dd919062000685565b6003819055505f80886001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa15801562000422573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019062000448919062000633565b50915091505f826001600160701b03161180156200046e57505f816001600160701b0316115b620004bc5760405162461bcd60e51b815260206004820152601f60248201527f506f6f6c20686173206e6f206c6971756964697479206174206465706c6f79006044820152606401620000a2565b5f84620004fe57826001600160701b0316670de0b6b3a7640000836001600160701b0316620004ec91906200069d565b620004f89190620006c7565b62000533565b816001600160701b0316670de0b6b3a7640000846001600160701b03166200052791906200069d565b620005339190620006c7565b90505f81116200057b5760405162461bcd60e51b81526020600482015260126024820152715a65726f20696e697469616c20707269636560701b6044820152606401620000a2565b5f55505042600181905560025550620006e795505050505050565b80516001600160a01b0381168114620005ad575f80fd5b919050565b5f805f60608486031215620005c5575f80fd5b620005d08462000596565b9250620005e06020850162000596565b9150620005f06040850162000596565b90509250925092565b5f602082840312156200060a575f80fd5b620006158262000596565b9392505050565b80516001600160701b0381168114620005ad575f80fd5b5f805f6060848603121562000646575f80fd5b62000651846200061c565b925062000661602085016200061c565b9150604084015163ffffffff811681146200067a575f80fd5b809150509250925092565b5f6020828403121562000696575f80fd5b5051919050565b8082028115828204841417620006c157634e487b7160e01b5f52601160045260245ffd5b92915050565b5f82620006e257634e487b7160e01b5f52601260045260245ffd5b500490565b60805160a05160c05160e051610ca5620007685f395f8181610296015281816102e8015281816105bd01528181610654015261079101525f818161026d015261031f01525f8181610168015261024501525f81816101b80152818161022001528181610368015281816104710152818161067901526106fe0152610ca55ff3fe608060405234801561000f575f80fd5b5060043610610106575f3560e01c8063a2e620451161009e578063c3f909d41161006e578063c3f909d414610212578063d4108e2a146102e3578063dc6a94221461031a578063dc76fabc14610341578063e402080414610349575f80fd5b8063a2e62045146101ab578063a8aa1b31146101b3578063aaf5eb68146101da578063b5d0db7a146101e9575f80fd5b80637de93f93116100d95780637de93f931461015257806391bf279b1461015b578063927ef7fa146101635780639d7f7e86146101a2575f80fd5b8063053f14da1461010a57806314bcec9f1461012557806325c684031461012e57806359e02dd714610137575b5f80fd5b6101125f5481565b6040519081526020015b60405180910390f35b61011260015481565b6101126101f481565b5f546002545b6040805192835260208301919091520161011c565b61011260025481565b610112603c81565b61018a7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161011c565b61011261012c81565b61013d610351565b61018a7f000000000000000000000000000000000000000000000000000000000000000081565b610112670de0b6b3a764000081565b6005546006546040805183815260ff90921660208301529115159181019190915260600161011c565b604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f0000000000000000000000000000000000000000000000000000000000000000811660208301527f000000000000000000000000000000000000000000000000000000000000000016918101919091527f0000000000000000000000000000000000000000000000000000000000000000151560608201526101f46080820152603c60a082015261012c60c0820152606460e08201526101000161011c565b61030a7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161011c565b61018a7f000000000000000000000000000000000000000000000000000000000000000081565b610112610363565b61030a610428565b5f8061035b610449565b915091509091565b5f805f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156103c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103e69190610b46565b5091509150816001600160701b03165f148061040957506001600160701b038116155b15610417575f549250505090565b61042182826105ba565b9250505090565b5f61043661012c6002610ba6565b6002546104439042610bbd565b10905090565b5f80603c6001544261045b9190610bbd565b101561046c5750505f546002549091565b5f805f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156104cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104ef9190610b46565b9250925092505f836001600160701b031611801561051557505f826001600160701b0316115b6105545760405162461bcd60e51b815260206004820152600c60248201526b4e6f206c697175696469747960a01b604482015260640160405180910390fd5b6004545f906105699063ffffffff1642610bd0565b90505f603c8263ffffffff16101561058c5761058585856105ba565b905061059b565b61059885858585610650565b90505b426001556105a881610878565b5f546002549650965050505050509091565b5f7f000000000000000000000000000000000000000000000000000000000000000061061657826001600160701b0316670de0b6b3a7640000836001600160701b03166106079190610ba6565b6106119190610c08565b610647565b816001600160701b0316670de0b6b3a7640000846001600160701b031661063d9190610ba6565b6106479190610c08565b90505b92915050565b5f807f00000000000000000000000000000000000000000000000000000000000000006106fc577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635909c0d56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106f79190610c27565b61077c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635a3d54936040518163ffffffff1660e01b8152600401602060405180830381865afa158015610758573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061077c9190610c27565b90504284900363ffffffff811615610815575f7f00000000000000000000000000000000000000000000000000000000000000006107df57876001600160701b03166070886001600160701b0316901b816107d9576107d9610bf4565b04610806565b866001600160701b03166070896001600160701b0316901b8161080457610804610bf4565b045b63ffffffff8316029290920191505b505f600354826108259190610bbd565b90505f63ffffffff60701b607086901b16610848670de0b6b3a764000084610ba6565b6108529190610c08565b60039390935550506004805463ffffffff19164263ffffffff1617905595945050505050565b5f545f036108cf575f8181554260028190556040805184815260208101929092528101919091527f2c0233f2ee34a876228db2e1c01e39264f7ffd29a8d12ff94b180c31592c7a609060600160405180910390a150565b5f805482116108ea57815f546108e59190610bbd565b6108f6565b5f546108f69083610bbd565b90505f8054826127106109099190610ba6565b6109139190610c08565b90506101f4811161097e575f8381554260028190556006805460ff1916905560058290556040805186815260208101929092528101919091527f2c0233f2ee34a876228db2e1c01e39264f7ffd29a8d12ff94b180c31592c7a609060600160405180910390a1505050565b6005545f90156109d7575f60055485116109a557846005546109a09190610bbd565b6109b2565b6005546109b29086610bbd565b6005549091506064906109c783612710610ba6565b6109d19190610c08565b11159150505b8015610a125760058490556006805460ff16905f6109f483610c3e565b91906101000a81548160ff021916908360ff16021790555050610a25565b60058490556006805460ff191660011790555b600654600360ff90911610610b25575f805460055411610a71576127106103e861ffff166005545f54610a589190610bbd565b610a629190610ba6565b610a6c9190610c08565b610a9e565b6127106103e861ffff165f54600554610a8a9190610bbd565b610a949190610ba6565b610a9e9190610c08565b90505f5460055411610abc57805f54610ab79190610bbd565b610ac9565b805f54610ac99190610c5c565b5f8181554260028190556006805460ff19169055600591909155604080519283526020830191909152600182820152517f2c0233f2ee34a876228db2e1c01e39264f7ffd29a8d12ff94b180c31592c7a609181900360600190a1505b50505050565b80516001600160701b0381168114610b41575f80fd5b919050565b5f805f60608486031215610b58575f80fd5b610b6184610b2b565b9250610b6f60208501610b2b565b9150604084015163ffffffff81168114610b87575f80fd5b809150509250925092565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761064a5761064a610b92565b8181038181111561064a5761064a610b92565b63ffffffff828116828216039080821115610bed57610bed610b92565b5092915050565b634e487b7160e01b5f52601260045260245ffd5b5f82610c2257634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215610c37575f80fd5b5051919050565b5f60ff821660ff8103610c5357610c53610b92565b60010192915050565b8082018082111561064a5761064a610b9256fea26469706673582212200938008797e0c07bd92eb28c899f02053a423bb60a8c539bb8d4794dc221934064736f6c63430008140033000000000000000000000000ca46e01f4bf6938e8d8b8d22a570ffe96e9f0b19000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2700000000000000000000000004b37fa64a8d73a37d636608e5f6f8e5ce1541aa
Deployed ByteCode
0x608060405234801561000f575f80fd5b5060043610610106575f3560e01c8063a2e620451161009e578063c3f909d41161006e578063c3f909d414610212578063d4108e2a146102e3578063dc6a94221461031a578063dc76fabc14610341578063e402080414610349575f80fd5b8063a2e62045146101ab578063a8aa1b31146101b3578063aaf5eb68146101da578063b5d0db7a146101e9575f80fd5b80637de93f93116100d95780637de93f931461015257806391bf279b1461015b578063927ef7fa146101635780639d7f7e86146101a2575f80fd5b8063053f14da1461010a57806314bcec9f1461012557806325c684031461012e57806359e02dd714610137575b5f80fd5b6101125f5481565b6040519081526020015b60405180910390f35b61011260015481565b6101126101f481565b5f546002545b6040805192835260208301919091520161011c565b61011260025481565b610112603c81565b61018a7f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a2781565b6040516001600160a01b03909116815260200161011c565b61011261012c81565b61013d610351565b61018a7f000000000000000000000000ca46e01f4bf6938e8d8b8d22a570ffe96e9f0b1981565b610112670de0b6b3a764000081565b6005546006546040805183815260ff90921660208301529115159181019190915260600161011c565b604080516001600160a01b037f000000000000000000000000ca46e01f4bf6938e8d8b8d22a570ffe96e9f0b19811682527f000000000000000000000000a1077a294dde1b09bb078844df40758a5d0f9a27811660208301527f00000000000000000000000004b37fa64a8d73a37d636608e5f6f8e5ce1541aa16918101919091527f0000000000000000000000000000000000000000000000000000000000000000151560608201526101f46080820152603c60a082015261012c60c0820152606460e08201526101000161011c565b61030a7f000000000000000000000000000000000000000000000000000000000000000081565b604051901515815260200161011c565b61018a7f00000000000000000000000004b37fa64a8d73a37d636608e5f6f8e5ce1541aa81565b610112610363565b61030a610428565b5f8061035b610449565b915091509091565b5f805f7f000000000000000000000000ca46e01f4bf6938e8d8b8d22a570ffe96e9f0b196001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156103c2573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103e69190610b46565b5091509150816001600160701b03165f148061040957506001600160701b038116155b15610417575f549250505090565b61042182826105ba565b9250505090565b5f61043661012c6002610ba6565b6002546104439042610bbd565b10905090565b5f80603c6001544261045b9190610bbd565b101561046c5750505f546002549091565b5f805f7f000000000000000000000000ca46e01f4bf6938e8d8b8d22a570ffe96e9f0b196001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156104cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104ef9190610b46565b9250925092505f836001600160701b031611801561051557505f826001600160701b0316115b6105545760405162461bcd60e51b815260206004820152600c60248201526b4e6f206c697175696469747960a01b604482015260640160405180910390fd5b6004545f906105699063ffffffff1642610bd0565b90505f603c8263ffffffff16101561058c5761058585856105ba565b905061059b565b61059885858585610650565b90505b426001556105a881610878565b5f546002549650965050505050509091565b5f7f000000000000000000000000000000000000000000000000000000000000000061061657826001600160701b0316670de0b6b3a7640000836001600160701b03166106079190610ba6565b6106119190610c08565b610647565b816001600160701b0316670de0b6b3a7640000846001600160701b031661063d9190610ba6565b6106479190610c08565b90505b92915050565b5f807f00000000000000000000000000000000000000000000000000000000000000006106fc577f000000000000000000000000ca46e01f4bf6938e8d8b8d22a570ffe96e9f0b196001600160a01b0316635909c0d56040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106d3573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106f79190610c27565b61077c565b7f000000000000000000000000ca46e01f4bf6938e8d8b8d22a570ffe96e9f0b196001600160a01b0316635a3d54936040518163ffffffff1660e01b8152600401602060405180830381865afa158015610758573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061077c9190610c27565b90504284900363ffffffff811615610815575f7f00000000000000000000000000000000000000000000000000000000000000006107df57876001600160701b03166070886001600160701b0316901b816107d9576107d9610bf4565b04610806565b866001600160701b03166070896001600160701b0316901b8161080457610804610bf4565b045b63ffffffff8316029290920191505b505f600354826108259190610bbd565b90505f63ffffffff60701b607086901b16610848670de0b6b3a764000084610ba6565b6108529190610c08565b60039390935550506004805463ffffffff19164263ffffffff1617905595945050505050565b5f545f036108cf575f8181554260028190556040805184815260208101929092528101919091527f2c0233f2ee34a876228db2e1c01e39264f7ffd29a8d12ff94b180c31592c7a609060600160405180910390a150565b5f805482116108ea57815f546108e59190610bbd565b6108f6565b5f546108f69083610bbd565b90505f8054826127106109099190610ba6565b6109139190610c08565b90506101f4811161097e575f8381554260028190556006805460ff1916905560058290556040805186815260208101929092528101919091527f2c0233f2ee34a876228db2e1c01e39264f7ffd29a8d12ff94b180c31592c7a609060600160405180910390a1505050565b6005545f90156109d7575f60055485116109a557846005546109a09190610bbd565b6109b2565b6005546109b29086610bbd565b6005549091506064906109c783612710610ba6565b6109d19190610c08565b11159150505b8015610a125760058490556006805460ff16905f6109f483610c3e565b91906101000a81548160ff021916908360ff16021790555050610a25565b60058490556006805460ff191660011790555b600654600360ff90911610610b25575f805460055411610a71576127106103e861ffff166005545f54610a589190610bbd565b610a629190610ba6565b610a6c9190610c08565b610a9e565b6127106103e861ffff165f54600554610a8a9190610bbd565b610a949190610ba6565b610a9e9190610c08565b90505f5460055411610abc57805f54610ab79190610bbd565b610ac9565b805f54610ac99190610c5c565b5f8181554260028190556006805460ff19169055600591909155604080519283526020830191909152600182820152517f2c0233f2ee34a876228db2e1c01e39264f7ffd29a8d12ff94b180c31592c7a609181900360600190a1505b50505050565b80516001600160701b0381168114610b41575f80fd5b919050565b5f805f60608486031215610b58575f80fd5b610b6184610b2b565b9250610b6f60208501610b2b565b9150604084015163ffffffff81168114610b87575f80fd5b809150509250925092565b634e487b7160e01b5f52601160045260245ffd5b808202811582820484141761064a5761064a610b92565b8181038181111561064a5761064a610b92565b63ffffffff828116828216039080821115610bed57610bed610b92565b5092915050565b634e487b7160e01b5f52601260045260245ffd5b5f82610c2257634e487b7160e01b5f52601260045260245ffd5b500490565b5f60208284031215610c37575f80fd5b5051919050565b5f60ff821660ff8103610c5357610c53610b92565b60010192915050565b8082018082111561064a5761064a610b9256fea26469706673582212200938008797e0c07bd92eb28c899f02053a423bb60a8c539bb8d4794dc221934064736f6c63430008140033