Message definitions for the SafHandle CosmWasm contract. Types use cosmwasm-schema (#[cw_serde]). Amounts are in usaf (6 decimal places).
v1 vs. Phase 2. The shipped v1 wasm registers short names only. Every phone message/query/field below (
LinkPhone,ReleasePhone,MarkPhoneVerified,ResolvePhone,PhoneRecord,phone_link_fee_usaf,verified,Handles.phone) is compiled out unless the crate is built with--features phone. Because#[cw_serde]denies unknown fields, sending a phone field to a v1 contract is rejected. Fields marked (phone feature) appear only in the phone build.
{
"native_denom": "usaf",
"name_registration_fee_usaf": "50000000",
"dev_module_wallet": "addr_safro1...",
"governance_admin": "addr_safro1..."
}| Field | Type | Description |
|---|---|---|
native_denom |
String |
Fee denom, typically usaf |
name_registration_fee_usaf |
Uint128 |
Default 50 SAF |
phone_link_fee_usaf |
Uint128 |
(phone feature) Default 100 SAF — omit in v1 |
dev_module_wallet |
String |
Recipient of all registration fees |
governance_admin |
String |
Address authorized for config updates (governance module account) |
Register a short name for the sender.
{
"register_name": {
"name": "john.saf"
}
}| Field | Type | Required | Description |
|---|---|---|---|
name |
String |
Yes | Short name (normalized by contract) |
Funds: Exactly name_registration_fee_usaf of native_denom.
Errors: NameTaken, InvalidName, EmailNotAllowed, ReservedName, InsufficientFee.
⚠️ Phase 2 only — not in the v1 build.LinkPhone,ReleasePhone,MarkPhoneVerified,ResolvePhone, andPhoneRecordare compiled out unless the crate is built with--features phone. The v1 wasm does not expose them. See PHONE_LINKING.md.
Link a phone number to the sender's address. Phones are stored as bare digits — no leading + (country code + subscriber, e.g. 243899123456). A + or any separator is rejected.
{
"link_phone": {
"phone": "243899123456"
}
}| Field | Type | Required | Description |
|---|---|---|---|
phone |
String |
Yes | Bare digits, 8–15 long, no leading + or 0 |
Funds: Exactly phone_link_fee_usaf of native_denom.
State: verified: false until Phase 2 attestation.
Errors: PhoneTaken, InvalidPhone, InsufficientFee.
Transfer name ownership to a new address. Only the current owner may call.
{
"transfer_name": {
"name": "john.saf",
"new_owner": "addr_safro1..."
}
}Burn ownership and free the name for re-registration. Only the owner may call.
{
"release_name": {
"name": "john.saf"
}
}Remove a phone link. Only the owner may call.
{
"release_phone": {
"phone": "243899123456"
}
}Update fee parameters and wallet routing. Callable only by governance_admin.
{
"update_config": {
"name_registration_fee_usaf": "50000000",
"dev_module_wallet": "addr_safro1..."
}
}All fields are optional; omitted fields retain current values. phone_link_fee_usaf is accepted only in the phone build (phone feature).
Mark a phone as verified after off-chain OTP proof. Callable only by authorized verifier contract or governance.
{
"mark_phone_verified": {
"phone": "243899123456"
}
}Resolve a short name or phone number.
{
"get_address": {
"input": "john"
}
}Response (v1):
{
"address": "addr_safro1...",
"record_type": "name",
"normalized_key": "john.saf"
}The verified field exists only in the phone build (phone feature). There, an all-digit input auto-resolves against the phone registry: record_type is "phone" and verified is true or false. In v1 an all-digit input is a numeric-only label, which is reserved → InvalidName / ReservedName.
Errors: NotFound, InvalidName, EmailNotAllowed.
Lookup by normalized name only.
{
"resolve_name": {
"name": "john.saf"
}
}Lookup by bare-digit phone (no +).
{
"resolve_phone": {
"phone": "243899123456"
}
}Return current contract configuration.
{
"config": {}
}Return full record for a name including owner and registration height.
{
"name_record": {
"name": "john.saf"
}
}Return full record for a phone including owner and verification status.
{
"phone_record": {
"phone": "243899123456"
}
}Reverse lookup for an address. Backed by the owner indexes (OWNER_NAMES, plus
OWNER_PHONES in the phone build), so it is a direct key read — never a scan.
Unlike the forward resolvers, this never errors on a missing record; absent
handles come back as null. In v1 the response has only a name field; the
phone field is present only (phone feature).
{
"handles": {
"address": "addr_safro1..."
}
}Response (phone build shown; v1 omits phone):
{
"name": "john.saf",
"phone": "243899123456"
}Either field is null when the address owns no record of that kind.
| Action | Key attributes |
|---|---|
register_name |
name, owner, fee_usaf |
transfer_name |
name, from, to |
release_name |
name, owner |
update_config |
updated_by |
link_phone (phone feature) |
phone, owner, fee_usaf, verified=false |
See safhandle-sdk API reference for TypeScript client methods that wrap these messages.