// LiquidityMining — Phase D of silent-iron-keystone v4. // // LP positions earn rewards from a per-pool emission rate. The // contract tracks share-block accruals tied to LP commitments // (NOT addresses, preserving privacy). Anti-flash-LP: minimum // 100-block holding period before any accrual starts. // // Privacy: per-position eligibility, no link to long-term identity. // Claims emit nullifiers + a token-transfer event for the reward. dark contract LiquidityMining { public mapping(bytes => bytes) eligPool; // positionId → pool_id public mapping(bytes => uint64) eligRegisteredBlk; // positionId → register block public mapping(bytes => uint64) eligAccumulated; // positionId → share-blocks accumulated public mapping(bytes => uint64) eligLastClaimBlock; // positionId → last claim block public mapping(bytes => bool) claimNullifiers; @direct entry register(bytes positionId, bytes pool_id) { require(eligRegisteredBlk[positionId] == 0, "MINE_DUPE_REGISTER"); eligPool[positionId] = pool_id; eligRegisteredBlk[positionId] = block.number; eligAccumulated[positionId] = 0; eligLastClaimBlock[positionId] = block.number; } // Anyone can call checkpoint to advance accumulation. Anti-flash-LP: // first checkpoint must be >100 blocks after register. After that, // checkpoints accrue (current_block - last_claim_block) share-blocks. @direct entry checkpoint(bytes positionId) { require(eligRegisteredBlk[positionId] != 0, "MINE_UNREGISTERED"); require(block.number > eligRegisteredBlk[positionId] + 100, "MINE_TOO_SOON"); require(block.number > eligLastClaimBlock[positionId], "MINE_NO_PROGRESS"); eligAccumulated[positionId] = eligAccumulated[positionId] + (block.number - eligLastClaimBlock[positionId]); eligLastClaimBlock[positionId] = block.number; } @direct entry claim(bytes positionId, bytes nullifier, uint64 claim_amount) { require(eligRegisteredBlk[positionId] != 0, "MINE_UNREGISTERED"); require(!claimNullifiers[nullifier], "MINE_REPLAY"); require(claim_amount > 0, "MINE_ZERO_CLAIM"); require(claim_amount <= eligAccumulated[positionId], "MINE_OVERCLAIM"); eligAccumulated[positionId] = eligAccumulated[positionId] - claim_amount; claimNullifiers[nullifier] = true; syscall(TOKEN_TRANSFER_EMIT_V1, ctx.txHash); } }