Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 72 additions & 5 deletions .gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
ClassicMemeLaunchSecurityRegressionTest:testFuzz_launchAcceptsEveryWholePercentAndNothingIsAddedToIt(uint8) (runs: 64, μ: 2905401, ~: 2905499)
ClassicMemeLaunchSecurityRegressionTest:testFuzz_launcherPointOnePercentIsIncludedNotAdded(uint96,uint8) (runs: 1000, μ: 17275, ~: 17371)
ClassicMemeLaunchSecurityRegressionTest:testFuzz_metadataBytesRoundTripThroughOfficialFactory(bytes32,bytes32) (runs: 64, μ: 2973664, ~: 2976152)
ClassicInitialBuyVestingWalletV1Test:test_cliffThenLinearStartsAtZeroAndReachesFullAllocationAtEnd() (gas: 853418)
ClassicInitialBuyVestingWalletV1Test:test_deployOrGetRejectsCodeThatWasNotAuthenticatedByTheFactory() (gas: 28873)
ClassicInitialBuyVestingWalletV1Test:test_factoryAddressAndConfigurationAreDeterministicAndAuthenticated() (gas: 776035)
ClassicInitialBuyVestingWalletV1Test:test_fixedLockReleasesEverythingOnlyAfterTheReleaseDay() (gas: 845889)
ClassicInitialBuyVestingWalletV1Test:test_linearVestingReleasesProRataFromLaunchUntilEnd() (gas: 845973)
ClassicInitialBuyVestingWalletV1Test:test_onlyImmutableBeneficiaryCanReleaseOrAttemptOwnershipChanges() (gas: 807726)
ClassicInitialBuyVestingWalletV1Test:test_rejectsInvalidSchedulesAndUnlockedDeployment() (gas: 31003)
ClassicLaunchPolicyV1Test:test_acceptsEveryPublishedBoundaryAndFiveUnequalAllocations() (gas: 690967)
ClassicLaunchPolicyV1Test:test_rejectsEachMetadataFieldAboveItsPublishedLimit() (gas: 713125)
ClassicLaunchPolicyV1Test:test_rejectsEmptyNameAndSymbol() (gas: 16930)
ClassicLaunchPolicyV1Test:test_rejectsInvalidRewardCountsWalletsSharesAndTotals() (gas: 38862)
ClassicMemeLaunchSecurityRegressionTest:testFuzz_launchAcceptsEveryWholePercentAndNothingIsAddedToIt(uint8) (runs: 64, μ: 2905406, ~: 2905499)
ClassicMemeLaunchSecurityRegressionTest:testFuzz_launcherPointOnePercentIsIncludedNotAdded(uint96,uint8) (runs: 1000, μ: 17279, ~: 17371)
ClassicMemeLaunchSecurityRegressionTest:testFuzz_metadataBytesRoundTripThroughOfficialFactory(bytes32,bytes32) (runs: 64, μ: 2973042, ~: 2976152)
ClassicMemeLaunchSecurityRegressionTest:test_creatorClaimBlocksReceiveReentrancyWithoutBlockingPayout() (gas: 3555280)
ClassicMemeLaunchSecurityRegressionTest:test_exactSupplyIsAccountedForInOneSidedPermanentlyCustodiedPosition() (gas: 3007527)
ClassicMemeLaunchSecurityRegressionTest:test_feeBoundariesLaunchAndRecordExactlyOneAndTenPercent() (gas: 5676952)
Expand All @@ -9,13 +20,37 @@ ClassicMemeLaunchSecurityRegressionTest:test_largerCreatorDevBuyExecutesInFullAn
ClassicMemeLaunchSecurityRegressionTest:test_launchRequiresTheMinimumCreatorDevBuy() (gas: 2926732)
ClassicMemeLaunchSecurityRegressionTest:test_rejectsFeesBelowAboveAndBetweenWholePercentSelections() (gas: 77261)
ClassicMemeLaunchSecurityRegressionTest:test_unregisteredPoolCannotBeClaimedAndPermissionlessClaimCannotRedirect() (gas: 3055701)
ClassicRewardVaultV1InvariantTest:invariant_activeSharesAlwaysTotalOneHundredPercent() (runs: 256, calls: 16384, reverts: 0)
ClassicRewardVaultV1InvariantTest:invariant_allReceivedEthIsClaimableOrAlreadyClaimed() (runs: 256, calls: 16384, reverts: 0)
ClassicRewardVaultV1InvariantTest:invariant_ctoAuthorityAndVaultDependenciesNeverChange() (runs: 256, calls: 16384, reverts: 0)
ClassicRewardVaultV1Test:testFuzz_splitConservationLeavesNoCreatorFeeStranded(uint96,uint16) (runs: 10000, μ: 1758176, ~: 1758353)
ClassicRewardVaultV1Test:test_acceptsSmartAndCounterfactualWalletBeneficiaries() (gas: 1646802)
ClassicRewardVaultV1Test:test_claimCannotCrossPoolVaultBoundaries() (gas: 3280649)
ClassicRewardVaultV1Test:test_ctoAuthorityMovesThroughTwoStepAcceptance() (gas: 1593992)
ClassicRewardVaultV1Test:test_ctoCanReplaceOneAllocationWithFiveUnequalAllocations() (gas: 1691508)
ClassicRewardVaultV1Test:test_ctoReplacesTheCompleteFutureConfigurationWithoutTakingOldRewards() (gas: 1915250)
ClassicRewardVaultV1Test:test_factoryDeploysAtPredictedAddressAndCommitsConfiguration() (gas: 1620987)
ClassicRewardVaultV1Test:test_onlyCtoAuthorityCanReplaceConfigurationAndReferenceCannotBeEmpty() (gas: 1560650)
ClassicRewardVaultV1Test:test_onlyCurrentPayoutWalletCanChangeItself() (gas: 1548297)
ClassicRewardVaultV1Test:test_payoutWalletCanConsolidateWithAnExistingPayoutWallet() (gas: 1706411)
ClassicRewardVaultV1Test:test_payoutWalletChangeMovesOnlyFutureRewardsAndNeedsNoAcceptance() (gas: 1850715)
ClassicRewardVaultV1Test:test_rejectsShareTotalOtherThanTenThousand() (gas: 69623)
ClassicRewardVaultV1Test:test_rejectsZeroAndMoreThanFiveBeneficiaries() (gas: 131122)
ClassicRewardVaultV1Test:test_rejectsZeroDuplicateAndZeroShareBeneficiaries() (gas: 190868)
ClassicRewardVaultV1Test:test_roundingRemainderGoesToFinalBeneficiaryWithoutStrandingCreatorFees() (gas: 1754534)
ClassicRewardVaultV1Test:test_supportsFiveUnequalRewardAllocations() (gas: 1658539)
ClassicV3FeeAccountingInvariantTest:invariant_callbackMaskAndLooseBalancesRemainExact() (runs: 256, calls: 16384, reverts: 0)
ClassicV3FeeAccountingInvariantTest:invariant_claimAndPayoutAccountingIsConserved() (runs: 256, calls: 16384, reverts: 0)
ClassicV3FeeAccountingInvariantTest:invariant_directionalEconomicsNeverChange() (runs: 256, calls: 16384, reverts: 0)
ClassicV3FeeAccountingInvariantTest:invariant_nativeClaimsExactlyCoverAccruedAccounting() (runs: 256, calls: 16384, reverts: 0)
ClassicV3FeeAccountingInvariantTest:invariant_rewardConfigurationNeverChanges() (runs: 256, calls: 16384, reverts: 0)
EthCreatorFeeHookV2InvariantTest:invariant_callbackMaskRemainsExact() (runs: 256, calls: 16384, reverts: 0)
EthCreatorFeeHookV2InvariantTest:invariant_feesNeverAccumulateAsLooseHookBalances() (runs: 256, calls: 16384, reverts: 0)
EthCreatorFeeHookV2InvariantTest:invariant_nativeClaimsAlwaysCoverInternalAccounting() (runs: 256, calls: 16384, reverts: 0)
EthCreatorFeeHookV2InvariantTest:invariant_poolFeeConfigurationNeverChanges() (runs: 256, calls: 16384, reverts: 0)
EthCreatorFeeHookV2InvariantTest:invariant_publicFeeDisclosureNeverChanges() (runs: 256, calls: 16384, reverts: 0)
EthCreatorFeeHookV2Test:testFuzz_exactOutputQuotesPreserveNetAmount(uint96,uint8) (runs: 10000, μ: 17945, ~: 17896)
EthCreatorFeeHookV2Test:testFuzz_grossFeeQuotesSplitTheSelectedTotal(uint96,uint8) (runs: 10000, μ: 16759, ~: 16709)
EthCreatorFeeHookV2Test:testFuzz_exactOutputQuotesPreserveNetAmount(uint96,uint8) (runs: 10000, μ: 17947, ~: 17896)
EthCreatorFeeHookV2Test:testFuzz_grossFeeQuotesSplitTheSelectedTotal(uint96,uint8) (runs: 10000, μ: 16762, ~: 16709)
EthCreatorFeeHookV2Test:test_allFourSwapModesAccrueOnlyNativeClaims() (gas: 501740)
EthCreatorFeeHookV2Test:test_anAlternativePoolDoesNotAccrueHookFees() (gas: 127709)
EthCreatorFeeHookV2Test:test_buyEmitsOpenZeppelinHookFeeAndUrc2HookSwap() (gas: 249672)
Expand All @@ -40,6 +75,23 @@ EthCreatorFeeHookV2Test:test_sellExactInputChargesCreatorAndLauncherInEth() (gas
EthCreatorFeeHookV2Test:test_sellExactOutputPreservesRequestedNetEthOutput() (gas: 236972)
EthCreatorFeeHookV2Test:test_sellExactOutputRevertsInsteadOfChargingARequestedPartialFill() (gas: 182555)
EthCreatorFeeHookV2Test:test_tinyGrossAmountsUseExplicitFloorRounding() (gas: 14655)
EthCreatorFeeHookV3Test:testFuzz_feeQuotesPreserveFixedEconomics(uint96,uint8) (runs: 1000, μ: 15459, ~: 15412)
EthCreatorFeeHookV3Test:test_acceptsIndependentOneAndTenPercentFeeBounds() (gas: 1569185)
EthCreatorFeeHookV3Test:test_addressChangeRedirectsExistingAndFutureRewardsWithoutMovingAuthority() (gas: 491928)
EthCreatorFeeHookV3Test:test_buyExactInputUsesBuyFee() (gas: 244471)
EthCreatorFeeHookV3Test:test_buyExactOutputUsesBuyFee() (gas: 252714)
EthCreatorFeeHookV3Test:test_configurationAndDisclosureAreExplicit() (gas: 44309)
EthCreatorFeeHookV3Test:test_duplicatePayoutDestinationsAreAllowed() (gas: 422469)
EthCreatorFeeHookV3Test:test_noDoubleClaimAndNoCrossBeneficiaryClaim() (gas: 1170754)
EthCreatorFeeHookV3Test:test_onlyPoolManagerCanCallEnabledHookCallbacksAndUnlockCallback() (gas: 28557)
EthCreatorFeeHookV3Test:test_onlyTreasuryCanClaimOrRedirectPlatformFees() (gas: 269819)
EthCreatorFeeHookV3Test:test_onlyVaultCanPullCreatorFeesAndOnlyBeneficiaryCanClaim() (gas: 247402)
EthCreatorFeeHookV3Test:test_platformShareIsAlwaysTenBpsAndNotAddedOnTop() (gas: 36659)
EthCreatorFeeHookV3Test:test_rejectsInvalidBuyAndSellFees() (gas: 8992154)
EthCreatorFeeHookV3Test:test_revertingPayoutDoesNotBlockAnotherBeneficiary() (gas: 491160)
EthCreatorFeeHookV3Test:test_sellExactInputUsesSellFee() (gas: 238488)
EthCreatorFeeHookV3Test:test_sellExactOutputUsesSellFee() (gas: 238048)
EthCreatorFeeHookV3Test:test_splitClaimsConserveAllCreatorFees() (gas: 432515)
MemeLaunchV1Test:test_acceptsEveryMetadataFieldAtItsExactUtf8ByteLimit() (gas: 9437731)
MemeLaunchV1Test:test_buyAndSellAccrueOnlyEthFeesForCreatorAndLauncher() (gas: 4419423)
MemeLaunchV1Test:test_creatorCanChooseALargerAtomicDevBuy() (gas: 5643416)
Expand All @@ -51,6 +103,21 @@ MemeLaunchV1Test:test_rejectsNonIntegerAndOutOfRangeTotalSwapFeesBeforeTokenCrea
MemeLaunchV1Test:test_rejectsOverlongDirectCallMetadataBeforeRegistryWrite() (gas: 840755)
MemeLaunchV1Test:test_reusesMatchingPredeployedPermanentPositionRecipient() (gas: 2891652)
MemeLaunchV1Test:test_supportsEveryIntegerTotalSwapFeeFromOneToTenPercent() (gas: 27777931)
MemeLaunchV2Test:test_approvedCtoChangesOnlyFutureRewardConfiguration() (gas: 4596640)
MemeLaunchV2Test:test_changePayoutWalletKeepsUnclaimedEthWithPreviousWallet() (gas: 4611114)
MemeLaunchV2Test:test_cliffLinearVestingStartsAtZeroAndUsesTheLaunchWalletForever() (gas: 5248238)
MemeLaunchV2Test:test_creatorCanChooseLargerInitialBuy() (gas: 4473953)
MemeLaunchV2Test:test_externalBeneficiaryNeedsNoAcceptanceAndAloneCanClaim() (gas: 4651134)
MemeLaunchV2Test:test_fixedLockRoutesTheEntireInitialBuyDirectlyIntoAuthenticatedCustody() (gas: 5276201)
MemeLaunchV2Test:test_forcedEthCannotBlockFutureLaunchesOrSubsidizeInitialBuy() (gas: 4473479)
MemeLaunchV2Test:test_invalidInitialBuyCustodyRevertsBeforeTokenCreation() (gas: 54276)
MemeLaunchV2Test:test_launchWalletAsSoleBeneficiaryPreservesLockedClassicLifecycle() (gas: 4500509)
MemeLaunchV2Test:test_onlyPoolManagerCanCallInitialBuyUnlockCallback() (gas: 10971)
MemeLaunchV2Test:test_rejectsInvalidDirectionalFeesAtomically() (gas: 3764042)
MemeLaunchV2Test:test_rejectsInvalidRewardConfigurationsBeforeTokenCreation() (gas: 125012)
MemeLaunchV2Test:test_reusesMatchingPredeployedRewardVaultInsteadOfAllowingMempoolGriefing() (gas: 4496450)
MemeLaunchV2Test:test_splitLaunchStoresUniqueSharesAndDirectionalFees() (gas: 4547072)
MemeLaunchV2Test:test_supportsFiveBeneficiariesAtLaunch() (gas: 4596598)
ProtocolRevenueDeepenerV1InvariantTest:invariant_compoundNonceMatchesSuccessfulCycles() (runs: 256, calls: 16384, reverts: 0)
ProtocolRevenueDeepenerV1InvariantTest:invariant_everyAcquiredTokenIsPendingOrPermanentlyAdded() (runs: 256, calls: 16384, reverts: 0)
ProtocolRevenueDeepenerV1InvariantTest:invariant_everyNativeWeiIsPendingOrPermanentlyProcessed() (runs: 256, calls: 16384, reverts: 0)
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ jobs:
- name: Verify model registry
run: node scripts/verify-model-registry.mjs

- name: Verify configurable Classic candidate
run: node scripts/verify-classic-configurable-candidate.mjs

- name: Verify release evidence
run: node scripts/verify-release-evidence.mjs

Expand Down
10 changes: 10 additions & 0 deletions MODELS.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ launch position and executes the creator's initial buy in one transaction. Its c
[Ethereum deployment](deployments/ethereum.json) ·
[Security properties](docs/security/CLASSIC_PROPERTIES.md)

### Configurable candidate

The next Classic release is deployed and lifecycle-tested on Sepolia. It adds separate buy and sell fees, up to five
reward wallets, beneficiary-owned payout changes, disclosed community takeovers and optional custody for the Initial
Buy. The current Ethereum release remains unchanged until equivalent Mainnet evidence is published.

[Candidate behavior and evidence](models/classic/candidates/configurable/README.md) ·
[Sepolia deployment](models/classic/candidates/configurable/sepolia.json) ·
[Security properties](docs/security/CLASSIC_CONFIGURABLE_PROPERTIES.md)

## Deep

<p>
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ change a model that has already been deployed.
| --- | --- | --- |
| Model registry | Current lifecycle status and documentation | [`models/registry.json`](models/registry.json) |
| Model manifest | Release, network, contracts and review state | [`models/<model>/model.json`](models/) |
| Candidate evidence | Source and rehearsal records awaiting an Ethereum release | [`models/classic/candidates/`](models/classic/candidates/) |
| Contract source | Hook, launcher and custody behavior | [`src/`](src/) |
| Test evidence | Unit, integration, fuzz, invariant and regression coverage | [`test/`](test/) |
| Fixed parameters | Compiler, dependencies and model settings | [`spec/`](spec/) |
Expand Down Expand Up @@ -130,6 +131,7 @@ or mutable fee allocation. Classic has not received an independent smart-contrac
| --- | --- |
| Current security status | [`SECURITY.md`](SECURITY.md) |
| Classic trust boundaries and invariants | [`docs/security/CLASSIC_PROPERTIES.md`](docs/security/CLASSIC_PROPERTIES.md) |
| Configurable Classic candidate | [`docs/security/CLASSIC_CONFIGURABLE_PROPERTIES.md`](docs/security/CLASSIC_CONFIGURABLE_PROPERTIES.md) |
| Protocol Revenue Deepener candidate | [`docs/security/PROTOCOL_REVENUE_DEEPENER_V1.md`](docs/security/PROTOCOL_REVENUE_DEEPENER_V1.md) |
| Automated checks and incident process | [`docs/OPERATIONS.md`](docs/OPERATIONS.md) |
| Independent review archive | [`audits/`](audits/) |
Expand Down
3 changes: 3 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ These checks are evidence, not a safety guarantee.
| Record | Scope |
| --- | --- |
| [Classic security properties](docs/security/CLASSIC_PROPERTIES.md) | Trust boundaries, permissions, accounting and invariant evidence |
| [Configurable Classic candidate](docs/security/CLASSIC_CONFIGURABLE_PROPERTIES.md) | Directional fees, reward custody and Sepolia lifecycle evidence |
| [Protocol Revenue Deepener V1](docs/security/PROTOCOL_REVENUE_DEEPENER_V1.md) | Candidate add-only `$V4` liquidity program |
| [Operations](docs/OPERATIONS.md) | Automated checks, monitoring status and incident response |
| [Independent reviews](audits/README.md) | Published external reports, currently none |
Expand Down Expand Up @@ -69,5 +70,7 @@ The detailed property-to-test map is in
- Metadata and project links may be indexed inconsistently by third-party services.
- Permanent lock properties depend on the pinned forwarder and PositionManager semantics described in the
[Classic model documentation](models/classic/README.md#liquidity-custody).
- Configurable Classic remains a Sepolia candidate until the exact Mainnet deployment and lifecycle evidence are
published.
- Protocol Revenue Deepener V1 is a candidate and is not active until an Ethereum deployment, exact source
verification and keeper receipts are published.
61 changes: 61 additions & 0 deletions docs/security/CLASSIC_CONFIGURABLE_PROPERTIES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Configurable Classic security properties

This document covers the configurable Classic candidate deployed on Sepolia. It is a review record, not an audit.

## Fixed boundaries

- Buy and sell fees are selected independently at launch from `1%` through `10%` in one-point steps.
- Programmable receives `0.10` percentage points from the applied fee. It is not added on top.
- Token transfers have no tax and the Uniswap v4 LP fee is zero.
- The complete token supply is accounted for between the permanently custodied position, the Initial Buy and bounded
launch dust.
- A launch has one to five non-zero reward allocations that total exactly `100%`.
- Only a beneficiary can claim its own ETH or redirect its future allocation.
- A payout change or community takeover checkpoints accrued fees before changing future destinations.
- Fixed-lock and vesting custody always use the launch wallet as the immutable beneficiary.
- There is no owner mint, blacklist, pause or post-launch fee setter.

## Authority

`ClassicCtoAuthorityV1` is the only administrative component. It can replace future creator-reward allocations after a
disclosed community-takeover decision. It cannot take previously accrued rewards, modify swap fees, unlock liquidity,
mint tokens or change Initial Buy custody.

The authority itself uses a two-step transfer. A transfer does not change any vault until a separate takeover call is
made.

## Accounting

For a gross native ETH amount `x` and selected fee rate `t`:

```text
totalFee = floor(x × t / 10,000)
programmable = floor(x × 10 / 10,000)
creatorRewards = totalFee - programmable
```

Creator rewards are pulled from `PoolManager` into the launch-specific reward vault. Rounding remainder is assigned to
the final allocation, so the full amount remains claimable.

## Evidence

| Property | Primary test |
| --- | --- |
| Directional fee settings never change | `invariant_directionalEconomicsNeverChange` |
| Native claims cover accrued accounting | `invariant_nativeClaimsExactlyCoverAccruedAccounting` |
| Reward accounting is conserved | `invariant_claimAndPayoutAccountingIsConserved` |
| Active shares always total `100%` | `invariant_activeSharesAlwaysTotalOneHundredPercent` |
| Prior rewards survive payout changes and takeovers | `test_approvedCtoChangesOnlyFutureRewardConfiguration` |
| Beneficiaries cannot claim for each other | `test_noDoubleClaimAndNoCrossBeneficiaryClaim` |
| Five unequal allocations are supported | `test_supportsFiveBeneficiariesAtLaunch` |
| Initial Buy custody is immutable | `test_cliffLinearVestingStartsAtZeroAndUsesTheLaunchWalletForever` |

The complete candidate suites are listed in
[`spec.json`](../../models/classic/candidates/configurable/spec.json). The Sepolia deployment and lifecycle evidence is
in [`sepolia.json`](../../models/classic/candidates/configurable/sepolia.json).

## Remaining release boundary

Sepolia evidence does not activate this candidate on Ethereum Mainnet. Mainnet deployment, runtime verification,
source verification and a complete Mainnet lifecycle must be published before the production interface can mark the
configurable release available.
11 changes: 11 additions & 0 deletions models/classic/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,14 @@ Classic has unit, integration, fuzz, invariant and regression coverage. It has n
smart-contract audit or public security contest. The full trust model and known limitations are in
[`SECURITY.md`](../../SECURITY.md), with the property-to-test map in
[`docs/security/CLASSIC_PROPERTIES.md`](../../docs/security/CLASSIC_PROPERTIES.md).

## Configurable candidate

A configurable Classic release is deployed and lifecycle-tested on Sepolia. It keeps the same launch model while
adding separate buy and sell fees, up to five reward wallets, beneficiary-controlled payout changes, disclosed
community takeovers and optional lock or vesting for the Initial Buy.

This candidate is not active on Ethereum Mainnet. The current Mainnet behavior and addresses above remain unchanged.

[Open the candidate record](candidates/configurable/README.md) ·
[Inspect the Sepolia evidence](candidates/configurable/sepolia.json)
Loading
Loading