Skip to content

Repository files navigation

Resolver

Resolver

An autonomous agent that lives in the Solana namespace.
It holds its own key, registers its own names, issues identities beneath them,
resolves and pays other wallets by name, and writes down every decision it makes.

ci status version node TypeScript SNS Helius license


Most "onchain agents" are a language model with a wallet bolted to the side. You tell it what to do, it produces a transaction, and the only thing standing between a bad completion and an empty wallet is that nobody has thought of the right sentence yet.

Resolver is built the other way round. It is an agent with a job — it operates in the Solana Name Service, where names are the assets, identities are the product and counterparties are addressed by something a human can read. The model is the smallest part of it. What the agent may do is a closed set of typed intents, decided by a policy layer that runs before anything is signed, recorded in an append-only journal that is written before the transaction goes out rather than after it comes back.

It owns its name. It registers more. It issues subdomains under the ones it holds and takes fees for them. It resolves bob.sol to the address bob actually agreed to be paid at, not merely the one somebody wrote down. And it does all of that on a loop, unattended, inside a budget denominated in lamports.

Agent wallet: ressmWY859teqC9xL4GUYa1xV9VGGSWjr7NqJnocMauresolver.sns

The agent addresses itself by name, so that is the handle worth keeping. The wallet behind it can be verified either way round:

resolver resolve resolver.sns
resolver resolve ressmWY859teqC9xL4GUYa1xV9VGGSWjr7NqJnocMau
Division Path What it is responsible for
Kernel src/kernel/ Domain contracts, the intent set, faults, charter. Imports nothing
Wallet src/wallet/ Custody, the policy gate, the action journal, the executor
Registry src/registry/ SNS derivation, registry decoding, registration pricing
Naming src/naming/ Name shape, generation, availability sweeps, valuation
Records src/records/ Record codecs, ownership proofs, resolution
Peers src/peers/ Counterparties, settled history, standing
Desks src/desks/ Twenty desks in nine divisions. Four work the namespace, sixteen the reserve
Intel src/intel/ Provenance, exposure, ranking, Monte Carlo, memos
Floor src/floor/ The terminal
Briefs briefs/ Long-form reports, BM25-indexed, cited by the operator

Built by kyle-vbc@kyle_vbc · github.

Contents

What it actually does

One pass, five stages. Nothing in the loop is a model call.

1 · Reconcile. The first thing the agent does on every pass is read its own journal and check anything marked submitted-but-unconfirmed against the chain. Nothing new happens until it knows what it already did. This is the entire difference between an agent that restarts and an agent that registers the same name twice and pays for both.

2 · Canvass. Every desk is asked what it can see. The namespace desks look at the name book — what is free, what is held, what is lapsing, what is listed. The capital desks look at the renewal reserve. They run concurrently with independent timeouts and settle independently: a dead marketplace API removes its own rows and reports itself unhealthy in resolver desks, and the pass continues.

3 · Mark and rank. Every candidate is priced, and every price is split. Registering a name has a known cost and a modelled value; the gap between them is booked as registration-spread, and the part that rests on nothing but "a buyer will appear" is booked as speculative-premium and is not counted as real. A name earning subdomain fees is a different asset from a name somebody might want, and Resolver will not average the two into one number.

4 · Form intents. The top of the book becomes a list of Intents — a closed union in src/kernel/domain.ts with nine members. The mapping from a ranking to an intent is a fifteen-line switch in src/cli/commands/run.ts, and it is that short so that it can be read in one sitting by somebody deciding whether to fund the wallet.

5 · Decide, sign, settle. Each intent is priced, passed to the policy gate, written to the journal, and only then — if the verdict is allow — handed to a signer. A verdict of escalate puts it in a queue a human can read. A verdict of deny is final and says which rule fired.

$ resolver run --take 3

  41 opportunities  ·  acting on 3  ·  0 unsettled

  renew resolver.sns
      confirmed  ·  0.1041 SOL  ·  within execute autonomy and inside every budget
  register relaypoint.sol
      confirmed  ·  0.1063 SOL  ·  within execute autonomy and inside every budget
  bid on lumen.sol
      escalated  ·  2.4000 SOL  ·  2.4000 SOL exceeds the 0.5000 SOL per-action cap

Autonomy, and what bounds it

"Fully autonomous" is a claim about who is in the loop. It is not a claim that anything goes, and an agent that cannot tell you the difference should not be holding a key.

Four levels, set in config or RESOLVER_AUTONOMY:

Level May sign
observe nothing. Reads only
propose nothing. Decides and queues everything for a human (default)
execute reversible actions: register, renew, records, subdomains, payments
unattended disposals too: transfer, list, bid

Above that sit three rules that no level relaxes:

  • Burning a name is never autonomous. It is the one action with no recovery path, and it always escalates.
  • Budgets are denominated in lamports, not calls. Rate limits are the wrong control for an agent with a wallet — ten cheap registrations are fine and one expensive one may not be. There is a per-action cap, a rolling daily cap computed from settled journal rows, and a reserve floor that renewals are paid out of and nothing else may touch.
  • The gate is deny-by-default and pure. No network, no clock but the one passed in, no model. The same intent under the same budget decides the same way every time, which means a decision can be replayed from the journal and checked. See src/wallet/policy.ts — it is 200 lines and worth reading before you fund anything.

The key itself lives in src/wallet/keypair.ts and is deliberately narrow: read from disk once, never logged, never serialised, never returned by any accessor, toJSON overridden to say [redacted]. There is exactly one method that produces a signature and it takes bytes — nothing in that class knows what a transaction is, so nothing in it can be talked into signing a different one.

Names as assets

A .sol name is two things at once, and confusing them is how agents end up renewing worthless names and letting good ones lapse.

As an identity, a name is a stable handle that survives the owner rotating keys. As an asset, it has a cost (length-priced registration, plus rent), a value (what somebody would pay), and a cash flow (what the subdomains and records under it earn). Resolver models both, separately, and the split is visible everywhere:

$ resolver name generate relay --check --limit 4

  relay.sol     $144 mark  ·  $20/yr  ·  modeled
      relay is a standalone root; nothing has to be explained to a buyer.
  relays.sol    $34 mark  ·  $20/yr  ·  modeled
      relays extends "relay" into a namespace one owner can hold end to end.
  getrelay.sol  $26 mark  ·  $20/yr  ·  modeled
      getrelay is the same root with a prefix that widens the buyer set.
  gorelay.sol   $26 mark  ·  $20/yr  ·  modeled
      gorelay is the same root with a prefix that widens the buyer set.

A seed narrows the search rather than adding to it. Ask for names around relay and you get names built from relay — not the three-letter roots and short numerics that mark higher than anything seeded and would otherwise crowd the seed off the page. Omit the seed and the whole lexicon is in play.

modeled is doing real work in that output. A mark with no comparables behind it is an opinion, and it is labelled as one — the secondary desk requires a 60% discount to a modeled mark before it will bid, against 20% for a measured one. Most listings fail that test. That is the desk working, not the desk finding nothing.

The generator is deterministic and local. Given the same seed and the same held book it produces the same list in the same order, so a registration can be audited backwards. It also refuses two categories outright: anything that reads as somebody else's mark, and anything whose skeleton collides with a name the agent already owns — s0lomon and resolver are the same string to a human and owning both is a cost, not a moat.

Availability is checked in batches through getMultipleAccounts, so a thousand candidates is a handful of round trips rather than a thousand, and every result carries the slot it was observed at. "Available" is a claim about a moment. A registration built on a five-minute-old availability check is a race the agent has already lost.

Resolution, and the rule that protects the balance

There are two answers to "where does bob.sol point", and they are not the same one.

The owner is whoever controls the name account. The payee is whoever the owner has said should receive value — the sol-record. Usually they are identical. When they are not, paying the owner is wrong, and paying an unverified record is worse, because anyone can write a record pointing anywhere.

So Resolver has one hard rule and it is not configurable away by accident:

A sol-record is used as the payee only if it is a V2 record whose right-of-association signature verifies. Otherwise the owner is the payee, and the caller is told why.

$ resolver resolve bob.sol --records

  bob.sol  (favourite)
  owner    9xQ…7mK
  pays to  4Fw…2pR  via a verified sol-record

  sol-record  4Fw…2pR              verified
  url         https://bob.example  V1 unverified
  twitter     @bob                 V2 unverified

V1 records are shown and never trusted for payment: the format has no way to prove the target agreed to be pointed at. That is not a hypothetical — it is the attack, and it is cheap. The codec is src/records/codec.ts; the decision is one function, decide, in src/records/profile.ts, and every payment path in the codebase goes through it.

Reverse resolution follows the same discipline. A wallet with no favourite domain is reported as an unnamed counterparty rather than being addressed by whichever of its names happened to sort first.

The desks

Nine divisions. Each desk implements one interface — Desk in src/kernel/domain.ts — and is four methods wide.

Division Desks The edge it is claiming
namespace Registration, renewal, subdomain The primary market, keeping what is held, and issuing under it
market Secondary An ask is a fact; a mark is an opinion. Act on the gap
staking Marinade, Jito, Sanctum Consensus rewards and MEV on the renewal reserve
credit Kamino, marginfi, Save Borrowers pay interest; the curve says when to care
liquidity Orca, Raydium, Meteora Trading fees, against inventory risk
derivatives Drift Funding and the basis, as a rate rather than a direction
arbitrage Venue spread, LST basis, funding carry The same asset priced twice, net of both legs
trading Momentum, mean reversion Regime, with the invalidation level committed up front
treasury In-house The agent's own wallet, read from chain state

The namespace divisions come first because they are the business. The capital divisions are the treasury function: the renewal reserve has to sit somewhere, and somewhere is not a wallet earning nothing.

Two of them are worth calling out.

Renewal is the least interesting decision in the business and the most expensive one to get wrong. A name that lapses does not lose some value — it becomes somebody else's name, immediately and permanently, along with every subdomain and record beneath it. So renewal is modelled as an opportunity like any other, and it usually wins by an enormous margin. That is not a trick to game the ranker; spending $20 to not lose $600 is the best trade on the page. The desk also emits the negative case: a name marked below its renewal cost gets a zero rate and a note, so the agent lets it go on purpose rather than by accident.

Subdomain issuance is the only desk in the building whose return is entirely real. Subdomain fees are paid by users, not implied by a future buyer, so they survive the speculative mark going to zero. It is also the smallest number on the page — which is the usual shape of that distinction, and the reason the agent keeps the two apart instead of blending them into one APY.

A desk that cannot honestly split subsidy from real revenue says so in confidence rather than guessing, and the ranker discounts it. Writing one: docs/desks.md.

Peers

Counterparties are keyed by address, never by name. Names are how the agent addresses a peer; they are not identity, because a name can be sold to somebody else on a Tuesday and the reputation must not go with it.

Standing is 0–100 and is built from settled on-chain facts only — how many interactions have actually confirmed, how long the agent has known them, and whether they publish a name at all. Nothing a counterparty says about itself enters the calculation. Deliberately not a term: how much value moved. A large trade is not a trustworthy trade, and pricing standing off size is exactly how an agent gets set up.

$ resolver peers

  bob.sol            72  ·  9 settled  ·  +1.240 SOL
  registry.sol       58  ·  4 settled  ·  -0.400 SOL
  8kR…3nQ            21  ·  2 settled  ·  +0.015 SOL

What it will not do

This list is a design constraint, not a roadmap gap.

  • No transaction the model wrote. The operator emits Intents. There is no method anywhere that accepts a pre-built transaction from a model, so a compromised completion cannot express "drain the wallet" — that sentence has no representation in the type.
  • No burn without a human. At any autonomy level, ever.
  • No payment to an unproven record. See resolution.
  • No name that reads as somebody's mark. Screened in the generator and screened again in the policy gate, because defence in depth is cheaper than a lawyer.
  • No number without a provenance. Every mark carries measured | reported | modeled | stale, and every rate carries the split between what is earned and what is hoped for.
  • No shell, no filesystem write, no arbitrary host. The operator's tool registry is a closed set in src/ops/tools.ts and the model cannot extend it.

Requirements

  • Node.js >= 22.6 — required for native TypeScript type-stripping, which is how bin/resolver.js runs an unbuilt checkout. 24.x is tested in CI.
  • A Helius API key for anything that touches Solana. Reverse lookups and subdomain enumeration need an indexed getProgramAccounts, which a vanilla RPC will refuse — that is the practical reason the dependency exists. Export HELIUS_API_KEY, or point rpcUrl at your own indexed node.
  • A keypair, but only for the commands that write. resolve, name check, name generate, peers, book and doctor all work without one — the agent should not need custody of a wallet to answer a question about somebody else's.
  • An Anthropic API key only for resolver ask and the floor's conversation pane. The autonomous loop does not call a model.
  • A terminal that reports truecolor for the intended palette. Resolver reads COLORTERM and downshifts to a 16-colour ramp rather than emitting truecolor escapes at a terminal that will render them as mud. NO_COLOR is honoured.

Install

npm install -g resolver
export HELIUS_API_KEY=…
resolver doctor

From a checkout, no build step required:

git clone https://github.com/kyle-vbc/resolver.git
cd resolver
npm ci
node bin/resolver.js doctor

Getting started

1 · Give it an identity.

resolver identity create

This mints a keypair into $RESOLVER_HOME/keys/agent.json at mode 0600 and prints the address. It is not backed up anywhere and there is no seed phrase. Copy the file somewhere safe before you fund it; if it is lost, every name registered under it is gone.

2 · Fund it, and look at it.

resolver identity
  Ag3nT7…9kQz
  1.4820 SOL  ·  autonomy propose

  no favourite domain set; peers will see an address, not a name
  holds no names — `resolver identity claim` registers one

3 · See what it would do, before it can do anything.

The default autonomy is propose: the agent decides and writes nothing.

resolver run --dry --take 5
resolver queue

resolver queue show <id> expands one row into the full decision — the intent, what it costs in lamports and dollars, which rule fired, and every sentence the policy layer emitted on the way to its verdict.

4 · Let it claim its name.

resolver --home ~/.resolver config set autonomy execute
resolver identity claim

That registers the best available candidate for the configured handle and writes a sol-record pointing at the agent's wallet, in that order — a name registered without a record is an identity nobody can pay.

5 · Let it run.

resolver run --every 60

One pass an hour, inside the budgets, journaling as it goes. Ctrl-C between passes exits cleanly; it will never be interrupted mid-transaction, and anything in flight is reconciled on the next start.

Command surface

resolver                                  # interactive floor
resolver identity                         # address, balance, names, autonomy
resolver identity create                  # mint the agent's keypair
resolver identity claim [name]            # register its own name and point it home
resolver name generate [seed]             # candidates, ranked by modelled value
resolver name check <names...>            # who owns these, at a stated slot
resolver name register <name>             # register to the agent's wallet
resolver name renew <name>                # extend a registration it holds
resolver resolve <name|address>           # both directions, owner vs payee
resolver peers                            # counterparties and standing
resolver pay <name|address> <sol>         # pay through the record rules
resolver run                              # one autonomous pass
resolver queue                            # what is waiting on a human
resolver queue show <id>                  # the full decision, rule by rule
resolver treasury [wallet]                # holdings, idle share, concentration
resolver book [wallet]                    # ranked opportunities
resolver allocate [wallet]                # a plan, with the rejection log
resolver memo <opportunity-id>            # mechanics, exposures, the tradeoff
resolver simulate [wallet]                # seeded Monte Carlo over the plan
resolver brief [query]                    # BM25 search over the corpus
resolver ask [prompt]                     # one headless operator turn
resolver watch [wallet]                   # refresh on an interval, diff changes
resolver desks                            # per-desk health and latency
resolver config <show|get|set|unset|path>
resolver doctor                           # keys, connectivity, cache, versions

Useful flags on the acting commands:

resolver run --dry                        # form intents and price them, submit nothing
resolver run --take <n>                   # how many ranked rows to act on
resolver run --every <minutes>            # loop forever on an interval
resolver name generate --check            # look each candidate up on-chain
resolver resolve --records                # print every record under the name
resolver queue --all                      # include settled and denied rows

Global options, valid on every subcommand:

-w, --wallet <address>
-a, --mandate <preservation|conservative|balanced|growth|degen>
    --json                  single JSON document on stdout, nothing else
    --no-tui                force the static renderer
    --refresh               bypass the cache for this run
    --log-level <level>     trace|debug|info|warn|error   (stderr)
    --no-color              equivalent to NO_COLOR=1
    --home <path>           override RESOLVER_HOME for this run
    --autonomy <level>      observe|propose|execute|unattended, this run only

Every command speaks --json: one document on stdout and nothing else.

resolver name generate --check --json | jq '.candidates[] | select(.mark.usd > 500)'
resolver queue --json                 | jq '.actions[] | select(.state == "escalated")'
resolver resolve bob.sol --json       | jq '.resolution.payTo'
resolver doctor --json                | jq '.checks[] | select(.ok == false)'

Methodology

The parts worth arguing with are in src/naming/ and src/intel/, kept separate from data collection so they can be read and disputed on their own. Both are pure: no I/O, no network, no import-time work, deterministic given the same input.

Valuation. A name's mark is a product of independent multipliers over a length-anchored base, not a base plus a stack of bonuses. That is how the secondary market actually behaves: a four-letter dictionary word is not "four-letter price plus dictionary bonus", it is a four-letter name that a much larger set of buyers can use. Multipliers compose; addends do not. Length is counted in code points💀.sol is a one-character name, and pricing it as four because UTF-8 said so is how an agent overpays for a skull.

Provenance. Real means someone paid for a service: subdomain fees, lease income, hosting, the discount to fair value captured at registration. Speculative means the number exists because a story does. realShare is the ratio, and it is the single most load-bearing figure in the product. A name whose entire return is speculative-premium can be excluded by one line in a mandate, which is the whole point of splitting it.

Exposure. Factors combine as 1 − Π(1 − wᵢ) rather than summing, scaled to 0–100, then discounted by a maturity multiplier and an audit multiplier with diminishing returns. Saturating combination is the point: ten cosmetic concerns should never outrank one custody risk. The namespace factors —expiry, custody, trademark, front-run, namespace-authority — sit in the same table as the DeFi ones and are weighted on the same scale.

Front-running is a modelled cost, not a footnote. Availability is public. Anything the agent can see, a sweeper can see, and short names carry a 0.8 weight on that factor for exactly that reason.

Score. (effectiveApy − hurdleApy) / (riskAversion × riskPenalty), then multiplied by liquidity, confidence, capacity and breakeven terms. If you disagree with a ranking, the output names the term to argue with.

Full derivations: docs/methodology.md.

Briefs

Long-form reports ship in briefs/, indexed at build time into a BM25 store — field-boosted, stemmed, phrase-aware — that the operator searches before it explains anything.

resolver brief "adverse selection"
resolver brief read real-yield-vs-emissions

They are versioned with the code on purpose: when the model's explanation and a brief disagree, the brief is the source of truth. The worked examples are illustrative — the mechanisms and the arithmetic are real, the specific figures are teaching numbers rather than a record of what any venue printed on a day.

Configuration

Resolution order, lowest priority first: built-in defaults, then $RESOLVER_HOME/config.json, then a project-local .resolver.json, then environment variables, then CLI flags. Secrets are only ever read from the environment or from a key file. Nothing that can be committed holds a key.

Setting Purpose
HELIUS_API_KEY Chain data. Required for anything that touches Solana
RESOLVER_KEYPAIR Path to the signing key (default $RESOLVER_HOME/keys/agent.json)
RESOLVER_AUTONOMY observe | propose | execute | unattended
RESOLVER_HANDLE The handle the agent claims its identity under
ANTHROPIC_API_KEY Model provider. Required only for ask and the floor
RESOLVER_HOME State root, must be absolute (default ~/.resolver)
RESOLVER_WALLET A wallet to read instead of the agent's own
RESOLVER_MANDATE Default mandate band
RESOLVER_RPC_URL Bring your own indexed RPC instead of Helius
RESOLVER_COLOR truecolor or off
NO_COLOR Honoured

Budgets, protected names and the blocklist live in config.json:

{
  "autonomy": "execute",
  "handle": "resolver",
  "budget": { "perActionSol": 0.5, "perDaySol": 2, "reserveSol": 0.25 },
  "protectedNames": ["resolver.sns"],
  "blocklist": [],
  "roots": {}
}

protectedNames cannot be transferred, listed or burned automatically at any autonomy level. reserveSol is a floor, not a budget: renewals are paid from it and nothing else may spend into it.

roots supplies the TLD root accounts. .sol has a built-in default; .sns does not, because it is a newer TLD with its own root account and Resolver will read against a fallback but will not write into a tree it had to guess. The agent's own name lives under .sns, so set roots.sns before asking it to write anything there — reads resolve without it, writes refuse.

State under RESOLVER_HOME: config.json, keys/ (0700), actions.jsonl (the append-only action journal), peers.json, cache/, minutes/, statements/, logs/.

Repository map

Path Purpose
src/kernel/ Domain contracts, the intent set, fault taxonomy, charter. Imports nothing
src/wallet/ Keypair custody, policy gate, action journal, executor
src/registry/ SNS program constants, PDA derivation, registry decoding, pricing
src/naming/ Name shape, lexicon, generator, availability sweeps, valuation
src/records/ Record codecs, V2 proof checking, resolution
src/peers/ Counterparty directory and standing
src/venues/ Helius RPC + DAS, base58 and account decoders, marks, treasury assembly
src/desks/ The nine divisions
src/book/ Discovery, sizing, capital allocation
src/intel/ Exposure, provenance, ranking, Monte Carlo, deterministic memos
src/ops/ Anthropic streaming client, tool registry, operator loop, directive
src/ledger/ Disk cache, minutes, statements
src/floor/ Ink panels, hooks, and the static non-TTY renderer
src/common/ Journal (redacting logger), formatting, concurrency primitives
src/identity/ Palette sampled from assets/mark.png, wordmark, drawing primitives
src/cli/ Commander program, per-command handlers, output contract

The dependency arrow points at src/kernel/ and never out of it. Nothing in src/naming/ or src/intel/ imports a network client.

Development

npm ci
npm run typecheck          # tsc --noEmit, 0 errors
npm run lint               # eslint, 0 warnings
npm run build              # tsc -p tsconfig.build.json -> dist/
npm test                   # hermetic node:test suite, no network
npm run run:dry            # one pass, priced, nothing submitted
npm run briefs:catalog     # rebuild briefs/catalog.json
node bin/resolver.js …      # run the checkout without building

The stable suite is hermetic by construction: src/naming/ and src/intel/ are pure, the simulator is seeded, the policy gate takes its clock as a parameter, and desk tests run against recorded fixtures. Any test that reaches the network is a bug, so CI runs without keys and fails loudly rather than passing quietly.

Status and known limits

Beta, 0.3.0. Type-clean under strict with noUncheckedIndexedAccess and exactOptionalPropertyTypes; zero any, zero @ts-ignore.

Stated plainly, because a tool that hides these is worse than useless:

  • Instruction assembly is a seam, not a shipped implementation. Everything above the signer — pricing, policy, journalling, reconciliation — is complete and tested. Executor.#build is one method, and it is where the SNS instruction builders land. Until it is filled in, run without a broadcaster signs and stops, which is the correct dry-run behaviour and is not a substitute for the real thing.
  • Name marks are modelled, not fitted. The multipliers in src/naming/valuation.ts are hand-calibrated against how the secondary market behaves, not regressed against a sales index. confidence says modeled because it is, and the desks discount it accordingly.
  • SNS names do not currently expire, so the renewal desk is modelling a mechanism the registrar has shipped before rather than one it is running today. The grace and auction branches exist so that the desk does not have to be rewritten the day that changes.
  • Subdomain demand is a curve, not an observation. Expected takers per namespace are a function of parent length. It is a defensible shape and it is not a forecast.
  • Standing is thin by design. Three terms, all observable. A thin signal that cannot be forged beats a rich one that can, but it is still thin.

Security

  • The key never leaves src/wallet/keypair.ts. Read once, never logged, never serialised, [redacted] in every dump.
  • Every write passes the policy gate. Deny-by-default, pure, replayable.
  • Every action is journalled before it is submitted, so a crash between signing and confirming leaves evidence rather than a mystery, and the next pass reconciles rather than repeats.
  • API keys are read from the environment only. The journal walks nested objects and arrays, redacting secret-shaped field names — including the x-api-key header form — and stripping credentials from any URL. config set refuses a value that carries a credential by shape.
  • Report a vulnerability privately: SECURITY.md.

Nothing here is financial advice. Names are illiquid, thinly bid, and frequently worth less than the model says. Every position Resolver takes can lose money, and the ones that score highest are usually being paid the most to carry a risk that has not shown up yet.

License

MIT. See LICENSE. Contributions: CONTRIBUTING.md.


Built by kyle-vbc · @kyle_vbc · github.com/kyle-vbc · resolver.sns · ressmWY859teqC9xL4GUYa1xV9VGGSWjr7NqJnocMau

About

An autonomous agent on Solana Name Service. Holds its own key, generates and registers .sol and .sns names, issues subdomains beneath them, resolves counterparties by name, and pays only addresses that proved they agreed to receive.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages