{"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":"9bf411ca-2719-4cab-b2a3-badcf83ed8d4","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"af3aa01159bbf354f621cafa5c0006f6169e0938a8b015be508b7377dbf165bc","skillId":"audit-judge","state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"waiting"},{"acceptedSubmissionHash":null,"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":"failed"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"waiting"},{"acceptedSubmissionHash":null,"dependsOn":["build_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"waiting"}],"objective":"X: https://x.com/imdplace\n\nGoblin Gacha v1 (working name). This job DEPLOYS ONLY the Goblin NFT mint (one contract, GoblinNFT, with its built-in ownerless mint escrow) on Ethereum mainnet. Every other contract below is written and tested as code in the same repo but NOT deployed in this job. No token actions. Inputs: research jobs b7e0e298 and 20ccee81 (artifacts/report.md). Use 20ccee81 section 3.7 parameters and the safety design of b7e0e298.\n\nGoblinNFT (deployed now): original on-chain generative 32x32 pixel-art goblin traders carrying loot bags full of coins and tokens, SVG assembled on-chain from traits (skin, ears, face/expression, outfit, headwear, bag type and what peeks out, held item, background), rarity tiers with a subtle glow for the rarest; traits must be assigned without letting minters pick rarity (no predictable rarity sniping). Supply 10,000, price 0.001 ETH, max 20 per wallet. Fully refundable until sellout: any holder may burn and get 0.001 ETH back at any time before sellout. At sellout the ETH is committed in the contract and can later be released only permissionlessly to the gacha contracts: 50% POL, 40% payout reserve, 10% VRF subscription; nothing to the team, ever. The gacha contracts do not exist yet, so the release must use a one-time permissionless bind proven by IMD ProjectFactory predictions and pinned creation-code hashes of the gacha contracts written in this repo (no owner, no setter). If not released within 90 days after sellout, every holder can refund 0.001 ETH per NFT. Holders will earn by holding: an ETH share of spins and 50% of the platform's 1% pool fee, accrued per tokenId and claimable by the current holder, so income moves with the NFT; each NFT gets 2 free Genesis spins and a 48 h holder-only Genesis window at d = 3%, max 5 spins per NFT. No owner, no admin, no withdraw, no proxy. Constructor: static words only, no external calls.\n\nGacha (code only in this job): an ETH-only gacha with ERC-20 \"Bags\". Depositors seal whitelisted ERC-20 tokens into a Bag (ERC-721); each depositor risks only their own tokens. Spins cost 0.01 ETH plus the Chainlink VRF v2.5 fee; a drawn Bag is kept (open it for the tokens or trade the NFT) or sold back for instant ETH at 88% of value (Bag returns to the pool). A depositor whose Bag is kept receives 95% of its value in ETH from the payout reserve. Valuation: min(30-min TWAP, 4-h TWAP) on a Uniswap v3/v4 WETH pair, min 50 ETH liquidity per side, quote fresher than 1 h. Tiers (multiple of spin price / odds): 0.3-0.7x 75%, 0.7-2x 18%, 2-6x 6.5%, 6-70x 0.5%. A Bag may not exceed 5% of the reserve; jackpot tier disabled while the reserve is below 20x the max jackpot.\n\nSafety (from b7e0e298, mandatory): one outstanding draw at a time; the eligible inventory snapshot and TWAP marks are committed at request time, before randomness; the VRF callback only stores the word and cannot be front-run to change the selected Bag (the July FWA callback exploit); settlement is a separate step; hard solvency invariant (free reserve minus every known and worst-case liability stays above a floor, else new spins revert); no admin rescue, no timeout reroll; document what happens if VRF stops.\n\nPlatform token (code only, launched later): working name GOBLIN, 1,000,000,000 supply. It will be launched on IMD as an evm_project: 10% to the liquidity pool, 10% to the swarm, and the remaining 80% sent in the launch transaction to GenesisVault by contract name. Write the exact launch plan and manifest. GenesisVault holds the 80% as virtual Genesis Bags drawn by spins. tokensPerBag = min((1-d)*P/min(TWAP30m,TWAP4h), schedule), d = 8% (oracle-bounded 5-12%), schedule linear over 540 days with 0.9^daysAhead decay, maxAheadDays 3. Genesis spin ETH: 40% protocol-owned liquidity (locked forever), 30% payout reserve, 15% NFT holders, 15% team. Regular spin ETH: 88% reserve; margin 4% platform-token buy-and-burn, 3% NFT holders, 2% POL, 3% team. Sealed Bags and pooled Bags earn platform-token dividends: 2% of supply over 540 days, sqrt-value shares, 24 h warm-up, poke at most once per 24 h; opening a Bag settles and stops its dividends.\n\nCurator (code only): no owner anywhere. The only authority is a Curator that acts solely on attested IMD oracle answers (verified attester signature, pinned question hashes, freshness, replay protection): token whitelist/delist with safety and liquidity checks, Genesis discount within 5-12%, tier odds within hard bounds (max 10% change per 24h), pause of a single token's Bags. If answers stop, the system keeps running on current settings.\n\nIMD limits: at most 8 contracts per launch, at most 16 static constructor words, no owner, no proxy, no external calls in constructors, runtime <= 24,576 bytes. Give the exact later deploy order (token, then gacha) and every constructor word.\n\nDeliver: Foundry repo (solc 0.8.26, optimizer 200, cancun, viaIR false, bytecode_hash none in foundry.toml); unit, fuzz and invariant tests with priority on GoblinNFT (refund accounting before and after sellout, 20-per-wallet cap, escrow can never pay a wallet, bind only to the pinned gacha contracts, 90-day refund, per-token revenue accrual) and on the gacha (reserve solvency, no double payout, dividend conservation, Genesis curve bounds); fork tests against real Uniswap v3 and the Chainlink VRF v2.5 coordinator on Ethereum; economic simulation; gas per mint, refund, deposit, spin, settle, claim; adversarial review with fixes for high/medium; report.md. De\n\nToken name: Goblin Gold\nToken symbol: GG\nTotal supply: 1,000,000,000","parentJobId":null,"planHash":"ebe534b67e906fc746c05b6a6432dd437e4c3fe01585141d6f4f5d15ec75825c","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"9bf411ca-2719-4cab-b2a3-badcf83ed8d4","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1545-goblin-gold"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51401","feedbackHash":"f7bc81ac3115f28c23ff369cfdcb82cc31fcf5e7f0883fabaea2094330636da2","nodeKey":"build_contract_project","submissionHash":"85a5163c04c22bcb202402eb97ed038c5bb916b497afb133616e7f1be3bb7d21","tag1":"verification:checks","tag2":"acceptance-v2","value":0}],"site":null,"snapshotHash":"a7bcfa590f8ea4e857ac1448dc14d3ccd1aad96521beedcbddbd02ef648ef3eb","state":"blocked","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"b97c0d2a66e1892680e6cc8cff2cd46e3aec955d82c613f6e3e1d056600ab9f3","device":"2ab0b432477fde6c","findings":[],"hash":"85a5163c04c22bcb202402eb97ed038c5bb916b497afb133616e7f1be3bb7d21","nodeId":"91518b48-188b-41c6-99ec-0d16508e807e","outcome":"completed","summary":"Work is complete and committed. Summary:\n\n**Delivered** a Foundry repo (solc 0.8.26, optimizer 200, cancun, viaIR off, bytecode_hash none) with vendored forge-std and OpenZeppelin v5.4.0 as plain files.\n\n**GoblinNFT** (the only contract this job deploys, 15,841 bytes runtime):\n- 10,000 supply, 0.001 ETH, 20 mints per wallet, on-chain 32×32 SVG goblins with 9 traits and rarity glow. Traits derive from the mint block's hash, so minters cannot simulate and snipe rarity.\n- Refund any time before sellout. At sellout the escrow is committed. One-time permissionless `bind` proves the gacha contracts via pinned creation-code hashes plus CREATE2 prediction from the deploying factory. `release` pays 50% POL, 40% reserve, 10% VRF subscription. If not released within 90 days, all holders refund.\n- Per-token revenue accrual claimable by the current holder. No owner, no admin, no withdraw, no proxy, static constructor.\n- Constructor words for the manifest are in report.md section 1. They are the creation-code hashes of GoblinGacha and GoblinPOL as built, so the gacha source must stay frozen until the NFT is launched.\n\n**Code only** (not deployed): GoblinGacha, GoblinBags, GenesisVault, GoblinPOL, GoblinCurator, reference GoblinGold ERC-20. The b7e0e298 safety design is implemented: single outstanding draw, snapshot and odds committed before the VRF request, store-only callback, separate settlement, hard solvency floor, no rescue or reroll, and documented behaviour if VRF stops.\n\n**Verification**:\n- `forge build`, `forge test` (58 tests across 4 suites, including fuzz and invariants) and `forge fmt --check` all pass.\n- Fork tests against the real USDC/WETH Uniswap v3 pool and the real Chainlink VRF v2.5 coordinator pass at mainnet block 26,182,626, run via the separate fork profile.\n\n**Caveats recorded in report.md**: the research inputs b7e0e298 and 20ccee81 were not present in the workspace, so parameters came from the brief. The POL liquidity path and buy-and-burn have interface-level code but no fork test. The exact later deploy order and every constructor word for the gacha launch are in report.md section 2.","treeHash":"b73d4d4be0fe673ed12bcbefb4e1d676f8798ee0","usage":{"cachedInputTokens":2953501,"inputTokens":834,"model":"claude-fable-5-1","outputTokens":117349,"runtime":"claude","turns":48,"wallClockMs":1634435}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"a68191e8efe5b6e4","findings":[],"hash":"e742e8359a3d99c682c17125248d1c62e55e2b0492e3afe086e0ab5b4846667a","nodeId":"91518b48-188b-41c6-99ec-0d16508e807e","outcome":"failed","summary":"needs input: The required artifacts/report.md inputs from research jobs b7e0e298 and 20ccee81 are absent from the supplied checkout and accessible artifact locations. In particular, the mandatory deployment and economic parameters in 20ccee81 section 3.7 cannot be read or verified. The supplied checks and reference guides do not contain those reports. — Please provide artifacts/report.md from both research jobs b7e0e298 and 20ccee81, including the complete section 3.7 and its referenced launch configuration, so the ownerless contracts can be implemented with the specified parameters rather than guessed values.","treeHash":null,"usage":{"cachedInputTokens":127360,"inputTokens":39585,"model":"gpt-6-astra","outputTokens":1910,"runtime":"codex","turns":3,"wallClockMs":97377}}],"verification":[{"checks":[{"durationMs":3503,"exitCode":0,"name":"build","output":"Compiling 62 files with Solc 0.8.26\nSolc 0.8.26 finished in 3.30s\nCompiler run successful!\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:11:42\n   │\n11 │             uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                          ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/GoblinCurator.sol:37:30\n   │\n37 │     constructor(address nft, address attester) {\n   │                              ━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/libraries/TwapLib.sol:25:33\n   │\n25 │         (int56[] memory cum,) = IUniswapV3Pool(pool).observe(ago);\n   │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TwapLib.sol:27:22\n   │\n27 │         int24 tick = int24(delta / int56(uint56(window)));\n   │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int24' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/GoblinPOL.sol:44:30\n   │\n44 │     constructor(address nft, address token, address weth, uint24 fee, address router, address pm, address factory) {\n   │                              ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/GoblinPOL.sol:44:45\n   │\n44 │     constructor(address nft, address token, address weth, uint24 fee, address router, address pm, address factory) {\n   │                                             ━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/GenesisVault.sol:46:30\n   │\n46 │     constructor(address nft, address token, address weth, address curator) {\n   │                              ━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/GoblinArt.sol:125:16\n    │\n125 │         return uint8(cum.length - 1);\n    │                ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint8' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/GenesisVault.sol:46:59\n   │\n46 │     constructor(address nft, address token, address weth, address curator) {\n   │                                                           ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:11:67\n   │\n11 │             uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));\n   │                                                                   ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/GenesisVault.sol:46:45\n   │\n46 │     constructor(address nft, address token, address weth, address curator) {\n   │                                             ━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:12:32\n   │\n12 │             require(absTick <= uint256(int256(MAX_TICK)), \"T\");\n   │                                ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/GoblinCurator.sol:56:13\n   │\n56 │         if (issuedAt > block.timestamp || block.timestamp - issuedAt > MAX_AGE) revert Stale();\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/GoblinCurator.sol:56:43\n   │\n56 │         if (issuedAt > block.timestamp || block.timestamp - issuedAt > MAX_AGE) revert Stale();\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/GoblinNFT.sol:102:29\n    │\n102 │         return !released && block.timestamp > selloutAt + RELEASE_WINDOW;\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/GoblinPOL.sol:77:26\n   │\n77 │         uint256 minOut = half * 1e18 / price * 97 / 100;\n   │                          ━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/GoblinCurator.sol:82:9\n   │\n82 │         emit Applied(question, nonce, payload);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/GoblinArt.sol:137:25\n    │\n137 │         for (uint256 i; i + 5 <= data.length; i += 5) {\n    │                         ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/GenesisVault.sol:62:29\n   │\n62 │     function setPricingPool(address pool) external {\n   │                             ━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/TickMath.sol:38:28\n   │\n38 │             sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));\n   │                            ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n   ╭▸ src/GoblinPOL.sol:77:26\n   │\n77 │         uint256 minOut = half * 1e18 / price * 97 / 100;\n   │                          ━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n   ╭▸ src/GenesisVault.sol:71:16\n   │\n71 │         return e > DURATION ? DURATION : e;\n   │                ━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n   ╭▸ src/GoblinPOL.sol:92:9\n   │\n92 │         emit LiquidityDeployed(id, wethLeft, got);\n   │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n   ╭▸ src/GoblinPOL.sol:86:27\n   │\n86 │           (uint256 id,,,) = PM.mint(\n   │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n87 │ ┃             INonfungiblePositionManager.MintParams(\n88 │ ┃                 t0, t1, FEE, -FULL_RANGE, FULL_RANGE, a0, a1, 0, 0, address(this), block.timestamp\n89 │ ┃             )\n90 │ ┃         );\n   │ ┗━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/GoblinPOL.sol:113:13\n    │\n113 │             IGachaSink(NFT.gacha()).fundReserve{value: ethFees - toHolders}();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/GoblinPOL.sol:106:13\n    │\n106 │             ethFees += w;\n    │             ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/GoblinPOL.sol:107:13\n    │\n107 │             ggFees += g;\n    │             ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/GoblinPOL.sol:100:40\n    │\n100 │               (uint256 a0, uint256 a1) = PM.collect(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n101 │ ┃                 INonfungiblePositionManager.CollectParams(\n102 │ ┃                     positions[i], address(this), type(uint128).max, type(uint128).max\n103 │ ┃                 )\n104 │ ┃             );\n    │ ┗━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-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/GoblinPOL.sol:116:9\n    │\n116 │         emit FeesCollected(ethFees / 2, ethFees - ethFees / 2, ggFees);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-oz-erc721-mint]: `ERC721._mint` does not check that the recipient can receive the token; use `_safeMint`\n    ╭▸ src/GoblinNFT.sol:128:13\n    │\n128 │             _mint(msg.sender, id);\n    │             ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-oz-erc721-mint\n\nwarning[missing-events-arithmetic]: `vrfFee` is changed without an event but is used in arithmetic\n    ╭▸ src/GoblinGacha.sol:195:9\n    │\n195 │         vrfFee = fee;\n    │         ━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-arithmetic\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/GoblinNFT.sol:126:29\n    │\n126 │             mintBlock[id] = uint64(block.number);\n    │                             ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/GoblinNFT.sol:129:41\n    │\n129 │             emit Minted(msg.sender, id, uint64(block.number));\n    │                                         ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `_active` is changed without an event but is used for access control\n    ╭▸ src/GoblinGacha.sol:316:9\n    │\n316 │         _active.word = randomWords[0];\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-events-access-control]: `_active` is changed without an event but is used for access control\n    ╭▸ src/GoblinGacha.sol:377:20\n    │\n377 │             delete _active.tiers[t];\n    │                    ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/GoblinBags.sol:71:47\n   │\n71 │     constructor(address nft, address curator, address weth, address vault) ERC721(\"Goblin Bags\", \"BAG\") {\n   │                                               ━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n   ╭▸ src/GoblinBags.sol:71:30\n   │\n71 │     constructor(address nft, address curator, address weth, address vault) ERC721(\"Goblin Bags\", \"BAG\") {\n   │                              ━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/GoblinGacha.sol:137:9\n    │\n137 │         address team,\n    │         ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/GoblinGacha.sol:136:9\n    │\n136 │         address curator_,\n    │         ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `subId` is updated\n    ╭▸ src/GoblinGacha.sol:165:21\n    │\n165 │             subId = COORDINATOR.createSubscription();\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/GoblinGacha.sol:160:9\n    │\n160 │         emit VrfFunded(subId, msg.value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/GoblinNFT.sol:179:38\n    │\n179 │         bytes32 initHash = keccak256(abi.encodePacked(code, args));\n    │                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/GoblinNFT.sol:196:9\n    │\n196 │         IGoblinEscrowSink(pol).fundPol{value: toPol}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/GoblinNFT.sol:197:9\n    │\n197 │         IGoblinEscrowSink(gacha).fundReserve{value: toReserve}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/GoblinNFT.sol:198:9\n    │\n198 │         IGoblinEscrowSink(gacha).fundVrf{value: toVrf}();\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/GoblinNFT.sol:189:13\n    │\n189 │         if (block.timestamp > selloutAt + RELEASE_WINDOW) revert RefundsClosed();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-oz-erc721-mint]: `ERC721._mint` does not check that the recipient can receive the token; use `_safeMint`\n    ╭▸ src/GoblinBags.sol:135:9\n    │\n135 │         _mint(address(this), bagId);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-oz-erc721-mint\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/GoblinNFT.sol:235:22\n    │\n235 │         (bool ok,) = to.call{value: amount}(\"\");\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/GoblinBags.sol:131:25\n    │\n131 │         b.depositedAt = uint64(block.timestamp);\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `totalShares` is updated\n    ╭▸ src/GoblinBags.sol:200:23\n    │\n200 │         uint256 got = VAULT.payout(address(this), type(uint256).max); // vault caps at accrued dividends\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/GoblinBags.sol:162:9\n    │\n162 │         emit Opened(bagId, msg.sender);\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/GoblinBags.sol:170:9\n    │\n170 │         emit Marked(bagId, b.markValue);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/GoblinBags.sol:169:22\n    │\n169 │         b.markedAt = uint64(block.timestamp);\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/GoblinGacha.sol:178:13\n    │\n178 │             sum += o[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/GoblinGacha.sol:173:13\n    │\n173 │         if (block.timestamp < lastOddsChange + 24 hours) revert TooSoon();\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/GoblinGacha.sol:177:30\n    │\n177 │             if (diff > 1000) revert OutOfBounds(); // max 10 percentage points per 24 h\n    │                              ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/GoblinBags.sol:211:13\n    │\n211 │         if (block.timestamp < b.depositedAt + WARMUP || block.timestamp < lastPoke[bagId] + POKE_INTERVAL) {\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/GoblinBags.sol:211:57\n    │\n211 │         if (block.timestamp < b.depositedAt + WARMUP || block.timestamp < lastPoke[bagId] + POKE_INTERVAL) {\n    │                                                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/GoblinBags.sol:221:9\n    │\n221 │         emit Poked(bagId, s);\n    │         ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/GoblinBags.sol:220:27\n    │\n220 │         lastPoke[bagId] = uint64(block.timestamp);\n    │                           ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_active` is updated\n    ╭▸ src/GoblinGacha.sol:166:13\n    │\n166 │             COORDINATOR.addConsumer(subId, address(this));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_active` is updated\n    ╭▸ src/GoblinGacha.sol:261:22\n    │\n261 │           uint256 id = COORDINATOR.requestRandomWords(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━┛\n262 │ ┃             IVRFCoordinatorV2_5.RandomWordsRequest({\n263 │ ┃                 keyHash: KEY_HASH,\n264 │ ┃                 subId: subId,\n    ‡ ┃\n269 │ ┃             })\n270 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hasActive` is updated\n    ╭▸ src/GoblinGacha.sol:166:13\n    │\n166 │             COORDINATOR.addConsumer(subId, address(this));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `hasActive` is updated\n    ╭▸ src/GoblinGacha.sol:261:22\n    │\n261 │           uint256 id = COORDINATOR.requestRandomWords(\n    │ ┏━━━━━━━━━━━━━━━━━━━━━━┛\n262 │ ┃             IVRFCoordinatorV2_5.RandomWordsRequest({\n263 │ ┃                 keyHash: KEY_HASH,\n264 │ ┃                 subId: subId,\n    ‡ ┃\n269 │ ┃             })\n270 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/GoblinGacha.sol:241:17\n    │\n241 │             if (block.timestamp >= start + HOLDER_WINDOW) revert TooSoon();\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/GoblinGacha.sol:248:20\n    │\n248 │         } else if (block.timestamp < start + HOLDER_WINDOW) {\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/GoblinGacha.sol:281:9\n    │\n281 │         emit SpinRequested(spinner, id, genesis, maxLiability);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/GoblinGacha.sol:268:51\n    │\n268 │                 extraArgs: abi.encodeWithSelector(bytes4(keccak256(\"VRF ExtraArgsV1\")), true) // native payment\n    │                                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'bytes4' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/GoblinGacha.sol:274:31\n    │\n274 │         _active.requestedAt = uint64(block.timestamp);\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/GoblinGacha.sol:306:15\n    │\n306 │             ++count;\n    │               ━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/GoblinGacha.sol:305:31\n    │\n305 │             if (b.markValue > maxMark) maxMark = b.markValue;\n    │                               ━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/GoblinGacha.sol:297:17\n    │\n297 │             if (b.markedAt + MARK_MAX_AGE < block.timestamp) continue;\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/GoblinGacha.sol:294:26\n    │\n294 │             uint256 id = BAGS.pooledAt(i);\n    │                          ━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/GoblinGacha.sol:295:40\n    │\n295 │             IGoblinBags.Bag memory b = BAGS.bagOf(id);\n    │                                        ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-loop\n\nwarning[calls-loop]: external call inside a loop\n    ╭▸ src/GoblinGacha.sol:296:29\n    │\n296 │             if (b.locked || BAGS.tokenPaused(b.token)) continue;\n    │                             ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/calls-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/GoblinGacha.sol:336:13\n    │\n336 │             emit GenesisPaid(spinner, tier, paid);\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/GoblinGacha.sol:359:9\n    │\n359 │         emit Drawn(spinner, bagId, tier, value);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/GoblinGacha.sol:357:58\n    │\n357 │         pendings[bagId] = Pending(spinner, bagId, value, uint64(block.timestamp + DECISION_WINDOW));\n    │                                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/GoblinGacha.sol:365:13\n    │\n365 │             acc += o[i];\n    │             ━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/GoblinGacha.sol:396:13\n    │\n396 │         if (block.timestamp < p.deadline) revert TooSoon();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/GoblinGacha.sol:407:9\n    │\n407 │         emit Kept(p.bagId, depositor, pay);\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/GoblinGacha.sol:421:9\n    │\n421 │         emit SoldBack(bagId, p.spinner, pay);\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/GoblinGacha.sol:431:13\n    │\n431 │         if (block.timestamp < _active.requestedAt + ABANDON_AFTER) revert TooSoon();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/GoblinGacha.sol:478:9\n    │\n478 │         emit Flushed(n, p, t);\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/GoblinGacha.sol:490:9\n    │\n490 │         emit Burned(eth, got);\n    │         ━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[arbitrary-send-eth]: ETH is sent to a user-controlled destination; restrict the destination or the caller\n    ╭▸ src/GoblinGacha.sol:494:22\n    │\n494 │         (bool ok,) = to.call{value: amount}(\"\");\n    │                      ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/arbitrary-send-eth\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GoblinGacha.t.sol:289:24\n    │\n289 │         uint256 now_ = block.timestamp;\n    │                        ━━━━━━━━━━━━━━━\n    ‡\n302 │         vm.warp(now_ + 2 hours);\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.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GoblinGacha.t.sol:406:17\n    │\n406 │         vm.warp(block.timestamp + 10 days);\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.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GoblinGacha.t.sol:438:17\n    │\n438 │         vm.warp(block.timestamp + 24 hours);\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.timestamp` may be reused across `vm.warp`\n    ╭▸ test/GoblinGacha.t.sol:444:17\n    │\n444 │         vm.warp(block.timestamp + 10 days);\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\n","passed":true},{"durationMs":1062,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Deploy.t.sol:DeployTest\n[PASS] test_deployWordsArePinnedCodeHashes() (gas: 12216407)\nLogs:\n  GACHA_CODE_HASH: 0x26aad0a61f3b066fc1db60c882934794cbf236b31f7828831d22ba8fa5d722ba\n  POL_CODE_HASH: 0x8401aba2212256892b02e6c3504c47f3fc37ae7d7252b1191d7c68adaf3f09da\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 962.84µs (623.90µs CPU time)\n\nRan 24 tests for test/GoblinGacha.t.sol:GoblinGachaTest\n[PASS] testFuzz_genesisQuoteNeverExceedsOracleOrRoom(uint16,uint32) (runs: 256, μ: 175692, ~: 175642)\n[PASS] test_abandonAfterSevenDaysWithoutWord() (gas: 981442)\n[PASS] test_abandonImpossibleOnceWordArrived() (gas: 900531)\n[PASS] test_curatorBounds() (gas: 687528)\n[PASS] test_curatorRejectsBadSignatureReplayAndStale() (gas: 210393)\n[PASS] test_depositMarksAndPools() (gas: 388611)\n[PASS] test_depositUnlistedReverts() (gas: 37093)\n[PASS] test_dividendConservation() (gas: 1781965)\n[PASS] test_fixture() (gas: 41652)\n[PASS] test_fullSpinKeepFlow() (gas: 1549498)\n[PASS] test_gasReport() (gas: 1149615)\nLogs:\n  gas deposit: 357884\n  gas spin (1 bag): 436462\n  gas settle: 184741\n  gas keep: 143329\n\n[PASS] test_genesisCurveBounds() (gas: 487384)\n[PASS] test_genesisHolderWindowFreeSpinsAndCaps() (gas: 2514504)\n[PASS] test_jackpotDisabledUntilReserveCovers() (gas: 1023407)\n[PASS] test_onlySpinnerDecidesAndFinalizeAfterWindow() (gas: 1211839)\n[PASS] test_quoteRevertsWithoutDepth() (gas: 453414)\n[PASS] test_sellBackReturnsBagToPool() (gas: 1174017)\n[PASS] test_snapshotCommittedBeforeRandomness() (gas: 1426681)\n[PASS] test_solvencyFloorBlocksSpins() (gas: 69106319)\n[PASS] test_spinRequiresEligibleBagAndExactPayment() (gas: 180579)\n[PASS] test_splitsAndFlush() (gas: 1229871)\n[PASS] test_staleMarkPausedAndOversizedBagsExcluded() (gas: 1482144)\n[PASS] test_vaultPayoutOnlyGachaOrBags() (gas: 153614)\n[PASS] test_withdrawAndOpenReturnTokens() (gas: 536277)\nSuite result: ok. 24 passed; 0 failed; 0 skipped; finished in 516.72ms (154.11ms CPU time)\n\nRan 32 tests for test/GoblinNFT.t.sol:GoblinNFTTest\n[PASS] testFuzz_mintQuantityWithinCap(uint8) (runs: 256, μ: 494460, ~: 392628)\n[PASS] testFuzz_revenueConservation(uint96,uint96,uint8) (runs: 256, μ: 757430, ~: 710710)\n[PASS] testFuzz_traitsAreInRange(bytes32) (runs: 256, μ: 6077, ~: 6287)\n[PASS] test_bindAndReleaseSplits() (gas: 564514594)\n[PASS] test_bindOnlyOnce() (gas: 564283897)\n[PASS] test_bindRejectsWalletAndImpostorCode() (gas: 563129662)\n[PASS] test_bindRequiresSellout() (gas: 34190)\n[PASS] test_claimNothingReverts() (gas: 213292)\n[PASS] test_constructorIsStaticAndFactoryIsDeployer() (gas: 46601)\n[PASS] test_escrowNeverPaysAWallet() (gas: 48891)\n[PASS] test_gasReport() (gas: 374080)\nLogs:\n  gas mint(1): 178017\n  gas claim: 62877\n  gas refund: 58191\n\n[PASS] test_mintAfterRevenueDoesNotBackdate() (gas: 443731)\n[PASS] test_mintHappyPath() (gas: 326569)\n[PASS] test_mintRevertsOnWrongPayment() (gas: 97685)\n[PASS] test_noRefundAfterRelease() (gas: 564485812)\n[PASS] test_notifyRevenueWithNoHoldersIsKeptAsDust() (gas: 334743)\n[PASS] test_rarityDistributionRoughly() (gas: 51188750)\n[PASS] test_refundBeforeSelloutReturnsPriceAndBurns() (gas: 310605)\n[PASS] test_refundIsReentrancySafe() (gas: 790186)\n[PASS] test_refundOnlyByHolder() (gas: 212703)\n[PASS] test_refundReopensAfterNinetyDaysWithoutRelease() (gas: 558787427)\n[PASS] test_refundThenSelloutCountsLiveSupply() (gas: 558876729)\n[PASS] test_releaseAfterNinetyDaysImpossibleAndRefundsStayOpen() (gas: 564287412)\n[PASS] test_releaseRequiresBindAndWindow() (gas: 564306634)\n[PASS] test_revealFallbackAfter256Blocks() (gas: 258457)\n[PASS] test_revealFutureBlockReverts() (gas: 32400)\n[PASS] test_revenueAccruesPerTokenAndMovesWithTransfer() (gas: 745560)\n[PASS] test_revenueNeverTouchesEscrow() (gas: 455700)\n[PASS] test_runtimeSizeWithinEip170() (gas: 5057)\n[PASS] test_selloutClosesMintAndRefunds() (gas: 558747750)\n[PASS] test_tokenURIUnrevealedThenRevealed() (gas: 855952)\n[PASS] test_walletCapIsTwentyMintsAndDoesNotResetOnRefund() (gas: 1317703)\nSuite result: ok. 32 passed; 0 failed; 0 skipped; finished in 577.47ms (4.46s CPU time)\n\nRan 1 test for test/GachaInvariant.t.sol:GachaInvariantTest\n[PASS]\nGachaInvariantTest invariants:\n[PASS] invariant_bagsBacked\n[PASS] invariant_ethConservation\n[PASS] invariant_reserveCoversCommitted\n[PASS] invariant_singleDraw\n GachaInvariantTest invariants (runs: 64, calls: 2048, reverts: 0)\n\n╭--------------+-------------+-------+---------+----------╮\n| Contract     | Selector    | Calls | Reverts | Discards |\n+=========================================================+\n| GachaHandler | decide      | 255   | 0       | 0        |\n|--------------+-------------+-------+---------+----------|\n| GachaHandler | deposit     | 260   | 0       | 0        |\n|--------------+-------------+-------+---------+----------|\n| GachaHandler | flush       | 249   | 0       | 0        |\n|--------------+-------------+-------+---------+----------|\n| GachaHandler | fulfill     | 256   | 0       | 0        |\n|--------------+-------------+-------+---------+----------|\n| GachaHandler | settle      | 222   | 0       | 0        |\n|--------------+-------------+-------+---------+----------|\n| GachaHandler | spin        | 536   | 0       | 0        |\n|--------------+-------------+-------+---------+----------|\n| GachaHandler | warpAbandon | 270   | 0       | 0        |\n╰--------------+-------------+-------+---------+----------╯\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 886.38ms (279.20ms CPU time)\n\nRan 4 test suites in 889.33ms (1.98s CPU time): 58 tests passed, 0 failed, 0 skipped (58 total tests)\n","passed":true},{"durationMs":55,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"GenesisVault.payout(address,uint256)\",\"GenesisVault.setPricingPool(address)\",\"GenesisVault.start()\",\"GoblinBags.approve(address,uint256)\",\"GoblinBags.claimDividends(uint256)\",\"GoblinBags.deposit(address,uint256)\",\"GoblinBags.lock(uint256,bool)\",\"GoblinBags.mark(uint256)\",\"GoblinBags.open(uint256)\",\"GoblinBags.poke(uint256)\",\"GoblinBags.safeTransferFrom(address,address,uint256)\",\"GoblinBags.safeTransferFrom(address,address,uint256,bytes)\",\"GoblinBags.setApprovalForAll(address,bool)\",\"GoblinBags.setListing(address,address,bool)\",\"GoblinBags.setPaused(address,bool)\",\"GoblinBags.transferFrom(address,address,uint256)\",\"GoblinBags.transferToWinner(uint256,address)\",\"GoblinBags.withdraw(uint256)\",\"GoblinCurator.apply_(bytes32,bytes,uint256,uint256,bytes)\",\"GoblinGacha.abandon()\",\"GoblinGacha.buyAndBurn(address,uint256)\",\"GoblinGacha.finalize(uint256)\",\"GoblinGacha.flush()\",\"GoblinGacha.fundReserve()\",\"GoblinGacha.fundVrf()\",\"GoblinGacha.keep(uint256)\",\"GoblinGacha.rawFulfillRandomWords(uint256,uint256[])\",\"GoblinGacha.sellBack(uint256)\",\"GoblinGacha.setGenesisDiscount(uint16)\",\"GoblinGacha.setOdds(uint16[4])\",\"GoblinGacha.setVrfFee(uint256)\",\"GoblinGacha.settle()\",\"GoblinGacha.spin()\",\"GoblinGacha.spinGenesis(uint256)\",\"GoblinGold.approve(address,uint256)\",\"GoblinGold.transfer(address,uint256)\",\"GoblinGold.transferFrom(address,address,uint256)\",\"GoblinNFT.approve(address,uint256)\",\"GoblinNFT.bind(bytes32,bytes,bytes,bytes32,bytes,bytes)\",\"GoblinNFT.claim(uint256)\",\"GoblinNFT.mint(uint256)\",\"GoblinNFT.notifyRevenue()\",\"GoblinNFT.refund(uint256)\",\"GoblinNFT.release()\",\"GoblinNFT.reveal(uint256)\",\"GoblinNFT.safeTransferFrom(address,address,uint256)\",\"GoblinNFT.safeTransferFrom(address,address,uint256,bytes)\",\"GoblinNFT.setApprovalForAll(address,bool)\",\"GoblinNFT.transferFrom(address,address,uint256)\",\"GoblinPOL.collectFees()\",\"GoblinPOL.deployLiquidity()\",\"GoblinPOL.fundPol()\",\"GoblinPOL.receive()\"],\"files\":{\".gitignore\":5,\"README.md\":21,\"foundry.toml\":33,\"remappings.txt\":2,\"report.md\":197,\"script/DeployGoblinNFT.s.sol\":29,\"src/GenesisVault.sol\":124,\"src/GoblinArt.sol\":244,\"src/GoblinBags.sol\":250,\"src/GoblinCurator.sol\":84,\"src/GoblinGacha.sol\":510,\"src/GoblinGold.sol\":16,\"src/GoblinNFT.sol\":294,\"src/GoblinPOL.sol\":126,\"src/interfaces/External.sol\":96,\"src/interfaces/IGoblin.sol\":53,\"src/libraries/TickMath.sol\":41,\"src/libraries/TwapLib.sol\":48,\"test-fork/Mainnet.fork.t.sol\":54,\"test/Deploy.t.sol\":23,\"test/GachaBase.t.sol\":150,\"test/GachaInvariant.t.sol\":143,\"test/GoblinGacha.t.sol\":485,\"test/GoblinNFT.t.sol\":508,\"test/mocks/Mocks.sol\":149},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":4717,"exitCode":0,"name":"slither","output":"[high/medium] arbitrary-send-eth at src/GoblinGacha.sol:493: GoblinGacha._send(address,uint256) (src/GoblinGacha.sol#493-496) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/GoblinPOL.sol:96: GoblinPOL.collectFees() (src/GoblinPOL.sol#96-117) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/GoblinPOL.sol:68: GoblinPOL.deployLiquidity() (src/GoblinPOL.sol#68-93) sends eth to arbitrary user\n[high/medium] arbitrary-send-eth at src/GoblinNFT.sol:186: GoblinNFT.release() (src/GoblinNFT.sol#186-199) sends eth to arbitrary user\n[high/medium] weak-prng at src/GoblinGacha.sol:322: GoblinGacha.settle() (src/GoblinGacha.sol#322-360) uses a weak PRNG: \"bagId = ids[uint256(keccak256(bytes)(abi.encode(word,uint8(2)))) % ids.length] (src/GoblinGacha.sol#350)\"\n[high/medium] weak-prng at src/GoblinGacha.sol:322: GoblinGacha.settle() (src/GoblinGacha.sol#322-360) uses a weak PRNG: \"mult = lo + (uint256(keccak256(bytes)(abi.encode(word,uint8(1)))) % (hi - lo)) (src/GoblinGacha.sol#332)\"\n[high/medium] weak-prng at src/GoblinGacha.sol:322: GoblinGacha.settle() (src/GoblinGacha.sol#322-360) uses a weak PRNG: \"tier = _drawTier(word % 10_000,_active.odds) (src/GoblinGacha.sol#327)\"\n[high/high] encode-packed-collision at src/GoblinNFT.sol:172: GoblinNFT._prove(bytes32,bytes32,bytes,bytes) (src/GoblinNFT.sol#172-182) calls abi.encodePacked() with multiple dynamic arguments:\n[medium/medium] divide-before-multiply at src/libraries/TickMath.sol:9: TickMath.getSqrtRatioAtTick(int24) (src/libraries/TickMath.sol#9-40) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/GoblinPOL.sol:68: GoblinPOL.deployLiquidity() (src/GoblinPOL.sol#68-93) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/GenesisVault.sol:101: GenesisVault.payout(address,uint256) (src/GenesisVault.sol#101-123) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/GoblinNFT.sol:155: GoblinNFT.bind(bytes32,bytes,bytes,bytes32,bytes,bytes) (src/GoblinNFT.sol#155-170) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/GenesisVault.sol:101: GenesisVault.payout(address,uint256) (src/GenesisVault.sol#101-123) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/GoblinNFT.sol:100: GoblinNFT.refundsOpen() (src/GoblinNFT.sol#100-103) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/GenesisVault.sol:68: GenesisVault._elapsed() (src/GenesisVault.sol#68-72) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/GenesisVault.sol:87: GenesisVault.quoteTokensPerBag(uint256) (src/GenesisVault.sol#87-98) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/GoblinBags.sol:208: Reentrancy in GoblinBags.poke(uint256) (src/GoblinBags.sol#208-222):\n[medium/medium] uninitialized-local at src/GoblinPOL.sol:97: GoblinPOL.collectFees().ethFees (src/GoblinPOL.sol#97) is a local variable never initialized\n[medium/medium] uninitialized-local at src/GoblinGacha.sol:174: GoblinGacha.setOdds(uint16[4]).sum (src/GoblinGacha.sol#174) is a local variable never initialized\n[medium/medium] uninitialized-local at src/GoblinGacha.sol:363: GoblinGacha._drawTier(uint256,uint16[4]).acc (src/GoblinGacha.sol#363) is a local variable never initialized\n[medium/medium] uninitialized-local at src/GoblinGacha.sol:291: GoblinGacha._snapshot().maxMark (src/GoblinGacha.sol#291) is a local variable never initialized\n[medium/medium] uninitialized-local at src/GoblinPOL.sol:98: GoblinPOL.collectFees().ggFees (src/GoblinPOL.sol#98) is a local variable never initialized\n[medium/medium] uninitialized-local at src/GoblinGacha.sol:292: GoblinGacha._snapshot().count (src/GoblinGacha.sol#292) is a local variable never initialized\n[medium/medium] unused-return at src/GoblinPOL.sol:68: GoblinPOL.deployLiquidity() (src/GoblinPOL.sol#68-93) ignores return value by (id,None,None,None) = PM.mint(INonfungiblePositionManager.MintParams(t0,t1,FEE,- FULL_RANGE,FULL_RANGE,a0,a1,0,0,address(this),block.timestamp)) (src/GoblinPOL.sol#86-90)\n[medium/medium] unused-return at src/libraries/TwapLib.sol:21: TwapLib.twapPrice(address,address,uint32) (src/libraries/TwapLib.sol#21-40) ignores return value by (cum,None) = IUniswapV3Pool(pool).observe(ago) (src/libraries/TwapLib.sol#25)\n[medium/medium] unused-return at src/GoblinCurator.sol:53: GoblinCurator.apply_(bytes32,bytes,uint256,uint256,bytes) (src/GoblinCurator.sol#53-83) ignores return value by (signer,err,None) = digest(question,payload,issuedAt,nonce).tryRecover(sig) (src/GoblinCurator.sol#58)\n[low/medium] events-maths at src/GoblinGacha.sol:192: GoblinGacha.setVrfFee(uint256) (src/GoblinGacha.sol#192-196) should emit an event for: \n[low/medium] missing-zero-check at src/GoblinCurator.sol:37: GoblinCurator.constructor(address,address).attester (src/GoblinCurator.sol#37) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GoblinPOL.sol:44: GoblinPOL.constructor(address,address,address,uint24,address,address,address).weth (src/GoblinPOL.sol#44) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GoblinPOL.sol:44: GoblinPOL.constructor(address,address,address,uint24,address,address,address).token (src/GoblinPOL.sol#44) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GenesisVault.sol:62: GenesisVault.setPricingPool(address).pool (src/GenesisVault.sol#62) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GoblinGacha.sol:136: GoblinGacha.constructor(address,address,address,address,address,address,bytes32,uint24).curator_ (src/GoblinGacha.sol#136) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GenesisVault.sol:46: GenesisVault.constructor(address,address,address,address).curator (src/GenesisVault.sol#46) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GenesisVault.sol:46: GenesisVault.constructor(address,address,address,address).weth (src/GenesisVault.sol#46) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GoblinGacha.sol:137: GoblinGacha.constructor(address,address,address,address,address,address,bytes32,uint24).team (src/GoblinGacha.sol#137) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GoblinBags.sol:71: GoblinBags.constructor(address,address,address,address).weth (src/GoblinBags.sol#71) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GenesisVault.sol:46: GenesisVault.constructor(address,address,address,address).token (src/GenesisVault.sol#46) lacks a zero-check on :\n[low/medium] missing-zero-check at src/GoblinBags.sol:71: GoblinBags.constructor(address,address,address,address).curator (src/GoblinBags.sol#71) lacks a zero-check on :\n[low/medium] calls-loop at src/GoblinGacha.sol:286: GoblinGacha._snapshot() (src/GoblinGacha.sol#286-310) has external calls inside a loop: b = BAGS.bagOf(id) (src/GoblinGacha.sol#295)\n[low/medium] calls-loop at src/GoblinPOL.sol:96: GoblinPOL.collectFees() (src/GoblinPOL.sol#96-117) has external calls inside a loop: (a0,a1) = PM.collect(INonfungiblePositionManager.CollectParams(positions[i],address(this),type()(uint128).max,type()(uint128).max)) (src/GoblinPOL.sol#100-104)\n[low/medium] calls-loop at src/GoblinGacha.sol:286: GoblinGacha._snapshot() (src/GoblinGacha.sol#286-310) has external calls inside a loop: b.locked || BAGS.tokenPaused(b.token) (src/GoblinGacha.sol#296)\n[low/medium] calls-loop at src/GoblinGacha.sol:286: GoblinGacha._snapshot() (src/GoblinGacha.sol#286-310) has external calls inside a loop: id = BAGS.pooledAt(i) (src/GoblinGacha.sol#294)\n[low/medium] reentrancy-benign at src/GoblinPOL.sol:68: Reentrancy in GoblinPOL.deployLiquidity() (src/GoblinPOL.sol#68-93):\n[low/medium] reentrancy-benign at src/GoblinGacha.sol:258: Reentrancy in GoblinGacha._request(address,bool,uint256,uint256) (src/GoblinGacha.sol#258-282):\n[low/medium] reentrancy-benign at src/GoblinBags.sol:231: Reentrancy in GoblinBags._settleDividends(uint256,address) (src/GoblinBags.sol#231-237):\n[low/medium] reentrancy-benign at src/GoblinBags.sol:198: Reentrancy in GoblinBags._pull() (src/GoblinBags.sol#198-205):\n[low/medium] reentrancy-events at src/GoblinGacha.sol:322: Reentrancy in GoblinGacha.settle() (src/GoblinGacha.sol#322-360):\n[low/medium] reentrancy-events at src/GoblinGacha.sol:412: Reentrancy in GoblinGacha.sellBack(uint256) (src/GoblinGacha.sol#412-423):\n[low/medium] reentrancy-events at src/GoblinGacha.sol:482: Reentrancy in GoblinGacha.buyAndBurn(address,uint256) (src/GoblinGacha.sol#482-491):\n[low/medium] reentrancy-events at src/GoblinGacha.sol:400: Reentrancy in GoblinGacha._keep(GoblinGacha.Pending) (src/GoblinGacha.sol#400-409):\n[low/medium] reentrancy-events at src/GoblinGacha.sol:322: Reentrancy in GoblinGacha.settle() (src/GoblinGacha.sol#322-360):\n[low/medium] reentrancy-events at src/GoblinPOL.sol:96: Reentrancy in GoblinPOL.collectFees() (src/GoblinPOL.sol#96-117):\n[low/medium] reentrancy-events at src/GoblinBags.sol:208: Reentrancy in GoblinBags.poke(uint256) (src/GoblinBags.sol#208-222):\n[low/medium] reentrancy-events at src/GoblinPOL.sol:68: Reentrancy in GoblinPOL.deployLiquidity() (src/GoblinPOL.sol#68-93):\n[low/medium] reentrancy-events at src/GoblinCurator.sol:53: Reentrancy in GoblinCurator.apply_(bytes32,bytes,uint256,uint256,bytes) (src/GoblinCurator.sol#53-83):\n[low/medium] reentrancy-events at src/GoblinGacha.sol:258: Reentrancy in GoblinGacha._request(address,bool,uint256,uint256) (src/GoblinGacha.sol#258-282):\n[low/medium] reentrancy-events at src/GoblinGacha.sol:157: Reentrancy in GoblinGacha.fundVrf() (src/GoblinGacha.sol#157-161):\n[low/medium] reentrancy-events at src/GoblinGacha.sol:468: Reentrancy in GoblinGacha.flush() (src/GoblinGacha.sol#468-479):\n[low/medium] timestamp at src/GoblinGacha.sol:171: GoblinGacha.setOdds(uint16[4]) (src/GoblinGacha.sol#171-184) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:234: GoblinGacha.spinGenesis(uint256) (src/GoblinGacha.sol#234-256) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:286: GoblinGacha._snapshot() (src/GoblinGacha.sol#286-310) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:427: GoblinGacha.abandon() (src/GoblinGacha.sol#427-443) uses timestamp for comparisons\n[low/medium] timestamp at src/GenesisVault.sol:101: GenesisVault.payout(address,uint256) (src/GenesisVault.sol#101-123) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:393: GoblinGacha.finalize(uint256) (src/GoblinGacha.sol#393-398) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:362: GoblinGacha._drawTier(uint256,uint16[4]) (src/GoblinGacha.sol#362-369) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinCurator.sol:53: GoblinCurator.apply_(bytes32,bytes,uint256,uint256,bytes) (src/GoblinCurator.sol#53-83) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinPOL.sol:96: GoblinPOL.collectFees() (src/GoblinPOL.sol#96-117) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinBags.sol:208: GoblinBags.poke(uint256) (src/GoblinBags.sol#208-222) uses timestamp for comparisons\n[low/medium] timestamp at src/GenesisVault.sol:54: GenesisVault.start() (src/GenesisVault.sol#54-60) uses timestamp for comparisons\n[low/medium] timestamp at src/GenesisVault.sol:87: GenesisVault.quoteTokensPerBag(uint256) (src/GenesisVault.sol#87-98) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinNFT.sol:95: GoblinNFT.soldOut() (src/GoblinNFT.sol#95-97) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:221: GoblinGacha.spin() (src/GoblinGacha.sol#221-229) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:199: GoblinGacha.freeReserve() (src/GoblinGacha.sol#199-201) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:313: GoblinGacha.rawFulfillRandomWords(uint256,uint256[]) (src/GoblinGacha.sol#313-319) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:385: GoblinGacha.keep(uint256) (src/GoblinGacha.sol#385-390) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinNFT.sol:116: GoblinNFT.mint(uint256) (src/GoblinNFT.sol#116-136) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:215: GoblinGacha.jackpotEnabled() (src/GoblinGacha.sol#215-217) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinNFT.sol:100: GoblinNFT.refundsOpen() (src/GoblinNFT.sol#100-103) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinNFT.sol:155: GoblinNFT.bind(bytes32,bytes,bytes,bytes32,bytes,bytes) (src/GoblinNFT.sol#155-170) uses timestamp for comparisons\n[low/medium] timestamp at src/GenesisVault.sol:79: GenesisVault.scheduleRoom() (src/GenesisVault.sol#79-84) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinNFT.sol:186: GoblinNFT.release() (src/GoblinNFT.sol#186-199) uses timestamp for comparisons\n[low/medium] timestamp at src/GoblinGacha.sol:412: GoblinGacha.sellBack(uint256) (src/GoblinGacha.sol#412-423) uses timestamp for comparisons\n[low/medium] timestamp at src/GenesisVault.sol:68: GenesisVault._elapsed() (src/GenesisVault.sol#68-72) uses timestamp for comparisons","passed":false}],"detail":"static analysis found encode-packed-collision at src/GoblinNFT.sol:172: GoblinNFT._prove(bytes32,bytes32,bytes,bytes) (src/GoblinNFT.sol#172-182) calls abi.encodePacked() with multiple dynamic arguments:","evaluation":"checks","profile":"foundry","status":"rejected","submissionHash":"85a5163c04c22bcb202402eb97ed038c5bb916b497afb133616e7f1be3bb7d21","verifiedTreeHash":"b73d4d4be0fe673ed12bcbefb4e1d676f8798ee0","verifierVersion":"0.1.0+327e1e9f"}]}