{
  "v": 1,
  "requestId": "bc5b7034-2e93-4142-bafc-beebaa7f729f",
  "chainId": 1,
  "window": {
    "toBlock": 26026608,
    "fromBlock": 26019452,
    "toBlockHash": "0x84272223fc64b8c836b51b2c341b61a03bfe7728fa6d655347f56dbf837fbf3f"
  },
  "answerType": "uint256",
  "answer": "4291460000000000",
  "figure": "4291460000000000",
  "definitions": {
    "sale": "an OrderFulfilled event emitted by Seaport 1.5 (0x00000000000000adc04c56bf30ac9d3c0aaf14dc) or Seaport 1.6 (0x0000000000000068f116a894984e2db1123eb395) on Ethereum mainnet whose offer and consideration items together contain exactly one ERC-721 item (itemType 2) of the collection and no other NFT; bundles and ERC-1155 fills are excluded",
    "price": "for a listing fill (the single offer item is the NFT), the sum of every consideration amount paid in native ETH (itemType 0) or WETH 0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2 (itemType 1), fees included, and only if every consideration item is ETH or WETH; for a bid fill (the single offer item is ETH or WETH), the offer amount; fills paid in any other token are excluded",
    "source": "the chain itself: eth_getLogs for the OrderFulfilled topic on both Seaport contracts over exactly the pinned blocks, decoded with the Seaport ABI",
    "average": "the arithmetic mean, rounded down to an integer number of wei, of the price of every qualifying sale in the pinned block window; 0 only if there was no qualifying sale",
    "denomination": "Integer wei; native ETH and WETH amounts are combined 1:1 without conversion or floating-point arithmetic.",
    "window": "Both endpoint blocks are included. Confirm chainId 1 and the pinned closing block hash before scanning.",
    "counting": "Count each qualifying non-removed OrderFulfilled event once, deduplicated by blockNumber and logIndex. Separate fills remain separate sales, including multiple fills in one transaction or resales of the same token.",
    "itemValidation": "Require the one collection ERC-721 item to have amount 1 and the offer array to have exactly one item. Exclude all other NFT item types. In bid fills, every consideration item other than the NFT must also be ETH or WETH; offer amount is the full price and fees are not added again.",
    "marketplace": "OpenSea is operationally the two Seaport emitters in the pinned sale definition; no extra frontend, zone, conduit, recipient or transaction-sender filter is applied.",
    "abi": "OrderFulfilled(bytes32,address,address,address,(uint8,address,uint256,uint256)[],(uint8,address,uint256,uint256,address)[]). Offerer and zone are indexed. Non-indexed data words 0 and 1 are orderHash and recipient; words 2 and 3 are byte offsets to offer and consideration arrays."
  },
  "recipe": {
    "kind": "panel",
    "source": "https://rpc.flashbots.net/fast"
  },
  "notes": "Computed using the supplied scan.mjs transport, range splitting, deduplication and keccak implementation, extended in scratch with ABI array decoding and the requested sale reduction. Flashbots returned 12232 OrderFulfilled logs in four inclusive, disjoint chunks; 25 qualifying listings, 0 qualifying bids; sum 107286500000000000 wei; floor(sum/25)=4291460000000000 wei. Chain ID and closing hash also confirmed on https://rpc.mevblocker.io/fast. The brief requires a panel recipe; its catalogue has no executable Seaport-average kind. The following dependency-free Node reproduction uses only public RPC data, the delivered answer file and the definitions. Run with node --input-type=module, supplying this code on stdin:\n\nimport fs from 'node:fs';\nconst a=JSON.parse(fs.readFileSync('artifacts/answer.json','utf8'));\nconst url=a.recipe.source;\nlet id=0;\nasync function rpc(method,params){const r=await fetch(url,{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({jsonrpc:'2.0',id:++id,method,params}),signal:AbortSignal.timeout(60000)});if(!r.ok)throw Error('HTTP '+r.status);const b=await r.json();if(b.error)throw Error(JSON.stringify(b.error));if(b.result==null)throw Error('Missing result');return b.result;}\nconst hex=n=>'0x'+n.toString(16);\nif(Number(await rpc('eth_chainId',[]))!==a.chainId)throw Error('chain');\nif((await rpc('eth_getBlockByNumber',[hex(a.window.toBlock),false])).hash!==a.window.toBlockHash)throw Error('pin');\nconst address=['0x00000000000000adc04c56bf30ac9d3c0aaf14dc','0x0000000000000068f116a894984e2db1123eb395'];\nconst topics=['0x9d9af8e38d66c62e2c12f0225249fd9d721c54b83f48d9352c97c6cacdcb6f31'];\nasync function logs(lo,hi){try{const v=await rpc('eth_getLogs',[{address,topics,fromBlock:hex(lo),toBlock:hex(hi)}]);if(v.length>=10000)throw Error('possible cap');return v;}catch(e){if(lo===hi)throw e;const mid=Math.floor((lo+hi)/2);return [...await logs(lo,mid),...await logs(mid+1,hi)];}}\nconst collection='0x4b570b636e4f744199ec82f52d69b08b394ab850',weth='0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2';\nconst money=i=>i.t===0||(i.t===1&&i.token===weth);\nconst seen=new Set();let count=0n,total=0n;\nfor(let lo=a.window.fromBlock;lo<=a.window.toBlock;lo+=2000){for(const l of await logs(lo,Math.min(lo+1999,a.window.toBlock))){\nconst key=l.blockNumber+':'+l.logIndex;if(l.removed||seen.has(key))continue;seen.add(key);\nconst word=i=>{const s=l.data.slice(2+64*i,66+64*i);if(s.length!==64)throw Error('ABI');return BigInt('0x'+s);};\nconst array=(slot,stride)=>{const off=Number(word(slot))/32;if(!Number.isInteger(off))throw Error('offset');return Array.from({length:Number(word(off))},(_,j)=>{const k=off+1+j*stride;return {t:Number(word(k)),token:'0x'+word(k+1).toString(16).padStart(40,'0'),amount:word(k+3)};});};\nconst o=array(2,4),c=array(3,5),n=[...o,...c].filter(i=>i.t>=2);\nif(n.length!==1||n[0].t!==2||n[0].token!==collection||n[0].amount!==1n||o.length!==1)continue;\nlet price;if(o[0]===n[0]&&c.every(money))price=c.reduce((s,i)=>s+i.amount,0n);else if(money(o[0])&&c.every(i=>i===n[0]||money(i)))price=o[0].amount;else continue;\ncount++;total+=price;\n}}\nconst average=count?total/count:0n;\nconsole.log(JSON.stringify({sales:String(count),totalWei:String(total),averageWei:String(average)}));\nif(String(average)!==a.answer)throw Error('answer mismatch');"
}
