{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"fa117565-998a-4aaa-ad09-233e642d4c1e","kind":"skill:build-contract-project","nodes":[{"acceptedSubmissionHash":"da84bb94904a111696d3a743cba45c006a16a720147744594e3f68cba84961c8","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","tools":[]},"key":"build_contract_project","kind":"code","role":"implement","skillHash":"6b8d2c2ebd3301cff2be8edb1e1cc6ba65c858c02fe7247be81722b969842265","skillId":"build-contract-project","state":"accepted"}],"objective":"PROJECT: BMC ILLUMINATI — COMPLETE STAKING ECOSYSTEM\n\nBuild production-quality Ethereum smart contracts for BMC token staking, BMC Illuminati Pass NFT staking, and combined token + NFT staking.\n\nEXISTING BMC TOKEN\n0x38224239f2BDae357D47cb864BC533d7f72dF961\n\nUse BMC as the only staking reward token. Do not create another token, mint new BMC, or use IMD as a staking reward.\n\nNFT COLLECTION\nBMC Illuminati Pass, 500 ERC-721 NFTs:\n- Token #1: Legendary Genesis\n- Tokens #2–40: Early Genesis\n- 37 additional Genesis randomly distributed in the mystery phase\n- 423 Standard NFTs\n\nThe NFT contract address will be supplied after independent review and deployment. Never deploy with a placeholder address.\n\nSTAKING REWARD ECONOMY\n\nUse a fixed-duration, fully prefunded BMC reward program.\n\nSuggested allocation:\n- 55% BMC token staking\n- 25% NFT staking\n- 15% combined staking bonus\n- 5% uncommitted reserve\n\nReward budgets and program duration must be set and funded before rewards accrue.\n\nNever promise guaranteed APY or distribute rewards exceeding the funded allocation.\n\nBMC TOKEN STAKING\n- Deposit BMC and receive proportional rewards from the funded token staking pool.\n- Track actual BMC received, accounting for possible transfer fees.\n- Support claims and withdrawals.\n- Clearly document withdrawal conditions and token transfer fees.\n- Use accurate reward-per-share accounting.\n- No new token issuance.\n\nNFT STAKING\n- Support staking or noncustodial locking/registration of verified BMC Illuminati Pass NFTs.\n- Standard NFT: weight 1.\n- Random Genesis: weight 2.\n- Early Genesis: weight 3.\n- Legendary Genesis #1: weight 5.\n- Use the NFT contract's verified tierOf and artwork assignment functions.\n- Do not determine mystery NFT rarity from token ID alone.\n- Prevent double-staking and reward claims by nonowners.\n- Handle pending-reveal NFTs safely.\n\nCOMBINED STAKING\n- Allow participants staking both BMC and eligible NFTs to earn a bonus from a separate funded bonus pool.\n- Target an additional reward weight of up to 20%, subject to the bonus pool's hard cap.\n- Set minimum BMC stake and maximum NFT-linked bonus exposure using transparent documented rules.\n- Prevent the same NFT or token stake from claiming multiple overlapping bonuses.\n- Stop combined bonus accrual when either required stake is withdrawn.\n\nSECURITY\n- Use audited OpenZeppelin libraries.\n- Reentrancy protection.\n- Safe ERC-20 and ERC-721 transfers.\n- Account for fee-on-transfer BMC behavior.\n- Separate user principal from reward reserves.\n- Never use deposited principal to pay staking rewards.\n- Use immutable or narrowly scoped configuration where feasible.\n- Any treasury funding or emergency privileges must be explicit and multisig-controlled.\n- Emergency controls must not permit confiscation of user principal.\n- Avoid unlimited token approvals.\n- Ensure rewards cannot exceed prefunded budgets.\n- Prevent reward manipulation using flash deposits, same-block stake/withdrawal, and accounting edge cases.\n- Provide an explicit treatment of unallocated rewards and rounding dust.\n\nTESTING\nUse Foundry to test:\n- Deposits, withdrawals and reward claims\n- Fee-on-transfer behavior\n- Reward exhaustion and funding\n- NFT ownership changes\n- Pending and revealed Genesis NFTs\n- Combined staking eligibility\n- Double-counting prevention\n- Reentrancy and accounting invariants\n- Principal solvency and total reward caps\n\nDELIVERY\nProvide:\n1. Solidity source code\n2. Foundry test suite and results\n3. Deployment and funding instructions\n4. Public staking interface specification\n5. GitHub repository or pull request\n6. Independent security review requirements\n\nRun the free IMD check and report blockers.\n\nDo not deploy to mainnet, request token transfers, or enable staking until independently reviewed and explicitly authorized. ADDITIONAL MANDATORY STAKING REQUIREMENTS\n\nACCESS CONTROL:\n- Anyone may stake their own eligible BMC tokens or BMC Illuminati Pass NFTs.\n- Only the verified stake owner may withdraw their principal and claim their earned rewards.\n- Reward funding is controlled by an explicitly designated multisignature treasury.\n- No administrator may withdraw users' deposited principal.\n- Emergency controls must preserve user withdrawal rights.\n\nREWARD RULES:\n- BMC is the only reward token.\n- No new BMC tokens may be minted.\n- All rewards must come from a fully funded, separately accounted reward pool.\n- Reward allocation: 55% BMC staking, 25% NFT staking, 15% combined staking, and 5% uncommitted reserve.\n- Initial program duration: 12 months, configurable only before activation.\n- Do not hardcode an unfunded reward amount or promise a guaranteed APY.\n- Total rewards distributed must never exceed the actual funded reward budget.\n- Combined staking bonus is capped at 20% additional reward weight, subject to its separately funded allocation.\n- No hidden deposit or withdrawal penalties.\n\nNFT REWARD WEIGHTS:\n- Standard NFT: 1x\n- Random Genesis: 2x\n- Early Genesis: 3x\n- Legendary Genesis #1: 5x\n\nCONTRACT CONTROL:\n- No upgradeable proxy.\n- No arbitrary owner withdrawals.\n- Emergency pause may stop new deposits but must not block safe principal withdrawals.\n- Changes to reward funding must be transparent and cannot retroactively reduce earned rewards.\n- Account for BMC transfer fees when calculating deposits, withdrawals, and rewards.\n\nEXTERNAL DEPENDENCIES:\n- Use the existing verified BMC token.\n- The NFT contract address must be verified before deployment.\n- Do not depend on unverified price oracles.\n- Do not add an automatic IMD buyback bot.\n- Keep IMD burning in a separate system.\n\nSECURITY:\n- Protect against reentrancy, double claims, accounting manipulation, and reward pool insolvency.\n- Test fee-on-transfer token behavior.\n- Provide Foundry tests covering all three staking modes.\n- Report any design conflict or missing requirement before requesting deployment.\n\nDo not deploy to Ethereum mainnet until an independent security review is completed and I explicitly approve. EXTERNAL CONTRACTS AND DEPENDENCIES\n\nEthereum Mainnet, chain ID 1.\n\nExisting BMC ERC-20 token:\n0x38224239f2BDae357D47cb864BC533d7f72dF961\n\nUse this existing token for staking deposits and BMC rewards. Do not create a replacement token.\n\nThe BMC Illuminati Pass ERC-721 NFT contract is being developed separately. Its final deployed address is not yet available.\n\nDo not deploy NFT staking or combined staking until the NFT contract address and interface are verified.\n\nThe NFT staking system must read the NFT owner's eligibility and the assigned rarity tier from the deployed NFT contract.\n\nNo external price oracle is required for the proposed fixed-budget BMC staking rewards.\n\nDo not integrate external automated trading, IMD buybacks, liquidity pools, or bridges into the staking contracts.\n\nReward funding will be transferred manually from an authorized treasury wallet after deployment and independent security review.\n\nIf any required external contract address or interface is missing, report it as a deployment blocker rather than substituting an invented address.\n\nGenerate source code and Foundry tests only. Do not deploy or request wallet approvals.","parentJobId":null,"planHash":"ca2c92db592ee3e682e6d9ac95d003efee06fdf47ceba1e1891a4e859879173c","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"fa117565-998a-4aaa-ad09-233e642d4c1e","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1357-project-bmc-illuminati"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52653","feedbackHash":"3ad1b6840a5f567d8b167007b9f04965a875e911887b76bc8f3394c75b17b8ec","nodeKey":"build_contract_project","submissionHash":"da84bb94904a111696d3a743cba45c006a16a720147744594e3f68cba84961c8","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"8d0e85db29c4b9b286daff23d589f1d4b4413c0b51987ff1b669a91384d13f57","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"13bd0d662da904ad66aa439fdea1328db0e6710557f70b79c18325447c869e92","device":"0bb52b557875d32e","findings":[],"hash":"da84bb94904a111696d3a743cba45c006a16a720147744594e3f68cba84961c8","nodeId":"25583bb8-b7fb-4d2d-9deb-0b6a8f64cd78","outcome":"completed","summary":"Implemented the staking contracts, vendored dependencies, tests, and [documentation](README.md).\n\nValidation passed:\n\n- `forge build`\n- `forge test`: 80 reported cases\n- 10,000 runs per fuzz test\n- Five stateful invariants across 16,384 actions\n- `forge fmt --check`\n\nFree IMD input check: **no blockers**. Full evidence is in [verification results](docs/VERIFICATION.md).\n\nDeployment remains blocked pending the verified NFT address/interface, actual multisig and economic parameters, independent security review, and explicit authorization. The separate launch check requires a future reviewed manifest.\n\nNo contracts were deployed, wallet approvals requested, or repository published.","treeHash":"ee6f331e81ca4e99d6cc259d1ff4422f27feccbb","usage":{"cachedInputTokens":2982528,"inputTokens":138743,"model":"gpt-6-astra","outputTokens":67772,"runtime":"codex","turns":10,"wallClockMs":2102536}}],"verification":[{"checks":[{"durationMs":3571,"exitCode":0,"name":"build","output":"Compiling 53 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.43s\nCompiler run successful!\nwarning[missing-events-access-control]: `expectedNFTId` is changed without an event but is used for access control\n    ╭▸ src/BMCStaking.sol:286:9\n    │\n286 │         expectedNFTId = tokenId;\n    │         ━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BMCStaking.sol:229:9\n    │\n229 │         emit Activated(start, end, tokenBudget, nftBudget, bonusBudget, uncommittedReserve);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BMCStaking.sol:482:13\n    │\n482 │             emit BonusWeightChanged(owner, next);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BMCStaking.sol:251:9\n    │\n251 │         emit TokenDeposited(msg.sender, amount, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BMCStaking.sol:270:9\n    │\n270 │         emit TokenWithdrawn(msg.sender, amount, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/BMCStaking.sol:287:9\n    │\n287 │         collection.safeTransferFrom(msg.sender, address(this), tokenId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BMCStaking.sol:291:9\n    │\n291 │         emit NFTStaked(msg.sender, tokenId, weight);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/BMCStaking.sol:305:9\n    │\n305 │         collection.safeTransferFrom(address(this), recipient, tokenId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BMCStaking.sol:306:9\n    │\n306 │         emit NFTWithdrawn(msg.sender, recipient, tokenId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BMCStaking.sol:331:9\n    │\n331 │         emit RewardClaimed(msg.sender, amounts[0], amounts[1], amounts[2], received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BMCStaking.sol:322:74\n    │\n322 │             if (p.paid > p.allocated || p.paid + p.recovered > p.budget) revert Insolvent();\n    │                                                                          ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/BMCStaking.sol:522:9\n    │\n522 │         emit TreasuryRecovered(kind, amount, received);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BMCStaking.sol:535:13\n    │\n535 │         if (block.timestamp >= end) revert ProgramEnded();\n    │             ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/BMCStaking.sol:540:24\n    │\n540 │         if (!active || block.timestamp < end) revert ProgramNotEnded();\n    │                        ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BMCStaking.sol:549:42\n    │\n549 │             if (owners[i] == address(0)) revert InvalidTreasury();\n    │                                          ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/BMCStaking.sol:551:45\n    │\n551 │                 if (owners[i] == owners[j]) revert InvalidTreasury();\n    │                                             ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n   ╭▸ test/Base.t.sol:86:17\n   │\n86 │         vm.warp(block.timestamp + seconds_);\n   │         ────────━━━━━━━━━━━━━━━──────────── `vm.warp` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockTimestamp()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.number` may be reused across `vm.roll`\n   ╭▸ test/Base.t.sol:87:17\n   │\n87 │         vm.roll(block.number + 1);\n   │         ────────━━━━━━━━━━━━───── `vm.roll` changes this environment here\n   │\n   ├ help: capture it with `vm.getBlockNumber()` instead\n   ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":8119,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 3 tests for test/AccountingBounds.t.sol:AccountingBoundsTest\n[PASS] testMaximumLinkedCapCannotOverflowOrDuplicatePrincipalWeight() (gas: 2177172)\n[PASS] testMaximumSupportedFundingAndPrincipalDoNotOverflow() (gas: 2752474)\n[PASS] testSingleRawUnitPrincipalWithMaximumRewardsDoesNotOverflowIndex() (gas: 1607789)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 7.95ms (2.81ms CPU time)\n\nRan 10 tests for test/CombinedStaking.t.sol:CombinedStakingTest\n[PASS] testASecondNFTDepositInSameBlockCannotClaimHistoricalBonus() (gas: 1151589)\n[PASS] testAllTokenPrincipalWithdrawnStopsBonusButNFTEarnsNormally() (gas: 1824965)\n[PASS] testBonusIsBoundedByBothPrincipalAndNFTLinkedExposure() (gas: 2145246)\n[PASS] testBonusWeightIsNotAnAPYOrAPerAccountPayoutPercentage() (gas: 916281)\n[PASS] testFallingBelowMinimumStopsBonusAndRestakingHasNoBackpay() (gas: 2363257)\n[PASS] testLosingLastNFTStopsBonusImmediatelyAndRetainsEarnedBonus() (gas: 1900136)\n[PASS] testMinimumIsMeasuredAfterTransferFees() (gas: 1184166)\n[PASS] testNFTTransferDoesNotCreateOverlappingBonusOrStealPriorBonus() (gas: 3054093)\n[PASS] testPartialNFTExitReducesBonusExposureBeforeNextInterval() (gas: 3444067)\n[PASS] testTokenAndNFTAreBothRequiredAndDepositOrderDoesNotMatter() (gas: 2679784)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 52.14ms (8.78ms CPU time)\n\nRan 8 tests for test/Settlement.t.sol:SettlementTest\n[PASS] testCannotRecoverIdleEmissionsOrDustEarly() (gas: 103412)\n[PASS] testDustRecoveryPreservesEveryAccruedWholeUnitIndefinitely() (gas: 3959243)\n[PASS] testFinalRecoveryAfterPartialIdleRecoveryCannotRecoverTwice() (gas: 1608255)\n[PASS] testFinalRemainderRequiresAllPositionsExited() (gas: 1400623)\n[PASS] testIdleRecoveryLeavesPrincipalAndUnclaimedRewardsUntouched() (gas: 1983701)\n[PASS] testRepeatedClaimsCannotExceedBudgetsAndDoNotEraseAccountFractions() (gas: 20815212)\n[PASS] testTinyRewardsPreservePerAccountFractionAcrossZeroValueCheckpoints() (gas: 4118623)\n[PASS] testUnusedProgramReturnsOnlyRewardsToTreasuryAfterExpiry() (gas: 824915)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 59.13ms (14.56ms CPU time)\n\nRan 11 tests for test/TransferFees.t.sol:TransferFeesTest\n[PASS] testDepositWithdrawalAndClaimFeesNeverSpendAnotherOwnersPrincipal() (gas: 2061431)\n[PASS] testFundingBudgetsUseNetReceipt() (gas: 929260)\n[PASS] testFuzzFeeOnTransferConservesGrossBudgets(uint16,uint96) (runs: 512, μ: 1653358, ~: 1656700)\nLogs:\n  Bound result 0\n  Bound result 94932605972175\n\n[PASS] testMinReceiptProtectsClaimsAndWithdrawalsAfterFeeIncrease() (gas: 2030823)\n[PASS] testMinReceiptProtectsDepositAndFailureIsAtomic() (gas: 1073520)\n[PASS] testMinReceiptProtectsFundingAndFailureIsAtomic() (gas: 434250)\n[PASS] testNoReturnERC20TransfersSupportedAndFalseReturnsRevert() (gas: 1988011)\n[PASS] testRawUnitAccountingWorksWithoutAssumingEighteenDecimals() (gas: 1621608)\n[PASS] testSurchargeCannotBePaidFromRewardReservesOrOtherPrincipal() (gas: 2145751)\n[PASS] testTreasuryRecoveryFeesAreDebitedOnlyFromItsAllocation() (gas: 986987)\n[PASS] testUnsupportedReflectionAndZeroReceiptRevert() (gas: 1257316)\nSuite result: ok. 11 passed; 0 failed; 0 skipped; finished in 60.41ms (65.98ms CPU time)\n\nRan 13 tests for test/TokenStaking.t.sol:TokenStakingTest\n[PASS] testBrokenTreasuryCannotBlockPrincipalWithdrawals() (gas: 1029232)\n[PASS] testDepositClaimAndWithdraw() (gas: 1098983)\n[PASS] testFuzzProportionalRewardsAndPrincipalConservation(uint96,uint96,uint32) (runs: 512, μ: 1739291, ~: 1749432)\nLogs:\n  Bound result 9925\n  Bound result 4639\n  Bound result 2228\n\n[PASS] testLateDepositsDoNotCaptureIdleEmissions() (gas: 919297)\n[PASS] testNobodyElseCanWithdrawOrClaimAnOwnersBalance() (gas: 673974)\n[PASS] testPartialWithdrawalsCheckpointOldWeight() (gas: 1482224)\n[PASS] testPauseBlocksNewStakesButNotExitsOrRewards() (gas: 1434805)\n[PASS] testProgramEndCapsRewardsAndKeepsWithdrawalsAndClaimsOpen() (gas: 1256680)\n[PASS] testRewardReserveDeficitDoesNotTrapSolventPrincipal() (gas: 1243728)\n[PASS] testSameBlockRoundTripAndClaimRejected() (gas: 805922)\n[PASS] testStaggeredDepositsReceiveOnlyTheirTimeWeightedShare() (gas: 1361648)\n[PASS] testWithdrawnAccountsKeepEarnedRewardsButStopAccruing() (gas: 1126780)\n[PASS] testZeroOversizedAndInsufficientAllowanceDepositsRevert() (gas: 382558)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 60.46ms (65.42ms CPU time)\n\nRan 5 tests for test/Reentrancy.t.sol:ReentrancyTest\n[PASS] testNFTReceiverCannotReenterRewardClaimAndSafeExitStillSucceeds() (gas: 2096622)\n[PASS] testRecoveryCannotReenterAnotherRecovery() (gas: 1056761)\n[PASS] testRejectingNFTReceiverRollsBackAccountingAndCanRetry() (gas: 2375791)\n[PASS] testTokenCallbackCannotReenterFundingOrActivation() (gas: 506043)\n[PASS] testTokenCallbacksCannotReenterDepositWithdrawalOrClaim() (gas: 2066168)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 60.52ms (4.23ms CPU time)\n\nRan 13 tests for test/NFTStaking.t.sol:NFTStakingTest\n[PASS] testCustodyPreventsOwnershipChangesAndDoubleStaking() (gas: 901475)\n[PASS] testExitChangesOwnerButOldEarnedRewardsRemainWithDepositor() (gas: 1924506)\n[PASS] testFourVerifiedTiersReceiveOneTwoThreeFiveWeights() (gas: 2800096)\n[PASS] testInconsistentKnownTiersAndOutOfRangeIDsRejected() (gas: 527774)\n[PASS] testInvalidRecipientsDoNotDestroyNFTPosition() (gas: 910816)\n[PASS] testMysteryRarityIsNotInferredFromID() (gas: 261605)\n[PASS] testNFTWithdrawAndClaimAfterProgramEnd() (gas: 1193766)\n[PASS] testOnlyCurrentNFTOwnerCanStakeEvenIfCallerIsApprovedOperator() (gas: 898828)\n[PASS] testPendingNFTCannotStakeThenFinalGenesisCanStakeWithoutBackpay() (gas: 1211205)\n[PASS] testSameBlockNFTWithdrawalFailsAndRewardIsZero() (gas: 777706)\n[PASS] testTierAndArtworkAssignmentBothRequired() (gas: 402459)\n[PASS] testUnsolicitedSafeTransfersAndForgedCallbacksRejected() (gas: 1528280)\n[PASS] testWithdrawalsWorkWhenPausedAndMetadataBreaks() (gas: 1290177)\nSuite result: ok. 13 passed; 0 failed; 0 skipped; finished in 60.54ms (6.26ms CPU time)\n\nRan 16 tests for test/Funding.t.sol:FundingTest\n[PASS] testCannotStakeBeforeActivation() (gas: 67536)\n[PASS] testDefaultsAndFixedToken() (gas: 128512)\n[PASS] testDirectDonationsCannotIncreaseBudgetsOrWeights() (gas: 859806)\n[PASS] testExactAllocationOfActualFunding() (gas: 895286)\n[PASS] testInvalidConfigurationAndWrongCollectionABI() (gas: 1463344)\n[PASS] testNoFundingOrConfigurationChangesAfterActivation() (gas: 788437)\n[PASS] testNoPrincipalOrArbitrarySweepAdministrativeFunction() (gas: 968655)\n[PASS] testOnlyTreasuryControlsFundingConfigurationAndRecovery() (gas: 832407)\n[PASS] testProgramParametersCanChangeBeforeActivation() (gas: 280877)\n[PASS] testRejectsInvalidTreasuries() (gas: 370531)\n[PASS] testRejectsZeroTreasuryConstructor() (gas: 3839)\n[PASS] testReserveIsBoundedAndDoesNotChangeEarnedRewards() (gas: 1434947)\n[PASS] testSplitRoundingGoesToReserveAndFundingAccumulates() (gas: 1015269)\n[PASS] testUnconfiguredStateBlocksActivationFundingAndNFTReads() (gas: 253008)\n[PASS] testUnfundedAndNegligiblyFundedProgramsCannotStart() (gas: 513479)\n[PASS] testWrongChainCannotFundOrActivate() (gas: 286634)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 60.56ms (8.10ms CPU time)\n\nRan 1 test for test/StakingInvariant.t.sol:StakingInvariantTest\n[PASS]\nStakingInvariantTest invariants:\n[PASS] invariantAllClaimableRewardsFitTheirOwnFundedBudgets\n[PASS] invariantCombinedExposureNeverExceedsTwentyPercent\n[PASS] invariantEveryOwnerRetainsTheirMeasuredPrincipal\n[PASS] invariantNFTCustodyAndWeightsAreUnique\n[PASS] invariantPrincipalSolventAndFundingConserved\n StakingInvariantTest invariants (runs: 128, calls: 16384, reverts: 0)\n\n╭----------------+---------------------+-------+---------+----------╮\n| Contract       | Selector            | Calls | Reverts | Discards |\n+===================================================================+\n| StakingHandler | advance             | 1316  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | changeFee           | 1251  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | claim               | 1247  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | deposit             | 1256  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | donate              | 1266  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | pause               | 1306  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | recoverDust         | 1235  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | recoverIdle         | 1291  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | recoverReserve      | 1250  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | stakeNFT            | 1244  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | transferUnstakedNFT | 1198  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | withdraw            | 1329  | 0       | 0        |\n|----------------+---------------------+-------+---------+----------|\n| StakingHandler | withdrawNFT         | 1195  | 0       | 0        |\n╰----------------+---------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 57627202915971205694307\n  Bound result 1743\n  Bound result 152\n  Bound result 306\n  Bound result 1024051926\n  Bound result 16319\n  Bound result 9475\n  Bound result 233181210308546\n  Bound result 4131\n  Bound result 6822\n  Bound result 14928\n  Bound result 5597\n  Bound result 140653902799191\n  Bound result 1503\n  Bound result 2015463\n  Bound result 5\n  Bound result 21078580327802974632288\n  Bound result 44818\n  Bound result 281184011\n  Bound result 1039181812295694307782\n  Bound result 920\n  Bound result 2\n  Bound result 4304\n  Bound result 13\n  Bound result 55\n  Bound result 15\n  Bound result 71\n  Bound result 93\n  Bound result 969\n  Bound result 15418302982062595\n  Bound result 1\n  Bound result 5315\n  Bound result 1\n  Bound result 9\n  Bound result 12391\n  Bound result 12603\n  Bound result 18\n  Bound result 1400\n  Bound result 9\n  Bound result 4216\n  Bound result 1996\n  Bound result 3\n  Bound result 6\n  Bound result 48707839688488255403657\n  Bound result 821\n  Bound result 10000\n  Bound result 10\n  Bound result 355\n  Bound result 3732\n  Bound result 15925\n  Bound result 743146918\n  Bound result 14744\n  Bound result 4213\n  Bound result 30493895537030019012824\n  Bound result 711\n  Bound result 11527\n  Bound result 2\n  Bound result 1\n  Bound result 370\n  Bound result 100000000000000000000\n  Bound result 2460010\n  Bound result 1219\n  Bound result 700\n  Bound result 48871728750872820062\n  Bound result 1680358778\n  Bound result 15492\n  Bound result 7521\n  Bound result 2527\n  Bound result 3383\n  Bound result 2777812\n  Bound result 12\n  Bound result 1259680690\n  Bound result 1855808784414\n  Bound result 358043\n  Bound result 3\n  Bound result 15\n  Bound result 12141\n  Bound result 50\n  Bound result 7292\n  Bound result 248\n  Bound result 50451864535768645357\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.04s (8.03s CPU time)\n\nRan 9 test suites in 8.04s (8.46s CPU time): 80 tests passed, 0 failed, 0 skipped (80 total tests)\n","passed":true},{"durationMs":47,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"BMCStaking.activate()\",\"BMCStaking.claim(uint256)\",\"BMCStaking.configureCollection(address,bytes32)\",\"BMCStaking.configureProgram(uint256,uint256,uint256)\",\"BMCStaking.fundRewards(uint256,uint256)\",\"BMCStaking.recoverRemainder(uint256)\",\"BMCStaking.recoverReserve(uint256,uint256)\",\"BMCStaking.recoverUnallocated(uint256)\",\"BMCStaking.setDepositsPaused(bool)\",\"BMCStaking.stakeBMC(uint256,uint256)\",\"BMCStaking.stakeNFT(uint256)\",\"BMCStaking.withdrawBMC(uint256,uint256)\",\"BMCStaking.withdrawNFT(uint256,address)\"],\"files\":{\".gitignore\":4,\"DEPENDENCIES.md\":19,\"LICENSE\":21,\"README.md\":107,\"docs/ACCOUNTING.md\":66,\"docs/DEPLOYMENT.md\":49,\"docs/INTERFACE.md\":63,\"docs/SECURITY_REVIEW.md\":43,\"docs/VERIFICATION.md\":64,\"docs/checks/bmc-mainnet-read.json\":16,\"docs/checks/build-artifact.json\":67,\"docs/checks/coverage.log\":138,\"docs/checks/dependency-sha256.txt\":49,\"docs/checks/empty-environment-test.log\":151,\"docs/checks/extended-fuzz.log\":14,\"docs/checks/forge-build.log\":152,\"docs/checks/forge-test.log\":151,\"docs/checks/format-check.log\":3,\"docs/checks/format.log\":3,\"docs/checks/imd-check-request-initial.json\":8,\"docs/checks/imd-check-request-template.json\":19,\"docs/checks/imd-check-request.json\":27,\"docs/checks/imd-check-response-initial.json\":1,\"docs/checks/imd-check-response-template.json\":1,\"docs/checks/imd-check-response.json\":1,\"docs/checks/imd-launch-check.log\":4,\"docs/checks/local-results.json\":85,\"docs/checks/source-sha256.txt\":17,\"foundry.toml\":25,\"src/BMCStaking.sol\":555,\"src/interfaces/IBMCIlluminatiPass.sol\":22,\"src/interfaces/IMultisigTreasury.sol\":8,\"test/AccountingBounds.t.sol\":65,\"test/Base.t.sol\":132,\"test/CombinedStaking.t.sol\":179,\"test/Funding.t.sol\":230,\"test/NFTStaking.t.sol\":211,\"test/Reentrancy.t.sol\":120,\"test/Settlement.t.sol\":155,\"test/StakingInvariant.t.sol\":327,\"test/TokenStaking.t.sol\":208,\"test/TransferFees.t.sol\":187,\"test/mocks/MockBMC.sol\":96,\"test/mocks/MockPass.sol\":44,\"test/mocks/MockTreasury.sol\":30},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":919,"exitCode":0,"name":"slither","output":"[high/medium] weak-prng at src/BMCStaking.sol:461: BMCStaking._earned(uint256,uint256,uint256) (src/BMCStaking.sol#461-470) uses a weak PRNG: \"remainder %= SCALE (src/BMCStaking.sol#469)\"\n[high/medium] reentrancy-balance at src/BMCStaking.sol:498: Reentrancy in BMCStaking._sendBMC(address,uint256,uint256) (src/BMCStaking.sol#498-514):\n[high/medium] reentrancy-balance at src/BMCStaking.sol:486: Reentrancy in BMCStaking._receiveBMC(uint256,uint256) (src/BMCStaking.sol#486-496):\n[high/medium] reentrancy-balance at src/BMCStaking.sol:498: Reentrancy in BMCStaking._sendBMC(address,uint256,uint256) (src/BMCStaking.sol#498-514):\n[medium/medium] uninitialized-local at src/BMCStaking.sol:313: BMCStaking.claim(uint256).amounts (src/BMCStaking.sol#313) is a local variable never initialized\n[low/medium] reentrancy-benign at src/BMCStaking.sol:273: Reentrancy in BMCStaking.stakeNFT(uint256) (src/BMCStaking.sol#273-292):\n[low/medium] timestamp at src/BMCStaking.sol:533: BMCStaking._requireDepositsOpen() (src/BMCStaking.sol#533-537) uses timestamp for comparisons\n[low/medium] timestamp at src/BMCStaking.sol:443: BMCStaking._updatePools() (src/BMCStaking.sol#443-454) uses timestamp for comparisons\n[low/medium] timestamp at src/BMCStaking.sol:539: BMCStaking._requireEnded() (src/BMCStaking.sol#539-541) uses timestamp for comparisons","passed":true},{"durationMs":211,"exitCode":0,"name":"aderyn","output":"[high] eth-send-unchecked-address at src/BMCStaking.sol:238: ETH transferred without address checks (3 places)\n[high] reentrancy-state-change at src/BMCStaking.sol:184: Reentrancy: State change after external call (3 places)\n[low] costly-loop at src/BMCStaking.sol:314: Costly operations inside loop (5 places)\n[low] large-numeric-literal at src/BMCStaking.sol:477: Large Numeric Literal\n[low] literal-instead-of-constant at src/BMCStaking.sol:218: Literal Instead of Constant (14 places)\n[low] require-revert-in-loop at src/BMCStaking.sol:314: Loop Contains `require`/`revert` (6 places)\n[low] uninitialized-local-variable at src/BMCStaking.sol:347: Uninitialized Local Variable (6 places)","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"da84bb94904a111696d3a743cba45c006a16a720147744594e3f68cba84961c8","verifiedTreeHash":"ee6f331e81ca4e99d6cc259d1ff4422f27feccbb","verifierVersion":"0.1.0+fb8278c5"}]}