Skip to content
Open
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
49 changes: 49 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
name: Bug Report
about: Create a report to help us improve
title: '[BUG] '
labels: bug
assignees: ''
---

## Bug Description
A clear and concise description of what the bug is.

## Steps to Reproduce
1. Go to '...'
2. Click on '...'
3. Execute '...'
4. See error

## Expected Behavior
A clear and concise description of what you expected to happen.

## Actual Behavior
What actually happened instead.

## Environment
- OS: [e.g., macOS 14.0, Ubuntu 22.04]
- Browser: [e.g., Chrome 120, Firefox 119]
- Node.js version: [e.g., 18.19.0]
- Network: [e.g., testnet, mainnet]
- Clarinet version: [e.g., 2.3.0]

## Component Affected
- [ ] Smart Contract (Clarity)
- [ ] Frontend (Next.js)
- [ ] Username Registration
- [ ] Domain Resolution

## Username Domain Context (if applicable)
- Username being registered
- Registration transaction hash
- Domain resolution attempt
- User's STX address

## Logs
```
Paste relevant error logs here
```

## Screenshots
If applicable, add screenshots to help explain your problem.
40 changes: 40 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: Feature Request
about: Suggest an idea for this project
title: '[FEATURE] '
labels: enhancement
assignees: ''
---

## Problem Statement
A clear and concise description of what problem this feature would solve.
Ex. I'm always frustrated when [...]

## Proposed Solution
A clear and concise description of what you want to happen.

## Alternative Solutions
A clear and concise description of any alternative solutions or features you've considered.

## Use Case
Describe the use case for this feature. How would it enhance the Bitcoin username domain experience?

## Technical Implementation
If you have ideas on how to implement this feature, please share them here:
- Which component would be affected? (Contract/Frontend/Both)
- Smart contract changes needed
- Username registration modifications
- Domain resolution impact

## Impact on Username System
How would this feature affect:
- Username registration process
- Domain resolution speed
- User experience
- Decentralized identity

## Examples
Provide examples of similar features in other decentralized identity systems.

## Additional Context
Add any mockups, references, or other relevant information.
48 changes: 48 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## Description
Brief description of the changes in this PR.

## Related Issue
Fixes #(issue number)

## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Code refactoring
- [ ] Performance improvement
- [ ] Security enhancement

## Changes Made
- Change 1
- Change 2
- Change 3

## Testing
Describe the tests you ran to verify your changes:
- [ ] Contract tests pass (`npm run clarinet:test`)
- [ ] Unit tests pass (`npm test`)
- [ ] Frontend builds successfully (`npm run build`)
- [ ] Manual testing performed
- [ ] New tests added for new functionality

## Component Checklist
- [ ] Smart Contract (Clarity)
- [ ] Gas optimization considered
- [ ] Username registration logic verified
- [ ] Domain resolution tested
- [ ] Backward compatibility maintained
- [ ] Frontend (Next.js)
- [ ] Responsive design maintained
- [ ] Wallet integration tested
- [ ] Registration flow verified
- [ ] Domain lookup accurate
- [ ] Tests (Vitest)
- [ ] Unit test coverage maintained
- [ ] Edge cases covered (username conflicts, etc.)
- [ ] Integration tests included

## Username Domain Impact (if applicable)
- [ ] Username registration tested
- [ ] Domain resolution verified
- [ ] User identities correctly managed
182 changes: 126 additions & 56 deletions contracts/biud-username.clar
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,39 @@
)
)

;; Validate subdomain label: supports sub.parent format
(define-private (validate-subdomain-label (label (string-utf8 32)))
(let
(
(dot-index (index-of label "."))
)
(if (is-some dot-index)
;; It's a subdomain
(let
(
(parent-end (unwrap-panic dot-index))
(sub-len (len label))
(parent (unwrap! (slice? label u0 parent-end) ERR_INVALID_LABEL))
(subdomain-start (+ parent-end u1))
(subdomain (unwrap! (slice? label subdomain-start sub-len) ERR_INVALID_LABEL))
)
;; Check parent and subdomain not empty
(asserts! (> (len parent) u0) ERR_INVALID_LABEL)
(asserts! (> (len subdomain) u0) ERR_INVALID_LABEL)
;; Validate parent and subdomain as valid labels
(try! (validate-label parent))
(try! (validate-label subdomain))
(ok { is-subdomain: true, parent: parent, subdomain: subdomain })
)
;; Not a subdomain
(begin
(try! (validate-label label))
(ok { is-subdomain: false, parent: "", subdomain: "" })
)
)
)
)

;; Generate the next name ID
(define-private (get-next-name-id)
(let
Expand Down Expand Up @@ -361,73 +394,110 @@
(let
(
;; Validate the label format
(validation-result (try! (validate-label label)))
;; Generate the full name with TLD
(full-name (unwrap! (as-max-len? (concat label u".sBTC") u64) ERR_INVALID_LABEL))
;; Check if name is premium
(is-premium (check-is-premium label))
;; Calculate the registration fee
(reg-fee (calculate-registration-fee is-premium))
;; Get existing registration if any
(existing (map-get? name-registry { label: label }))
;; Generate new name ID
(new-name-id (get-next-name-id))
;; Calculate expiry height
(expiry (+ block-height REGISTRATION_PERIOD))
(validation-result (try! (validate-subdomain-label label)))
;; Check parent ownership if subdomain
(is-subdomain (get is-subdomain validation-result))
)
;; Check if name is available
(match existing
name-record
;; Name exists - check if expired
(begin
(asserts! (is-name-expired (get expiry-height name-record)) ERR_NAME_TAKEN)
;; Remove from previous owner's list
(try! (remove-name-from-owner (get owner name-record) (get name-id name-record)))
;; If subdomain, verify parent ownership
(if is-subdomain
(let
(
(parent (get parent validation-result))
(parent-record (unwrap! (map-get? name-registry { label: parent }) ERR_NAME_NOT_FOUND))
)
(asserts! (is-eq (get owner parent-record) tx-sender) ERR_NOT_OWNER)
(asserts! (<= block-height (get expiry-height parent-record)) ERR_NAME_EXPIRED)
true
)
;; Name doesn't exist - proceed
true
)

;; Collect registration fee
(asserts! (> reg-fee u0) ERR_ZERO_FEE)
(try! (distribute-fees reg-fee))

;; Create the name record
(map-set name-registry
{ label: label }
{
;; Generate the full name with TLD
(let
(
(full-name (if is-subdomain
(let
(
(parent (get parent validation-result))
(subdomain (get subdomain validation-result))
)
(unwrap! (as-max-len? (concat (concat subdomain ".") (concat parent ".sBTC")) u64) ERR_INVALID_LABEL)
)
(unwrap! (as-max-len? (concat label ".sBTC") u64) ERR_INVALID_LABEL)
))
;; Check if name is premium
(is-premium (check-is-premium label))
;; Calculate the registration fee
(reg-fee (calculate-registration-fee is-premium))
;; Get existing registration if any
(existing (map-get? name-registry { label: label }))
;; Generate new name ID
(new-name-id (get-next-name-id))
;; Calculate expiry height
(expiry (+ block-height REGISTRATION_PERIOD))
)
;; Check if name is available
(match existing
name-record
;; Name exists - check if expired
(begin
(asserts! (is-name-expired (get expiry-height name-record)) ERR_NAME_TAKEN)
;; Remove from previous owner's list
(try! (remove-name-from-owner (get owner name-record) (get name-id name-record)))
)
;; Name doesn't exist - proceed
true
)

;; Collect registration fee
(asserts! (> reg-fee u0) ERR_ZERO_FEE)
(try! (distribute-fees reg-fee))

;; Create the name record
(map-set name-registry
{ label: label }
{
name-id: new-name-id,
full-name: full-name,
owner: tx-sender,
resolver: none,
expiry-height: expiry,
is-premium: is-premium,
created-at: block-height,
last-renewed: block-height
}
)

;; Set reverse lookup
(map-set name-id-to-label
{ name-id: new-name-id }
{ label: label }
)

;; Add to owner's name list
(try! (add-name-to-owner tx-sender new-name-id))

;; Emit registration event
(emit-name-registered label full-name tx-sender new-name-id expiry reg-fee is-premium)

(ok {
name-id: new-name-id,
full-name: full-name,
owner: tx-sender,
resolver: none,
expiry-height: expiry,
is-premium: is-premium,
created-at: block-height,
last-renewed: block-height
}
)

;; Set reverse lookup
(map-set name-id-to-label
{ name-id: new-name-id }
{ label: label }
fee-paid: reg-fee
})
)

;; Add to owner's name list
(try! (add-name-to-owner tx-sender new-name-id))

;; Emit registration event
(emit-name-registered label full-name tx-sender new-name-id expiry reg-fee is-premium)

(ok {
name-id: new-name-id,
full-name: full-name,
expiry-height: expiry,
fee-paid: reg-fee
})
)
)

;; Register multiple names in one transaction (up to 10)
(define-private (register-name-wrapper (label (string-utf8 32)))
(register-name label)
)

(define-public (register-multiple-names (labels (list 10 (string-utf8 32))))
(ok (map register-name-wrapper labels))
)

;; ════════════════════════════════════════════════════════════════════════════
;; PUBLIC FUNCTIONS - RENEWAL
;; ════════════════════════════════════════════════════════════════════════════
Expand Down
Loading