RFC and fixes

This commit is contained in:
Alain Brenzikofer committed 2026-09-22 16:59:50 +02:00
1 parent adcdb54c02
commit 861e9890c6
3 files changed
+80 -1

No files matched your search

+1 -1
View File
@@ -10,7 +10,7 @@ Crypto:
SMP protocol:
- `ROWN` command (v23): the names an address owns, and whether the account has
been used at all, so a recovered wallet seed can be scanned for the accounts
already in use.
already in use. See `plans/2026-09-22-names-owned-by.md`.
# 6.5.1
+78
View File
@@ -0,0 +1,78 @@
# Owned-by: the names an address owns
A recovered seed does not say how many of its accounts have been used. Until it
does, a restored device cannot take a fresh account without risking one its
owner already has, and cannot find the names it already holds. This adds the
question the protocol could not ask: what does this address own.
This is Workstream B of the SimpleX names v2 plan, after the Ethereum crypto
primitives. The client consumer is the wallet recovery scan in simplex-chat.
## What this delivers
```
GET /v2/owned-by/<address>?offset=N resolver, JSON OwnedNames
ROWN <address> <offset> -> ROWND SMP v23 (nameOwnedSMPVersion)
ownedNames server, agent client, agent
```
The agent returns the relay it used alongside the answer, so a caller can pass
it back as used and ask the next account elsewhere. Sending every account of a
seed to one relay would tell that relay the accounts belong to one wallet; the
scan therefore asks one account per relay, and `getNextNameServer` avoids the
hosts already used where the configured set allows. `proxiedSMPRelayVersion` is
pinned to the current version so ROWN can be proxied at all — a scan that falls
back to a direct session hands the relay its address with its IP.
Enumeration is read off the ERC-721 registrar (`balanceOf`,
`tokenOfOwnerByIndex`, `labelOf`), not from registration logs: the token is the
name, so a name acquired by transfer counts. The registrar does not maintain
enumeration on expiry — it states this as an invariant, and burns a token only
when the name is re-registered — so a lapsed name stays listed. It is reported
with its `status` rather than filtered, because a caller scanning a recovered
seed is exactly the caller who needs to be told a name can still be renewed.
## What `inUse` actually answers
`inUse` is `holds a name now, or nonce > 0, or balance > 0`, on the one chain
the resolver is configured with. Holding a name is only one way for an account
to be in use: an account that was funded, or ever sent a transaction, is in use
with no name, and a scan that reads names alone hands out an account its owner
is already using. Within that scope the signal is sound — an EOA's balance can
only fall through its own transaction, which bumps the nonce, so "funded then
drained" still reads as used, and an EIP-7702 delegation leaves the authority's
nonce incremented, so it needs no separate code check.
It does not see:
- **Accounts holding only other tokens.** An EOA can hold ERC-20s or NFTs with
nonce 0 and no ether. ERC-20 has no reverse index, so answering this needs
`eth_getLogs` over Transfer topics for all history, which providers cap, or an
external indexer. Out of scope here.
- **Accounts used on another chain.** The same key is the same address on every
L2 and sidechain; this chain's nonce and balance stay 0.
- **History, as opposed to current state.** `balanceOf` is present ownership. A
name registered for an account by a controller — which leaves the owner at
nonce 0 — and later transferred away, or lapsed and re-registered by someone
else, leaves no trace.
The cost is bounded. A name-holding account is always found, so no account that
holds a name is ever mislabelled. A missed account matters only as a gap-limit
reset: the scan can stop up to `scanGapLimit` indexes early and not reach a name
beyond that. That is recovery incompleteness, recoverable by scanning again on a
better signal, not loss. In the other direction a dust transfer marks an account
used; the indexes come from hardened derivation with no published xpub, so they
cannot be enumerated to be dusted.
## What is deliberately absent
- **No token or indexer integration**, per the limits above.
- **Nonce and balance are not carried over SMP.** The resolver reports them, and
`OwnedNames` keeps only the names, the flag and the cursor, so a client cannot
yet see why an account is in use.
- **No caching.** One owned-by is many `eth_call`s, so it is forked on the
server the same way RSLV is, and nothing is memoised.
- **Enumeration is not atomic.** `balanceOf` and each `tokenOfOwnerByIndex` are
separate calls at `latest`, so a transfer between them can duplicate or skip an
entry, and successive pages can straddle blocks. Pinning every call to one
block number is the fix if it ever matters for a recovery scan.
+1
View File
@@ -178,6 +178,7 @@ smpBlockSize = 16384
-- 20 - public namespaces resolver, RSLV command (6/20/2026)
-- 21 - server public information in handshake (7/5/2026)
-- 22 - RNAME answers name availability as well as the record (7/25/2026)
-- 23 - ROWN command, the names an address owns (9/22/2026)
data SMPVersion