feat: price dotNS names on a scarcity curve - #208
Open
sphamjoli wants to merge 8 commits into
Open
Conversation
Replace flat pricing with a geometric curve on base length: the price doubles for each character below nine and flattens to the base fee from nine upward. Every caller pays the curve; personhood gates access to the premium band rather than discounting it. Transfers re-price at the name's own length. Rename the escrow insurance fund to protocol fees, a non-refundable pot that only accumulates, and remove the dead refund-shortfall draw so refunds draw solely on the per-asset reserve.
Contributor
CI Summary
4naly3er AnalysisMedium (5)
Low (10)
Gas (15)
Informational (11)
Slither AnalysisHigh (3)
Medium (38)
Low (54)
Informational (60)
Contract Tests (Unit + Fuzz)BasicDotnsIntegrationReverts (test/intergration/BasicDotns.reverts.t.sol)
BasicDotnsIntegration (test/intergration/BasicDotns.t.sol)
DeployCreate3FactoryTest (test/unit/deploy/DeployCreate3Factory.t.sol)
DeterministicDeploymentTest (test/unit/deploy/DeterministicDeployment.t.sol)
DotnsContentResolverTests (test/unit/resolver/DotnsContentResolver.t.sol)
DotnsNameEscrowTest (test/unit/escrow/DotnsNameEscrow.t.sol)
DotnsNameEscrowFuzzTest (test/fuzz/escrow/DotnsNameEscrowFuzz.t.sol)
DotnsNameEscrowRefundsTest (test/unit/escrow/DotnsNameEscrowRefunds.t.sol)
DotnsPopControllerTests (test/unit/registrar/DotnsPopController.t.sol)
DotnsPopControllerFuzz (test/fuzz/registrar/DotnsPopControllerFuzz.t.sol)
DotnsPopResolverTests (test/unit/resolver/DotnsPopResolver.t.sol)
DotnsProtocolRegistryTldTests (test/unit/registry/DotnsProtocolRegistry.t.sol)
DotnsProtocolRegistryFuzzTest (test/fuzz/registry/DotnsProtocolRegistryFuzz.t.sol)
DotnsRegistrarTests (test/unit/registrar/DotnsRegistrar.t.sol)
DotnsRegistrarControllerTest (test/unit/registrar/DotnsRegistrarController.t.sol)
DotnsRegistrarControllerFuzzTest (test/fuzz/registrar/DotnsRegistrarControllerFuzz.t.sol)
DotnsRegistrarControllerLifecycleTest (test/unit/registrar/DotnsRegistrarControllerLifecycle.t.sol)
DotnsRegistryTests (test/unit/registry/DotnsRegistry.t.sol)
DotnsRegistryFuzzTest (test/fuzz/registry/DotnsRegistryFuzz.t.sol)
DotnsResolverTests (test/unit/resolver/DotnsResolver.t.sol)
DotnsReverseResolverTests (test/unit/resolver/DotnsReverseResolver.t.sol)
LabelStoreTests (test/unit/store/LabelStore.t.sol)
LabelStoreFuzzTest (test/fuzz/store/LabelStoreFuzz.t.sol)
NoStatusDepositLifecycle (test/intergration/NoStatusDepositLifecycle.t.sol)
PopRulesFuzzTest (test/fuzz/pop/PopFuzz.t.sol)
PopLifecycleFlow (test/intergration/PopLifecycleFlow.t.sol)
PopRulesTests (test/unit/pop/PopRules.t.sol)
RootGatewayDispatcherTests (test/unit/registrar/RootGatewayDispatcher.t.sol)
StoreFactoryTests (test/unit/store/StoreFactory.t.sol)
StoreIntegrationTest (test/intergration/StoreIntegration.t.sol)
StoreStressTest (test/stress/store/StoreStress.t.sol)
UserStoreTests (test/unit/store/UserStore.t.sol)
UserStoreFuzzTest (test/fuzz/store/UserStoreFuzz.t.sol)
WhitelistOperatorFlow (test/intergration/WhitelistOperatorFlow.t.sol)
Contract Tests (Invariant)DotnsNameEscrowInvariantTest (test/invariant/escrow/DotnsNameEscrowInvariant.t.sol)
DotnsPopControllerInvariant (test/invariant/registrar/DotnsPopControllerInvariant.t.sol)
DotnsRegistrarControllerInvariantTest (test/invariant/registrar/DotnsRegistrarControllerInvariant.t.sol)
DotnsRegistrarControllerRoleInvariantTest (test/invariant/registrar/DotnsRegistrarControllerRoleInvariant.t.sol)
DotnsRegistryInvariantTest (test/invariant/registry/DotnsRegistryInvariant.t.sol)
StoreInvariantTest (test/invariant/store/StoreInvariant.t.sol)
Gas ReportDotnsProtocolRegistry
DotnsRegistrar
DotnsRegistrarController
DotnsRegistry
DotnsReverseResolver
PopRules
Coverage
Deploy ContractsDeployed addresses vs DEPLOYMENTS.mdExpected is the committed manifest; actual is this CI deployment of the same pipeline.
Labelssmartcontracts, scope: registration, type: test, type: docs, scope: pop |
…in state The protocol-fee conservation invariant mirrored the on-chain balance delta into its own tracker, so it compared the escrow balance against an echo of itself and could never catch a miscredit. The handler now accumulates the independently computed charge and quoted transfer fee, and a new invariant asserts those tracked inflows equal the on-chain protocol fees. Dead insurance-draw scaffolding, its recorded-log parsing, and stale insurance wording are removed to match the protocol-fee model.
27 tasks
…in state (#210) ## Description Follow-up to the scarcity-pricing change. The protocol-fee conservation invariant used to read the on-chain protocol-fee balance before and after each action and fold the difference into its own tracker. Because both sides came from the same source, the check compared the balance against an echo of itself and would have passed even if a caller had been charged the wrong amount. The handler now accumulates the fee it independently expects (the charge on a cross-paid registration, the quoted fee on a payable transfer), so the invariant proves the escrow credited exactly what the caller was asked to pay. A second invariant asserts that the tracked inflows sum to the on-chain protocol-fee balance, which holds because protocol fees only ever accrue. ## Type - [ ] Bug fix - [ ] Feature - [ ] Breaking change - [ ] Documentation - [ ] Chore - [ ] Refactor - [ ] Security ## Scope - [ ] Registration - [ ] Resolver - [ ] Store - [ ] Proof of Personhood - [ ] Deployment scripts - [x] Tests ## Related Issues Stacked on #208. ## Fixes ## Checklist ### Code - [x] Follows project style - [x] `forge build` passes - [x] `forge test` passes - [x] No new compiler warnings ### Testing - [ ] New tests added for changed behavior - [ ] Fuzz tests added where applicable - [x] Invariant tests verified ### Security - [x] No new `selfdestruct` or `delegatecall` - [x] Access control reviewed - [x] No storage layout conflicts (for upgradeable contracts) ### Documentation - [x] NatSpec updated on changed interfaces - [x] README updated if needed ### Breaking Changes - [x] No breaking changes - [ ] Breaking changes documented below **Breaking changes:** ## How to test ```bash forge test --mc DotnsNameEscrowInvariantTest ``` ## Notes Stacks on #208; review and merge that first. The new pricing-invariant suite is tracked separately in #209.
The base-fee setter rejects a value large enough to overflow the scarcity multiplier, so short-name pricing and transfers cannot be knocked offline by an oversized fee. Cross-payer registration charges the name's own curve price directly; the floor comparison that could never change the amount is removed. The transfer-fee event fires only when a fee is taken, so a zero-fee position rebind emits nothing. The escrow transfer-fee parameter and its registrar call sites read transferFee to match the value they carry, and the transfer-floor and fee-parameter documentation is completed.
The free name is claimed per wallet through the personhood gateway, which waives the price. The gateway lane accepts a name of any length and applies no public band gate; it only refuses the governance-reserved stems of five characters or fewer.
Contributor
|
I would keep this PR on hold and have a broader discussion on this argument. This can be taken as a concrete proposal. |
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Prices every name by its length on a single geometric curve instead of a flat fee. A name's price doubles for each character below nine and flattens to the base fee from nine upward, so short, scarce names cost more. A trailing number never changes the price.
Three bands share the curve. Names of nine characters or more are open to anyone at the base fee. Names of six to eight characters are premium, and only a verified person may register them, paying the curve for the length. Names of five characters or fewer stay reserved to governance.
Personhood buys access to the premium band: a verified person pays the same curve as anyone else, with no discount inside it. Each wallet gets one free name from the gateway, of any length, on the unpriced lane. Moving a name re-prices it at its own length, so a scarce name cannot be handed cheaply to a party who could never have registered it.
Registering under your own key locks a refundable deposit on the curve. Fees, paid when someone else pays for a name or on a transfer, are non-refundable and gather in one protocol fee pot that governance can send to a burn or the treasury. The pot no longer backs refunds; a refund draws only on its own reserve.
The formula
Below nine letters, dropping one letter doubles the price, because a name one letter shorter is rarer. At nine letters and above the price is flat at$D$ , because names that long are plentiful. The exponent $9 - n$ is how many doublings you are above the base fee, so a one-letter name sits eight doublings, $2^8 = 256$ times $D$ , above it.
Every length, at the launch fee$D = 10$ DOT
In practice:
Type
Scope
Related Issues
None.
Fixes
None.
Checklist
Code
forge buildpassesforge testpassesTesting
Security
selfdestructordelegatecallDocumentation
Breaking Changes
Breaking changes: the escrow fee pot is renamed from the insurance fund to protocol fees. The
insuranceFund()view becomesprotocolFees(),depositInsurancebecomesdepositProtocolFee, and the withdrawal shortfall event is removed. Consumers reading the fee balance must move to the new names.How to test
forge test --mt test_price_follows_scarcity_curveNotes
The fee pot's governance routing to a burn or treasury, the one-free-name-per-person cap, and a bounded band on the base fee are the target model described in the README and land in follow-up work.