PunkStrategy48ETHResolver

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/PunkStrategy48ETHResolver.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

/// @notice Minimal interface to the provided PredictionMarket.
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
        );
}

/**
 * @title PunkStrategy48ETHResolver
 * @notice Single-purpose resolver for the test market:
 * "Will PunkStrategy hold >= 48 ETH at or before timestamp 1759699999?"
 *
 * Usage:
 * 1) Create the PredictionMarket with THIS contract as resolver and canClose = true.
 * 2) Call link(marketId) once (verifies resolver).
 * 3) Anyone can call poke() to close/resolve early on threshold, or at/after T, or if already closed.
 */
contract PunkStrategy48ETHResolver {
    // ------------------ HARD-CODED CONFIG ------------------
    address public constant PM_ADDR = 0x0000000000337f99F242D11AF1908469B0424C8D;
    address public constant PUNK_STRATEGY = 0xc50673EDb3A7b94E8CAD8a7d4E0cD68864E33eDF;
    uint256 public constant THRESHOLD_WEI = 48_000000000000000000; // 48 ETH
    uint256 public constant TARGET_TS = 1759699999; // observation time

    // ------------------ STATE ------------------
    IPredictionMarketMinimal private constant PM = IPredictionMarketMinimal(PM_ADDR);
    uint256 public marketId; // set once via link()
    uint256 public observedBalanceWei; // first snapshot used for outcome
    bool public observed; // sticky once set

    // ------------------ EVENTS ------------------
    event Linked(uint256 indexed marketId);
    event Closed(uint256 indexed marketId, uint256 atTs);
    event Observed(uint256 balanceWei, uint256 atTs);
    event Resolved(uint256 indexed marketId, bool outcome, uint256 usedBalanceWei);

    // ------------------ ERRORS ------------------
    error AlreadyLinked();
    error NotLinked();
    error WrongResolver();
    error TooEarly();

    /// @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 Idempotent automation entrypoint.
    /// - Pre-T: if balance >= threshold -> close & resolve(true).
    /// - At/after T: close if open, snapshot if needed, resolve(snapshot >= threshold).
    /// - If closed & not resolved: snapshot if needed then resolve.
    /// - If already resolved: no-op.
    function poke() external {
        uint256 id = marketId;
        if (id == 0) revert NotLinked();

        (,,, bool isResolved,,,,) = PM.getMarket(id);
        bool isOpen = PM.tradingOpen(id);
        if (isResolved) return;

        uint256 bal = address(PUNK_STRATEGY).balance;

        // 1) EARLY success before TARGET_TS: threshold hit -> close now & resolve true.
        if (block.timestamp < TARGET_TS && isOpen && bal >= THRESHOLD_WEI) {
            _observeOnce(bal);
            PM.closeMarket(id); // requires canClose = true on market creation
            emit Closed(id, block.timestamp);
            PM.resolve(id, true);
            emit Resolved(id, true, observedBalanceWei);
            return;
        }

        // 2) AT/AFTER TARGET_TS: ensure closed, snapshot if needed, resolve by snapshot.
        if (block.timestamp >= TARGET_TS) {
            if (isOpen) {
                _observeOnce(bal);
                PM.closeMarket(id);
                emit Closed(id, block.timestamp);
            }
            if (!observed) _observeOnce(bal);
            bool outcome = (observedBalanceWei >= THRESHOLD_WEI);
            PM.resolve(id, outcome);
            emit Resolved(id, outcome, observedBalanceWei);
            return;
        }

        // 3) ALREADY CLOSED (pre-T) & not resolved -> resolve now from snapshot/current.
        if (!isOpen) {
            if (!observed) _observeOnce(bal);
            bool outcomeClosed = (observedBalanceWei >= THRESHOLD_WEI);
            PM.resolve(id, outcomeClosed);
            emit Resolved(id, outcomeClosed, observedBalanceWei);
            return;
        }

        // Otherwise too early and threshold not yet met.
        revert TooEarly();
    }

    // ------------------ INTERNAL ------------------
    function _observeOnce(uint256 bal) internal {
        if (!observed) {
            observed = true;
            observedBalanceWei = bal;
            emit Observed(bal, block.timestamp);
        }
    }
}
"
    }
  },
  "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
  }
}}

Tags:
Factory|addr:0xc1a37d96f8d80da2686eb8aa8d0fc39ee4c04dc5|verified:true|block:23513620|tx:0xa6193a4bc313aa525789cc792dce2810201a6e46733a3d382faf15d77a2261c8|first_check:1759692457

Submitted on: 2025-10-05 21:27:37

Comments

Log in to comment.

No comments yet.