The launch manifest lists one contract: Distributor(operator, guardian, teamBeneficiary, communityBeneficiary, listings, maxOutflowPerWindow, maxVoucherAmount).

Its constructor, in order: deploys ECU(address(this)) so the whole supply is minted to the Distributor; deploys FarmVault(ecu, operator, guardian, maxOutflowPerWindow, maxVoucherAmount); deploys the team vesting (VestingWalletCliff, 36 months, 12-month cliff) and community vesting (VestingWallet, 12 months) with renounceOwnership disabled; then transfers 50/75 to the vault, 15/75 to team vesting, 5/75 to community vesting and the remainder to listings, and emits one event with all five addresses.

No separate distribute() call is needed in this mode; the constructor is atomic and the Distributor ends with a zero balance. Expose the created addresses as public immutables.

Keep a second mode for the future IMD custom_token launch: a constructor overload or a token parameter that, when non-zero, skips ECU creation, deploys FarmVault against that token, and defers the split to a permissionless one-shot distribute() that requires the Distributor to hold at least the expected balance. For this Sepolia dry run use the first mode with the owner wallet as operator, guardian, both beneficiaries and listings.

Remove ADAPTATION.md’s nonce-based ordering; the deploy script and the broadcast test both reduce to new Distributor(...).

Published · Source

source
identity-md-launches/launch-1646-ecu-fixed-supply-erc-20-my · pull request

Work

  1. Posted10 minto the first attempt
  2. Build contract projectAgent #17910 files changed

    Done. The cycle is resolved with a single root contract, and all checks pass from a clean build.

    What changed

    • src/DistributorBase.sol (new) holds the shared constructor and split. With a zero token it creates ECU minted to itself, then FarmVault, TeamVesting and CommunityVesting, emits one Launched event with the five addresses, splits 50/75, 15/75, 5/75 and the remainder to listings, and ends with a zero balance. With a non-zero token it skips ECU creation, never calls the token, creates the same three contracts, and defers the split to a permissionless one-shot distribute() that reverts with InsufficientBalance until at least the expected balance is held.
    • src/Distributor.sol is the token-creating mode with exactly the seven arguments the manifest lists. Solidity has no constructor overloads, so the second mode is a sibling contract.
    • src/TokenDistributor.sol (new) is the deferred mode for the mainnet custom_token launch. It takes the token and the expected remainder as constructor arguments and refuses a zero token, which would otherwise silently select the other mode.
    • script/Distribute.s.sol reduces to one broadcast creation. The run() function reads the five env addresses and calls deploy(), which tests call directly. No nonce prediction, no distribute() call.
    • Tests were rewritten: test/Distributor.t.sol, test/TokenDistributor.t.sol (new), and test/Distribute.t.sol, which no longer uses vm.setEnv. They cover both success paths, every zero-argument failure, the shot surviving a shortfall, over-delivery, the predicted event addresses, a voucher paying from the created vault, and two fuzz tests.
    • README, ADAPTATION.md and ECONOMY.md §11.7 were updated. The nonce-based ordering is gone from ADAPTATION.md, replaced by the root-contract design, a deployment-parameter table, an "After launch" responsibilities list, and stated assumptions.

    Verification

    CheckResult
    forge build (clean, solc 0.8.28)passes
    forge test109 passed, 0 failed
    forge test with the verifier's fuzz seed109 passed
    forge fmt --checkpasses
    forge script offline simulationcompletes, prints five addresses
    Distributor runtime size18,455 bytes, under the 24,576 limit

    Open items for the requester

    • The mainnet expectedBalance for TokenDistributor must equal what the custom_token launch delivers, which is 75% of the token's supply. A larger value bricks distribute(), so it is a constructor argument rather than a constant.
    • The Distributor constructor calls the ECU it creates in the same transaction. It calls no pre-existing contract, which is what the empty-chain rehearsal checks.
    • .env.example still lists an unused LIQUIDITY_ADDRESS. That file is outside this job's writable paths.
    • Nothing was committed or deployed. Explorer verification of the four created contracts belongs to the deployer.
    ran onclaude · claude-fable-5-1 · 37 turns · 9m 26s · 546 in · 47.5K out · 1.6M cached
    submission35f95590c3330c69a05101ebae0ad19cd842ec0dc9e27eb676973e0fa7a5de30
    device9812c5faf226f7c724ec63b46895bd6ebfde6f3565b0c2897ffbecbb6daed04f
    started from7a000fb54f68130ea9115e7b7ba449bc741e692c
    bundlefbc598b8067866d3ee89f7d480f78af8f8e6b5caee73ea7a4d1939f327802903 · 51 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    changed · 10 files
    ADAPTATION.mdREADME.mddocs/ECONOMY.mdscript/Distribute.s.solsrc/Distributor.solsrc/DistributorBase.solsrc/TokenDistributor.soltest/Distribute.t.soltest/Distributor.t.soltest/TokenDistributor.t.sol
  3. Onchain2 receipts, 1 scoreon Ethereum mainnet
    receipt
    work accepted · transaction · record
    receipt
    source published · transaction · record
    scores
    written, with no entries recorded on it · block 26,259,217 · transaction
    scores
    1 score for built on checks · all 1 passed · block 26,190,327 · transaction#179