Planning job

d8bd07d1submittedscores queued
the whole request

Build and launch a token-gated membership project on Sepolia, end to end: contracts, token and pool, a public GitHub repository, and a website hosted on IPFS.

Contracts (Foundry, with tests and an independent adversarial review):

  • The project token: a fixed-supply ERC-20 whose name and symbol you choose to fit a membership club.
  • A membership badge contract: an ERC-721 where any address holding at least a threshold balance of the token can mint exactly one badge for itself. The threshold is set at deployment. A badge is soulbound (non-transferable). Anyone can check whether an address is currently eligible and whether it holds a badge. If a holder later falls below the threshold the badge stays, but a view reports it as lapsed.
  • Emit events for mints so the site can list members.

Launch: deploy the token and the badge contract as an evm_project on Sepolia and seed the token pool, so the token can be bought to qualify.

Website (static, hosted on IPFS, reading the deployed addresses from the launch handoff): connect a wallet on Sepolia, show the token balance against the threshold, a link to buy the token on the pool, a mint button when eligible, the badge once minted, and a public member list built from mint events with lapsed members marked.

Context and requirements

Sepolia only. Keep contracts small and well tested. The site must work from the IPFS gateway with no backend.

planner instructions · round 2

Read .imd/reads/planning.json and propose the requested workflow in artifacts/plan.json. Do not implement or dispatch the proposed work.

Workflow checks passed and execution was submitted. This page tracks the planning assignment.

Proposed workflow

3 step(s) · round 2

This proposal must pass workflow and requirement checks before it can become an execution job.

Handoff from contracts to review, launch and frontend (Sepolia, chainId 11155111).

Token: fixed-supply ERC-20 (worker picks a membership-club name/symbol), whole supply minted at construction, no mint function afterwards.

Badge: soulbound ERC-721 with constructor(address token, uint256 threshold); threshold is immutable.

Functions: mint() mints exactly one badge to msg.sender when token.balanceOf(msg.sender) >= threshold; isEligible(address) view; hasBadge(address) view; isLapsed(address) view, true when the address holds a badge but its balance is now below threshold; badgeOf(address) view returns the tokenId, or 0 if none; token() and threshold() views. Every transfer or approval path reverts except the mint.

Event: BadgeMinted(address indexed member, uint256 indexed tokenId), alongside the standard ERC-721 Transfer from address(0). ABI JSON in docs/abi/MembershipToken.json and docs/abi/MembershipBadge.json; integration notes in docs/contracts.md. The frontend reads deployed addresses, the pool reference and ABI hashes from the deployment handoff at .imd/reads/deployment.json, never from hardcoded values.

1. contractsbuild contract project

Can start without another proposed step.

Start from the empty tree and create the complete Foundry project. Commit its dependencies (forge-std, OpenZeppelin) as ordinary vendored files with no git submodules. Implement the fixed-supply ERC-20 project token and the soulbound ERC-721 membership badge exactly as described in sharedInterfaces, keeping both contracts small.

Write thorough Foundry tests. Export ABI JSON to docs/abi/ and write docs/contracts.md covering constructor parameters, the eligibility and lapsed semantics, and the event the site uses to list members. Deployment on Sepolia, pool seeding and publication belong to the control plane's evm_project launch; do not deploy.

Acceptance criteria

  • forge build and forge test pass offline using only committed files, with no submodules

  • The token has a fixed supply minted once at construction and cannot be minted again

  • The badge allows one mint per address and only when balance >= the threshold set at deployment; a second mint and a mint below the threshold both revert

  • Every transfer and approval path on the badge reverts; tests prove the badge stays after the holder's balance falls below the threshold and isLapsed then reports true

  • isEligible, hasBadge and isLapsed are public views, and each mint emits BadgeMinted(member, tokenId)

  • docs/abi/MembershipToken.json, docs/abi/MembershipBadge.json and docs/contracts.md match the compiled contracts

File scope: src/**, test/**, script/**, lib/**, foundry.toml, remappings.txt, .gitignore, README.md, docs/abi/**, docs/contracts.md

2. reviewadversarial review

After: contracts

Final independent review of the launch, run after the control plane generates the launch manifest and before deployment. Review the token and badge contracts and their tests as an attacker would, independently of the writer: mint bypasses, double mints, soulbound bypasses (transferFrom, safeTransferFrom, approve, setApprovalForAll), wrong eligibility or lapsed logic, and supply inflation.

Finish by inspecting the source, docs/abi, docs/contracts.md and the generated launch manifest (Sepolia evm_project, token and badge constructor arguments, pool seeding) for consistency. Write nothing.

Acceptance criteria

  • Findings cite the specific functions and the tests that cover them, or name the tests that are missing

  • The review confirms the ABI JSON, docs/contracts.md and the generated launch manifest are consistent with the source and target Sepolia (chainId 11155111)

  • It gives a clear blocking/non-blocking verdict for the launch

3. frontendfrontend for contract

After: review

After deployment, build a static Vite and React site under web/ with its export at repository-root dist/. It must work from an IPFS gateway with no backend: relative asset paths and hash routing. Read contract addresses, the pool reference and ABIs from the deployment handoff (.imd/reads/deployment.json) and docs/abi/.

Features: connect a wallet and require Sepolia; show the connected token balance against the threshold; link to buy the token on the seeded pool; show a mint button only when the connected address is eligible and has no badge; show the badge once minted; show a public member list built from BadgeMinted events read over RPC, marking lapsed members via isLapsed.

Acceptance criteria

  • The site builds to dist/ and loads from a gateway subpath with no backend or server routes

  • Addresses and ABIs come from the deployment handoff and docs/abi, with nothing hardcoded that deviates from them

  • It prompts a network switch when the wallet is not on chainId 11155111

  • Tests cover the eligibility and mint-button states, the badge display, and building the member list from mint events with lapsed marking

File scope: web/**, web/.gitignore, dist/**, docs/web/**

Work

  1. postedunder a minuteto the first attempt
  2. plan proposedWorkflow planner
    Workflow planneraccepted
    writes toartifacts/plan.json
    #1943

    I wrote artifacts/plan.json. It passes the planning schema check.

    The feedback asked for a final independent review after the launch manifest. The revised plan keeps the same three worker steps and makes that review step the final one. The control plane adds the launch manifest, so the plan has four steps in total.

    1. contracts (build-contract-project): sets up the empty repository as a Foundry project, with its dependencies committed as ordinary files and no submodules. It builds the fixed-supply membership token and the soulbound badge. The badge has one mint per address, a threshold set at deployment, the isEligible, hasBadge and isLapsed checks, and a BadgeMinted event. This step also writes the tests, the ABI files in docs/abi/ and docs/contracts.md. It does not deploy anything.
    2. review (adversarial-review, depends on contracts): now explicitly the final independent launch review. It runs after the launch manifest is generated and before deployment. It looks for ways to get around the mint and threshold rules, to transfer a badge, or to create extra tokens. It checks that the source, the ABIs, the docs and the manifest match each other and target Sepolia (including the token pool seeding), and gives a blocking or non-blocking verdict. It writes nothing.
    3. frontend (frontend-for-contract, depends on review): the last worker step, which starts after deployment. It builds a static site under web/ and exports it to dist/, and it works from an IPFS gateway with no backend. It reads addresses and ABIs from the deployment handoff rather than hardcoding them. It includes all the requested features: wallet connection on Sepolia, balance against the threshold, a link to buy on the pool, the mint button, the badge display, and the member list with lapsed members marked.

    The plan keeps the full request, the Sepolia-only and IPFS/GitHub permissions, and the rule that the control plane handles deployment, pool seeding and publication. The contracts and frontend write to separate paths, and they share one agreed interface (sharedInterfaces). There are no open questions.

    The feedback's wording ("after the manifest") could also mean the validator wants the review somewhere else. But the planning rules say the frontend must be the final worker step with no review after it, so I kept the order. If the validator rejects this again, that ordering is the likely cause. I left the file untracked, as the output instructions require.

    ran onclaude · claude-opus-5-5 · 3 turns · 46s · 6 in · 4.9K out · 72.3K cached
    submission9202915d056de7ae680c23ce4598494f5b1c682d52dd2fd9abc7f86ec442a505
    device00d95fd75f8b224cbade9810011b337d6448b20f22483c8826ccb3772627a4eb
    started from0243d7da4a4337ae8b16bcdf15bb4ead736fd68f
    bundlefe70ec8c3683fa8ef2fb9913fa1fc5e8c2a986c7234baca696b4dc57c5895101 · 359 bytes
    made · 1 file
    artifacts/plan.json · 5.6 KB
  3. onchain
    1 receipt, 1 score queuedon Ethereum mainnet
    receipt
    work accepted · record queued
    scores
    1 score for built on structural · all 1 passed#1943

Outputs

1 file
planaccepted
fileartifacts/plan.json
typeapplication/json
size5.6 KB

File integrity and allowed paths were checked. Content accuracy and quality were not evaluated.