{
  "language": "Solidity",
  "sources": {
    "WinPonsCollectors.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\n\ninterface IPonsFactory {\n    struct Launch {\n        address token; address curve; address deployer; address creatorFeeRecipient;\n        address pairToken; uint256 graduationThreshold; uint24 poolFee; int24 tickSpacing;\n        uint16 creatorTaxBps; bool buybackEnabled; uint8 phase; uint256 sweptQuote;\n        uint256 sweptTokens; uint256 sweptAt; bool exists;\n    }\n    function getLaunchedToken(address token) external view returns (Launch memory);\n    function feeEscrow() external view returns (address);\n}\ninterface IPonsEscrow {\n    function claim() external returns (uint256);\n    function balanceOf(address recipient) external view returns (uint256);\n}\ninterface IWinFeeRouter {\n    // The separately reviewed jackpot router must authenticate msg.sender against\n    // collectorFor(token), then account for the approved coin/global split.\n    function depositCreatorFees(address token) external payable;\n}\n\n/**\n * Superseded direct-launch integration candidate; retained for regression tests.\n * Use WinPonsLauncher for new development: curve sweeps require deployer rights.\n * One collector per launch keeps Pons' recipient-keyed escrow attributable.\n * Nothing here selects winners, records entries, or claims that jackpots are live.\n */\ncontract WinPonsCollector is ReentrancyGuard {\n    address public immutable registry;\n    address public immutable creator;\n    IPonsEscrow public immutable escrow;\n    IWinFeeRouter public immutable router;\n    address public token;\n    uint256 public totalForwarded;\n    error Unauthorized();\n    error NotBound();\n    error AlreadyBound();\n    error ReceiptMismatch();\n    event FeesForwarded(address indexed token, uint256 amount);\n\n    constructor(address creator_, address escrow_, address router_) {\n        registry = msg.sender;\n        creator = creator_;\n        escrow = IPonsEscrow(escrow_);\n        router = IWinFeeRouter(router_);\n    }\n    receive() external payable { if (msg.sender != address(escrow)) revert Unauthorized(); }\n    function bind(address token_) external {\n        if (msg.sender != registry) revert Unauthorized();\n        if (token != address(0)) revert AlreadyBound();\n        if (token_ == address(0)) revert NotBound();\n        token = token_;\n    }\n    // Anyone can run collection; proceeds can only reach the immutable router.\n    function collect() external nonReentrant returns (uint256 amount) {\n        if (token == address(0)) revert NotBound();\n        if (escrow.balanceOf(address(this)) == 0) return 0;\n        uint256 beforeBalance = address(this).balance;\n        amount = escrow.claim();\n        if (amount == 0 || address(this).balance - beforeBalance != amount) revert ReceiptMismatch();\n        totalForwarded += amount;\n        router.depositCreatorFees{value: amount}(token);\n        emit FeesForwarded(token, amount);\n    }\n}\n\ncontract WinPonsCollectors is ReentrancyGuard {\n    IPonsFactory public immutable ponsFactory;\n    address public immutable feeEscrow;\n    address public immutable feeRouter;\n    mapping(address => bool) public isCollector;\n    mapping(address => address) public collectorFor;\n    mapping(address => address) public creatorFor;\n    mapping(address => uint256) public createdAt;\n    address[] private tokens;\n    error InvalidDependency();\n    error InvalidLaunch();\n    error AlreadyRegistered();\n    event CollectorCreated(address indexed collector, address indexed creator, bytes32 indexed salt);\n    event TokenRegistered(address indexed token, address indexed collector, address indexed creator);\n\n    constructor(address factory_, address router_) {\n        if (factory_.code.length == 0 || router_.code.length == 0) revert InvalidDependency();\n        ponsFactory = IPonsFactory(factory_);\n        feeEscrow = IPonsFactory(factory_).feeEscrow();\n        if (feeEscrow.code.length == 0) revert InvalidDependency();\n        feeRouter = router_;\n    }\n    function predictCollector(address creator, bytes32 salt) public view returns (address) {\n        bytes32 namespaced = keccak256(abi.encode(creator, salt));\n        bytes32 initHash = keccak256(abi.encodePacked(type(WinPonsCollector).creationCode,\n            abi.encode(creator, feeEscrow, feeRouter)));\n        return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), namespaced, initHash)))));\n    }\n    function createCollector(bytes32 salt) external nonReentrant returns (address collector) {\n        bytes32 namespaced = keccak256(abi.encode(msg.sender, salt));\n        collector = address(new WinPonsCollector{salt: namespaced}(msg.sender, feeEscrow, feeRouter));\n        isCollector[collector] = true;\n        emit CollectorCreated(collector, msg.sender, salt);\n    }\n    // Direct wallet -> Pons launch preserves the real deployer. Registration can\n    // be retried by anybody after a successful launch if the UI is interrupted.\n    function register(address token) external nonReentrant {\n        if (collectorFor[token] != address(0)) revert AlreadyRegistered();\n        IPonsFactory.Launch memory launch = ponsFactory.getLaunchedToken(token);\n        address collector = launch.creatorFeeRecipient;\n        if (!launch.exists || launch.token != token || token.code.length == 0 ||\n            !isCollector[collector] || launch.pairToken != address(0) ||\n            launch.creatorTaxBps != 0 || launch.buybackEnabled) revert InvalidLaunch();\n        if (WinPonsCollector(payable(collector)).creator() != launch.deployer) revert InvalidLaunch();\n        WinPonsCollector(payable(collector)).bind(token);\n        collectorFor[token] = collector;\n        creatorFor[token] = launch.deployer;\n        createdAt[token] = block.timestamp;\n        tokens.push(token);\n        emit TokenRegistered(token, collector, launch.deployer);\n    }\n    function totalTokens() external view returns (uint256) { return tokens.length; }\n    function tokenAt(uint256 index) external view returns (address) { return tokens[index]; }\n}\n"
    },
    "WinPonsLauncher.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport {IPonsFactory, IPonsEscrow, IWinFeeRouter} from \"./WinPonsCollectors.sol\";\n\ninterface IPonsLaunch is IPonsFactory {\n    struct Socials {string twitter;string telegram;string discord;string website;string farcaster;}\n    struct TokenParams {\n        string name;string symbol;string logo;string description;Socials socials;\n        address creatorFeeRecipient;uint16 creatorTaxBps;bool buybackEnabled;\n        bytes32 expectedEconomics;bytes32 salt;\n    }\n    function launchToken(TokenParams calldata params,uint256 config,address pair) external payable returns(address,address);\n    function memeHook()external view returns(address);\n}\ninterface IPonsCurveSweep {function sweepFees(uint256 minBuybackTokensOut) external;}\ninterface IPonsPoolSweep {\n    function feeSweepOperator()external view returns(address);\n    function sweepPoolFees(bytes32 poolId,uint256 minConversionQuoteOut,uint256 minBuybackTokensOut)external;\n}\n\n/** Per-coin Pons deployer and fee recipient. Only the fixed vault can receive fees. */\ncontract WinPonsLaunchAccount is ReentrancyGuard {\n    address public immutable registry;\n    address public immutable creator;\n    IPonsLaunch public immutable factory;\n    IPonsEscrow public immutable escrow;\n    IWinFeeRouter public immutable vault;\n    address public token;\n    address public curve;\n    uint256 public totalForwarded;\n    error Unauthorized();error InvalidLaunch();error ReceiptMismatch();\n    event FeesForwarded(address indexed token,uint256 amount);\n    event PoolSweepDeferred(address indexed token,bytes32 indexed poolId);\n\n    constructor(address creator_,address factory_,address escrow_,address vault_) {\n        registry=msg.sender;creator=creator_;factory=IPonsLaunch(factory_);\n        escrow=IPonsEscrow(escrow_);vault=IWinFeeRouter(vault_);\n    }\n    receive() external payable {if(msg.sender!=address(escrow))revert Unauthorized();}\n    function launch(IPonsLaunch.TokenParams calldata input,uint256 config) external payable returns(address,address) {\n        if(msg.sender!=registry||token!=address(0))revert Unauthorized();\n        if(input.creatorTaxBps!=0||input.buybackEnabled||input.expectedEconomics==bytes32(0))revert InvalidLaunch();\n        IPonsLaunch.TokenParams memory params=input;\n        params.creatorFeeRecipient=address(this);\n        (token,curve)=factory.launchToken{value:msg.value}(params,config,address(0));\n        IPonsFactory.Launch memory record=factory.getLaunchedToken(token);\n        if(token.code.length==0||curve.code.length==0||!record.exists||record.token!=token||\n            record.curve!=curve||record.deployer!=address(this)||record.creatorFeeRecipient!=address(this)||\n            record.pairToken!=address(0)||record.creatorTaxBps!=0||record.buybackEnabled)revert InvalidLaunch();\n        return(token,curve);\n    }\n    // Pons permits the account to sweep quote-only pool fees. Memecoin conversion\n    // still needs its operator; failure leaves those fees in Pons for later retry.\n    function collect() external nonReentrant returns(uint256 amount) {\n        if(token==address(0))revert InvalidLaunch();\n        IPonsFactory.Launch memory record=factory.getLaunchedToken(token);\n        if(record.phase==0)IPonsCurveSweep(curve).sweepFees(0);\n        else if(record.phase==2){\n            address hook=factory.memeHook();\n            bytes32 poolId=keccak256(abi.encode(address(0),token,record.poolFee,record.tickSpacing,hook));\n            // Never execute conversions with a zero minimum, even if Pons were\n            // to designate this account as its trusted operator in the future.\n            if(IPonsPoolSweep(hook).feeSweepOperator()==address(this)){emit PoolSweepDeferred(token,poolId);}\n            else{try IPonsPoolSweep(hook).sweepPoolFees(poolId,0,0){}catch{emit PoolSweepDeferred(token,poolId);}}\n        }\n        if(escrow.balanceOf(address(this))==0)return 0;\n        uint256 beforeBalance=address(this).balance;\n        amount=escrow.claim();\n        if(amount==0||address(this).balance-beforeBalance!=amount)revert ReceiptMismatch();\n        totalForwarded+=amount;vault.depositCreatorFees{value:amount}(token);\n        emit FeesForwarded(token,amount);\n    }\n}\n\n/** Unreviewed launch candidate. Defaults closed; cannot bypass Pons economics. */\ncontract WinPonsLauncher is ReentrancyGuard {\n    address public immutable owner;\n    IPonsLaunch public immutable factory;\n    address public immutable feeEscrow;\n    address public immutable vault;\n    bytes32 public immutable factoryHash;\n    bool public paused=true;\n    mapping(address=>address) public collectorFor;\n    mapping(address=>address) public creatorFor;\n    mapping(address=>uint256) public createdAt;\n    address[] private tokens;\n    error Unauthorized();error InvalidDependency();error LaunchesPaused();\n    event TokenRegistered(address indexed token,address indexed collector,address indexed creator,address curve);\n    event PauseChanged(bool paused);\n    constructor(address owner_,address factory_,address vault_,bytes32 expectedHash) {\n        if(owner_==address(0)||factory_.code.length==0||vault_.code.length==0||factory_.codehash!=expectedHash)revert InvalidDependency();\n        owner=owner_;factory=IPonsLaunch(factory_);factoryHash=expectedHash;vault=vault_;\n        feeEscrow=IPonsLaunch(factory_).feeEscrow();\n        if(feeEscrow.code.length==0)revert InvalidDependency();\n    }\n    function setPaused(bool value) external {if(msg.sender!=owner)revert Unauthorized();paused=value;emit PauseChanged(value);}\n    function launch(IPonsLaunch.TokenParams calldata params,uint256 config) external payable nonReentrant returns(address token,address account) {\n        if(paused)revert LaunchesPaused();\n        if(address(factory).codehash!=factoryHash||factory.feeEscrow()!=feeEscrow)revert InvalidDependency();\n        bytes32 salt=keccak256(abi.encode(msg.sender,params.salt));\n        WinPonsLaunchAccount created=new WinPonsLaunchAccount{salt:salt}(msg.sender,address(factory),feeEscrow,vault);\n        address curve;(token,curve)=created.launch{value:msg.value}(params,config);account=address(created);\n        collectorFor[token]=account;creatorFor[token]=msg.sender;createdAt[token]=block.timestamp;tokens.push(token);\n        emit TokenRegistered(token,account,msg.sender,curve);\n    }\n    function predictAccount(address creator,bytes32 salt) external view returns(address) {\n        bytes32 initHash=keccak256(abi.encodePacked(type(WinPonsLaunchAccount).creationCode,abi.encode(creator,address(factory),feeEscrow,vault)));\n        return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff),address(this),keccak256(abi.encode(creator,salt)),initHash)))));\n    }\n    function totalTokens() external view returns(uint256){return tokens.length;}\n    function tokenAt(uint256 index) external view returns(address){return tokens[index];}\n}\n"
    },
    "WinPonsGateway.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport {IPonsFactory} from \"./WinPonsCollectors.sol\";\nimport {IWinRegistry} from \"./WinJackpotVault.sol\";\n\ninterface IWinEntries {function recordTrade(address token,address wallet,uint256 executedETH) external;}\ninterface IWinCollector {function collect() external returns(uint256);}\ninterface IPonsTrade {\n    function buy(uint256 quoteIn,uint256 minTokensOut,address recipient) external payable returns(uint256);\n    function sell(uint256 tokensIn,uint256 minQuoteOut,address recipient) external returns(uint256);\n}\ninterface IPonsPools {\n    function poolManager()external view returns(address);\n    function memeHook()external view returns(address);\n}\n// ABI-compatible subset of Uniswap V4 PoolManager. Native ETH sorts before token.\ninterface IWinPoolManager {\n    struct Key {address currency0;address currency1;uint24 fee;int24 tickSpacing;address hooks;}\n    struct Swap {bool zeroForOne;int256 amountSpecified;uint160 sqrtPriceLimitX96;}\n    function unlock(bytes calldata data)external returns(bytes memory);\n    function swap(Key calldata key,Swap calldata params,bytes calldata hookData)external returns(int256);\n    function sync(address currency)external;\n    function settle()external payable returns(uint256);\n    function take(address currency,address to,uint256 amount)external;\n}\n\n/** Unreviewed native-ETH curve and graduated V4 trading candidate. */\ncontract WinPonsGateway is ReentrancyGuard {\n    using SafeERC20 for IERC20;\n    IPonsFactory public immutable factory;\n    IWinRegistry public immutable registry;\n    IWinEntries public immutable vault;\n    bytes32 public immutable factoryHash;\n    IWinPoolManager public immutable poolManager;\n    address public immutable hook;\n    bytes32 public immutable poolManagerHash;\n    bytes32 public immutable hookHash;\n    address private activeCurve;\n    bytes32 private pendingUnlock;\n    bool private poolTradeActive;\n    event TradeRecorded(address indexed token,address indexed trader,bool buy,uint256 input,uint256 output);\n    event CollectionDeferred(address indexed token,address indexed collector);\n    error InvalidTrade();error TransferFailed();error Unauthorized();\n    constructor(address factory_,address registry_,address vault_,bytes32 expectedHash) {\n        if(factory_.code.length==0||registry_.code.length==0||vault_.code.length==0||factory_.codehash!=expectedHash)revert InvalidTrade();\n        factory=IPonsFactory(factory_);registry=IWinRegistry(registry_);vault=IWinEntries(vault_);factoryHash=expectedHash;\n        address manager=IPonsPools(factory_).poolManager();hook=IPonsPools(factory_).memeHook();\n        if(manager.code.length==0||hook.code.length==0)revert InvalidTrade();\n        poolManager=IWinPoolManager(manager);poolManagerHash=manager.codehash;hookHash=hook.codehash;\n    }\n    receive() external payable {if(!(msg.sender==activeCurve&&activeCurve!=address(0))&&!(poolTradeActive&&msg.sender==address(poolManager)))revert Unauthorized();}\n    function _market(address token,uint256 deadline) private view returns(IPonsFactory.Launch memory record,address collector) {\n        if(block.timestamp>deadline||address(factory).codehash!=factoryHash)revert InvalidTrade();\n        collector=registry.collectorFor(token);record=factory.getLaunchedToken(token);\n        if(collector==address(0)||!record.exists||record.token!=token||record.deployer!=collector||\n            record.creatorFeeRecipient!=collector||record.pairToken!=address(0)||(record.phase!=0&&record.phase!=2)||\n            record.creatorTaxBps!=0||record.buybackEnabled||record.curve.code.length==0)revert InvalidTrade();\n        return(record,collector);\n    }\n    function buy(address token,uint256 minTokensOut,uint256 deadline) external payable nonReentrant returns(uint256 received) {\n        if(msg.value==0||minTokensOut==0)revert InvalidTrade();\n        (IPonsFactory.Launch memory market,address collector)=_market(token,deadline);\n        uint256 priorETH=address(this).balance-msg.value;uint256 priorTokens=IERC20(token).balanceOf(msg.sender);\n        if(market.phase==0){activeCurve=market.curve;IPonsTrade(market.curve).buy{value:msg.value}(msg.value,minTokensOut,msg.sender);activeCurve=address(0);}\n        else{_poolSwap(market,true,msg.value,msg.sender);}\n        received=IERC20(token).balanceOf(msg.sender)-priorTokens;\n        // WIN enforces an absolute minimum, including after tax and partial fills.\n        if(received<minTokensOut)revert InvalidTrade();\n        uint256 refund=address(this).balance-priorETH;\n        if(refund>=msg.value)revert InvalidTrade();\n        _finish(token,collector,msg.value-refund);\n        if(refund!=0){(bool ok,)=msg.sender.call{value:refund}(\"\");if(!ok)revert TransferFailed();}\n        emit TradeRecorded(token,msg.sender,true,msg.value-refund,received);\n    }\n    function sell(address token,uint256 tokensIn,uint256 minETHOut,uint256 deadline) external nonReentrant returns(uint256 received) {\n        if(tokensIn==0||minETHOut==0)revert InvalidTrade();\n        (IPonsFactory.Launch memory market,address collector)=_market(token,deadline);\n        IERC20 asset=IERC20(token);uint256 priorTokens=asset.balanceOf(address(this));\n        asset.safeTransferFrom(msg.sender,address(this),tokensIn);\n        if(asset.balanceOf(address(this))-priorTokens!=tokensIn)revert InvalidTrade();\n        uint256 priorETH=address(this).balance;\n        if(market.phase==0){\n            asset.forceApprove(market.curve,tokensIn);activeCurve=market.curve;\n            IPonsTrade(market.curve).sell(tokensIn,minETHOut,address(this));activeCurve=address(0);asset.forceApprove(market.curve,0);\n        }else{_poolSwap(market,false,tokensIn,address(this));}\n        received=address(this).balance-priorETH;\n        if(received<minETHOut||asset.balanceOf(address(this))!=priorTokens)revert InvalidTrade();\n        _finish(token,collector,received);\n        (bool ok,)=msg.sender.call{value:received}(\"\");if(!ok)revert TransferFailed();\n        emit TradeRecorded(token,msg.sender,false,tokensIn,received);\n    }\n    function _poolSwap(IPonsFactory.Launch memory market,bool buying,uint256 amount,address recipient)private{\n        if(amount>uint256(uint128(type(int128).max))||address(poolManager).codehash!=poolManagerHash||hook.codehash!=hookHash||\n            IPonsPools(address(factory)).memeHook()!=hook)revert InvalidTrade();\n        IWinPoolManager.Key memory key=IWinPoolManager.Key(address(0),market.token,market.poolFee,market.tickSpacing,hook);\n        bytes memory data=abi.encode(key,buying,amount,recipient);pendingUnlock=keccak256(data);poolTradeActive=true;\n        poolManager.unlock(data);\n        if(pendingUnlock!=bytes32(0))revert InvalidTrade();poolTradeActive=false;\n    }\n    function unlockCallback(bytes calldata data)external returns(bytes memory){\n        if(msg.sender!=address(poolManager)||!poolTradeActive||pendingUnlock==bytes32(0)||pendingUnlock!=keccak256(data))revert Unauthorized();\n        pendingUnlock=bytes32(0);\n        (IWinPoolManager.Key memory key,bool buying,uint256 amount,address recipient)=abi.decode(data,(IWinPoolManager.Key,bool,uint256,address));\n        // Canonical V4 bounds; user slippage is enforced on the actual received amount.\n        uint160 limit=buying?4295128740:1461446703485210103287273052203988822378723970341;\n        int256 packed=poolManager.swap(key,IWinPoolManager.Swap(buying,-int256(amount),limit),\"\");\n        int128 delta0=int128(packed>>128);int128 delta1=int128(packed);\n        int256 input=buying?int256(delta0):int256(delta1);int256 output=buying?int256(delta1):int256(delta0);\n        // V4 path is exact input. A partial fill reverts rather than keeping dust.\n        if(input!=-int256(amount)||output<=0)revert InvalidTrade();\n        address inputCurrency=buying?address(0):key.currency1;\n        poolManager.sync(inputCurrency);\n        if(buying){if(poolManager.settle{value:amount}()!=amount)revert InvalidTrade();}\n        else{IERC20(inputCurrency).safeTransfer(address(poolManager),amount);if(poolManager.settle()!=amount)revert InvalidTrade();}\n        poolManager.take(buying?key.currency1:address(0),recipient,uint256(output));\n        return \"\";\n    }\n    function _finish(address token,address collector,uint256 executedETH) private {\n        vault.recordTrade(token,msg.sender,executedETH);\n        // A Pons sweep outage cannot trap a seller. Entries remain on-chain and\n        // collection is retryable; failed collection never books invented fees.\n        try IWinCollector(collector).collect() returns(uint256){}catch{emit CollectionDeferred(token,collector);}\n    }\n}\n"
    },
    "WinActivity.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\n/** Bounded maintenance and logarithmic weighted selection. Each credit expires separately. */\nlibrary WinActivity {\n    struct Credit {uint64 expires;uint32 index;uint128 amount;}\n    struct Data {\n        address[] wallets;\n        mapping(address=>uint256) index;\n        uint256[] volumes;\n        uint256[] tree;\n        Credit[] credits;\n        uint256 head;\n        uint256 eligible;\n        uint256 totalWeight;\n    }\n    function weight(uint256 volume,uint256 unit,uint256 cap) internal pure returns(uint256 result) {\n        // Integer square-root tiers: 1, 4, 9, 16 units earn weights 1, 2, 3, 4.\n        for(uint256 i=1;i<=cap;i++){if(volume<unit*i*i)break;result=i;}\n    }\n    function prefix(Data storage d,uint256 i) internal view returns(uint256 total) {\n        while(i>0){total+=d.tree[i];i-=i&(~i+1);}\n    }\n    function _change(Data storage d,uint256 index,uint256 volume,uint256 unit,uint256 cap) private {\n        uint256 beforeWeight=weight(d.volumes[index-1],unit,cap);uint256 afterWeight=weight(volume,unit,cap);\n        d.volumes[index-1]=volume;\n        if(beforeWeight==afterWeight)return;\n        if(beforeWeight==0)d.eligible++;else if(afterWeight==0)d.eligible--;\n        if(afterWeight>beforeWeight)d.totalWeight+=afterWeight-beforeWeight;\n        else d.totalWeight-=beforeWeight-afterWeight;\n        for(uint256 i=index;i<d.tree.length;i+=i&(~i+1)){\n            if(afterWeight>beforeWeight)d.tree[i]+=afterWeight-beforeWeight;\n            else d.tree[i]-=beforeWeight-afterWeight;\n        }\n    }\n    function add(Data storage d,address wallet,uint128 amount,uint64 expires,uint256 unit,uint256 cap) internal {\n        uint256 index=d.index[wallet];\n        if(index==0){\n            index=d.wallets.length+1;require(index<=type(uint32).max,\"ACTIVITY_CAPACITY\");\n            d.index[wallet]=index;d.wallets.push(wallet);d.volumes.push(0);\n            if(d.tree.length==0)d.tree.push(0);\n            // Appending a Fenwick node must include existing children, including at powers of two.\n            d.tree.push(prefix(d,index-1)-prefix(d,index-(index&(~index+1))));\n        }\n        _change(d,index,d.volumes[index-1]+amount,unit,cap);\n        d.credits.push(Credit(expires,uint32(index),amount));\n    }\n    function due(Data storage d,uint256 timestamp) internal view returns(bool) {\n        return d.head<d.credits.length&&d.credits[d.head].expires<=timestamp;\n    }\n    function prune(Data storage d,uint256 limit,uint256 timestamp,uint256 unit,uint256 cap) internal returns(uint256 processed) {\n        while(processed<limit&&due(d,timestamp)){\n            Credit memory credit=d.credits[d.head];delete d.credits[d.head++];\n            _change(d,credit.index,d.volumes[credit.index-1]-credit.amount,unit,cap);processed++;\n        }\n    }\n    // A ticket is zero-based, the returned wallet index is one-based.\n    function select(Data storage d,uint256 ticket) internal view returns(uint256 index) {\n        require(ticket<d.totalWeight,\"TICKET_RANGE\");\n        uint256 step=1;while(step<d.tree.length)step<<=1;\n        for(step>>=1;step>0;step>>=1){\n            uint256 next=index+step;\n            if(next<d.tree.length&&d.tree[next]<=ticket){ticket-=d.tree[next];index=next;}\n        }\n        return index+1;\n    }\n}\n"
    },
    "WinJackpotVault.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport {WinActivity} from \"./WinActivity.sol\";\n\ninterface IWinRegistry {\n    function collectorFor(address token) external view returns(address);\n}\ninterface IWinRandomness {\n    function fee() external view returns(uint256);\n    function request(bytes32 commitment) external payable returns(uint256);\n}\n\n/** Three-winner integration candidate. Deployments start paused. Not audited. */\ncontract WinJackpotVault is ReentrancyGuard {\n    using WinActivity for WinActivity.Data;\n    uint256 public constant COIN_THRESHOLD = 0.5 ether;\n    uint256 public constant GLOBAL_THRESHOLD = 2 ether;\n    uint256 public constant MIN_ENTRANTS = 3;\n    uint256 public constant ENTRY_UNIT = 0.01 ether;\n    uint256 public constant MAX_WEIGHT = 4;\n    uint256 public constant ENTRY_LIFETIME = 24 hours;\n    address public immutable owner;\n    IWinRegistry public registry;\n    address public gateway;\n    IWinRandomness public randomness;\n    bool public configured;\n    bool public paused = true;\n    uint256 public roundCount;\n    uint256 public totalReceived;\n    uint256 public totalAvailable;\n    uint256 public totalReserved;\n    uint256 public totalCredits;\n    uint256 public totalPaid;\n    bool public emergencyMode;\n    address public recoveryDestination;\n    uint256 public totalEmergencyWithdrawn;\n    uint256 public totalEmergencyReturned;\n    enum Phase { Missing, Open, Frozen, Requested, Ready, Settled }\n    struct Pool {uint256 available;uint256 remainder;uint256 activeRound;}\n    struct Round {\n        address scope;uint256 award;uint256 requestId;uint256 word;\n        bytes32 commitment;Phase phase;WinActivity.Data activity;uint256 cutoff;\n        address[3] winners;uint256[3] prizes;bool[3] paid;\n    }\n    mapping(address=>Pool) public pools;\n    mapping(uint256=>Round) private rounds;\n    mapping(uint256=>mapping(address=>bool)) public entered;\n    mapping(uint256=>uint256) public roundForRequest;\n    event Configured(address registry,address gateway,address randomness);\n    event PauseChanged(bool paused);\n    event EntryAdded(uint256 indexed roundId,address indexed wallet);\n    event ActivityRecorded(uint256 indexed roundId,address indexed wallet,uint256 volume,uint256 expires);\n    event ActivityPruned(uint256 indexed roundId,uint256 processed);\n    event CreatorFeesReceived(address indexed token,uint256 amount,uint256 coinPart,uint256 globalPart);\n    event RoundFrozen(uint256 indexed roundId,address indexed scope,uint256 award,uint256 entrants,bytes32 commitment);\n    event RandomnessRequested(uint256 indexed roundId,uint256 indexed requestId);\n    event RandomnessStored(uint256 indexed roundId,uint256 word);\n    event WinnersSelected(uint256 indexed roundId,address[3] winners,uint256[3] amounts);\n    event PrizePaid(uint256 indexed roundId,uint256 indexed rank,address indexed winner,address destination,uint256 amount);\n    event RecoveryStarted();\n    event EmergencyWithdrawal(address indexed destination,uint256 amount);\n    event EmergencyFundsReturned(address indexed sender,uint256 amount);\n    event RecoveryFinished();\n    error Unauthorized();error InvalidConfiguration();error WrongPhase();error InvalidEntry();error TransferFailed();\n    error RecoveryActive();error RecoveryNotReady();error UnfundedLiabilities();\n    modifier onlyOwner(){if(msg.sender!=owner)revert Unauthorized();_;}\n    constructor(address owner_){if(owner_==address(0))revert InvalidConfiguration();owner=owner_;}\n    function configure(address registry_,address gateway_,address randomness_) external onlyOwner {\n        if(configured||registry_.code.length==0||gateway_.code.length==0||randomness_.code.length==0)revert InvalidConfiguration();\n        registry=IWinRegistry(registry_);gateway=gateway_;randomness=IWinRandomness(randomness_);configured=true;\n        emit Configured(registry_,gateway_,randomness_);\n    }\n    function setPaused(bool value) external onlyOwner {if(!configured)revert InvalidConfiguration();if(!value&&emergencyMode)revert RecoveryActive();paused=value;emit PauseChanged(value);}\n    // Custodial power, with no timelock: the owner can withdraw any/all unpaid\n    // prize backing. Existing liabilities and fixed winners remain recorded and owed.\n    function startRecovery() external onlyOwner nonReentrant {\n        if(!configured)revert InvalidConfiguration();\n        emergencyMode=true;paused=true;emit PauseChanged(true);emit RecoveryStarted();\n    }\n    function emergencyWithdraw(address destination,uint256 amount) external onlyOwner nonReentrant {\n        if(!configured||destination==address(0)||destination==address(this)||amount==0||amount>address(this).balance)revert InvalidConfiguration();\n        emergencyMode=true;paused=true;recoveryDestination=destination;totalEmergencyWithdrawn+=amount;\n        emit PauseChanged(true);emit RecoveryStarted();\n        (bool ok,)=destination.call{value:amount}(\"\");if(!ok)revert TransferFailed();\n        emit EmergencyWithdrawal(destination,amount);\n    }\n    function restoreEmergencyFunds() external payable nonReentrant {\n        if(!emergencyMode||msg.value==0)revert InvalidEntry();\n        totalEmergencyReturned+=msg.value;emit EmergencyFundsReturned(msg.sender,msg.value);\n    }\n    function finishRecovery() external onlyOwner nonReentrant {\n        if(!emergencyMode)revert RecoveryNotReady();\n        if(address(this).balance<liabilities())revert UnfundedLiabilities();\n        emergencyMode=false;emit RecoveryFinished(); // Entries stay paused until explicitly reopened.\n    }\n    function recoveryInfo() external view returns(bool active,address destination,uint256 shortfall,uint256 withdrawn,uint256 returnedFunds){\n        uint256 owed=liabilities();return(emergencyMode,recoveryDestination,owed>address(this).balance?owed-address(this).balance:0,totalEmergencyWithdrawn,totalEmergencyReturned);\n    }\n    function _open(address scope) private returns(uint256 id){\n        Pool storage p=pools[scope];id=p.activeRound;\n        if(id==0){id=++roundCount;p.activeRound=id;Round storage r=rounds[id];r.scope=scope;r.phase=Phase.Open;\n            r.commitment=keccak256(abi.encode(block.chainid,address(this),scope,id));}\n    }\n    function recordTrade(address token,address wallet,uint256 executedETH) external {\n        if(msg.sender!=gateway)revert Unauthorized();\n        if(paused||wallet==address(0)||token==address(0)||registry.collectorFor(token)==address(0)||executedETH==0||executedETH>type(uint128).max)revert InvalidEntry();\n        _enter(token,wallet,uint128(executedETH));_enter(address(0),wallet,uint128(executedETH));\n        _freeze(token);_freeze(address(0));\n    }\n    function _enter(address scope,address wallet,uint128 volume) private {\n        uint256 id=_open(scope);Round storage r=rounds[id];\n        // Bounded work on the trading path; the keeper drains any older backlog.\n        r.activity.prune(1,block.timestamp,ENTRY_UNIT,MAX_WEIGHT);\n        if(!entered[id][wallet]){entered[id][wallet]=true;emit EntryAdded(id,wallet);}\n        uint64 expires=uint64(block.timestamp+ENTRY_LIFETIME);\n        r.activity.add(wallet,volume,expires,ENTRY_UNIT,MAX_WEIGHT);\n        r.commitment=keccak256(abi.encode(r.commitment,wallet,volume,expires));\n        emit ActivityRecorded(id,wallet,volume,expires);\n    }\n    function prune(address scope,uint256 limit) external {\n        if(limit==0||limit>16)revert InvalidEntry();\n        uint256 id=pools[scope].activeRound;if(id==0)return;\n        uint256 processed=rounds[id].activity.prune(limit,block.timestamp,ENTRY_UNIT,MAX_WEIGHT);\n        emit ActivityPruned(id,processed);_freeze(scope);\n    }\n    function needsPruning(uint256 id) public view returns(bool){\n        return rounds[id].phase==Phase.Open&&rounds[id].activity.due(block.timestamp);\n    }\n    function readyToFreeze(uint256 id) external view returns(bool){\n        Round storage r=rounds[id];uint256 threshold=r.scope==address(0)?GLOBAL_THRESHOLD:COIN_THRESHOLD;\n        return !emergencyMode&&r.phase==Phase.Open&&pools[r.scope].activeRound==id&&pools[r.scope].available>=threshold&&r.activity.eligible>=MIN_ENTRANTS&&!needsPruning(id);\n    }\n    function depositCreatorFees(address token) external payable nonReentrant {\n        if(!configured||token==address(0)||registry.collectorFor(token)!=msg.sender||msg.value==0)revert Unauthorized();\n        Pool storage coin=pools[token];uint256 scaled=msg.value*8000+coin.remainder;\n        uint256 coinPart=scaled/10000;coin.remainder=scaled%10000;\n        uint256 globalPart=msg.value-coinPart;coin.available+=coinPart;pools[address(0)].available+=globalPart;\n        totalReceived+=msg.value;totalAvailable+=msg.value;\n        emit CreatorFeesReceived(token,msg.value,coinPart,globalPart);\n        _freeze(token);_freeze(address(0));\n    }\n    function _freeze(address scope) private {\n        if(emergencyMode)return;\n        Pool storage p=pools[scope];uint256 id=p.activeRound;if(id==0)return;\n        Round storage r=rounds[id];uint256 threshold=scope==address(0)?GLOBAL_THRESHOLD:COIN_THRESHOLD;\n        if(p.available<threshold||r.activity.eligible<MIN_ENTRANTS||needsPruning(id))return;\n        r.cutoff=block.timestamp;\n        r.award=p.available;r.phase=Phase.Frozen;\n        r.commitment=keccak256(abi.encode(r.commitment,r.award,r.cutoff,r.activity.totalWeight,ENTRY_UNIT,MAX_WEIGHT,uint256(5000),uint256(3000),uint256(2000)));\n        // Detach the locked award/entries immediately. Later fees and trades fund\n        // a new round even while this one awaits randomness or unpaid prizes.\n        totalAvailable-=r.award;totalReserved+=r.award;p.available=0;p.activeRound=0;\n        emit RoundFrozen(id,scope,r.award,r.activity.eligible,r.commitment);\n    }\n    // Oracle costs are paid separately by caller/keeper, never deducted from prizes.\n    function requestRound(uint256 id) external payable nonReentrant {\n        if(emergencyMode)revert RecoveryActive();\n        Round storage r=rounds[id];if(r.phase!=Phase.Frozen)revert WrongPhase();\n        if(msg.value!=randomness.fee())revert InvalidConfiguration();\n        r.phase=Phase.Requested;uint256 requestId=randomness.request{value:msg.value}(r.commitment);\n        if(requestId==0||roundForRequest[requestId]!=0)revert InvalidConfiguration();\n        r.requestId=requestId;roundForRequest[requestId]=id;emit RandomnessRequested(id,requestId);\n    }\n    // Store only. Duplicate, late and unknown authenticated callbacks do not reroll.\n    function receiveRandomness(uint256 requestId,uint256 word) external {\n        if(msg.sender!=address(randomness))revert Unauthorized();\n        uint256 id=roundForRequest[requestId];Round storage r=rounds[id];\n        if(id==0||r.phase!=Phase.Requested)return;\n        r.word=word;r.phase=Phase.Ready;emit RandomnessStored(id,word);\n    }\n    function settleRound(uint256 id) external {\n        if(emergencyMode)revert RecoveryActive();\n        Round storage r=rounds[id];if(r.phase!=Phase.Ready)revert WrongPhase();\n        uint256[3] memory selected;\n        uint256 remaining=r.activity.totalWeight;\n        for(uint256 rank;rank<3;rank++){\n            uint256 n=remaining;uint256 limit=type(uint256).max-(type(uint256).max%n);\n            uint256 counter;uint256 sample;\n            do{sample=uint256(keccak256(abi.encode(r.commitment,r.word,rank,counter++)));}while(sample>=limit);\n            uint256 ticket=sample%n;\n            // Skip prior winners' full ticket intervals without mutating the frozen tree.\n            uint256 a=selected[0];uint256 b=selected[1];if(rank==2&&b<a){(a,b)=(b,a);}\n            if(rank>=1&&ticket>=r.activity.prefix(a-1))ticket+=WinActivity.weight(r.activity.volumes[a-1],ENTRY_UNIT,MAX_WEIGHT);\n            if(rank==2&&ticket>=r.activity.prefix(b-1))ticket+=WinActivity.weight(r.activity.volumes[b-1],ENTRY_UNIT,MAX_WEIGHT);\n            uint256 index=r.activity.select(ticket);\n            selected[rank]=index;r.winners[rank]=r.activity.wallets[index-1];\n            remaining-=WinActivity.weight(r.activity.volumes[index-1],ENTRY_UNIT,MAX_WEIGHT);\n        }\n        r.prizes[0]=r.award*5000/10000;r.prizes[1]=r.award*3000/10000;r.prizes[2]=r.award-r.prizes[0]-r.prizes[1];\n        r.phase=Phase.Settled;totalReserved-=r.award;totalCredits+=r.award;\n        emit WinnersSelected(id,r.winners,r.prizes);\n    }\n    function payWinner(uint256 id,uint256 rank) external nonReentrant {if(rank>=3)revert WrongPhase();_pay(id,rank,rounds[id].winners[rank]);}\n    function claimTo(uint256 id,uint256 rank,address payable destination) external nonReentrant {\n        if(rank>=3||msg.sender!=rounds[id].winners[rank]||destination==address(0))revert Unauthorized();_pay(id,rank,destination);\n    }\n    function _pay(uint256 id,uint256 rank,address destination) private {\n        if(emergencyMode)revert RecoveryActive();\n        Round storage r=rounds[id];if(rank>=3||r.phase!=Phase.Settled||r.paid[rank])revert WrongPhase();\n        uint256 amount=r.prizes[rank];r.paid[rank]=true;totalCredits-=amount;totalPaid+=amount;\n        (bool ok,)=destination.call{value:amount}(\"\");if(!ok)revert TransferFailed();\n        emit PrizePaid(id,rank,r.winners[rank],destination,amount);\n    }\n    function roundInfo(uint256 id) external view returns(address,uint256,uint256,uint256,bytes32,Phase){\n        Round storage r=rounds[id];return(r.scope,r.award,r.activity.eligible,r.requestId,r.commitment,r.phase);\n    }\n    function winnerInfo(uint256 id) external view returns(address[3] memory,uint256[3] memory,bool[3] memory){\n        Round storage r=rounds[id];return(r.winners,r.prizes,r.paid);\n    }\n    function entrantAt(uint256 id,uint256 index) external view returns(address){return rounds[id].activity.wallets[index];}\n    function entryInfo(uint256 id,address wallet) external view returns(uint256 volume,uint256 weight){\n        WinActivity.Data storage d=rounds[id].activity;uint256 index=d.index[wallet];if(index==0)return(0,0);\n        volume=d.volumes[index-1];weight=WinActivity.weight(volume,ENTRY_UNIT,MAX_WEIGHT);\n    }\n    function roundActivity(uint256 id) external view returns(uint256 wallets,uint256 totalWeight,uint256 cutoff,bool pruning){\n        Round storage r=rounds[id];return(r.activity.wallets.length,r.activity.totalWeight,r.cutoff,needsPruning(id));\n    }\n    function liabilities() public view returns(uint256){return totalAvailable+totalReserved+totalCredits;}\n}\n"
    },
    "WinQuiverAdapter.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\ninterface IQuiverCoordinator {\n    function getFee(address provider) external view returns(uint128);\n    function requestWithCallback(address provider,bytes32 userRandomNumber) external payable returns(uint64);\n}\ninterface IWinRandomConsumer {function receiveRandomness(uint256 requestId,uint256 word) external;}\n\n/** Candidate adapter. Quiver provider withholding/liveness must be reviewed before activation. */\ncontract WinQuiverAdapter {\n    IQuiverCoordinator public immutable coordinator;\n    address public immutable provider;\n    address public immutable consumer;\n    bytes32 public immutable coordinatorHash;\n    uint256 public nonce;\n    mapping(uint64=>bool) public requested;\n    mapping(uint64=>bool) public delivered;\n    error Unauthorized();error InvalidConfiguration();\n    constructor(address coordinator_,address provider_,address consumer_,bytes32 expectedHash){\n        if(coordinator_.code.length==0||consumer_.code.length==0||provider_==address(0)||coordinator_.codehash!=expectedHash)revert InvalidConfiguration();\n        coordinator=IQuiverCoordinator(coordinator_);provider=provider_;consumer=consumer_;coordinatorHash=expectedHash;\n    }\n    function fee() external view returns(uint256){return coordinator.getFee(provider);}\n    function request(bytes32 commitment) external payable returns(uint256){\n        if(msg.sender!=consumer)revert Unauthorized();\n        if(address(coordinator).codehash!=coordinatorHash||msg.value!=coordinator.getFee(provider))revert InvalidConfiguration();\n        bytes32 contribution=keccak256(abi.encode(block.chainid,address(this),consumer,++nonce,commitment));\n        uint64 seq=coordinator.requestWithCallback{value:msg.value}(provider,contribution);\n        if(seq==0||requested[seq])revert InvalidConfiguration();requested[seq]=true;return seq;\n    }\n    function quiverCallback(uint64 seq,address provider_,bytes32 word) external {\n        if(msg.sender!=address(coordinator)||provider_!=provider)revert Unauthorized();\n        if(!requested[seq]||delivered[seq])return;\n        delivered[seq]=true;IWinRandomConsumer(consumer).receiveRandomness(seq,uint256(word));\n    }\n}\n"
    },
    "WinPonsSnapshotVault.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport {IWinRegistry,IWinRandomness} from \"./WinJackpotVault.sol\";\n\n/** PONS-only candidate. The immutable indexer attests complete trade snapshots.\n * Merkle-sum proofs verify selection, not the truth/completeness of the indexer's inputs.\n * Starts closed. No deployed gateway vault is upgraded by this contract. */\ncontract WinPonsSnapshotVault is ReentrancyGuard {\n    uint256 public constant COIN_THRESHOLD=0.5 ether;\n    uint256 public constant GLOBAL_THRESHOLD=2 ether;\n    uint256 public constant ENTRY_UNIT=0.01 ether;\n    uint256 public constant MAX_WEIGHT=4;\n    uint256 public constant ENTRY_LIFETIME=24 hours;\n    uint256 public constant MIN_ENTRANTS=3;\n    uint256 public constant CONFIRMATIONS=32;\n    address public immutable owner;\n    address public immutable indexer;\n    IWinRegistry public registry;\n    IWinRandomness public randomness;\n    bool public configured;\n    bool public paused=true;\n    bool public emergencyMode;\n    uint256 public roundCount;\n    uint256 public totalReceived;\n    uint256 public totalAvailable;\n    uint256 public totalReserved;\n    uint256 public totalCredits;\n    uint256 public totalPaid;\n    uint256 public totalEmergencyWithdrawn;\n    uint256 public totalEmergencyReturned;\n    address public recoveryDestination;\n    enum Phase {Missing,Open,Frozen,Requested,Ready,Settled}\n    struct Pool {uint256 available;uint256 remainder;uint256 activeRound;}\n    struct Round {\n        address scope; uint256 award; uint256 requestId; uint256 word;\n        bytes32 commitment; Phase phase; uint256 entrants; uint256 totalWeight;\n        bytes32 root; bytes32 manifestHash; uint256 openedBlock;\n        uint256 afterBlock; uint256 cutoffBlock; bytes32 cutoffHash;\n        address[3] winners; uint256[3] prizes; bool[3] paid;\n    }\n    struct EntryProof {uint256 index;address wallet;uint256 weight;bytes32[] hashes;uint256[] sums;}\n    mapping(address=>Pool) public pools;\n    mapping(address=>uint256) public lastCutoff;\n    mapping(uint256=>Round) private rounds;\n    mapping(uint256=>uint256) public roundForRequest;\n    event PauseChanged(bool paused);\n    event CreatorFeesReceived(address indexed token,uint256 amount,uint256 coinPart,uint256 globalPart);\n    event RoundOpened(uint256 indexed roundId,address indexed scope,uint256 award,uint256 afterBlock);\n    event SnapshotCommitted(uint256 indexed roundId,bytes32 root,bytes32 manifestHash,uint256 totalWeight,uint256 cutoffBlock,bytes32 cutoffHash);\n    event RoundFrozen(uint256 indexed roundId,address indexed scope,uint256 award,uint256 entrants,bytes32 commitment);\n    event RandomnessRequested(uint256 indexed roundId,uint256 indexed requestId);\n    event RandomnessStored(uint256 indexed roundId,uint256 word);\n    event WinnersSelected(uint256 indexed roundId,address[3] winners,uint256[3] amounts);\n    event PrizePaid(uint256 indexed roundId,uint256 indexed rank,address indexed winner,address destination,uint256 amount);\n    event RecoveryStarted();\n    event EmergencyWithdrawal(address indexed destination,uint256 amount);\n    event EmergencyFundsReturned(address indexed sender,uint256 amount);\n    event RecoveryFinished();\n    error Unauthorized(); error InvalidConfiguration(); error WrongPhase(); error InvalidEntry();\n    error TransferFailed(); error RecoveryActive(); error UnfundedLiabilities(); error InvalidProof();\n    modifier onlyOwner(){if(msg.sender!=owner)revert Unauthorized();_;}\n    constructor(address owner_,address indexer_){\n        if(owner_==address(0)||indexer_==address(0))revert InvalidConfiguration();owner=owner_;indexer=indexer_;\n    }\n    function configure(address registry_,address randomness_) external onlyOwner {\n        if(configured||registry_.code.length==0||randomness_.code.length==0)revert InvalidConfiguration();\n        registry=IWinRegistry(registry_);randomness=IWinRandomness(randomness_);configured=true;\n    }\n    function setPaused(bool value) external onlyOwner {\n        if(!configured)revert InvalidConfiguration();if(!value&&emergencyMode)revert RecoveryActive();paused=value;emit PauseChanged(value);\n    }\n    function depositCreatorFees(address token) external payable nonReentrant {\n        if(!configured||token==address(0)||registry.collectorFor(token)!=msg.sender||msg.value==0)revert Unauthorized();\n        Pool storage coin=pools[token];uint256 scaled=msg.value*8000+coin.remainder;\n        uint256 coinPart=scaled/10000;coin.remainder=scaled%10000;uint256 globalPart=msg.value-coinPart;\n        coin.available+=coinPart;pools[address(0)].available+=globalPart;totalReceived+=msg.value;totalAvailable+=msg.value;\n        emit CreatorFeesReceived(token,msg.value,coinPart,globalPart);_open(token);_open(address(0));\n    }\n    function openRound(address scope) external {if(scope!=address(0)&&registry.collectorFor(scope)==address(0))revert InvalidEntry();_open(scope);}\n    function _open(address scope) private {\n        Pool storage p=pools[scope];uint256 threshold=scope==address(0)?GLOBAL_THRESHOLD:COIN_THRESHOLD;\n        if(paused||emergencyMode||p.activeRound!=0||p.available<threshold)return;\n        uint256 id=++roundCount;p.activeRound=id;Round storage r=rounds[id];r.scope=scope;r.phase=Phase.Open;\n        r.award=p.available;r.openedBlock=block.number;r.afterBlock=lastCutoff[scope];\n        p.available=0;totalAvailable-=r.award;totalReserved+=r.award;\n        emit RoundOpened(id,scope,r.award,r.afterBlock);\n    }\n    // Only one uncommitted snapshot per scope. Its cutoff advances monotonically.\n    // Funds arriving after RoundOpened are already assigned to the next jackpot.\n    function commitSnapshot(uint256 id,bytes32 root,bytes32 manifestHash,uint256 entrants,uint256 totalWeight,uint256 cutoffBlock,bytes32 cutoffHash) external {\n        if(msg.sender!=indexer)revert Unauthorized();if(paused||emergencyMode)revert RecoveryActive();\n        Round storage r=rounds[id];\n        if(r.phase!=Phase.Open||pools[r.scope].activeRound!=id)revert WrongPhase();\n        if(root==bytes32(0)||manifestHash==bytes32(0)||entrants<3||entrants>1000000||totalWeight<entrants||totalWeight>entrants*4||\n            cutoffBlock<r.openedBlock||cutoffBlock<=r.afterBlock||block.number<=cutoffBlock||block.number-cutoffBlock<CONFIRMATIONS||\n            block.number-cutoffBlock>256||cutoffHash==bytes32(0)||blockhash(cutoffBlock)!=cutoffHash)revert InvalidEntry();\n        r.root=root;r.manifestHash=manifestHash;r.entrants=entrants;r.totalWeight=totalWeight;r.cutoffBlock=cutoffBlock;r.cutoffHash=cutoffHash;\n        r.commitment=keccak256(abi.encode(block.chainid,address(this),id,r.scope,r.award,root,manifestHash,totalWeight,r.afterBlock,cutoffBlock,cutoffHash));\n        r.phase=Phase.Frozen;lastCutoff[r.scope]=cutoffBlock;pools[r.scope].activeRound=0;\n        emit SnapshotCommitted(id,root,manifestHash,totalWeight,cutoffBlock,cutoffHash);\n        emit RoundFrozen(id,r.scope,r.award,entrants,r.commitment);\n        // The next pool can start while this draw awaits randomness/payouts.\n        _open(r.scope);\n    }\n    function requestRound(uint256 id) external payable nonReentrant {\n        if(paused||emergencyMode)revert RecoveryActive();Round storage r=rounds[id];if(r.phase!=Phase.Frozen)revert WrongPhase();\n        if(msg.value!=randomness.fee())revert InvalidConfiguration();r.phase=Phase.Requested;\n        uint256 requestId=randomness.request{value:msg.value}(r.commitment);\n        if(requestId==0||roundForRequest[requestId]!=0)revert InvalidConfiguration();r.requestId=requestId;roundForRequest[requestId]=id;\n        emit RandomnessRequested(id,requestId);\n    }\n    function receiveRandomness(uint256 requestId,uint256 word) external {\n        if(msg.sender!=address(randomness))revert Unauthorized();uint256 id=roundForRequest[requestId];Round storage r=rounds[id];\n        if(id==0||r.phase!=Phase.Requested)return;r.word=word;r.phase=Phase.Ready;emit RandomnessStored(id,word);\n    }\n    function _proof(Round storage r,EntryProof calldata p) private view returns(uint256 start){\n        if(p.index>=r.entrants||p.wallet==address(0)||p.weight==0||p.weight>4||p.hashes.length!=p.sums.length||p.hashes.length>20)revert InvalidProof();\n        bytes32 hash=keccak256(abi.encode(uint8(0),p.index,p.wallet,p.weight));uint256 sum=p.weight;uint256 index=p.index;\n        for(uint256 i;i<p.hashes.length;i++){\n            if((index&1)==1){start+=p.sums[i];hash=keccak256(abi.encode(uint8(1),p.hashes[i],p.sums[i],hash,sum));}\n            else hash=keccak256(abi.encode(uint8(1),hash,sum,p.hashes[i],p.sums[i]));\n            sum+=p.sums[i];index>>=1;\n        }\n        if(index!=0||hash!=r.root||sum!=r.totalWeight)revert InvalidProof();\n    }\n    function settleRound(uint256 id,EntryProof[3] calldata entries) external {\n        if(paused||emergencyMode)revert RecoveryActive();Round storage r=rounds[id];if(r.phase!=Phase.Ready)revert WrongPhase();\n        uint256[3] memory starts;uint256 remaining=r.totalWeight;\n        for(uint256 rank;rank<3;rank++){\n            starts[rank]=_proof(r,entries[rank]);uint256 limit=type(uint256).max-(type(uint256).max%remaining);uint256 sample;uint256 counter;\n            do{sample=uint256(keccak256(abi.encode(r.commitment,r.word,rank,counter++)));}while(sample>=limit);\n            uint256 ticket=sample%remaining;\n            uint256 a;uint256 b=1;if(rank==2&&starts[b]<starts[a]){(a,b)=(b,a);}\n            if(rank>=1&&ticket>=starts[a])ticket+=entries[a].weight;\n            if(rank==2&&ticket>=starts[b])ticket+=entries[b].weight;\n            if(ticket<starts[rank]||ticket>=starts[rank]+entries[rank].weight)revert InvalidProof();\n            for(uint256 previous;previous<rank;previous++)if(entries[previous].wallet==entries[rank].wallet)revert InvalidProof();\n            r.winners[rank]=entries[rank].wallet;remaining-=entries[rank].weight;\n        }\n        r.prizes[0]=r.award/2;r.prizes[1]=r.award*3/10;r.prizes[2]=r.award-r.prizes[0]-r.prizes[1];\n        r.phase=Phase.Settled;totalReserved-=r.award;totalCredits+=r.award;emit WinnersSelected(id,r.winners,r.prizes);\n    }\n    function payWinner(uint256 id,uint256 rank) external nonReentrant {if(rank>=3)revert WrongPhase();_pay(id,rank,rounds[id].winners[rank]);}\n    function claimTo(uint256 id,uint256 rank,address payable destination) external nonReentrant {\n        if(rank>=3||msg.sender!=rounds[id].winners[rank]||destination==address(0))revert Unauthorized();_pay(id,rank,destination);\n    }\n    function _pay(uint256 id,uint256 rank,address destination) private {\n        if(paused||emergencyMode)revert RecoveryActive();Round storage r=rounds[id];if(r.phase!=Phase.Settled||r.paid[rank])revert WrongPhase();\n        uint256 amount=r.prizes[rank];r.paid[rank]=true;totalCredits-=amount;totalPaid+=amount;\n        (bool ok,)=destination.call{value:amount}(\"\");if(!ok)revert TransferFailed();emit PrizePaid(id,rank,r.winners[rank],destination,amount);\n    }\n    function startRecovery() external onlyOwner nonReentrant {if(!configured)revert InvalidConfiguration();emergencyMode=true;paused=true;emit PauseChanged(true);emit RecoveryStarted();}\n    // Explicit custodial owner power retained at the user's request. Liabilities survive withdrawal.\n    function emergencyWithdraw(address destination,uint256 amount) external onlyOwner nonReentrant {\n        if(!configured||destination==address(0)||destination==address(this)||amount==0||amount>address(this).balance)revert InvalidConfiguration();\n        emergencyMode=true;paused=true;recoveryDestination=destination;totalEmergencyWithdrawn+=amount;emit PauseChanged(true);emit RecoveryStarted();\n        (bool ok,)=destination.call{value:amount}(\"\");if(!ok)revert TransferFailed();emit EmergencyWithdrawal(destination,amount);\n    }\n    function restoreEmergencyFunds() external payable nonReentrant {if(!emergencyMode||msg.value==0)revert InvalidEntry();totalEmergencyReturned+=msg.value;emit EmergencyFundsReturned(msg.sender,msg.value);}\n    function finishRecovery() external onlyOwner nonReentrant {if(!emergencyMode)revert WrongPhase();if(address(this).balance<liabilities())revert UnfundedLiabilities();emergencyMode=false;emit RecoveryFinished();}\n    function recoveryInfo() external view returns(bool,address,uint256,uint256,uint256){uint256 owed=liabilities();return(emergencyMode,recoveryDestination,owed>address(this).balance?owed-address(this).balance:0,totalEmergencyWithdrawn,totalEmergencyReturned);}\n    function liabilities() public view returns(uint256){return totalAvailable+totalReserved+totalCredits;}\n    function roundInfo(uint256 id) external view returns(address,uint256,uint256,uint256,bytes32,Phase){Round storage r=rounds[id];return(r.scope,r.award,r.entrants,r.requestId,r.commitment,r.phase);}\n    function snapshotInfo(uint256 id) external view returns(bytes32,bytes32,uint256,uint256,uint256,bytes32,uint256){Round storage r=rounds[id];return(r.root,r.manifestHash,r.totalWeight,r.afterBlock,r.cutoffBlock,r.cutoffHash,r.openedBlock);}\n    function randomWord(uint256 id) external view returns(uint256){return rounds[id].word;}\n    function winnerInfo(uint256 id) external view returns(address[3] memory,uint256[3] memory,bool[3] memory){Round storage r=rounds[id];return(r.winners,r.prizes,r.paid);}\n}\n"
    },
    "WinPonsTaxedLauncher.sol": {
      "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.30;\n\nimport {ReentrancyGuard} from \"@openzeppelin/contracts/utils/ReentrancyGuard.sol\";\nimport {IPonsFactory, IPonsEscrow, IWinFeeRouter} from \"./WinPonsCollectors.sol\";\nimport {IPonsLaunch, IPonsCurveSweep, IPonsPoolSweep} from \"./WinPonsLauncher.sol\";\n\ninterface ITaxedCurvePolicy {\n    function feeBps() external view returns(uint256);\n    function protocolFeeShareBps() external view returns(uint16);\n}\ninterface ITaxedHookPolicy {\n    function currentFeePolicy() external view returns(address,uint16,uint16,uint16,uint16);\n}\n\n/** Per-coin Pons deployer and fee recipient. Only the fixed vault can receive fees. */\ncontract WinPonsTaxedLaunchAccount is ReentrancyGuard {\n    uint16 public constant CREATOR_TAX_BPS=200;\n    address public immutable registry;\n    address public immutable creator;\n    IPonsLaunch public immutable factory;\n    IPonsEscrow public immutable escrow;\n    IWinFeeRouter public immutable vault;\n    address public token;\n    address public curve;\n    uint256 public totalForwarded;\n    error Unauthorized();error InvalidLaunch();error ReceiptMismatch();\n    event FeesForwarded(address indexed token,uint256 amount);\n    event PoolSweepDeferred(address indexed token,bytes32 indexed poolId);\n\n    constructor(address creator_,address factory_,address escrow_,address vault_) {\n        registry=msg.sender;creator=creator_;factory=IPonsLaunch(factory_);\n        escrow=IPonsEscrow(escrow_);vault=IWinFeeRouter(vault_);\n    }\n    receive() external payable {if(msg.sender!=address(escrow))revert Unauthorized();}\n    function launch(IPonsLaunch.TokenParams calldata input,uint256 config) external payable returns(address,address) {\n        if(msg.sender!=registry||token!=address(0))revert Unauthorized();\n        if(config!=0||input.creatorTaxBps!=CREATOR_TAX_BPS||input.buybackEnabled||input.expectedEconomics==bytes32(0))revert InvalidLaunch();\n        (,,,uint16 hookFee,)=ITaxedHookPolicy(factory.memeHook()).currentFeePolicy();\n        if(hookFee!=100)revert InvalidLaunch();\n        IPonsLaunch.TokenParams memory params=input;\n        params.creatorFeeRecipient=address(this);\n        (token,curve)=factory.launchToken{value:msg.value}(params,config,address(0));\n        IPonsFactory.Launch memory record=factory.getLaunchedToken(token);\n        if(token.code.length==0||curve.code.length==0||!record.exists||record.token!=token||\n            record.curve!=curve||record.deployer!=address(this)||record.creatorFeeRecipient!=address(this)||\n            record.pairToken!=address(0)||record.creatorTaxBps!=CREATOR_TAX_BPS||record.buybackEnabled||record.poolFee!=0)revert InvalidLaunch();\n        // Base fee 1%, PONS share 30% of that base, plus 2% entirely to WIN.\n        // Every collected creator fee reaches the existing 80/20 jackpot ledger.\n        if(ITaxedCurvePolicy(curve).feeBps()!=100||ITaxedCurvePolicy(curve).protocolFeeShareBps()!=3000)revert InvalidLaunch();\n        return(token,curve);\n    }\n    // Pons permits the account to sweep quote-only pool fees. Memecoin conversion\n    // still needs its operator; failure leaves those fees in Pons for later retry.\n    function collect() external nonReentrant returns(uint256 amount) {\n        if(token==address(0))revert InvalidLaunch();\n        IPonsFactory.Launch memory record=factory.getLaunchedToken(token);\n        if(record.phase==0)IPonsCurveSweep(curve).sweepFees(0);\n        else if(record.phase==2){\n            address hook=factory.memeHook();\n            bytes32 poolId=keccak256(abi.encode(address(0),token,record.poolFee,record.tickSpacing,hook));\n            // Never execute conversions with a zero minimum, even if Pons were\n            // to designate this account as its trusted operator in the future.\n            if(IPonsPoolSweep(hook).feeSweepOperator()==address(this)){emit PoolSweepDeferred(token,poolId);}\n            else{try IPonsPoolSweep(hook).sweepPoolFees(poolId,0,0){}catch{emit PoolSweepDeferred(token,poolId);}}\n        }\n        if(escrow.balanceOf(address(this))==0)return 0;\n        uint256 beforeBalance=address(this).balance;\n        amount=escrow.claim();\n        if(amount==0||address(this).balance-beforeBalance!=amount)revert ReceiptMismatch();\n        totalForwarded+=amount;vault.depositCreatorFees{value:amount}(token);\n        emit FeesForwarded(token,amount);\n    }\n}\n\n/** Unreviewed launch candidate. Defaults closed; cannot bypass Pons economics. */\ncontract WinPonsTaxedLauncher is ReentrancyGuard {\n    uint16 public constant CREATOR_TAX_BPS=200;\n    address public immutable owner;\n    IPonsLaunch public immutable factory;\n    address public immutable feeEscrow;\n    address public immutable vault;\n    bytes32 public immutable factoryHash;\n    bool public paused=true;\n    mapping(address=>address) public collectorFor;\n    mapping(address=>address) public creatorFor;\n    mapping(address=>uint256) public createdAt;\n    address[] private tokens;\n    error Unauthorized();error InvalidDependency();error LaunchesPaused();\n    event TokenRegistered(address indexed token,address indexed collector,address indexed creator,address curve);\n    event PauseChanged(bool paused);\n    constructor(address owner_,address factory_,address vault_,bytes32 expectedHash) {\n        if(owner_==address(0)||factory_.code.length==0||vault_.code.length==0||factory_.codehash!=expectedHash)revert InvalidDependency();\n        owner=owner_;factory=IPonsLaunch(factory_);factoryHash=expectedHash;vault=vault_;\n        feeEscrow=IPonsLaunch(factory_).feeEscrow();\n        if(feeEscrow.code.length==0)revert InvalidDependency();\n    }\n    function setPaused(bool value) external {if(msg.sender!=owner)revert Unauthorized();paused=value;emit PauseChanged(value);}\n    function launch(IPonsLaunch.TokenParams calldata params,uint256 config) external payable nonReentrant returns(address token,address account) {\n        if(paused)revert LaunchesPaused();\n        if(address(factory).codehash!=factoryHash||factory.feeEscrow()!=feeEscrow)revert InvalidDependency();\n        bytes32 salt=keccak256(abi.encode(msg.sender,params.salt));\n        WinPonsTaxedLaunchAccount created=new WinPonsTaxedLaunchAccount{salt:salt}(msg.sender,address(factory),feeEscrow,vault);\n        address curve;(token,curve)=created.launch{value:msg.value}(params,config);account=address(created);\n        collectorFor[token]=account;creatorFor[token]=msg.sender;createdAt[token]=block.timestamp;tokens.push(token);\n        emit TokenRegistered(token,account,msg.sender,curve);\n    }\n    function predictAccount(address creator,bytes32 salt) external view returns(address) {\n        bytes32 initHash=keccak256(abi.encodePacked(type(WinPonsTaxedLaunchAccount).creationCode,abi.encode(creator,address(factory),feeEscrow,vault)));\n        return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff),address(this),keccak256(abi.encode(creator,salt)),initHash)))));\n    }\n    function totalTokens() external view returns(uint256){return tokens.length;}\n    function tokenAt(uint256 index) external view returns(address){return tokens[index];}\n}\n"
    },
    "@openzeppelin/contracts/utils/ReentrancyGuard.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)\n\npragma solidity ^0.8.20;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,\n * consider using {ReentrancyGuardTransient} instead.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant NOT_ENTERED = 1;\n    uint256 private constant ENTERED = 2;\n\n    uint256 private _status;\n\n    /**\n     * @dev Unauthorized reentrant call.\n     */\n    error ReentrancyGuardReentrantCall();\n\n    constructor() {\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        _nonReentrantBefore();\n        _;\n        _nonReentrantAfter();\n    }\n\n    function _nonReentrantBefore() private {\n        // On the first call to nonReentrant, _status will be NOT_ENTERED\n        if (_status == ENTERED) {\n            revert ReentrancyGuardReentrantCall();\n        }\n\n        // Any calls to nonReentrant after this point will fail\n        _status = ENTERED;\n    }\n\n    function _nonReentrantAfter() private {\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = NOT_ENTERED;\n    }\n\n    /**\n     * @dev Returns true if the reentrancy guard is currently set to \"entered\", which indicates there is a\n     * `nonReentrant` function in the call stack.\n     */\n    function _reentrancyGuardEntered() internal view returns (bool) {\n        return _status == ENTERED;\n    }\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-20 standard as defined in the ERC.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the value of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the value of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the\n     * allowance mechanism. `value` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)\n\npragma solidity ^0.8.20;\n\nimport {IERC20} from \"../IERC20.sol\";\nimport {IERC1363} from \"../../../interfaces/IERC1363.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC-20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    /**\n     * @dev An operation with an ERC-20 token failed.\n     */\n    error SafeERC20FailedOperation(address token);\n\n    /**\n     * @dev Indicates a failed `decreaseAllowance` request.\n     */\n    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);\n\n    /**\n     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     */\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the\n     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.\n     */\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));\n    }\n\n    /**\n     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.\n     */\n    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {\n        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));\n    }\n\n    /**\n     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 oldAllowance = token.allowance(address(this), spender);\n        forceApprove(token, spender, oldAllowance + value);\n    }\n\n    /**\n     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no\n     * value, non-reverting calls are assumed to be successful.\n     *\n     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the \"client\"\n     * smart contract uses ERC-7674 to set temporary allowances, then the \"client\" smart contract should avoid using\n     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract\n     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.\n     */\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {\n        unchecked {\n            uint256 currentAllowance = token.allowance(address(this), spender);\n            if (currentAllowance < requestedDecrease) {\n                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);\n            }\n            forceApprove(token, spender, currentAllowance - requestedDecrease);\n        }\n    }\n\n    /**\n     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,\n     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval\n     * to be set to zero before setting it to a non-zero value, such as USDT.\n     *\n     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function\n     * only sets the \"standard\" allowance. Any temporary allowance will remain active, in addition to the value being\n     * set here.\n     */\n    function forceApprove(IERC20 token, address spender, uint256 value) internal {\n        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));\n\n        if (!_callOptionalReturnBool(token, approvalCall)) {\n            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));\n            _callOptionalReturn(token, approvalCall);\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            safeTransfer(token, to, value);\n        } else if (!token.transferAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target\n     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function transferFromAndCallRelaxed(\n        IERC1363 token,\n        address from,\n        address to,\n        uint256 value,\n        bytes memory data\n    ) internal {\n        if (to.code.length == 0) {\n            safeTransferFrom(token, from, to, value);\n        } else if (!token.transferFromAndCall(from, to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no\n     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when\n     * targeting contracts.\n     *\n     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.\n     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}\n     * once without retrying, and relies on the returned value to be true.\n     *\n     * Reverts if the returned value is other than `true`.\n     */\n    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {\n        if (to.code.length == 0) {\n            forceApprove(token, to, value);\n        } else if (!token.approveAndCall(to, value, data)) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            // bubble errors\n            if iszero(success) {\n                let ptr := mload(0x40)\n                returndatacopy(ptr, 0, returndatasize())\n                revert(ptr, returndatasize())\n            }\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n\n        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {\n            revert SafeERC20FailedOperation(address(token));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     *\n     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.\n     */\n    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {\n        bool success;\n        uint256 returnSize;\n        uint256 returnValue;\n        assembly (\"memory-safe\") {\n            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)\n            returnSize := returndatasize()\n            returnValue := mload(0)\n        }\n        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);\n    }\n}\n"
    },
    "@openzeppelin/contracts/interfaces/IERC1363.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)\n\npragma solidity >=0.6.2;\n\nimport {IERC20} from \"./IERC20.sol\";\nimport {IERC165} from \"./IERC165.sol\";\n\n/**\n * @title IERC1363\n * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].\n *\n * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract\n * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.\n */\ninterface IERC1363 is IERC20, IERC165 {\n    /*\n     * Note: the ERC-165 identifier for this interface is 0xb0202a11.\n     * 0xb0202a11 ===\n     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^\n     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^\n     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))\n     */\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from the caller's account to `to`\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);\n\n    /**\n     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism\n     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.\n     * @param from The address which you want to send tokens from.\n     * @param to The address which you want to transfer to.\n     * @param value The amount of tokens to be transferred.\n     * @param data Additional data with no specified format, sent in call to `to`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value) external returns (bool);\n\n    /**\n     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the\n     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     * @param data Additional data with no specified format, sent in call to `spender`.\n     * @return A boolean value indicating whether the operation succeeded unless throwing.\n     */\n    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);\n}\n"
    },
    "@openzeppelin/contracts/interfaces/IERC20.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC20} from \"../token/ERC20/IERC20.sol\";\n"
    },
    "@openzeppelin/contracts/interfaces/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)\n\npragma solidity >=0.4.16;\n\nimport {IERC165} from \"../utils/introspection/IERC165.sol\";\n"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)\n\npragma solidity >=0.4.16;\n\n/**\n * @dev Interface of the ERC-165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[ERC].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "evmVersion": "shanghai",
    "outputSelection": {
      "*": {
        "*": [
          "abi",
          "evm.bytecode.object",
          "evm.deployedBytecode.object"
        ]
      }
    }
  }
}