# username_registry Привязка читаемых `@username` к адресам (Ed25519 pubkey). Forward (`name → addr`) и reverse (`addr → name`) lookup, передача ownership, освобождение имени. **Реализация: native Go** (`blockchain/native_username.go`). Работает без WASM VM — нулевая латентность, не может повесить AddBlock. Старая WASM-версия заменена; клиенты получают канонический ID через `/api/well-known-contracts`. ## Ключевые свойства | | | |---|---| | **Contract ID** | `native:username_registry` | | **Version** | `2.1.0-native` | | **Регистрация** | Flat fee 10 000 µT (0.01 T), **burn** — никому не идёт | | **Ограничения имени** | 4–32 символа, `a-z 0-9 _ -`, первый символ — буква | | **Зарезервированные** | `system`, `admin`, `root`, `dchain`, `null`, `none` | | **Один адрес — одно имя** | Чтобы сменить, нужно `release` + `register` | Комиссия 10 000 µT выбрана как баланс: достаточно дёшево для реальных пользователей, достаточно дорого чтобы один ID-squatter не забил тысячу имён из скучающего бота. ## Оплата Плата передаётся в `tx.Amount` (видна в истории транзакций), контракт проверяет её точное значение и вычитает из баланса отправителя. Не направляется никуда — токены сгорают. Дополнительно платится `tx.Fee = 1 000 µT` за саму транзакцию — это network fee валидатору, стандартный `MinFee` для любой tx. Итого: `register(name)` стоит **11 000 µT ≈ 0.011 T**. ## Методы ### `register(name)` — payable 10000 Зарегистрировать имя для `tx.From`. **Проверки** (в порядке): 1. `name` валиден (длина, символы, не reserved) 2. `tx.Amount == 10 000` (ошибка `register requires tx.amount = 10000 µT`) 3. Имя не занято 4. `tx.From` не владеет другим именем 5. Баланс отправителя достаточен для `amount + fee + gas` **Успех:** - Списывает 10 000 µT с баланса (burn) - `cstate[name:] = tx.From` - `cstate[addr:] = name` - Лог `registered: ` **CLI-пример:** ```bash client call-contract \ --key my.json \ --contract native:username_registry \ --method register \ --args '["alice"]' \ --amount 10000 \ --node http://localhost:8081 ``` **Клиент-приложение** делает это автоматически через Settings → «Купить никнейм». ### `resolve(name)` — free Прочитать владельца имени. Логирует `owner: ` или `not found: `. Клиент в HTTP-API обычно использует прямое чтение state: ``` GET /api/contracts/native:username_registry/state/name:alice → { value_hex: "" } ``` ### `lookup(address)` — free Обратный lookup. Логирует `name: ` или `no name:
`. Клиент использует `GET .../state/addr:`. ### `transfer(name, new_owner)` — free Передать `name` другому адресу. Только текущий владелец может вызвать. Новый владелец не должен уже иметь имя. ### `release(name)` — free Удалить привязку. Только текущий владелец. Освобождает `name` и `addr:` для будущих регистраций. ## State layout Все ключи записываются в общий namespace `cstate:native:username_registry:`: | Key | Value | |-----|-------| | `name:` | Hex pubkey владельца (64 символа) | | `addr:` | ASCII-строка с именем | Значения хранятся как байты; HTTP endpoint `/api/contracts/:id/state/:key` возвращает их в `value_hex`, клиент делает `hex → UTF-8` перед показом. ## Клиентская интеграция - `useWellKnownContracts` хук авто-синхронизирует `settings.contractId = native:username_registry` - `resolveUsername(contractId, name)` и `reverseResolve(contractId, addr)` в `client-app/lib/api.ts` делают HTTP-запрос + hex-decode - Settings экран покупает никнейм через `buildCallContractTx({amount: 10_000, ...})` + автоматический `reverseResolve` polling после submit для показа `@name` в профиле за ~1 блок ## Отличия от предыдущей WASM-версии | | WASM v1 | Native v2 | |---|---------|-----------| | **Fee** | 10^(7-len), tiered | Flat 10 000 µT | | **Fee destination** | Contract treasury | Burn | | **Min length** | 1 | **4** | | **Payment point** | Debited inside contract, invisible in tx | `tx.Amount`, visible in history | | **Latency** | ~10 ms (wazero startup) | ~50 µs (direct Go call) | | **VM hang risk** | Да (требует timeout) | Нет | Зарегистрированные в старой WASM-версии имена не мигрируются автоматически — операторам нужно пере-зарегистрировать после reset chain (см. `CHANGELOG.md` «Compatibility notes»).