Skip to content

Conversation

@bimakw
Copy link

@bimakw bimakw commented Jan 19, 2026

Summary

Design document for p/gnoland/antisquat, a pluggable anti-squatting library for gno.land namespaces.

Addresses #2727

Proposed Mechanisms

  1. Rate Limiting - Max 3 registrations per address per 30 days
  2. Protected Names - DAO-managed list of reserved names (system, brands, governance)
  3. Length-Based Pricing - Shorter names cost more (ENS-style)
  4. Vickrey Auction (Phase 2) - Sealed-bid auction for premium/contested names

Key Design Decisions

  • Pluggable library (p/) - Can be imported by any realm, not just r/sys/users
  • Modular architecture - Rate limiting, protected names, and pricing are separate components
  • GovDAO integration - Protected names managed via governance proposals
  • Commit-reveal auction - Prevents front-running for premium names

Document Contents

  • Architecture overview with diagrams
  • Core types and interfaces (Gno code)
  • Implementation details for each mechanism
  • Validation flow
  • GovDAO integration patterns
  • Testing strategy
  • Security considerations

Open Questions (feedback welcome)

  1. Should protected names live in antisquat package or separate p/gnoland/protectednames?
  2. Are default pricing tiers appropriate for mainnet?
  3. Rate limit: 30 days reasonable? Block-based or time-based?

Looking forward to feedback before starting implementation.


Related: #2827, #3020

This design document proposes p/gnoland/antisquat, a pluggable library
to prevent username squatting through:

- Rate limiting (3 registrations per address per 30 days)
- Protected names (DAO-managed reserved names list)
- Length-based pricing (shorter names cost more)
- Vickrey sealed-bid auction for premium names (Phase 2)

Addresses gnolang#2727
@github-actions github-actions bot added the 📖 documentation Improvements or additions to documentation label Jan 19, 2026
@Gno2D2 Gno2D2 requested a review from a team January 19, 2026 17:08
@Gno2D2 Gno2D2 added the review/triage-pending PRs opened by external contributors that are waiting for the 1st review label Jan 19, 2026
@Gno2D2
Copy link
Collaborator

Gno2D2 commented Jan 19, 2026

🛠 PR Checks Summary

🔴 Changes to 'docs' folder must be reviewed/authored by at least one devrel and one tech-staff
🔴 Pending initial approval by a review team member, or review from tech-staff

Manual Checks (for Reviewers):
  • IGNORE the bot requirements for this PR (force green CI check)
  • The pull request description provides enough details
Read More

🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers.

✅ Automated Checks (for Contributors):

🟢 Maintainers must be able to edit this pull request (more info)
🔴 Changes to 'docs' folder must be reviewed/authored by at least one devrel and one tech-staff
🔴 Pending initial approval by a review team member, or review from tech-staff

☑️ Contributor Actions:
  1. Fix any issues flagged by automated checks.
  2. Follow the Contributor Checklist to ensure your PR is ready for review.
    • Add new tests, or document why they are unnecessary.
    • Provide clear examples/screenshots, if necessary.
    • Update documentation, if required.
    • Ensure no breaking changes, or include BREAKING CHANGE notes.
    • Link related issues/PRs, where applicable.
☑️ Reviewer Actions:
  1. Complete manual checks for the PR, including the guidelines and additional checks if applicable.
📚 Resources:
Debug
Automated Checks
Maintainers must be able to edit this pull request (more info)

If

🟢 Condition met
└── 🟢 And
    ├── 🟢 The base branch matches this pattern: ^master$
    └── 🟢 The pull request was created from a fork (head branch repo: bimakw/gno)

Then

🟢 Requirement satisfied
└── 🟢 Maintainer can modify this pull request

Changes to 'docs' folder must be reviewed/authored by at least one devrel and one tech-staff

If

🟢 Condition met
└── 🟢 And
    ├── 🟢 The base branch matches this pattern: ^master$
    └── 🟢 A changed file matches this pattern: ^docs/ (filename: docs/design/antisquat-design.md)

Then

🔴 Requirement not satisfied
└── 🔴 And
    ├── 🔴 Or
    │   ├── 🔴 Pull request author is a member of the team: tech-staff
    │   └── 🔴 At least 1 user(s) of the team tech-staff reviewed pull request(with state "APPROVED")
    └── 🔴 Or
        ├── 🔴 Pull request author is a member of the team: devrels
        └── 🔴 At least 1 user(s) of the team devrels reviewed pull request(with state "APPROVED")

Pending initial approval by a review team member, or review from tech-staff

If

🟢 Condition met
└── 🟢 And
    ├── 🟢 The base branch matches this pattern: ^master$
    └── 🟢 Not (🔴 Pull request author is a member of the team: tech-staff)

Then

🔴 Requirement not satisfied
└── 🔴 If
    ├── 🔴 Condition
    │   └── 🔴 Or
    │       ├── 🔴 At least one of these user(s) reviewed the pull request: [jefft0 notJoon omarsy MikaelVallenet] (with state "APPROVED")
    │       ├── 🔴 At least 1 user(s) of the team tech-staff reviewed pull request
    │       └── 🔴 This pull request is a draft
    └── 🔴 Else
        └── 🔴 And
            ├── 🟢 This label is applied to pull request: review/triage-pending
            └── 🔴 On no pull request

Manual Checks
**IGNORE** the bot requirements for this PR (force green CI check)

If

🟢 Condition met
└── 🟢 On every pull request

Can be checked by

  • Any user with comment edit permission
The pull request description provides enough details

If

🟢 Condition met
└── 🟢 And
    ├── 🟢 Not (🔴 Pull request author is a member of the team: core-contributors)
    └── 🟢 Not (🔴 Pull request author is user: dependabot[bot])

Can be checked by

  • team core-contributors

Copy link
Member

@notJoon notJoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the current design is in a complete form. The rationale for why this structure was chosen is missing, and from an operational perspective, the content still appears to be lacking. I believe we can only discuss the overall design validity after these areas have been addressed in the document.

{4, 4, 10_000_000_000}, // 10 GNOT
{5, 5, 5_000_000_000}, // 5 GNOT
{6, 7, 2_000_000_000}, // 2 GNOT
{8, -1, 1_000_000_000}, // 1 GNOT (default)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 gnot is 1,000,000 ugnot. This pricing policy has been set incorrectly. please refer to this link

Timestamp time.Time
}

func (rl *rateLimiter) CanRegister(addr address, now time.Time) bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CanRegister iterates through the entire record every time, and since the cost increases as the record length per address grows, this does not appear to be an efficient implementation.

Timestamp: now,
})
// Prune expired records
rl.pruneOldRecords(history, now)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears that the prune logic only runs when RecordRegistration is called. If there are accounts that are called infrequently, old records may continue to accumulate.

if those accounts are no longer doing anything new, it probably doesn't matter much. Is there a specific reason for designing the state management this way?

Comment on lines +277 to +288
systemNames := []string{
"gno", "gnoland", "gnolang", "admin", "root", "system",
"official", "support", "api", "www",
}
for _, name := range systemNames {
addProtectedInternal(name, CategorySystem, "system reserved")
}

govNames := []string{"dao", "govdao", "governance", "voting", "treasury"}
for _, name := range govNames {
addProtectedInternal(name, CategoryGovernance, "governance reserved")
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

systemName and govNames are fixed right after the deployment. Is there a way to update it if there are new names that need to be protected later?

- **Front-running prevention:** Bids hidden until reveal
- **Commitment binding:** Hash includes bidder address
- **Deposit requirement:** Must lock funds >= bid
- **Griefing mitigation:** Non-revealers just lose opportunity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could consider economic penalties such as partial deposit burning, rather than losing opportunity. How about adding this as an open question as well?

req := antisquat.RegistrationRequest{
Name: username,
Caller: runtime.PreviousRealm().Address(),
Payment: banker.OriginSend().AmountOf("ugnot"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems that the flow involves receiving a payment first, then checking whether the amount is sufficient in Validate.

I don't see any details in the documentation about who owns and handles the fees. Is there a direction or policy you have in mind for this?

Addresses reviewer feedback from @notJoon requesting:
- Design Rationale section explaining WHY this approach was chosen
- Operational Considerations covering deployment, monitoring, failure scenarios

Changes:
- Section 4: Design Rationale (multi-layer approach, ENS pricing model, Vickrey auction, pluggable design, GovDAO integration)
- Section 15: Operational Considerations (deployment strategy, monitoring, failure scenarios, upgrade path, performance, incident response)
- Renumbered all subsequent sections
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📖 documentation Improvements or additions to documentation review/triage-pending PRs opened by external contributors that are waiting for the 1st review

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants