Description:
Smart contract deployed on Ethereum with Factory features.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"src/WethOver4800DoublePokeResolver.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
/// @notice Minimal interface to your PredictionAMM.
interface IPredictionMarketMinimal {
function closeMarket(uint256 marketId) external;
function resolve(uint256 marketId, bool outcome) external;
function tradingOpen(uint256 marketId) external view returns (bool);
function getMarket(uint256 marketId)
external
view
returns (
uint256 yesSupply,
uint256 noSupply,
address resolver,
bool resolved,
bool outcome,
uint256 pot,
uint256 payoutPerShare,
string memory desc
);
}
/// @notice Minimal interface to CheckTheChain (CTC).
interface ICheckTheChain {
// Use the address overload to avoid relying on symbol registration.
function checkPrice(address token)
external
view
returns (uint256 price, string memory priceStr);
}
/**
* @title WethOver4800DoublePokeResolver
* @notice YES iff WETH price in USDC (6 decimals) from CheckTheChain is strictly > 4800.000000
* in TWO snapshots: first ≥ 24h after deploy, second ≥ minDelay after the first.
* Only the deployer (owner) may call `poke()`.
*
* - Source: CheckTheChain (spot) at 0x0000000000cDC1F8d393415455E382c30FBc0a84
* - Asset: WETH at 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
* - Strike: 4_800_000_000 (4800.000000 USDC, 6 decimals)
* - Anti-MEV: requires two offside reads separated by time (minDelay), raising attack cost
*/
contract WethOver4800DoublePokeResolver {
// ---- Constants / config ----
ICheckTheChain public constant CTC = ICheckTheChain(0x0000000000cDC1F8d393415455E382c30FBc0a84);
address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
uint256 public constant STRIKE_X6 = 4_800_000_000; // 4800.000000 USDC
// ---- Immutable deps ----
IPredictionMarketMinimal public immutable PM;
address public immutable owner; // deployer
uint256 public immutable earliestTs; // deployedAt + 24h
uint256 public immutable minDelay; // seconds between snapshot#1 and #2
// ---- State ----
uint256 public marketId; // set via link()
bool public observed1; // first snapshot done
bool public observed2; // second snapshot done
uint256 public price1X6; // first snapshot price
uint256 public price2X6; // second snapshot price
uint256 public t1; // timestamp of first snapshot
uint256 public t2; // timestamp of second snapshot
// ---- Events ----
event Linked(uint256 indexed marketId);
event Observed1(uint256 priceX6, string pretty, uint256 atTs, uint256 atBlock);
event Observed2(uint256 priceX6, string pretty, uint256 atTs, uint256 atBlock);
event Closed(uint256 indexed marketId, uint256 atTs);
event Resolved(uint256 indexed marketId, bool yesOutcome);
// ---- Errors ----
error AlreadyLinked();
error NotLinked();
error WrongResolver();
error TooEarlyForFirst();
error TooEarlyForSecond();
error MarketStillOpen();
error NotOwner();
constructor() {
PM = IPredictionMarketMinimal(0x000000000088B4B43A69f8CDa34d93eD1d6f1431);
owner = msg.sender;
earliestTs = block.timestamp + 24 hours;
minDelay = 180;
}
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
/// @notice One-time link; verifies this contract is the market's resolver.
function link(uint256 _marketId) external {
if (marketId != 0) revert AlreadyLinked();
(,, address resolver,,,,,) = PM.getMarket(_marketId);
if (resolver != address(this)) revert WrongResolver();
marketId = _marketId;
emit Linked(_marketId);
}
/// @notice Deployer-only: take snapshots and resolve when both are collected.
/// Call #1 (≥ earliestTs): records price1.
/// Call #2 (≥ t1 + minDelay): records price2, then closes (if allowed) and resolves.
function poke() external onlyOwner {
uint256 id = marketId;
if (id == 0) revert NotLinked();
// 1) First observation gate
if (!observed1) {
if (block.timestamp < earliestTs) revert TooEarlyForFirst();
(uint256 px, string memory pretty) = CTC.checkPrice(WETH);
price1X6 = px;
observed1 = true;
t1 = block.timestamp;
emit Observed1(px, pretty, t1, block.number);
return; // need a second call later
}
// 2) Second observation gate
if (!observed2) {
if (block.timestamp < t1 + minDelay) revert TooEarlyForSecond();
(uint256 px2, string memory pretty2) = CTC.checkPrice(WETH);
price2X6 = px2;
observed2 = true;
t2 = block.timestamp;
emit Observed2(px2, pretty2, t2, block.number);
// fallthrough to resolve in same tx
}
// 3) Try to close market if still open (works when canClose = true)
if (PM.tradingOpen(id)) {
try PM.closeMarket(id) {
emit Closed(id, block.timestamp);
} catch {}
}
// 4) If still open, can’t resolve yet; snapshots persist — call again later.
if (PM.tradingOpen(id)) revert MarketStillOpen();
// 5) Resolve: YES only if BOTH snapshots are strictly above strike.
bool yes = (price1X6 > STRIKE_X6) && (price2X6 > STRIKE_X6);
PM.resolve(id, yes);
emit Resolved(id, yes);
}
/// @notice View helper for UIs.
function preview()
external
view
returns (
uint256 nowTs,
uint256 earliestAllowedTs,
uint256 minDelaySeconds,
bool isLinked,
bool gotObs1,
bool gotObs2,
uint256 obs1PriceX6,
uint256 obs2PriceX6,
uint256 obs1Ts,
uint256 obs2Ts,
bool bothAboveStrikeNowIfLive
)
{
nowTs = block.timestamp;
earliestAllowedTs = earliestTs;
minDelaySeconds = minDelay;
isLinked = (marketId != 0);
gotObs1 = observed1;
gotObs2 = observed2;
obs1PriceX6 = price1X6;
obs2PriceX6 = price2X6;
obs1Ts = t1;
obs2Ts = t2;
if (gotObs2) {
bothAboveStrikeNowIfLive = (price1X6 > STRIKE_X6) && (price2X6 > STRIKE_X6);
} else if (gotObs1) {
(uint256 px,) = CTC.checkPrice(WETH);
bothAboveStrikeNowIfLive = (price1X6 > STRIKE_X6) && (px > STRIKE_X6);
} else {
(uint256 px,) = CTC.checkPrice(WETH);
bothAboveStrikeNowIfLive = (px > STRIKE_X6) && (px > STRIKE_X6); // same value twice
}
}
}
"
}
},
"settings": {
"remappings": [
"@solady/=lib/solady/",
"@soledge/=lib/soledge/",
"@forge/=lib/forge-std/src/",
"forge-std/=lib/forge-std/src/",
"solady/=lib/solady/src/"
],
"optimizer": {
"enabled": true,
"runs": 9999999
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": true
}
}}
Submitted on: 2025-10-09 09:27:14
Comments
Log in to comment.
No comments yet.