Practical · Worked examples · Byte counts computed, not estimated
Working with SRC-101
This page walks through the five operations with complete payloads, shows exactly how many bytes each one occupies on chain, works out what a term costs, and explains how to tell whether your registration actually happened. Every example is constructed for illustration. The addresses and the public key are well formed and pass every checksum, because a broken example teaches the wrong lesson, but they are derived from fixed text rather than from any key anyone holds. No transaction hash here names a transaction that exists.
Contents
1. Before you spend anything
Four things decide whether an SRC-101 transaction does what you meant, and all four are settled before you sign.
The namespace
A 64-character transaction hash. It fixes the price list, the addresses that may collect payment, the term granularity, and the mint window. There is no global list of namespaces in the protocol; you have to be given the hash.
The exact key set
Four of the five operations reject a payload with a single extra or missing key, and reject it silently. Run your payload through the validator before you build the transaction.
The payment output
Output 0 must pay one of the namespace's recipient addresses, and must pay at least the computed amount. One satoshi short is a failure with status IRV, and the fee is still spent.
The name, decoded
Names are compared after Base64 decoding and lower-casing. Confirm what your Base64 actually decodes to before you pay for it.
Both are specific to SRC-101 and neither exists in SRC-20. First, a malformed key set is excluded: your transaction confirms, your fee is spent, and no record of an attempt exists anywhere. Second, a multi-name mint drops taken names and proceeds: you pay for what you asked for and receive only the names that were free. Neither produces a warning.
2. Opening a namespace
A deploy is the largest payload in the protocol and the only one with no hash. All sixteen keys are mandatory.
{
"p": "src-101",
"op": "DEPLOY",
"root": "btc",
"name": "bitnames",
"tick": "bitname",
"lim": "1",
"owner": "14caKuhoxA2wCj7JYjVJhgsuxTsbu5rzch",
"rec": ["bc1qs2x9wz22tasf8pfejlcc3e8yhnzhv9qs2kgwls"],
"pri": { "0": 200000, "3": 2000000, "4": 800000 },
"desc": "Bitcoin name registry",
"mintstart": "1732924800",
"mintend": "0",
"wla": "02bb9e14cd42f6487e94071cb25fe5bd6f42753de771be11d21c6a80b5f08cf4a4",
"imglp": "https://names.example/i/",
"imgf": "png",
"idua": "1"
}
| Field | Effect |
|---|---|
root | Labels the namespace. Shorter than 32 characters, no special characters. Not used in any check |
name | Human-readable namespace name. Shorter than 32, no special characters |
tick | Shorter than 32. Lower-cased and hashed with SHA3-256 into a stored tick_hash |
lim | Not a limit. Only a presence sentinel. Must be greater than zero or the namespace is unusable |
owner | Stored. Not consulted by any authorisation or payment check |
rec | The addresses that may collect mint and renew payments. Order is not preserved |
pri | Price in satoshis per decoded name length. The key 0 is the fallback for any other length |
desc | Free text, stored, never validated |
mintstart | Unix seconds. Minting is allowed when the block timestamp is at least this |
mintend | Unix seconds. Zero means no end, stored as 18446744073709551615 |
wla | Compressed secp256k1 public key. Signs discount authorisations for mints |
imglp | Image URL prefix. Shorter than 255 |
imgf | Image file extension. Shorter than 32 |
idua | Term granularity in years. Every requested term is rounded up to a multiple of this |
Setting lim to "0" makes every later operation fail with ND, because the namespace lookup treats a zero limit as "not found". Setting idua to "0" makes every mint and renew fail with ITID, because the term rounding divides by it. Neither is caught at deploy time. The deploy is recorded as valid and the namespace is dead.
Also worth knowing before you deploy: you cannot mint in the same block. The in-block namespace lookup cannot resolve a namespace deployed in that same block, so a mint in the deploy's own block fails with ND. Wait for a confirmation.
3. Claiming a name
A mint at block 872200 or above. The tokenid value c2F0b3NoaQ== is Base64 for satoshi.
{
"p": "src-101",
"op": "MINT",
"hash": "3a7f1c8e0b45d29a6f13e874c05b9d2e6a8f04713bc9e25d8a06f1c34b7e9c19",
"toaddress": "bc1qs2x9wz22tasf8pfejlcc3e8yhnzhv9qs2kgwls",
"tokenid": ["c2F0b3NoaQ=="],
"dua": "2",
"prim": "true",
"sig": "",
"coef": "1000"
}
Five details in that payload are easy to get wrong:
tokenidis a list even for one name. The string form is rejected withITT.primis the string"true". The JSON booleantruediscards the whole payload.sigis present but empty. It is mandatory below block 872200 and, if you want the payload to work at every height, worth keeping.coefis"1000", meaning full price. Any value below 1000 is ignored unlesssigproves it.toaddressis where the name goes, and it need not be you. Output 0 is where the money goes, and that must be a namespace recipient.
Below block 872200 the same mint additionally required an img list, and the entries had to match the derived URLs exactly:
"img": ["https://names.example/i/satoshi.png"],
At and above 872200 an img you supply is discarded and the derived value is written instead, so there is no reason to include it.
Minting several names at once
"tokenid": ["c2F0b3NoaQ==", "Yml0Y29pbg==", "bGFwc2Vk"],
The three decode to satoshi, bitcoin and lapsed. If bitcoin is already held with a live expiry, it is dropped and the other two are minted. The required payment is computed over the full submitted list, before the drop, so you pay for three and receive two. If all three were taken you would get status DM and nothing at all.
4. What a term costs
The arithmetic is short and entirely deterministic. Using the deploy above, whose pri is {"0": 200000, "3": 2000000, "4": 800000} and whose idua is 1:
| Operation | Name and length | dua | Rounds | Unit price | Required at output 0 |
|---|---|---|---|---|---|
| mint | satoshi, 7 | 2 | 2 | 200000, the fallback | 400000 |
| mint | abc, 3 | 1 | 1 | 2000000 | 2000000 |
| mint | abcd, 4 | 3 | 3 | 800000 | 2400000 |
| mint, three names | satoshi, bitcoin, lapsed | 1 | 1 | 200000 each, all use the fallback | 600000 |
| renew | satoshi, 7 | 1 | 1 | 200000 | 200000 |
When the granularity bites
If the namespace had "idua": "2" instead, a request for "dua": "3" would round up to 4, giving 2 rounds, and you would pay for four years while asking for three. The rounded value is what is stored, so you do get the four years. It is not a penalty, but it is not what you asked for either, and it is the value that goes into the discount signature.
The discount, if you have one
A namespace operator can pre-authorise a discount by signing over your specific mint with the namespace's whitelist key. You then set coef to the agreed value in parts per thousand and put the signature in sig. A coef of 250 means you pay a quarter. If the signature does not verify against either of the two accepted message forms, the mint fails outright with IRS; it does not fall back to full price. The exact message forms are in rule 51. Two traps: the dua in the signed message is the value after rounding, and coef and dua are serialised as strings.
There is no discount on renewal. The renew key set has no coef and no sig.
5. Pointing a name somewhere
A name with no records is just a reservation. setrecord is what makes it resolve.
{
"p": "src-101",
"op": "SETRECORD",
"hash": "3a7f1c8e0b45d29a6f13e874c05b9d2e6a8f04713bc9e25d8a06f1c34b7e9c19",
"tokenid": "c2F0b3NoaQ==",
"type": "address",
"data": { "btc": "bc1qs2x9wz22tasf8pfejlcc3e8yhnzhv9qs2kgwls" },
"prim": "true"
}
Note that tokenid here is the plain string form, not a list. Only mint takes a list.
Two record kinds exist. "type": "address" writes a resolved address, and "type": "txt" writes free text. Any other type value produces neither and the operation fails with ID.
The Ethereum record is a signature, not an address
This is the least obvious part of SRC-101. Inside data, the eth member is not an Ethereum address. It is the hexadecimal signature of an Ethereum personal-sign message, and the message text is the hexadecimal, byte-reversed hash of the transaction your input 0 is spending. The indexer recovers the signer from that signature and stores the recovered address, without its 0x prefix.
"data": { "eth": "<hex signature over the reversed previous txid>" },
The effect is that you cannot claim an Ethereum address you do not control, and the proof is bound to this specific Bitcoin transaction. The cost is that the signature has to be produced after you have chosen your inputs and before you sign the Bitcoin transaction.
The primary flag
Setting "prim": "true" marks this name as the primary one for its holder within this namespace. Two constraints follow. The payload must also carry an address record whose btc member equals the address funding input 0, else status IDB. And the flag is cleared from every other name that address holds in the namespace: one primary per address per namespace.
Records merge rather than replace. A setrecord that sets only txt leaves an existing address record in place. The only thing that clears records is a transfer.
6. Handing a name on
{
"p": "src-101",
"op": "TRANSFER",
"hash": "3a7f1c8e0b45d29a6f13e874c05b9d2e6a8f04713bc9e25d8a06f1c34b7e9c19",
"toaddress": "bc1qs2x9wz22tasf8pfejlcc3e8yhnzhv9qs2kgwls",
"tokenid": "c2F0b3NoaQ=="
}
Five keys, no payment, no term change. The address funding input 0 must be the current owner, and the term must still be running. What the new owner receives is the name and the remainder of the existing term, with every record cleared and the primary flag off.
Check the expiry before you pay. A transfer does not extend the term, so a name with three weeks left is a name with three weeks left, and a renewal is a separate transaction with a separate payment. Check the records too: they will be empty the moment the transfer lands, and re-establishing them is your job, including the Ethereum proof.
There is also nothing in the protocol that makes a sale atomic. The transfer moves the name; whatever you paid for it moved separately, in a transaction the protocol knows nothing about. SRC-101 has no escrow primitive and no on-chain trade path, which is the same reason no Bitcoin Universe product implements one.
7. Keeping a name
{
"p": "src-101",
"op": "RENEW",
"hash": "3a7f1c8e0b45d29a6f13e874c05b9d2e6a8f04713bc9e25d8a06f1c34b7e9c19",
"tokenid": "c2F0b3NoaQ==",
"dua": "1"
}
Five keys, and a payment at output 0 to a namespace recipient. The new expiry is the existing expiry plus the term, so renewing early costs you nothing in time. That is the important asymmetry with the expiry rule:
renewed one block early
Accepted- condition
- block time < expiry
- new expiry
- old expiry plus term
- time lost
- none
- owner
- unchanged
renewed one block late
Refused, OE- condition
- block time >= expiry
- result
- no state change, fee spent
- grace period
- none
- the name
- claimable by anyone
Because there is no grace period, and because the comparison uses the block timestamp rather than the time you broadcast, renewing at the last minute is a race against block production and against anyone watching for the name to lapse. Renew with real margin.
8. Byte framing and outputs
The framed buffer is a two-byte big-endian length, then stamp:, then the JSON. The declared length covers the prefix and the JSON and excludes itself. The counts below are computed from the exact payloads on this page.
| Payload | JSON bytes | Declared length | Framed total | Multisig data outputs | P2WSH data outputs |
|---|---|---|---|---|---|
DEPLOY | 431 | 01b5 (437) | 439 | 8 | 14 |
MINT, 872200 and above | 232 | 00ee (238) | 240 | 4 | 8 |
MINT with img | 278 | 011c (284) | 286 | 5 | 9 |
TRANSFER | 187 | 00c1 (193) | 195 | 4 | 7 |
SETRECORD | 222 | 00e4 (228) | 230 | 4 | 8 |
RENEW | 137 | 008f (143) | 145 | 3 | 5 |
The two output counts come from the carrier geometry. A multisig data output is a 1-of-3 bare multisig whose third key is a burn key; the two data-bearing keys contribute 31 bytes each, so 62 bytes per output. A P2WSH data output carries a 32-byte witness program, so 32 bytes per output, and only outputs after the first count, since output 0 is the payment. Every transaction also needs output 0 and usually a change output on top of the data outputs above.
The practical consequence: a deploy is expensive and a renew is cheap. The deploy above needs roughly three times the data of a renew. If you are choosing a carrier, note that P2WSH needs about twice as many outputs for the same payload but each is a cheap 32-byte program, while multisig packs more per output but uses uncompressible keys.
The decoder reads output 0's value on the P2WSH branch only from block 940000. Below that height a P2WSH-carried mint or renew is seen as paying zero and fails with IRV, no matter what you actually paid. deploy, transfer and setrecord are unaffected because they never read that value. Use bare multisig for paid operations below that height.
9. Reading a result
After your transaction confirms, there are three things it might have become, and only one of them is what you wanted.
- Valid
- The register changed. Your name appears with your owner address and an expiry.
- Invalid, with a status code
- The operation was understood and refused. There is a record with a code such as
IRVorOE, and the status table explains it. Nothing in the register changed. - Excluded
- The payload was never an SRC-101 operation. No record, no status code, nothing to look up. If you cannot find your transaction at all in an SRC-101 view, this is almost certainly what happened, and the cause is almost certainly the key set or a field type.
The most common causes of exclusion, in the order worth checking:
- An extra or missing key. Compare against the key set table character by character.
primwritten as a JSON boolean rather than a string.- A numeric field written as a decimal string, such as
"dua": "1.5". - A
tokenidwhose Base64 is not a multiple of four characters long, or which uses the URL-safe alphabet. - Below block 872200, a mint missing
img.
10. What Bitcoin Universe supports
Taken from the ecosystem capability registry, which is generated from the Core protocol registry and records what the product code implements.
| Surface | Actions |
|---|---|
| Core | view, discover, view-collection, view-activity, view-transaction |
| Wallet | view, send, receive |
| Inscribe | mint, transfer |
| Marketplace | None recorded. The registry has no marketplace entry for SRC-101 at all |
Three consequences follow directly from that table, and it is worth being blunt about all three.
- No product implements a trade path. There is no list, no buy, no offer, no settle. This is not a narrowed marketplace with unsupported actions recorded against it, as SRC-20 has; there is no marketplace entry for the protocol at all.
- Inscribe cannot deploy, renew or write records. Its two recorded actions are mint and transfer. Opening a namespace, renewing a term and setting a record are operations you would need to construct and broadcast yourself.
- No confirmation, freshness or reorg policy is recorded. The registry entry for SRC-101 carries a null source of truth, a null indexer, and null policies for all three. Where a protocol like SRC-20 can point at a stated policy, SRC-101 cannot.
This site states what the registry records and nothing beyond it. A capability that is not in the registry is not claimed here, and support recorded in the registry is a statement about product code, not a promise that a feature is enabled in production.
11. Safety
Names can look identical
Names are decoded from Base64 and lower-cased, and the character rules reject spaces and format characters but not homoglyphs. Two names can render the same and be different registrations. Compare the decoded bytes, not the rendering.
The namespace is the whole context
The same name in a different namespace is a different registration with a different owner. A name shown without its namespace hash tells you nothing.
Expiry is unforgiving
No grace period, no redemption. Note your expiry, renew early, and remember that a transfer does not extend it.
Records are claims, one of them proved
A txt record is whatever the owner wrote. A btc record is a well-formed address, not a proved one. Only the eth record carries a signature the indexer verifies. Do not treat the others as attestations.
Nobody can undo a broadcast
A confirmed transaction cannot be reversed, a mint cannot be un-minted, and no operator can move a name back. Verify the namespace, the decoded name, the recipient and the payment amount before you sign.
There is no consensus safety net
SRC-101 contributes nothing to the block ledger hash and has no cross-implementation check. Two explorers can disagree about who owns a name and nothing will flag it. Where the answer matters, read more than one.