Routing Contracts
The routing contract is the central contribution of Directory. Rather than returning a static wallet address, the DRS returns a signed document describing how value should be delivered. This document is intentionally short-lived.
Structure
{ "address": "alice@gmail.com", "routes": [ { "value_type": "USDC", "transfer_type": "ethereum", "destination": "0xABC123...", "ttl_seconds": 300 }, { "value_type": "ETH", "transfer_type": "ethereum", "destination": "0xABC123...", "ttl_seconds": 300 } ], "issued_at": "2026-03-08T12:00:00Z", "expires_at": "2026-03-08T12:05:00Z", "signature": "base64-encoded-ed25519-signature"}Fields
| Field | Type | Description |
|---|---|---|
address | string | The Directory address that was resolved (normalized) |
routes | array | One or more delivery routes |
routes[].value_type | string | What is being transferred |
routes[].transfer_type | string | How it moves |
routes[].destination | string | Where to send it (transfer-type-specific) |
routes[].ttl_seconds | integer | Route validity, 30–3600 |
issued_at | string (RFC 3339) | Contract creation timestamp |
expires_at | string (RFC 3339) | Contract expiry timestamp |
signature | string | Base64-encoded Ed25519 signature |
Unknown top-level fields MUST be signed alongside the known fields and MUST be preserved by clients (forward compatibility).
Limits
routesMUST contain between 1 and 32 entries.ttl_secondsMUST be 30–3600.- Contract body MUST be
<= 64 KiB. issued_atMUST NOT be more than60 sin the future relative to the verifier’s clock.expires_atMUST NOT be more than60 sin the past relative to the verifier’s clock.
Canonicalization and Signing
Contracts are signed using Ed25519 over a canonical JSON serialization produced by RFC 8785 JSON Canonicalization Scheme (JCS):
- Remove the
signaturefield. - Canonicalize the remaining object with JCS (lexicographic key ordering, number canonicalization, no whitespace).
- Sign the resulting UTF-8 bytes with the domain’s Ed25519 private key.
- Base64-encode the signature and return the complete contract.
Non-finite numbers (NaN, ±Infinity) are forbidden. undefined values are stripped before canonicalization.
Verification Rules
Clients MUST:
- Canonicalize the received contract with JCS, excluding
signature. - Verify the Ed25519 signature against each Ed25519 key published at
_drskey.<domain>until one succeeds. - Reject the contract if no key verifies.
- Reject the contract if
issued_atis too far in the future orexpires_atis too far in the past (±60 s tolerance). - On verification failure, re-fetch DNS records once and retry — this handles key-rotation overlap without breaking senders in flight.
TTL
Short TTLs prevent replay and ensure stale instructions cannot misdirect value after the recipient changes their routing. Typical values are 60–300 seconds. The protocol requires 30–3600.
Destination Patterns
The destination in a routing contract may be:
- Direct wallet address — the recipient’s own wallet or a proxy managed by the operator.
- Temporary deposit address — generated per transaction, expires with the TTL.
- Payment endpoint — an HTTPS endpoint for initiating the transfer.
What the destination is — that’s the operator’s decision. The sender follows the contract.