{"language":"Solidity","sources":{"DrandEvmnetVerifier.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {BLS} from \"./vendor/BLS.sol\";\n\n/// @notice Candidate only: pinned evmnet key and signature verification, no funds.\ncontract DrandEvmnetVerifier {\n    bytes32 public constant BEACON_CHAIN_HASH =\n        0x04f1e9062b8a81f848fded9c12306733282b2727ecced50032187751166ec8c3;\n    string public constant DST = \"BLS_SIG_BN254G1_XMD:KECCAK-256_SVDW_RO_NUL_\";\n    uint64 public constant GENESIS_TIME = 1727521075;\n    uint64 public constant PERIOD = 3;\n\n    error InvalidSignature();\n    error InvalidBeaconRound();\n\n    function publicKey() public pure returns (BLS.PointG2 memory) {\n        return BLS.PointG2(\n            [uint256(0x557ec32c2ad488e4d4f6008f89a346f18492092ccc0d594610de2732c8b808f),\n             uint256(0x7e1d1d335df83fa98462005690372c643340060d205306a9aa8106b6bd0b382)],\n            [uint256(0x297d3a4f9749b33eb2d904c9d9ebf17224150ddd7abd7567a9bec6c74480ee0b),\n             uint256(0x95685ae3a85ba243747b1b2f426049010f6b73a0cf1d389351d5aaaa1047f6)]\n        );\n    }\n\n    /// @dev Uses the exact evmnet message encoding; never trusts API randomness.\n    function verifyBeacon(uint64 beaconRound, bytes calldata signature) public view returns (bytes32) {\n        if (beaconRound == 0) revert InvalidBeaconRound();\n        if (signature.length != 64) revert InvalidSignature();\n        BLS.PointG1 memory point = BLS.g1Unmarshal(signature);\n        if (point.x == 0 && point.y == 0) revert InvalidSignature();\n        (bool pairingSuccess, bool callSuccess) = BLS.verifySingle(\n            point, publicKey(),\n            BLS.hashToPoint(bytes(DST), abi.encodePacked(keccak256(abi.encodePacked(beaconRound))))\n        );\n        if (!pairingSuccess || !callSuccess) revert InvalidSignature();\n        return sha256(signature);\n    }\n\n    function beaconTime(uint64 beaconRound) public pure returns (uint256) {\n        if (beaconRound == 0) revert InvalidBeaconRound();\n        return uint256(GENESIS_TIME) + (uint256(beaconRound) - 1) * PERIOD;\n    }\n}\n"},"TapeoutDrandRandomness.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {DrandEvmnetVerifier} from \"./DrandEvmnetVerifier.sol\";\n\n/// @notice Candidate randomness adapter, not an integrated/deployed raffle.\n/// @dev The immutable consumer must atomically close sales before requesting.\n/// It must bind its sold-ticket snapshot to entriesCommitment and never reopen it.\ncontract TapeoutDrandRandomness is DrandEvmnetVerifier {\n    address public immutable consumer;\n    // Candidate finality margin, subject to review before BNB mainnet deployment.\n    uint64 public constant BEACON_DELAY = 60;\n    uint64 public constant FULFILLMENT_WINDOW = 24 hours;\n    bytes32 public constant SEED_DOMAIN = keccak256(\"Tapeout SparkDraw drand candidate v1\");\n\n    struct Draw {\n        uint64 beaconRound;\n        uint64 requestedAt;\n        uint32 sold;\n        bool fulfilled;\n        bool expired;\n        bytes32 entriesCommitment;\n        bytes32 beaconRandomness;\n        bytes32 drawSeed;\n    }\n    mapping(uint256 => Draw) public draws;\n    // Two storage words per verified signature, with public retrieval below.\n    mapping(uint256 => bytes32[2]) private signatures;\n\n    error UnauthorizedConsumer();\n    error InvalidRequest();\n    error AlreadyRequested();\n    error NotRequested();\n    error AlreadyFulfilled();\n    error BeaconNotDue();\n    error RequestExpired();\n    error DeadlineNotPassed();\n\n    event RandomnessRequested(uint256 indexed drawId, uint64 indexed beaconRound,\n        uint32 sold, bytes32 entriesCommitment, uint256 scheduledBeaconTime);\n    event RandomnessVerified(uint256 indexed drawId, uint64 indexed beaconRound,\n        bytes32 beaconRandomness, bytes32 drawSeed, bytes signature, address submitter);\n    event RandomnessExpired(uint256 indexed drawId, uint64 indexed beaconRound);\n\n    constructor(address fixedConsumer) {\n        if (fixedConsumer == address(0)) revert InvalidRequest();\n        consumer = fixedConsumer;\n    }\n\n    /// @notice Called exactly once by the raffle during its sealing transaction.\n    function requestRandomness(uint256 drawId, uint32 sold, bytes32 entriesCommitment)\n        external returns (uint64 beaconRound)\n    {\n        if (msg.sender != consumer) revert UnauthorizedConsumer();\n        if (drawId == 0 || sold == 0 || sold > 10000 || entriesCommitment == bytes32(0)) revert InvalidRequest();\n        if (draws[drawId].beaconRound != 0) revert AlreadyRequested();\n        uint256 target = block.timestamp + BEACON_DELAY;\n        if (target < GENESIS_TIME) revert InvalidRequest();\n        // First beacon at or after target; the caller cannot supply a round.\n        uint256 round = (target - GENESIS_TIME + PERIOD - 1) / PERIOD + 1;\n        if (round > type(uint64).max || block.timestamp > type(uint64).max) revert InvalidRequest();\n        beaconRound = uint64(round);\n        draws[drawId] = Draw(beaconRound, uint64(block.timestamp), sold, false, false,\n            entriesCommitment, bytes32(0), bytes32(0));\n        emit RandomnessRequested(drawId, beaconRound, sold, entriesCommitment, beaconTime(beaconRound));\n    }\n\n    /// @notice Anyone may relay the fixed beacon; no operator key or paid API.\n    function fulfillRandomness(uint256 drawId, bytes calldata signature) external {\n        Draw storage draw = draws[drawId];\n        if (draw.beaconRound == 0) revert NotRequested();\n        if (draw.fulfilled) revert AlreadyFulfilled();\n        if (draw.expired || block.timestamp > expiresAt(drawId)) revert RequestExpired();\n        if (block.timestamp < beaconTime(draw.beaconRound)) revert BeaconNotDue();\n        bytes32 value = verifyBeacon(draw.beaconRound, signature);\n        bytes32 seed = keccak256(abi.encode(SEED_DOMAIN, block.chainid, address(this),\n            consumer, drawId, draw.sold, draw.entriesCommitment, BEACON_CHAIN_HASH, draw.beaconRound, value));\n        draw.fulfilled = true;\n        draw.beaconRandomness = value;\n        draw.drawSeed = seed;\n        signatures[drawId] = [bytes32(signature[:32]), bytes32(signature[32:])];\n        emit RandomnessVerified(drawId, draw.beaconRound, value, seed, signature, msg.sender);\n    }\n\n    function proof(uint256 drawId) external view returns (bytes memory) {\n        if (!draws[drawId].fulfilled) return bytes(\"\");\n        return abi.encodePacked(signatures[drawId][0], signatures[drawId][1]);\n    }\n\n    function expiresAt(uint256 drawId) public view returns (uint256) {\n        uint64 round = draws[drawId].beaconRound;\n        if (round == 0) revert NotRequested();\n        return uint256(draws[drawId].requestedAt) + FULFILLMENT_WINDOW;\n    }\n\n    /// @notice The raffle must use this condition to enable principal refunds.\n    /// It must not depend on a server sending expireRandomness first.\n    function isTimedOut(uint256 drawId) public view returns (bool) {\n        Draw storage draw = draws[drawId];\n        return draw.beaconRound != 0 && !draw.fulfilled && block.timestamp > expiresAt(drawId);\n    }\n\n    /// @notice Public audit event; this adapter holds no funds and cannot refund.\n    function expireRandomness(uint256 drawId) external {\n        Draw storage draw = draws[drawId];\n        if (draw.beaconRound == 0) revert NotRequested();\n        if (draw.fulfilled) revert AlreadyFulfilled();\n        if (draw.expired) revert RequestExpired();\n        if (!isTimedOut(drawId)) revert DeadlineNotPassed();\n        draw.expired = true;\n        emit RandomnessExpired(drawId, draw.beaconRound);\n    }\n}\n"},"BemDrandRaffleCandidate.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\n// V4 partial-fill candidate. Release leaves pin a formal denomination.\n// Container authorization and operating cadence belong to the series wrapper.\n\ninterface IDrandRaffleToken {\n    function decimals() external view returns (uint8);\n    function balanceOf(address account) external view returns (uint256);\n    function transfer(address to, uint256 amount) external returns (bool);\n    function transferFrom(address from, address to, uint256 amount) external returns (bool);\n}\n\ninterface IDrandRaffleCircuitSource {\n    function netlist(uint256 id) external view returns (bytes memory);\n    function circuitInfo(uint256 id) external view returns (uint32, uint32, uint32, uint32);\n    function eval(uint256 id, bytes calldata inputs) external view returns (bytes memory);\n}\n\nimport {DrandEvmnetVerifier} from \"./DrandEvmnetVerifier.sol\";\n\n/// @notice Independent candidate derived from the V4 WIP; not a production release.\n/// Uses fixed future drand beacons, public proofs, and fixed refund/burn deadlines.\n/// The live 2075 circuit is still required for settlement. Its failure also permits\n/// principal refunds after 24 hours. Token transfer failure cannot be bypassed.\ncontract BemDrandRaffleCandidate {\n    bool public constant PARTIAL_FILL = true;\n    uint256 public immutable TICKET_PRICE; // Fixed by the release leaf, 8 BEM decimals\n    uint32 public constant TICKETS_PER_ROUND = 10_000;\n    // Each transaction remains subject to the network gas limit; wallets estimate\n    // the chosen tickets before sending. Multiple buys share the address limit.\n    uint32 public constant MAX_TICKETS_PER_PURCHASE = 5000;\n    uint32 public constant MAX_TICKETS_PER_ADDRESS = 5000;\n    uint64 public constant REFUND_CLAIM_WINDOW = 24 hours;\n    uint64 public constant REFUND_PUBLIC_NOTICE_DELAY = 12 hours;\n    mapping(uint256 => uint256) public refundedPrincipal;\n    mapping(uint256 => bool) public unclaimedPrincipalBurned;\n    uint256 public immutable ROUND_POOL;\n    uint256 public immutable ORGANIZER_AMOUNT;\n    uint256 public immutable BLACKHOLE_AMOUNT;\n    uint256 public immutable BURN_PERCENT;\n    uint32 public constant EARLY_DRAW_THRESHOLD = 9500;\n    uint64 public constant EARLY_DRAW_DELAY = 30 minutes;\n    bool public constant BITMAP_TICKETS = true;\n    mapping(uint256 => uint64) public earlyDrawDeadline;\n    uint256 public immutable WINNER_AMOUNT;\n    address public constant BLACKHOLE = 0x000000000000000000000000000000000000dEaD;\n    address public constant OFFICIAL_BEM = 0x5ce033B2bFCa3Af30b3e8C8457DeaF776A8b695a;\n    address public constant CIRCUITS = 0x1F5Cb4aeaE1807Bf60c3b9C0D8aDBCC14e91f12C;\n    uint256 public constant CIRCUIT_ID = 2075;\n    bytes32 public constant CIRCUIT_HASH = 0xa375924f2a31f5169606ea20e357efa2aeeb2355aff859f28f40a15519714eef;\n    bytes internal constant CIRCUIT_RAW = hex\"0000000200000a0000000a00000e0000000200000e0000000b00000b00000003000003000000110000120000000300000b0000000e0000140000001300001500000013000016000000130000140000000e000017000000180000190000000400000c0000000c00000c000000040000040000001c00001d0000001b00001e0000001600001f000000160000200000001f0000200000000500000d0000000d00000d00000005000005000000240000250000001e000026000000230000270000001b000023000000260000290000001600002a0000002800002b0000000600002c0000002600002c000000230000260000001e00002f0000003000003000000021000031000000060000070000000600002b000000060000330000002c000033000000280000350000003400003600000007000034000000360000370000000800002c00000008000033000000330000330000000800003d0000003d00003e0000003c00003f0000002d0000400000000900002c0000000900003e000000090000090000003e00003e00000044000045000000430000460000002d00004700000009000045000000490000490000002d00004a0000000f0000100000001700001a000000210000220000002e0000320000002d0000380000003900003a0000003b000041000000420000480000004b00004b\";\n\n    enum Status { Unstarted, Funding, Locked, Requested, Ready, Settled, Refunding }\n    struct Round {\n        Status status;\n        uint32 sold;\n        uint64 fundingDeadline;\n        uint64 drawDeadline;\n        uint256 requestId;\n        uint256 ticketWord;\n        uint256 circuitWord;\n        uint32 drawCursor;\n        uint32 winningTicket;\n        address winner;\n    }\n    struct Attempt {\n        uint16 input0;\n        uint16 input1;\n        uint16 output0;\n        uint16 output1;\n        uint16 candidate;\n        bool accepted;\n        uint32 ticket;\n    }\n    IDrandRaffleToken public immutable bem;\n    DrandEvmnetVerifier public immutable verifier;\n    uint64 public constant DRAW_TIMEOUT = 24 hours;\n    uint64 public constant BEACON_DELAY = 60;\n    uint64 public constant BEACON_GENESIS = 1727521075;\n    uint64 public constant BEACON_PERIOD = 3;\n    bytes32 public constant BEACON_CHAIN_HASH = 0x04f1e9062b8a81f848fded9c12306733282b2727ecced50032187751166ec8c3;\n    uint256 public constant MAX_REFUND_BATCH = 64;\n    mapping(uint256 => uint64) public sealedAt;\n    mapping(uint256 => uint64) public beaconRound;\n    mapping(uint256 => bytes32) public beaconRandomness;\n    mapping(uint256 => bytes) public randomnessProof;\n    struct Prize {\n        uint256 amount;\n        uint64 settledAt;\n        uint64 claimDeadline;\n        bool claimed;\n        bool burned;\n    }\n    mapping(uint256 => Prize) public prizes;\n    event BeaconFixed(uint256 indexed roundId, uint64 indexed beaconRound, uint64 availableAt);\n    event BeaconVerified(uint256 indexed roundId, uint64 indexed beaconRound, bytes32 randomness, bytes signature);\n    event RefundBatchClaimed(address indexed participant, uint256 amount, uint256 roundsPaid);\n    event PrizeAvailable(uint256 indexed roundId, address indexed winner, uint256 amount, uint64 claimDeadline);\n    event PrizeClaimed(uint256 indexed roundId, address indexed winner, uint256 amount);\n    event PrizesClaimed(address indexed winner, uint256 amount, uint256 roundsPaid);\n    event UnclaimedPrizeBurned(uint256 indexed roundId, address indexed winner, uint256 amount);\n    error InvalidRefundBatch();\n    address public immutable organizer;\n    uint32 public immutable fundingWindow;\n    uint256 public immutable sourceVerifiedAtBlock;\n    uint256 public currentRoundId = 1;\n    uint256 public totalLiability;\n    uint256 private guard = 1;\n    mapping(uint256 => Round) public rounds;\n    // Each storage word packs 18 14-bit buyer IDs.\n    // ID 0 means unsold. At most 10,000 distinct buyers can exist in one round.\n    mapping(uint256 => mapping(uint256 => uint256)) private packedTicketOwners;\n    mapping(uint256 => mapping(address => uint16)) public ticketBuyerId;\n    mapping(uint256 => mapping(uint16 => address)) public ticketBuyer;\n    mapping(uint256 => uint16) private nextTicketBuyerId;\n    mapping(uint256 => uint32) private automaticTicketCursor;\n    error TicketAlreadySold(uint32 ticket);\n    error TicketsNotStrictlyAscending();\n    mapping(uint256 => mapping(address => uint32)) public ticketsOf;\n\n    error BadConfiguration();\n    error WrongCircuit();\n    error WrongState();\n    error DeadlinePassed();\n    error TooEarly();\n    error InvalidTicketCount();\n    error PurchaseLimitExceeded(uint256 requested, uint256 maximum);\n    error TokenTransferFailed();\n    error UnexpectedTokenAmount();\n    error ReentrantCall();\n    error NothingToRefund();\n    error AddressTicketLimitExceeded(uint256 requestedTotal, uint256 maximum);\n    error RefundClaimPeriodEnded(uint64 deadline);\n    error NothingToBurn();\n    event UnclaimedPrincipalBurned(uint256 indexed roundId, uint256 amount);\n    error InvalidRandomness();\n    error Insolvent();\n    error WrongRound(uint256 expectedRoundId, uint256 actualRoundId);\n\n    event RoundStarted(uint256 indexed roundId, uint64 fundingDeadline);\n    event EarlyDrawScheduled(uint256 indexed roundId, uint64 closesAt, uint32 sold);\n    event TicketsAllocated(uint256 indexed roundId, address indexed buyer, uint256[40] bitmap, uint32 count, uint256 paid);\n    event UnsoldTicketSkipped(uint256 indexed roundId, uint32 cursor, uint32 ticket);\n    event PurchaseResult(uint256 indexed roundId, address indexed buyer, uint32 requested, uint32 filled, uint256 paid, uint256 unspent);\n    event TicketsPurchased(uint256 indexed roundId, address indexed buyer, uint32 firstTicket, uint32 endExclusive, uint256 paid);\n    event RoundLocked(uint256 indexed roundId, uint64 drawDeadline);\n    event DrawRequested(uint256 indexed roundId, uint256 indexed requestId);\n    event RandomnessReceived(uint256 indexed roundId, uint256 indexed requestId, uint256 ticketWord, uint256 circuitWord);\n    event RandomnessIgnored(uint256 indexed requestId);\n    event RefundsOpened(uint256 indexed roundId);\n    event Refunded(uint256 indexed roundId, address indexed buyer, uint256 amount);\n    event AttemptEvaluated(uint256 indexed roundId, uint32 indexed cursor, uint16 input0, uint16 input1, uint16 output0, uint16 output1, uint16 candidate, bool accepted);\n    event DrawProgress(uint256 indexed roundId, uint32 nextCursor);\n    event Settled(uint256 indexed roundId, address indexed winner, uint32 winningTicket);\n    event BlackholeTransfer(uint256 indexed roundId, uint256 amount);\n\n    modifier nonReentrant() {\n        if (guard != 1) revert ReentrantCall();\n        guard = 2;\n        _;\n        guard = 1;\n    }\n\n    constructor(\n        uint256 poolBaseUnits,\n        address token,\n        address drandVerifier,\n        address organizerAddress\n    ) {\n        if (poolBaseUnits != 10_000_000 && poolBaseUnits != 500_000_000 && poolBaseUnits != 1_000_000_000\n            && poolBaseUnits != 5_000_000_000 && poolBaseUnits != 10_000_000_000) revert BadConfiguration();\n        ROUND_POOL = poolBaseUnits;\n        TICKET_PRICE = poolBaseUnits / TICKETS_PER_ROUND;\n        ORGANIZER_AMOUNT = poolBaseUnits / 100;\n        uint256 burnPercent = poolBaseUnits == 10_000_000 ? 4 : poolBaseUnits == 500_000_000 ? 3 : poolBaseUnits == 1_000_000_000 ? 4 : poolBaseUnits == 5_000_000_000 ? 5 : 6;\n        BURN_PERCENT = burnPercent;\n        BLACKHOLE_AMOUNT = poolBaseUnits * burnPercent / 100;\n        WINNER_AMOUNT = poolBaseUnits - ORGANIZER_AMOUNT - BLACKHOLE_AMOUNT;\n        if (token.code.length == 0 || drandVerifier.code.length == 0 || organizerAddress == address(0)\n            || organizerAddress == BLACKHOLE || organizerAddress == address(this)) revert BadConfiguration();\n        verifier = DrandEvmnetVerifier(drandVerifier);\n        if (verifier.BEACON_CHAIN_HASH() != BEACON_CHAIN_HASH || verifier.GENESIS_TIME() != BEACON_GENESIS\n            || verifier.PERIOD() != BEACON_PERIOD) revert BadConfiguration();\n        if (IDrandRaffleToken(token).decimals() != 8) revert BadConfiguration();\n        if (keccak256(CIRCUIT_RAW) != CIRCUIT_HASH) revert WrongCircuit();\n        IDrandRaffleCircuitSource source = IDrandRaffleCircuitSource(CIRCUITS);\n        if (keccak256(source.netlist(CIRCUIT_ID)) != CIRCUIT_HASH) revert WrongCircuit();\n        (uint32 nIn, uint32 nOut, uint32 nState, uint32 gateCount) = source.circuitInfo(CIRCUIT_ID);\n        if (nIn != 12 || nOut != 9 || nState != 0 || gateCount != 71) revert WrongCircuit();\n        bem = IDrandRaffleToken(token);\n        organizer = organizerAddress;\n        fundingWindow = 24 hours;\n        sourceVerifiedAtBlock = block.number;\n    }\n\n    /// @notice Buy up to count tickets, limited by current stock and address quota.\n    /// Only the filled quantity is charged; unspent BEM stays in the buyer wallet.\n    function buy(uint256 expectedRoundId, uint32 count) external nonReentrant returns (uint256 roundId) {\n        uint32 filled;\n        (roundId, filled) = _beginTicketPurchase(expectedRoundId, count);\n        if (filled != 0) {\n            _assignAutomaticTickets(roundId, filled, _ticketBuyerId(roundId));\n            _finishTicketPurchase(roundId, filled);\n        }\n        _purchaseResult(roundId, count, filled);\n    }\n\n    /// @notice Validate the entire ascending, zero-based selection, then fill\n    /// its prefix up to available stock/address quota. Sold selected numbers\n    /// retain the previous deterministic forward replacement with wraparound.\n    function buySelected(uint256 expectedRoundId, uint16[] calldata selectedTickets)\n        external nonReentrant returns (uint256 roundId)\n    {\n        uint256 length = selectedTickets.length;\n        if (length == 0) revert InvalidTicketCount();\n        if (length > MAX_TICKETS_PER_PURCHASE) revert PurchaseLimitExceeded(length, MAX_TICKETS_PER_PURCHASE);\n        // Validate even a tail that will not be filled, including zero-fill races.\n        // All tickets must be valid even if only a prefix is filled. Validate\n        // padded calldata in one bounded pass, without repeated array decoding.\n        assembly (\"memory-safe\") {\n            let previous := 0\n            for { let i := 0 } lt(i,length) { i := add(i,1) } {\n                let ticket := calldataload(add(selectedTickets.offset,mul(i,32)))\n                if iszero(lt(ticket,10000)) { mstore(0,shl(224,0x8e71bef9)) revert(0,4) }\n                if and(iszero(iszero(i)),iszero(gt(ticket,previous))) { mstore(0,shl(224,0x6e7dc806)) revert(0,4) }\n                previous := ticket\n            }\n        }\n        uint32 filled;\n        (roundId, filled) = _beginTicketPurchase(expectedRoundId, uint32(length));\n        if (filled != 0) {\n            _assignSelectedTickets(roundId, selectedTickets[:filled], _ticketBuyerId(roundId));\n            _finishTicketPurchase(roundId, filled);\n        }\n        _purchaseResult(roundId, uint32(length), filled);\n    }\n\n    function _purchaseResult(uint256 roundId, uint32 requested, uint32 filled) private {\n        emit PurchaseResult(roundId, msg.sender, requested, filled,\n            uint256(filled) * TICKET_PRICE, uint256(requested - filled) * TICKET_PRICE);\n    }\n\n    function _beginTicketPurchase(uint256 expectedRoundId, uint32 count)\n        private returns (uint256 roundId, uint32 filled)\n    {\n        if (count == 0) revert InvalidTicketCount();\n        if (count > MAX_TICKETS_PER_PURCHASE) revert PurchaseLimitExceeded(count, MAX_TICKETS_PER_PURCHASE);\n        roundId = currentRoundId;\n        if (expectedRoundId != roundId) {\n            // A previously full round may have locked between simulation and\n            // mining. Record a zero fill, never route the order to a new round.\n            if (expectedRoundId < roundId && rounds[expectedRoundId].sold >= EARLY_DRAW_THRESHOLD && rounds[expectedRoundId].status != Status.Funding && rounds[expectedRoundId].status != Status.Refunding) {\n                return (expectedRoundId, 0);\n            }\n            revert WrongRound(expectedRoundId, roundId);\n        }\n        _requireRoundAuthorization(roundId);\n        Round storage r = rounds[roundId];\n        if (r.status == Status.Unstarted) {\n            r.status = Status.Funding;\n            r.fundingDeadline = uint64(block.timestamp + fundingWindow);\n            emit RoundStarted(roundId, r.fundingDeadline);\n        }\n        if (r.status != Status.Funding) revert WrongState();\n        if (block.timestamp >= fundingClosesAt(roundId)) revert DeadlinePassed();\n        filled = count;\n        uint32 remaining = TICKETS_PER_ROUND - r.sold;\n        if (filled > remaining) filled = remaining;\n        uint32 quota = MAX_TICKETS_PER_ADDRESS - ticketsOf[roundId][msg.sender];\n        if (filled > quota) filled = quota;\n    }\n\n    function _ticketBuyerId(uint256 roundId) private returns (uint16 id) {\n        id = ticketBuyerId[roundId][msg.sender];\n        if (id == 0) {\n            id = ++nextTicketBuyerId[roundId];\n            ticketBuyerId[roundId][msg.sender] = id;\n            ticketBuyer[roundId][id] = msg.sender;\n        }\n    }\n\n    // 18 owners per storage word, 14 bits per ID: 10,000 buyers fit without\n    // truncation. One bitmap event avoids thousands of per-range log entries.\n    function _assignSelectedTickets(uint256 roundId, uint16[] calldata tickets, uint16 buyerId) private {\n        uint256[556] memory words;\n        uint256[40] memory allocated;\n        uint16[] memory missing = new uint16[](tickets.length);\n        // All calldata tickets were validated ascending and <10,000 before this\n        // call. Word indices are <=555, bitmap indices <=39, buyerId <=10,000.\n        // Scratch memory is only 0..63; arrays are compiler-allocated and bounded.\n        assembly (\"memory-safe\") {\n            mstore(0, roundId)\n            mstore(32, packedTicketOwners.slot)\n            let base := keccak256(0,64)\n            for { let w := 0 } lt(w,556) { w := add(w,1) } {\n                mstore(0,w) mstore(32,base)\n                mstore(add(words,mul(w,32)),sload(keccak256(0,64)))\n            }\n            let nMissing := 0\n            for { let i := 0 } lt(i,tickets.length) { i := add(i,1) } {\n                let ticket := calldataload(add(tickets.offset,mul(i,32)))\n                let location := add(words,mul(div(ticket,18),32))\n                let shift := mul(mod(ticket,18),14)\n                let packed := mload(location)\n                switch and(shr(shift,packed),16383)\n                case 0 {\n                    mstore(location,or(packed,shl(shift,buyerId)))\n                    let bitmap := add(allocated,mul(shr(8,ticket),32))\n                    mstore(bitmap,or(mload(bitmap),shl(and(ticket,255),1)))\n                }\n                default { mstore(add(add(missing,32),mul(nMissing,32)),ticket) nMissing := add(nMissing,1) }\n            }\n            let cursor := 0\n            let scanned := 0\n            let wrapped := 0\n            for { let i := 0 } lt(i,nMissing) { i := add(i,1) } {\n                let requested := mload(add(add(missing,32),mul(i,32)))\n                if and(iszero(wrapped),iszero(gt(cursor,requested))) { cursor := add(requested,1) }\n                for { } 1 { } {\n                    if eq(cursor,10000) { cursor := 0 wrapped := 1 }\n                    scanned := add(scanned,1)\n                    if gt(scanned,20000) { revert(0,0) }\n                    let location := add(words,mul(div(cursor,18),32))\n                    let shift := mul(mod(cursor,18),14)\n                    let packed := mload(location)\n                    if iszero(and(shr(shift,packed),16383)) {\n                        mstore(location,or(packed,shl(shift,buyerId)))\n                        let bitmap := add(allocated,mul(shr(8,cursor),32))\n                        mstore(bitmap,or(mload(bitmap),shl(and(cursor,255),1)))\n                        cursor := add(cursor,1)\n                        break\n                    }\n                    cursor := add(cursor,1)\n                }\n            }\n            for { let w := 0 } lt(w,556) { w := add(w,1) } {\n                mstore(0,w) mstore(32,base)\n                let key := keccak256(0,64)\n                let packed := mload(add(words,mul(w,32)))\n                if iszero(eq(sload(key),packed)) { sstore(key,packed) }\n            }\n        }\n        emit TicketsAllocated(roundId, msg.sender, allocated, uint32(tickets.length), tickets.length * TICKET_PRICE);\n    }\n\n    function _assignAutomaticTickets(uint256 roundId, uint32 count, uint16 buyerId) private {\n        unchecked {\n            uint32 cursor = automaticTicketCursor[roundId];\n            uint32 assigned;\n            uint256[40] memory allocated;\n            while (assigned < count) {\n                uint256 word = cursor / 18;\n                uint256 packed = packedTicketOwners[roundId][word];\n                uint256 original = packed;\n                do {\n                    uint256 shift = (cursor % 18) * 14;\n                    if (((packed >> shift) & 16383) == 0) {\n                        packed |= uint256(buyerId) << shift;\n                        allocated[cursor >> 8] |= uint256(1) << (cursor & 255);\n                        ++assigned;\n                    }\n                    ++cursor;\n                } while (cursor % 18 != 0 && assigned < count);\n                if (packed != original) packedTicketOwners[roundId][word] = packed;\n            }\n            automaticTicketCursor[roundId] = cursor;\n            emit TicketsAllocated(roundId, msg.sender, allocated, count, uint256(count) * TICKET_PRICE);\n        }\n    }\n\n    function fundingClosesAt(uint256 roundId) public view returns (uint64) {\n        uint64 early = earlyDrawDeadline[roundId];\n        return early == 0 ? rounds[roundId].fundingDeadline : early;\n    }\n\n    /// Anyone may close a due 95%-funded round; no caller can choose its winner.\n    function closeRound(uint256 roundId) external nonReentrant {\n        Round storage r = rounds[roundId];\n        if (roundId != currentRoundId || r.status != Status.Funding || r.sold < EARLY_DRAW_THRESHOLD) revert WrongState();\n        if (block.timestamp >= r.fundingDeadline) revert DeadlinePassed();\n        if (earlyDrawDeadline[roundId] == 0 || block.timestamp < fundingClosesAt(roundId)) revert TooEarly();\n        _lockFundingRound(roundId, r);\n    }\n\n    function _lockFundingRound(uint256 roundId, Round storage r) private {\n        r.status = Status.Requested;\n        sealedAt[roundId] = uint64(block.timestamp);\n        r.drawDeadline = uint64(block.timestamp + DRAW_TIMEOUT);\n        uint64 target = uint64((block.timestamp + BEACON_DELAY - BEACON_GENESIS + BEACON_PERIOD - 1) / BEACON_PERIOD + 1);\n        beaconRound[roundId] = target;\n        r.requestId = roundId;\n        emit BeaconFixed(roundId, target, uint64(uint256(BEACON_GENESIS) + (uint256(target) - 1) * BEACON_PERIOD));\n        emit DrawRequested(roundId, roundId);\n        currentRoundId = roundId + 1;\n        emit RoundLocked(roundId, r.drawDeadline);\n        _afterRoundLocked(roundId);\n    }\n\n    function _finishTicketPurchase(uint256 roundId, uint32 count) private {\n        Round storage r = rounds[roundId];\n        uint256 amount = uint256(count) * TICKET_PRICE;\n        uint256 beforeBalance = bem.balanceOf(address(this));\n        _tokenCall(abi.encodeCall(IDrandRaffleToken.transferFrom, (msg.sender, address(this), amount)));\n        if (bem.balanceOf(address(this)) != beforeBalance + amount) revert UnexpectedTokenAmount();\n        r.sold += count;\n        ticketsOf[roundId][msg.sender] += count;\n        totalLiability += amount;\n        if (r.sold == TICKETS_PER_ROUND) {\n            _lockFundingRound(roundId, r);\n        } else if (r.sold >= EARLY_DRAW_THRESHOLD && earlyDrawDeadline[roundId] == 0) {\n            uint64 closes = uint64(block.timestamp + EARLY_DRAW_DELAY);\n            if (closes > r.fundingDeadline) closes = r.fundingDeadline;\n            earlyDrawDeadline[roundId] = closes;\n            emit EarlyDrawScheduled(roundId, closes, r.sold);\n        }\n        _assertSolvent();\n    }\n\n    /// @notice Prove exactly the beacon fixed when this round sealed. Anyone may relay.\n    function fulfillRandomness(uint256 roundId, bytes calldata signature) external nonReentrant {\n        Round storage r = rounds[roundId];\n        if (r.status != Status.Requested) revert WrongState();\n        if (block.timestamp >= r.drawDeadline) revert DeadlinePassed();\n        uint64 target = beaconRound[roundId];\n        if (block.timestamp < uint256(BEACON_GENESIS) + (uint256(target) - 1) * BEACON_PERIOD) revert TooEarly();\n        bytes32 random = verifier.verifyBeacon(target, signature);\n        if (random != sha256(signature)) revert InvalidRandomness();\n        beaconRandomness[roundId] = random;\n        randomnessProof[roundId] = signature;\n        // Round IDs and immutable onchain ownership bind the sealed entries.\n        r.ticketWord = uint256(keccak256(abi.encode(\"Tapeout drand tickets v1\", block.chainid, address(this), roundId, r.sold, BEACON_CHAIN_HASH, target, random)));\n        r.circuitWord = uint256(keccak256(abi.encode(\"Tapeout drand circuit v1\", block.chainid, address(this), roundId, r.sold, BEACON_CHAIN_HASH, target, random)));\n        r.status = Status.Ready;\n        emit BeaconVerified(roundId, target, random, signature);\n        emit RandomnessReceived(roundId, roundId, r.ticketWord, r.circuitWord);\n        _afterRandomnessReceived(roundId);\n    }\n\n    /// @notice Anyone may settle; recipients and amounts cannot be chosen by the caller.\n    /// @dev Transfer fees only; the winner has 24 hours to claim the reserved prize.\n    /// This locks tokens at the dead address; it does NOT reduce BEM totalSupply().\n    function settle(uint256 roundId) external nonReentrant {\n        Round storage r = rounds[roundId];\n        if (r.status != Status.Ready) revert WrongState();\n        if (block.timestamp >= r.drawDeadline) revert DeadlinePassed();\n        _beforeSettlement(roundId);\n        // At most eight live circuit calls per transaction. The caller cannot\n        // choose or skip candidates; only rejected samples advance the cursor.\n        for (uint256 i; i < 4; ++i) {\n            uint32 cursor = r.drawCursor;\n            Attempt memory a = previewAttempt(r.ticketWord, r.circuitWord, cursor);\n            emit AttemptEvaluated(roundId, cursor, a.input0, a.input1, a.output0, a.output1, a.candidate, a.accepted);\n            if (a.accepted && ticketOwner(roundId, a.ticket) != address(0)) {\n                _payWinner(roundId, r, a.ticket);\n                return;\n            }\n            if (a.accepted) emit UnsoldTicketSkipped(roundId, cursor, a.ticket);\n            r.drawCursor = cursor + 1;\n        }\n        emit DrawProgress(roundId, r.drawCursor);\n    }\n\n    function _payWinner(uint256 roundId, Round storage r, uint32 ticket) private {\n        address winner = ticketOwner(roundId, ticket);\n        r.status = Status.Settled;\n        r.winningTicket = ticket;\n        r.winner = winner;\n        uint256 gross = uint256(r.sold) * TICKET_PRICE;\n        uint256 fee = gross / 100;\n        uint256 burn = gross * BURN_PERCENT / 100;\n        uint256 prize = gross - fee - burn;\n        prizes[roundId] = Prize(prize, uint64(block.timestamp), uint64(block.timestamp + REFUND_CLAIM_WINDOW), false, false);\n        totalLiability -= burn + fee;\n        uint256 balanceBefore = bem.balanceOf(address(this));\n        uint256 deadBefore = bem.balanceOf(BLACKHOLE);\n        _tokenCall(abi.encodeCall(IDrandRaffleToken.transfer, (BLACKHOLE, burn)));\n        if (bem.balanceOf(BLACKHOLE) != deadBefore + burn) revert UnexpectedTokenAmount();\n        emit BlackholeTransfer(roundId, burn);\n        _tokenCall(abi.encodeCall(IDrandRaffleToken.transfer, (organizer, fee)));\n        if (bem.balanceOf(address(this)) + burn + fee != balanceBefore) revert UnexpectedTokenAmount();\n        _assertSolvent();\n        emit Settled(roundId, winner, ticket);\n        emit PrizeAvailable(roundId, winner, prize, prizes[roundId].claimDeadline);\n        _afterSettlement(roundId);\n    }\n\n    function claimablePrize(uint256 roundId, address participant) public view returns (uint256) {\n        Prize storage prize = prizes[roundId];\n        if (rounds[roundId].winner != participant || prize.amount == 0 || prize.claimed || prize.burned\n            || block.timestamp >= prize.claimDeadline) return 0;\n        return prize.amount;\n    }\n\n    function claimPrize(uint256 roundId) external nonReentrant {\n        address winner = rounds[roundId].winner;\n        uint256 amount = _takePrize(roundId, winner);\n        if (amount == 0) revert NothingToRefund();\n        _transferRefund(winner, amount);\n    }\n\n    function claimPrizes(uint256[] calldata roundIds, address participant) external nonReentrant {\n        if (roundIds.length == 0 || roundIds.length > MAX_REFUND_BATCH) revert InvalidRefundBatch();\n        uint256 total;\n        uint256 paidRounds;\n        for (uint256 i; i < roundIds.length; ++i) {\n            if (roundIds[i] == 0 || (i != 0 && roundIds[i] <= roundIds[i - 1])) revert InvalidRefundBatch();\n            uint256 amount = _takePrize(roundIds[i], participant);\n            total += amount;\n            if (amount != 0) ++paidRounds;\n        }\n        if (total == 0) revert NothingToRefund();\n        _transferRefund(participant, total);\n        emit PrizesClaimed(participant, total, paidRounds);\n    }\n\n    function _takePrize(uint256 roundId, address participant) private returns (uint256 amount) {\n        amount = claimablePrize(roundId, participant);\n        if (amount == 0) return 0;\n        prizes[roundId].claimed = true;\n        totalLiability -= amount;\n        emit PrizeClaimed(roundId, participant, amount);\n    }\n\n    function burnUnclaimedPrize(uint256 roundId) external nonReentrant {\n        Prize storage prize = prizes[roundId];\n        if (prize.amount == 0 || prize.claimed || prize.burned) revert NothingToBurn();\n        if (block.timestamp < prize.claimDeadline) revert TooEarly();\n        prize.burned = true;\n        totalLiability -= prize.amount;\n        uint256 balanceBefore = bem.balanceOf(address(this));\n        uint256 deadBefore = bem.balanceOf(BLACKHOLE);\n        _tokenCall(abi.encodeCall(IDrandRaffleToken.transfer, (BLACKHOLE, prize.amount)));\n        if (bem.balanceOf(BLACKHOLE) != deadBefore + prize.amount\n            || bem.balanceOf(address(this)) + prize.amount != balanceBefore) revert UnexpectedTokenAmount();\n        _assertSolvent();\n        emit UnclaimedPrizeBurned(roundId, rounds[roundId].winner, prize.amount);\n    }\n\n    /// @notice A fixed deadline is independent of when a server first observes it.\n    function refundTriggerAt(uint256 roundId) public view returns (uint64) {\n        Round storage r = rounds[roundId];\n        return sealedAt[roundId] == 0 ? r.fundingDeadline : r.drawDeadline;\n    }\n\n    function openRefunds(uint256 roundId) public {\n        Round storage r = rounds[roundId];\n        if (r.status == Status.Refunding) return;\n        if (r.status != Status.Funding && r.status != Status.Locked\n            && r.status != Status.Requested && r.status != Status.Ready) revert WrongState();\n        uint64 trigger = refundTriggerAt(roundId);\n        if (trigger == 0 || block.timestamp < trigger) revert TooEarly();\n        if (currentRoundId == roundId) currentRoundId = roundId + 1;\n        r.status = Status.Refunding;\n        emit RefundsOpened(roundId);\n        _afterRefundsOpened(roundId);\n    }\n\n    function refundClaimDeadline(uint256 roundId) public view returns (uint64) {\n        uint64 trigger = refundTriggerAt(roundId);\n        return trigger == 0 ? 0 : trigger + REFUND_CLAIM_WINDOW;\n    }\n\n    /// @notice Website public notice begins halfway through the fixed refund window.\n    /// The original refund claim deadline is never extended by publication.\n    function refundPublicNoticeAt(uint256 roundId) public view returns (uint64) {\n        uint64 trigger = refundTriggerAt(roundId);\n        return trigger == 0 ? 0 : trigger + REFUND_PUBLIC_NOTICE_DELAY;\n    }\n\n    function refundablePrincipal(uint256 roundId, address participant) public view returns (uint256) {\n        Round storage r = rounds[roundId];\n        uint64 trigger = refundTriggerAt(roundId);\n        if (r.status == Status.Settled || r.status == Status.Unstarted || trigger == 0\n            || block.timestamp < trigger || block.timestamp >= refundClaimDeadline(roundId)\n            || unclaimedPrincipalBurned[roundId]) return 0;\n        return uint256(ticketsOf[roundId][participant]) * TICKET_PRICE;\n    }\n\n    /// @notice Same wallet's purchases in a round are already accumulated.\n    function refund(uint256 roundId, address participant) external nonReentrant {\n        uint256 amount = _takeRefund(roundId, participant);\n        if (amount == 0) revert NothingToRefund();\n        _transferRefund(participant, amount);\n    }\n\n    /// @notice One transaction and one BEM transfer for many eligible rounds.\n    /// Anyone may pay Gas, but cannot replace the original participant recipient.\n    function refundMany(uint256[] calldata roundIds, address participant) external nonReentrant {\n        if (roundIds.length == 0 || roundIds.length > MAX_REFUND_BATCH) revert InvalidRefundBatch();\n        uint256 total;\n        uint256 paidRounds;\n        for (uint256 i; i < roundIds.length; ++i) {\n            if (roundIds[i] == 0 || (i != 0 && roundIds[i] <= roundIds[i - 1])) revert InvalidRefundBatch();\n            // Skip already-paid/expired/non-refundable rows instead of blocking other credits.\n            uint256 amount = _takeRefund(roundIds[i], participant);\n            total += amount;\n            if (amount != 0) ++paidRounds;\n        }\n        if (total == 0) revert NothingToRefund();\n        _transferRefund(participant, total);\n        emit RefundBatchClaimed(participant, total, paidRounds);\n    }\n\n    function _takeRefund(uint256 roundId, address participant) private returns (uint256 amount) {\n        amount = refundablePrincipal(roundId, participant);\n        if (amount == 0) return 0;\n        openRefunds(roundId);\n        ticketsOf[roundId][participant] = 0;\n        refundedPrincipal[roundId] += amount;\n        totalLiability -= amount;\n        emit Refunded(roundId, participant, amount);\n    }\n\n    function _transferRefund(address participant, uint256 amount) private {\n        uint256 beforeBalance = bem.balanceOf(participant);\n        _tokenCall(abi.encodeCall(IDrandRaffleToken.transfer, (participant, amount)));\n        if (bem.balanceOf(participant) != beforeBalance + amount) revert UnexpectedTokenAmount();\n        _assertSolvent();\n    }\n\n    /// @notice After the fixed claim deadline, anyone can move only this failed\n    /// round's unclaimed principal to the dead address. No other round is touched.\n    function burnUnclaimed(uint256 roundId) external nonReentrant {\n        Round storage r = rounds[roundId];\n        if (r.status == Status.Settled || r.status == Status.Unstarted) revert WrongState();\n        uint64 deadline = refundClaimDeadline(roundId);\n        if (deadline == 0 || block.timestamp < deadline) revert TooEarly();\n        if (unclaimedPrincipalBurned[roundId]) revert NothingToBurn();\n        openRefunds(roundId);\n        uint256 amount = uint256(r.sold) * TICKET_PRICE - refundedPrincipal[roundId];\n        if (amount == 0) revert NothingToBurn();\n        unclaimedPrincipalBurned[roundId] = true;\n        totalLiability -= amount;\n        uint256 beforeBalance = bem.balanceOf(address(this));\n        uint256 deadBefore = bem.balanceOf(BLACKHOLE);\n        _tokenCall(abi.encodeCall(IDrandRaffleToken.transfer, (BLACKHOLE, amount)));\n        if (bem.balanceOf(BLACKHOLE) != deadBefore + amount\n            || bem.balanceOf(address(this)) + amount != beforeBalance) revert UnexpectedTokenAmount();\n        _assertSolvent();\n        emit UnclaimedPrincipalBurned(roundId, amount);\n    }\n\n    function circuitNetlist() external pure returns (bytes memory) { return CIRCUIT_RAW; }\n\n    /// @notice Exact zero-based ticket ownership. Unsold tickets return zero.\n    /// Ownership remains a historical record after refund; tickets cannot be resold.\n    function ticketOwner(uint256 roundId, uint32 ticket) public view returns (address) {\n        if (ticket >= TICKETS_PER_ROUND) revert InvalidTicketCount();\n        uint16 id = uint16((packedTicketOwners[roundId][ticket / 18] >> ((ticket % 18) * 14)) & 16383);\n        return ticketBuyer[roundId][id];\n    }\n\n    /// @notice Up to 556 words. Each has 18 low-to-high 14-bit buyer IDs; zero=unsold.\n    function ticketWords(uint256 roundId, uint16 startWord, uint16 count)\n        external view returns (uint256[] memory words)\n    {\n        if (uint256(startWord) + count > 556) revert InvalidTicketCount();\n        words = new uint256[](count);\n        for (uint256 i; i < count; ++i) words[i] = packedTicketOwners[roundId][uint256(startWord) + i];\n    }\n\n    /// @notice MUST call the real circuit. Known arithmetic is a validation guard,\n    /// not a substitute for the call. Inputs and outputs use little-endian bytes.\n    function runCircuit2075(uint16 input) public view returns (uint16 output) {\n        if (input > 4095) revert WrongCircuit();\n        IDrandRaffleCircuitSource source = IDrandRaffleCircuitSource(CIRCUITS);\n        if (keccak256(source.netlist(CIRCUIT_ID)) != CIRCUIT_HASH) revert WrongCircuit();\n        bytes memory result = source.eval(CIRCUIT_ID, abi.encodePacked(uint8(input), uint8(input >> 8)));\n        if (result.length != 2) revert WrongCircuit();\n        output = uint16(uint8(result[0])) | (uint16(uint8(result[1])) << 8);\n        if (output != (input & 255) + (input >> 8)) revert WrongCircuit();\n    }\n\n    /// @notice Public replay of any attempt. Settlement always uses the stored cursor.\n    /// The first 20 attempts use disjoint verified beacon-derived bits. Later attempts use a fixed,\n    /// domain-separated cryptographic expansion of the SAME verified words.\n    function previewAttempt(uint256 word0, uint256 word1, uint32 cursor) public view returns (Attempt memory a) {\n        uint256 group = uint256(cursor) / 10;\n        uint256 word = group == 0 ? word0 : group == 1 ? word1\n            : uint256(keccak256(abi.encode(\"BEM2075_INPUTS_V1\", word0, word1, group)));\n        uint256 shift = (uint256(cursor) % 10) * 24;\n        a.input0 = uint16((word >> shift) & 4095);\n        a.input1 = uint16((word >> (shift + 12)) & 4095);\n        a.output0 = runCircuit2075(a.input0);\n        a.output1 = runCircuit2075(a.input1);\n        // Each output's LOW byte is uniform: for every high input nibble b,\n        // a -> (a+b) mod 256 permutes all 256 low input bytes.\n        a.candidate = (uint16(uint8(a.output0)) << 8) | uint16(uint8(a.output1));\n        a.accepted = a.candidate < 60_000;\n        if (a.accepted) a.ticket = uint32(a.candidate % TICKETS_PER_ROUND);\n    }\n\n    /// @dev Specialized games may require an irreversible authorization BEFORE\n    /// accepting any ticket money. Settlement and refunds do not use this hook.\n    function _requireRoundAuthorization(uint256) internal view virtual {}\n    function _afterRoundLocked(uint256) internal virtual {}\n    function _afterRandomnessReceived(uint256) internal virtual {}\n    function _beforeSettlement(uint256) internal view virtual {}\n    function _afterSettlement(uint256) internal virtual {}\n    function _afterRefundsOpened(uint256) internal virtual {}\n\n    function _tokenCall(bytes memory data) private {\n        (bool ok, bytes memory result) = address(bem).call(data);\n        if (!ok || (result.length != 0 && (result.length != 32 || !abi.decode(result, (bool))))) revert TokenTransferFailed();\n    }\n    function _assertSolvent() private view {\n        if (bem.balanceOf(address(this)) < totalLiability) revert Insolvent();\n    }\n}\n"},"TapeoutSparkDrawBSC.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\nimport {BemDrandRaffleCandidate} from \"./BemDrandRaffleCandidate.sol\";\nimport {DrandEvmnetVerifier} from \"./DrandEvmnetVerifier.sol\";\ninterface ISparkDrawContainer { function token() external view returns(uint256,address,uint256); }\ninterface ISparkDrawNft { function ownerOf(uint256) external view returns(address); }\ninterface ISparkDrawOpener {\n    function accountOf(address,uint256) external view returns(address);\n    function isOpened(address,uint256) external view returns(bool);\n}\n\n/// @notice BNB release with immutable official token, revenue and verifier bindings.\n/// Deployment activates purchases. The first actual purchase starts each 24h funding clock.\n/// No further container execution, token custody permission or owner intervention is needed.\ncontract TapeoutSparkDrawBSC is BemDrandRaffleCandidate {\n    address public constant DEPLOYER = 0x7674fa446D42b1f7f150DC5e678cc525d275Ea53;\n    address public constant REVENUE_CONTAINER = 0x001f110422F04a90bF7D6eC96714f75046BD7126;\n    address public constant REVENUE_NFT = 0xb1024b89886B9a34Aa4ff5F31C411D708b20a14C;\n    uint256 public constant REVENUE_TOKEN_ID = 13061;\n    address public constant OPENER = 0x021745DE2f42A7839d96f2d3634d0294487D81F1;\n    bool public constant seriesAuthorized = true;\n    uint256 public constant CONTRACT_VERSION = 5;\n    event RevenueBindingFixed(address indexed container,address indexed nft,uint256 tokenId);\n\n    constructor(uint256 poolBaseUnits,address drandVerifier)\n        BemDrandRaffleCandidate(poolBaseUnits,OFFICIAL_BEM,drandVerifier,REVENUE_CONTAINER)\n    {\n        if(block.chainid!=56 || msg.sender!=DEPLOYER) revert BadConfiguration();\n        if(drandVerifier.codehash!=keccak256(type(DrandEvmnetVerifier).runtimeCode)) revert BadConfiguration();\n        if(ISparkDrawNft(REVENUE_NFT).ownerOf(REVENUE_TOKEN_ID)!=DEPLOYER\n            || ISparkDrawOpener(OPENER).accountOf(REVENUE_NFT,REVENUE_TOKEN_ID)!=REVENUE_CONTAINER\n            || !ISparkDrawOpener(OPENER).isOpened(REVENUE_NFT,REVENUE_TOKEN_ID)) revert BadConfiguration();\n        (uint256 chain,address nft,uint256 id)=ISparkDrawContainer(REVENUE_CONTAINER).token();\n        if(chain!=56 || nft!=REVENUE_NFT || id!=REVENUE_TOKEN_ID) revert BadConfiguration();\n        emit RevenueBindingFixed(REVENUE_CONTAINER,REVENUE_NFT,REVENUE_TOKEN_ID);\n    }\n}\n"},"vendor/BLS.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8;\n\nimport {ModexpInverse, ModexpSqrt} from \"./ModExp.sol\";\n\nimport \"./Precompiles.sol\";\n\n/// @title  Boneh–Lynn–Shacham (BLS) signature scheme on Barreto-Naehrig 254 bit curve (BN-254) used to verify BLS signaturess on the BN254 curve in Solidity\n/// @notice We use BLS signature aggregation to reduce the size of signature data to store on chain.\n/// @dev We can use G1 points for signatures and messages, and G2 points for public keys or vice versa\n/// @dev G1 is 64 bytes (uint256[2] in Solidity) and G2 is 128 bytes (uint256[4] in Solidity)\n/// @dev Adapted from https://github.com/kevincharm/bls-bn254.git\nlibrary BLS {\n    struct PointG1 {\n        uint256 x;\n        uint256 y;\n    }\n\n    struct PointG2 {\n        uint256[2] x; // x coordinate (represented as 2 uint256 values) / Fp2 coordinates\n        uint256[2] y; // y coordinate (represented as 2 uint256 values) / Fp2 coordinates\n    }\n\n    // GfP2 implements a field of size p² as a quadratic extension of the base field.\n    struct GfP2 {\n        uint256 x;\n        uint256 y;\n    }\n\n    // Field order\n    // p is a prime over which we form a basic field\n    // go-ethereum/crypto/bn256/cloudflare/constants.go\n    uint256 private constant N = 21888242871839275222246405745257275088696311157297823662689037894645226208583;\n\n    // Generator of G1\n    uint256 private constant G1_X = 1;\n    uint256 private constant G1_Y = 2;\n\n    // Negated generator of G1\n    uint256 private constant N_G1_X = 1;\n    uint256 private constant N_G1_Y = 21888242871839275222246405745257275088696311157297823662689037894645226208581;\n\n    // Negated generator of G2\n    uint256 private constant N_G2_X1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;\n    uint256 private constant N_G2_X0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;\n    uint256 private constant N_G2_Y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052;\n    uint256 private constant N_G2_Y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653;\n\n    uint256 private constant T24 = 0x1000000000000000000000000000000000000000000000000;\n    uint256 private constant MASK24 = 0xffffffffffffffffffffffffffffffffffffffffffffffff;\n\n    /// @notice Param A of BN254\n    uint256 private constant A = 0;\n    /// @notice Param B of BN254\n    uint256 private constant B = 3;\n    /// @notice Param Z for SVDW over E\n    uint256 private constant Z = 1;\n    /// @notice g(Z) where g(x) = x^3 + 3\n    uint256 private constant C1 = 0x4;\n    /// @notice -Z / 2 (mod N)\n    uint256 private constant C2 = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3;\n    /// @notice C3 = sqrt(-g(Z) * (3 * Z^2 + 4 * A)) (mod N)\n    ///     and sgn0(C3) == 0\n    uint256 private constant C3 = 0x16789af3a83522eb353c98fc6b36d713d5d8d1cc5dffffffa;\n    /// @notice 4 * -g(Z) / (3 * Z^2 + 4 * A) (mod N)\n    uint256 private constant C4 = 0x10216f7ba065e00de81ac1e7808072c9dd2b2385cd7b438469602eb24829a9bd;\n    /// @notice (N - 1) / 2\n    uint256 private constant C5 = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3;\n\n    error BNAddFailed(uint256[4] input);\n    error InvalidFieldElement(uint256 x);\n    error MapToPointFailed(uint256 noSqrt);\n    error InvalidDSTLength(bytes dst);\n    error ModExpFailed(uint256 base, uint256 exponent, uint256 modulus);\n\n    /// @notice Computes the negation of a point on the G1 curve.\n    /// @dev Returns the negation of the input point p on the elliptic curve.\n    ///      If the point is at infinity (x = 0, y = 0), it returns the point\n    ///      itself. Otherwise, it returns a new point with the same x-coordinate\n    ///      and the negated y-coordinate modulo the curve's prime N.\n    /// @param p The point on the G1 curve to negate.\n    /// @return The negated point on the G1 curve, such that p + negate(p) = 0.\n    function negate(PointG1 memory p) internal pure returns (PointG1 memory) {\n        // The prime q in the base field F_q for G1\n        if (p.x == 0 && p.y == 0) {\n            return PointG1(0, 0);\n        } else {\n            return PointG1(p.x, N - (p.y % N));\n        }\n    }\n\n    /// @notice Adds two points on the G1 curve.\n    /// @dev Uses the precompiled contract at address 0x06 to perform\n    ///      elliptic curve point addition in the G1 group. This function\n    ///      returns the resulting point r = p1 + p2.\n    /// @dev Reverts if the point addition operation fails.\n    /// @param p1 The first point on the G1 curve.\n    /// @param p2 The second point on the G1 curve.\n    /// @return r The resulting point from adding p1 and p2 on the G1 curve.\n    function addG1Points(PointG1 memory p1, PointG1 memory p2) internal view returns (PointG1 memory r) {\n        uint256[4] memory input;\n        input[0] = p1.x;\n        input[1] = p1.y;\n        input[2] = p2.x;\n        input[3] = p2.y;\n        bool success;\n\n        assembly {\n            success := staticcall(gas(), ECADD_ADDRESS, input, 0xc0, r, 0x60)\n        }\n\n        require(success, \"G1 addition failed\");\n    }\n\n    /// @notice Performs scalar multiplication of a point on the G1 curve.\n    /// @dev Uses the precompiled contract at address 0x07 to perform\n    ///      scalar multiplication of a point on the G1 curve, i.e.,\n    ///      computes r = s * p, where s is the scalar and p is the point.\n    /// @dev Reverts if the scalar multiplication operation fails.\n    /// @param p The point on the G1 curve to be multiplied.\n    /// @param s The scalar value to multiply the point by.\n    /// @return r The resulting point from scalar multiplication, r = s * p.\n    function scalarMulG1Point(PointG1 memory p, uint256 s) internal view returns (PointG1 memory r) {\n        uint256[3] memory input;\n        input[0] = p.x;\n        input[1] = p.y;\n        input[2] = s;\n        bool success;\n        assembly {\n            success := staticcall(gas(), ECMUL_ADDRESS, input, 0x80, r, 0x60)\n        }\n        require(success, \"G1 scalar multiplication failed\");\n    }\n\n    /// @notice Compute a scalar multiplication with a scalar and the base point.\n    function scalarMulG1Base(uint256 s) internal view returns (PointG1 memory r) {\n        uint256[3] memory input;\n        input[0] = G1_X;\n        input[1] = G1_Y;\n        input[2] = s;\n        bool success;\n        assembly {\n            success := staticcall(gas(), ECMUL_ADDRESS, input, 0x80, r, 0x60)\n        }\n        require(success, \"G1 scalar multiplication failed\");\n    }\n\n    /// @notice Verify signed message on g1 against signature on g1 and public key on g2\n    /// @param signature Signature to check\n    /// @param pubkey Public key of signer\n    /// @param message Message to check\n    /// @return pairingSuccess bool indicating if the pairing check was successful\n    /// @return callSuccess bool indicating if the static call to the evm precompile was successful\n    function verifySingle(PointG1 memory signature, PointG2 memory pubkey, PointG1 memory message)\n        internal\n        view\n        returns (bool pairingSuccess, bool callSuccess)\n    {\n        uint256[12] memory input = [\n            signature.x,\n            signature.y,\n            N_G2_X1,\n            N_G2_X0,\n            N_G2_Y1,\n            N_G2_Y0,\n            message.x,\n            message.y,\n            pubkey.x[1],\n            pubkey.x[0],\n            pubkey.y[1],\n            pubkey.y[0]\n        ];\n        uint256[1] memory out;\n        assembly {\n            callSuccess := staticcall(gas(), BN254_ECPAIRING_ADDRESS, input, 384, out, 0x20)\n        }\n        return (out[0] != 0, callSuccess);\n    }\n\n    /// @notice Verifies that the same scalar is used in both rG1 and rG2.\n    function verifyEqualityG1G2(PointG1 memory rG1, PointG2 memory rG2)\n        internal\n        view\n        returns (bool pairingSuccess, bool callSuccess)\n    {\n        uint256[12] memory input =\n            [rG1.x, rG1.y, N_G2_X1, N_G2_X0, N_G2_Y1, N_G2_Y0, G1_X, G1_Y, rG2.x[1], rG2.x[0], rG2.y[1], rG2.y[0]];\n        uint256[1] memory out;\n        assembly {\n            callSuccess := staticcall(gas(), BN254_ECPAIRING_ADDRESS, input, 384, out, 0x20)\n        }\n        return (out[0] != 0, callSuccess);\n    }\n\n    /// @notice Verify signed message on g2 against signature on g2 and public key on g1\n    /// @param signature Signature to check\n    /// @param pubkey Public key of signer\n    /// @param message Message to check\n    /// @return pairingSuccess bool indicating if the pairing check was successful\n    /// @return callSuccess bool indicating if the static call to the evm precompile was successful\n    function verifySingleG2(PointG2 memory signature, PointG1 memory pubkey, PointG2 memory message)\n        internal\n        view\n        returns (bool pairingSuccess, bool callSuccess)\n    {\n        uint256[12] memory input = [\n            N_G1_X,\n            N_G1_Y,\n            signature.x[1],\n            signature.x[0],\n            signature.y[1],\n            signature.y[0],\n            pubkey.x,\n            pubkey.y,\n            message.x[1],\n            message.x[0],\n            message.y[1],\n            message.y[0]\n        ];\n        uint256[1] memory out;\n        assembly {\n            callSuccess := staticcall(gas(), BN254_ECPAIRING_ADDRESS, input, 384, out, 0x20)\n        }\n        return (out[0] != 0, callSuccess);\n    }\n\n    /// @notice Hash to BN254 G1\n    /// @param domain Domain separation tag\n    /// @param message Message to hash\n    /// @return point in G1\n    function hashToPoint(bytes memory domain, bytes memory message) internal view returns (PointG1 memory point) {\n        uint256[2] memory u = hashToField(domain, message);\n        uint256[2] memory p0 = mapToPoint(u[0]);\n        uint256[2] memory p1 = mapToPoint(u[1]);\n        uint256[4] memory bnAddInput;\n        bnAddInput[0] = p0[0];\n        bnAddInput[1] = p0[1];\n        bnAddInput[2] = p1[0];\n        bnAddInput[3] = p1[1];\n        bool success;\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            success := staticcall(gas(), ECADD_ADDRESS, bnAddInput, 128, p0, 64)\n        }\n        if (!success) revert BNAddFailed(bnAddInput);\n        point = PointG1({x: p0[0], y: p0[1]});\n        return point;\n    }\n\n    /// @notice Check if point in g1 is a valid\n    /// @param point The point on g1 to check\n    function isValidPointG1(PointG1 memory point) internal pure returns (bool) {\n        if ((point.x >= N) || (point.y >= N)) {\n            return false;\n        } else {\n            return isOnCurveG1(point);\n        }\n    }\n\n    /// @notice Check if point is a valid g2 point\n    /// @param point the point to check\n    function isValidPointG2(PointG2 memory point) internal pure returns (bool) {\n        if ((point.x[0] >= N) || (point.x[1] >= N) || (point.y[0] >= N || (point.y[1] >= N))) {\n            return false;\n        } else {\n            return isOnCurveG2(point);\n        }\n    }\n\n    /// @notice Check if `point` is in G1\n    /// @param p Point to check\n    function isOnCurveG1(PointG1 memory p) internal pure returns (bool _isOnCurve) {\n        uint256[2] memory point = [p.x, p.y];\n        assembly {\n            let t0 := mload(point)\n            let t1 := mload(add(point, 32))\n            let t2 := mulmod(t0, t0, N)\n            t2 := mulmod(t2, t0, N)\n            t2 := addmod(t2, 3, N)\n            t1 := mulmod(t1, t1, N)\n            _isOnCurve := eq(t1, t2)\n        }\n    }\n\n    /// @notice Check if `point` is in G2\n    /// @param p Point to check\n    function isOnCurveG2(PointG2 memory p) internal pure returns (bool _isOnCurve) {\n        uint256[4] memory point = [p.x[0], p.x[1], p.y[0], p.y[1]];\n        assembly {\n            // x0, x1\n            let t0 := mload(point)\n            let t1 := mload(add(point, 32))\n            // x0 ^ 2\n            let t2 := mulmod(t0, t0, N)\n            // x1 ^ 2\n            let t3 := mulmod(t1, t1, N)\n            // 3 * x0 ^ 2\n            let t4 := add(add(t2, t2), t2)\n            // 3 * x1 ^ 2\n            let t5 := addmod(add(t3, t3), t3, N)\n            // x0 * (x0 ^ 2 - 3 * x1 ^ 2)\n            t2 := mulmod(add(t2, sub(N, t5)), t0, N)\n            // x1 * (3 * x0 ^ 2 - x1 ^ 2)\n            t3 := mulmod(add(t4, sub(N, t3)), t1, N)\n\n            // x ^ 3 + b\n            t0 := addmod(t2, 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5, N)\n            t1 := addmod(t3, 0x009713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2, N)\n\n            // y0, y1\n            t2 := mload(add(point, 64))\n            t3 := mload(add(point, 96))\n            // y ^ 2\n            t4 := mulmod(addmod(t2, t3, N), addmod(t2, sub(N, t3), N), N)\n            t3 := mulmod(shl(1, t2), t3, N)\n\n            // y ^ 2 == x ^ 3 + b\n            _isOnCurve := and(eq(t0, t4), eq(t1, t3))\n        }\n    }\n\n    /// @notice Check if `signature` is a valid signature\n    /// @param signature Signature to check\n    function isValidSignature(uint256[2] memory signature) internal pure returns (bool) {\n        if ((signature[0] >= N) || (signature[1] >= N)) {\n            return false;\n        }\n        return isOnCurveG1(PointG1({x: signature[0], y: signature[1]}));\n    }\n\n    /// @notice Check if `publicKey` is a valid public key\n    /// @param publicKey PK to check\n    function isValidPublicKey(uint256[4] memory publicKey) internal pure returns (bool) {\n        if ((publicKey[0] >= N) || (publicKey[1] >= N) || (publicKey[2] >= N || (publicKey[3] >= N))) {\n            return false;\n        }\n        return isOnCurveG2(PointG2({x: [publicKey[0], publicKey[1]], y: [publicKey[2], publicKey[3]]}));\n    }\n\n    /// @notice Unmarshals a point on G1 from bytes in an uncompressed form.\n    /// @param m Representation of the point, using 32-byte big-endian integers for x, then y.\n    /// @return A G1 point.\n    function g1Unmarshal(bytes memory m) internal pure returns (PointG1 memory) {\n        require(m.length == 64, \"Invalid G1 bytes length\");\n\n        bytes32 x;\n        bytes32 y;\n\n        assembly {\n            x := mload(add(m, 0x20))\n            y := mload(add(m, 0x40))\n        }\n\n        return PointG1(uint256(x), uint256(y));\n    }\n\n    /// @notice Marshals a point on G1 to bytes form.\n    /// @param point A G1 point.\n    /// @return 64 bytes containing the representation of the point, using 32-byte big-endian integers for x, then y.\n    function g1Marshal(PointG1 memory point) internal pure returns (bytes memory) {\n        bytes memory m = new bytes(64);\n        bytes32 x = bytes32(point.x);\n        bytes32 y = bytes32(point.y);\n\n        assembly {\n            mstore(add(m, 32), x)\n            mstore(add(m, 64), y)\n        }\n\n        return m;\n    }\n\n    /// @dev Unmarshals a point on G2 from bytes in an uncompressed form.\n    /// @param m Representation of the point, starting with the coefficient of the term of degree 1 of x as a 32-byte big-endian integer, then the coefficient of degree 0 of x, then the same for y.\n    /// @return A G2 point.\n    function g2Unmarshal(bytes memory m) internal pure returns (PointG2 memory) {\n        require(m.length == 128, \"Invalid G2 bytes length\");\n\n        uint256 x1;\n        uint256 x0;\n        uint256 y1;\n        uint256 y0;\n\n        assembly {\n            x1 := mload(add(m, 0x20))\n            x0 := mload(add(m, 0x40))\n            y1 := mload(add(m, 0x60))\n            y0 := mload(add(m, 0x80))\n        }\n\n        return PointG2([x0, x1], [y0, y1]);\n    }\n\n    /// @dev Marshals a point on G2 to an uncompressed form.\n    /// @param point A G2 point.\n    /// @return 128 bytes containing the representation of the point, starting with the coefficient of the term of degree 1 of x as a 32-byte big-endian integer, then the coefficient of degree 0 of x, then the same for y.\n    function g2Marshal(PointG2 memory point) internal pure returns (bytes memory) {\n        bytes memory m = new bytes(128);\n        bytes32 x0 = bytes32(point.x[0]);\n        bytes32 x1 = bytes32(point.x[1]);\n        bytes32 y0 = bytes32(point.y[0]);\n        bytes32 y1 = bytes32(point.y[1]);\n\n        assembly {\n            mstore(add(m, 0x20), x1)\n            mstore(add(m, 0x40), x0)\n            mstore(add(m, 0x60), y1)\n            mstore(add(m, 0x80), y0)\n        }\n\n        return m;\n    }\n\n    /// @notice sqrt(xx) mod N\n    /// @param xx Input\n    function sqrt(uint256 xx) internal pure returns (uint256 x, bool hasRoot) {\n        x = ModexpSqrt.run(xx);\n        hasRoot = mulmod(x, x, N) == xx;\n    }\n\n    /// @notice a^{-1} mod N\n    /// @param a Input\n    function inverse(uint256 a) internal pure returns (uint256) {\n        return ModexpInverse.run(a);\n    }\n\n    /// @notice Hash a message to the field\n    /// @param domain Domain separation tag\n    /// @param message Message to hash\n    function hashToField(bytes memory domain, bytes memory message) internal pure returns (uint256[2] memory) {\n        bytes memory _msg = expandMsgTo96(domain, message);\n        uint256 u0;\n        uint256 u1;\n        uint256 a0;\n        uint256 a1;\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            let p := add(_msg, 24)\n            u1 := and(mload(p), MASK24)\n            p := add(_msg, 48)\n            u0 := and(mload(p), MASK24)\n            a0 := addmod(mulmod(u1, T24, N), u0, N)\n            p := add(_msg, 72)\n            u1 := and(mload(p), MASK24)\n            p := add(_msg, 96)\n            u0 := and(mload(p), MASK24)\n            a1 := addmod(mulmod(u1, T24, N), u0, N)\n        }\n        return [a0, a1];\n    }\n\n    function hashToFieldSingle(bytes memory domain, bytes memory message) internal pure returns (uint256) {\n        bytes memory _msg = expandMsg(domain, message, 48);\n        uint256 u0;\n        uint256 u1;\n        uint256 a0;\n        // solium-disable-next-line security/no-inline-assembly\n        assembly {\n            let p := add(_msg, 24)\n            u1 := and(mload(p), MASK24)\n            p := add(_msg, 48)\n            u0 := and(mload(p), MASK24)\n            a0 := addmod(mulmod(u1, T24, N), u0, N)\n        }\n        return a0;\n    }\n\n    /// @notice Expand arbitrary message to n bytes, as described\n    ///     in rfc9380 section 5.3.1, using H = keccak256.\n    /// @param DST Domain separation tag\n    /// @param message The message to expand\n    /// @param n_bytes The number of bytes to extend to\n    function expandMsg(bytes memory DST, bytes memory message, uint8 n_bytes) internal pure returns (bytes memory) {\n        uint256 domainLen = DST.length;\n        if (domainLen > 255) {\n            revert InvalidDSTLength(DST);\n        }\n        bytes memory zpad = new bytes(136);\n        bytes memory b_0 = abi.encodePacked(zpad, message, uint8(0), n_bytes, uint8(0), DST, uint8(domainLen));\n        bytes32 b0 = keccak256(b_0);\n\n        bytes memory b_i = abi.encodePacked(b0, uint8(1), DST, uint8(domainLen));\n        bytes32 bi = keccak256(b_i);\n        bytes memory out = new bytes(n_bytes);\n        uint256 ell = (n_bytes + uint256(31)) >> 5;\n        for (uint256 i = 1; i < ell; i++) {\n            b_i = abi.encodePacked(b0 ^ bi, uint8(1 + i), DST, uint8(domainLen));\n            assembly {\n                let p := add(32, out)\n                p := add(p, mul(32, sub(i, 1)))\n                mstore(p, bi)\n            }\n            bi = keccak256(b_i);\n        }\n        assembly {\n            let p := add(32, out)\n            p := add(p, mul(32, sub(ell, 1)))\n            mstore(p, bi)\n        }\n        return out;\n    }\n\n    /// @notice Expand arbitrary message to 96 pseudorandom bytes, as described\n    ///     in rfc9380 section 5.3.1, using H = keccak256.\n    /// @param DST Domain separation tag\n    /// @param message Message to expand\n    function expandMsgTo96(bytes memory DST, bytes memory message) internal pure returns (bytes memory) {\n        uint256 domainLen = DST.length;\n        if (domainLen > 255) {\n            revert InvalidDSTLength(DST);\n        }\n        bytes memory zpad = new bytes(136);\n        bytes memory b_0 = abi.encodePacked(zpad, message, uint8(0), uint8(96), uint8(0), DST, uint8(domainLen));\n        bytes32 b0 = keccak256(b_0);\n\n        bytes memory b_i = abi.encodePacked(b0, uint8(1), DST, uint8(domainLen));\n        bytes32 bi = keccak256(b_i);\n\n        bytes memory out = new bytes(96);\n        uint256 ell = 3;\n        for (uint256 i = 1; i < ell; i++) {\n            b_i = abi.encodePacked(b0 ^ bi, uint8(1 + i), DST, uint8(domainLen));\n            assembly {\n                let p := add(32, out)\n                p := add(p, mul(32, sub(i, 1)))\n                mstore(p, bi)\n            }\n            bi = keccak256(b_i);\n        }\n        assembly {\n            let p := add(32, out)\n            p := add(p, mul(32, sub(ell, 1)))\n            mstore(p, bi)\n        }\n        return out;\n    }\n\n    /// @notice Map field element to E using SvdW\n    /// @param u Field element to map\n    /// @return p Point on curve\n    function mapToPoint(uint256 u) internal view returns (uint256[2] memory p) {\n        if (u >= N) revert InvalidFieldElement(u);\n\n        uint256 tv1 = mulmod(mulmod(u, u, N), C1, N);\n        uint256 tv2 = addmod(1, tv1, N);\n        tv1 = addmod(1, N - tv1, N);\n        uint256 tv3 = inverse(mulmod(tv1, tv2, N));\n        uint256 tv5 = mulmod(mulmod(mulmod(u, tv1, N), tv3, N), C3, N);\n        uint256 x1 = addmod(C2, N - tv5, N);\n        uint256 x2 = addmod(C2, tv5, N);\n        uint256 tv7 = mulmod(tv2, tv2, N);\n        uint256 tv8 = mulmod(tv7, tv3, N);\n        uint256 x3 = addmod(Z, mulmod(C4, mulmod(tv8, tv8, N), N), N);\n\n        bool hasRoot;\n        uint256 gx;\n        if (legendre(g(x1)) == 1) {\n            p[0] = x1;\n            gx = g(x1);\n            (p[1], hasRoot) = sqrt(gx);\n            if (!hasRoot) revert MapToPointFailed(gx);\n        } else if (legendre(g(x2)) == 1) {\n            p[0] = x2;\n            gx = g(x2);\n            (p[1], hasRoot) = sqrt(gx);\n            if (!hasRoot) revert MapToPointFailed(gx);\n        } else {\n            p[0] = x3;\n            gx = g(x3);\n            (p[1], hasRoot) = sqrt(gx);\n            if (!hasRoot) revert MapToPointFailed(gx);\n        }\n        if (sgn0(u) != sgn0(p[1])) {\n            p[1] = N - p[1];\n        }\n    }\n\n    /// @notice g(x) = y^2 = x^3 + 3\n    function g(uint256 x) private pure returns (uint256) {\n        return addmod(mulmod(mulmod(x, x, N), x, N), B, N);\n    }\n\n    /// @notice https://datatracker.ietf.org/doc/html/rfc9380#name-the-sgn0-function\n    function sgn0(uint256 x) private pure returns (uint256) {\n        return x % 2;\n    }\n\n    /// @notice Compute Legendre symbol of u\n    /// @param u Field element\n    /// @return 1 if u is a quadratic residue, -1 if not, or 0 if u = 0 (mod p)\n    function legendre(uint256 u) private view returns (int8) {\n        uint256 x = modexpLegendre(u);\n        if (x == N - 1) {\n            return -1;\n        }\n        if (x != 0 && x != 1) {\n            revert MapToPointFailed(u);\n        }\n        return int8(int256(x));\n    }\n\n    /// @notice This is cheaper than an addchain for exponent (N-1)/2\n    function modexpLegendre(uint256 u) private view returns (uint256 output) {\n        bytes memory input = new bytes(192);\n        bool success;\n        assembly {\n            let p := add(input, 32)\n            mstore(p, 32) // len(u)\n            p := add(p, 32)\n            mstore(p, 32) // len(exp)\n            p := add(p, 32)\n            mstore(p, 32) // len(mod)\n            p := add(p, 32)\n            mstore(p, u) // u\n            p := add(p, 32)\n            mstore(p, C5) // (N-1)/2\n            p := add(p, 32)\n            mstore(p, N) // N\n\n            success := staticcall(\n                gas(),\n                MODEXP_ADDRESS,\n                add(input, 32),\n                192,\n                0x00, // scratch space <- result\n                32\n            )\n            output := mload(0x00) // output <- result\n        }\n        if (!success) {\n            revert ModExpFailed(u, C5, N);\n        }\n    }\n}\n"},"vendor/ModExp.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8;\n\n/// @title Compute Inverse by Modular Exponentiation\n/// @notice Compute $input^(N - 2) mod N$ using Addition Chain method.\n/// Where     N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47\n/// and   N - 2 = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45\n/// @dev the function body is generated with the modified addchain script\n/// see https://github.com/kobigurk/addchain/commit/2c37a2ace567a9bdc680b4e929c94aaaa3ec700f\n/// Adapted from https://github.com/kobigurk/addchain/commit/2c37a2ace567a9bdc680b4e929c94aaaa3ec700f\nlibrary ModexpInverse {\n    function run(uint256 t2) internal pure returns (uint256 t0) {\n        assembly {\n            let n := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47\n            t0 := mulmod(t2, t2, n)\n            let t5 := mulmod(t0, t2, n)\n            let t1 := mulmod(t5, t0, n)\n            let t3 := mulmod(t5, t5, n)\n            let t8 := mulmod(t1, t0, n)\n            let t4 := mulmod(t3, t5, n)\n            let t6 := mulmod(t3, t1, n)\n            t0 := mulmod(t3, t3, n)\n            let t7 := mulmod(t8, t3, n)\n            t3 := mulmod(t4, t3, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t7, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t7, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t7, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t3, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t3, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t3, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n        }\n    }\n}\n\n/// @title Compute Square Root by Modular Exponentiation\n/// @notice Compute $input^{(N + 1) / 4} mod N$ using Addition Chain method.\n/// Where           N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47\n/// and   (N + 1) / 4 = 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52\nlibrary ModexpSqrt {\n    function run(uint256 t6) internal pure returns (uint256 t0) {\n        assembly {\n            let n := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47\n\n            t0 := mulmod(t6, t6, n)\n            let t4 := mulmod(t0, t6, n)\n            let t2 := mulmod(t4, t0, n)\n            let t3 := mulmod(t4, t4, n)\n            let t8 := mulmod(t2, t0, n)\n            let t1 := mulmod(t3, t4, n)\n            let t5 := mulmod(t3, t2, n)\n            t0 := mulmod(t3, t3, n)\n            let t7 := mulmod(t8, t3, n)\n            t3 := mulmod(t1, t3, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t7, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t7, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t8, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t7, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t3, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t6, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t5, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t4, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t3, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t3, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t2, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t0, n)\n            t0 := mulmod(t0, t1, n)\n            t0 := mulmod(t0, t0, n)\n        }\n    }\n}\n"},"vendor/Precompiles.sol":{"content":"// SPDX-License-Identifier: MIT\npragma solidity ^0.8;\n\n// @notice address of the EIP-198 modular exponentiation precompile\nuint256 constant MODEXP_ADDRESS = 5;\n\n// @notice address of the EIP-196 BN254 G1 point addition\nuint256 constant ECADD_ADDRESS = 6;\n\n// @notice address of the EIP-196 BN254 G1 scalar multiplication\nuint256 constant ECMUL_ADDRESS = 7;\n\n// @notice address of the EIP-197 BN254 pairing check\nuint256 constant BN254_ECPAIRING_ADDRESS = 8;\n\n// @notice address of the EIP-2537 BLS12-381 point addition precompile\nuint256 constant BLS12_G1ADD = 0x0b;\n\n// @notice address of the EIP-2537 BLS12-381 pairing check precompile\nuint256 constant BLS12_PAIRING_CHECK = 0x0f;\n\n// @notice address of the EIP-2537 BLS12-381 base field element to point precompile\n// @dev it uses the Simplified Shallue-van de Woestĳne-Ulas mapping (SSWU)\nuint256 constant BLS12_MAP_FP_TO_G1 = 0x10;\n"}},"settings":{"optimizer":{"enabled":true,"runs":200},"viaIR":true,"evmVersion":"shanghai","outputSelection":{"*":{"*":["abi","evm.bytecode.object","evm.deployedBytecode.object","evm.deployedBytecode.immutableReferences"]}}}}