https://github.com/base/builder-codes
https://github.com/base/builder-codes
Last synced: 24 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/base/builder-codes
- Owner: base
- License: mit
- Created: 2025-09-29T04:21:41.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-11-19T14:05:32.000Z (7 months ago)
- Last Synced: 2026-05-24T13:35:13.650Z (24 days ago)
- Language: Solidity
- Homepage:
- Size: 2.56 MB
- Stars: 6
- Watchers: 0
- Forks: 7
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# Builder Codes
An ERC-721 NFT contract that enables builders to register unique codes (e.g., `"myapp"`) with an associated payout addresses for revenue attribution and distribution. Implements the [ERC-8021](https://eip.tools/eip/8021) `ICodesRegistry` interface.
## Features
- **Unique Code Registration**: Mint ERC-721 tokens representing alphanumeric codes (1-32 characters)
- **Flexible Registration Methods**: Direct registration via authorized registrars or gasless signature-based registration
- **Revenue Attribution**: Each code has a configurable payout address for tracking and distributing revenue
- **Role-Based Access Control**: Granular permissions for registration, transfers, and metadata updates
- **Upgradeable Design**: UUPS proxy pattern enables future enhancements while preserving state
- **Gas-Optimized**: Efficient storage layout using ERC-7201 and Solady libraries
## Architecture
### ERC-721 NFT
BuilderCodes implements the ERC-721 standard where each token represents a unique builder code. The token ID is deterministically derived from the code string itself, ensuring a 1:1 mapping between codes and token IDs. The contract uses OpenZeppelin's upgradeable ERC-721 implementation as the base.
### Access Control
The contract employs a **central registry with periphery registrars** architecture:
- **Central Registry**: The BuilderCodes contract serves as the authoritative registry, storing all code ownership and payout mappings
- **Periphery Registrars**: External contracts or EOAs granted `REGISTER_ROLE` can register codes on behalf of users
- **Restricted Transfers**: Only addresses with `TRANSFER_ROLE` can initiate transfers, preventing unauthorized code transfers
**Roles:**
- `REGISTER_ROLE`: Authorize code registration (direct calls or signatures)
- `TRANSFER_ROLE`: Authorize token transfers
- `METADATA_ROLE`: Update token metadata URIs
- **Owner**: Automatically has all roles via `hasRole()` override and can manage role grants
### Upgradeability
The contract uses the **UUPS (Universal Upgradeable Proxy Standard)** pattern:
- **Proxy Pattern**: ERC-1967 transparent proxy separates logic (implementation) from state (proxy)
- **Storage Safety**: ERC-7201 namespaced storage prevents collisions during upgrades
- **Owner-Only Upgrades**: Only the contract owner can authorize implementation upgrades via `_authorizeUpgrade()`
## Code System
### Valid Code Format
Builder codes must adhere to strict formatting rules:
- **Length**: 1-32 characters
- **Allowed Characters**: Lowercase letters (`a-z`), digits (`0-9`), and underscore (`_`)
### Token ID Conversion
The contract provides `toCode()` and `toTokenId()` as pure functions that bidirectionally map between builder codes and token IDs. This deterministic 1:1 mapping is enabled by 7-bit ASCII encoding of the allowed character set.
## Registration
### Direct Registration
The `register()` function allows authorized registrars to mint codes:
```solidity
function register(
string memory code,
address initialOwner,
address initialPayoutAddress
) external onlyRole(REGISTER_ROLE)
```
**Flow:**
1. Caller must have `REGISTER_ROLE` (or be owner)
2. Code is validated for format compliance
3. Token is minted to `initialOwner`
4. Payout address is set to `initialPayoutAddress`
5. Events emitted: `Transfer`, `CodeRegistered`, `PayoutAddressUpdated`
### Signature-Based Registration
The `registerWithSignature()` function enables gasless registration via EIP-712 signatures:
```solidity
function registerWithSignature(
string memory code,
address initialOwner,
address initialPayoutAddress,
uint48 deadline,
address signer,
bytes memory signature
) external
```
**Flow:**
1. Verify deadline has not passed
2. Verify `signer` has `REGISTER_ROLE`
3. Compute EIP-712 typed data hash for registration parameters
4. Validate signature against signer's address
5. Execute registration (same as direct registration)
**EIP-712 Typed Data:**
```
BuilderCodeRegistration(
string code,
address initialOwner,
address payoutAddress,
uint48 deadline
)
```
This pattern allows users to obtain off-chain signatures from authorized registrars and submit registrations without the registrar paying gas.
## Transfer Restrictions
BuilderCodes implements a permission-gated transfer system to control how codes can be transferred between addresses.
**How it works:**
1. Transfers are only allowed if initiated by an address with `TRANSFER_ROLE`
2. Holders of `TRANSFER_ROLE` cannot move tokens unilaterally—they still need approval from each owner to transfer tokens
This design enables intentional rollout of specific transfer patterns, such as controlled marketplaces or recovery mechanisms.