covenants: the subscription and the delivery escrow, on one shared base (draft)
The roadmap asks for the covenant capability to be built once and used three
times. covenant.js is the shared part: artifact to bytecode, redeem script and
lock, signing a covenant input, an unlocking script for any function, and
assembling a transaction around covenant inputs. The registry library now
sits on it, and so do the two new contracts.
Subscription: the buyer funds a balance. Anyone may send one period's price
to the host once per period, the rest going back to the same script; the
buyer may take the balance back at any time with only their signature. A
draw spends its input alone, because with two inputs one payment and one
return could satisfy both and the host would keep a balance.
Delivery escrow: a payment that can be collected only by the transaction
that mints the agreed certificate to the buyer and publishes the agreed
registration, or refunded by the buyer after a wait. It forbids any other
token in the transaction: resolvers accept an update from any token of a
name's category, so a deliverer who minted a second one alongside the
certificate could later rewrite the buyer's name. It also sits at a fixed
input, so two payments cannot be collected against one certificate.
Neither can see the registry: an escrow cannot know the name was taken
between payment and delivery. The contract says so.
Drafts, not reviewed. The tests run every path in the VM under the 2025 and
2026 rules and count that the VM itself refused the tampered ones.
2026-10-04 16:08:10 +02:00
{
"contractName" : "DeliveryEscrow" ,
"constructorInputs" : [
{ "name" : "buyerPkh" , "type" : "bytes20" } ,
{ "name" : "certLock" , "type" : "bytes" } ,
{ "name" : "nameCommitment" , "type" : "bytes" } ,
{ "name" : "payloadLock" , "type" : "bytes" } ,
{ "name" : "beaconLock" , "type" : "bytes" } ,
{ "name" : "beaconDust" , "type" : "int" } ,
{ "name" : "refundAfter" , "type" : "int" }
] ,
"abi" : [
{ "name" : "deliver" , "inputs" : [ ] } ,
{
"name" : "refund" ,
"inputs" : [
{ "name" : "pk" , "type" : "pubkey" } ,
{ "name" : "s" , "type" : "sig" }
]
}
] ,
2026-10-04 16:53:56 +02:00
"bytecode" : "OP_7 OP_PICK OP_0 OP_NUMEQUAL OP_IF OP_INPUTINDEX OP_1 OP_NUMEQUALVERIFY OP_0 OP_OUTPOINTINDEX OP_0 OP_NUMEQUALVERIFY OP_0 OP_OUTPOINTTXHASH OP_0 OP_OUTPUTBYTECODE OP_3 OP_ROLL OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCOMMITMENT OP_ROT OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENAMOUNT OP_0 OP_NUMEQUALVERIFY OP_1 OP_OUTPUTBYTECODE OP_ROT OP_EQUALVERIFY OP_1 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_2 OP_OUTPUTBYTECODE OP_ROT OP_EQUALVERIFY OP_2 OP_OUTPUTVALUE OP_ROT OP_GREATERTHANOREQUAL OP_VERIFY OP_2 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_TXOUTPUTCOUNT OP_4 OP_LESSTHANOREQUAL OP_VERIFY OP_TXOUTPUTCOUNT OP_3 OP_GREATERTHAN OP_IF OP_3 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_3 OP_OUTPUTBYTECODE OP_1 OP_SPLIT OP_DROP 6a OP_EQUAL OP_NOT OP_VERIFY OP_ENDIF OP_2DROP OP_DROP OP_1 OP_ELSE OP_7 OP_ROLL OP_1 OP_NUMEQUALVERIFY OP_7 OP_PICK OP_HASH160 OP_EQUALVERIFY OP_7 OP_ROLL OP_7 OP_ROLL OP_CHECKSIGVERIFY OP_5 OP_PICK OP_1 000001 OP_WITHIN OP_VERIFY OP_5 OP_ROLL OP_CHECKSEQUENCEVERIFY OP_2DROP OP_2DROP OP_2DROP OP_1 OP_ENDIF" ,
"source" : "pragma cashscript ^0.13.0;\n\n// DeliveryEscrow — payment for a name that can only be collected by the\n// transaction that registers it to the buyer.\n// (Decentralized.DNS/DESIGN-trustless-purchase.md §4.)\n//\n// STATUS: chipnet draft. NOT REVIEWED.\n//\n// A buyer who cannot build a registration themselves (pay-by-QR, any wallet)\n// pays this script instead of paying a registrar. The money then has exactly\n// two ways out:\n//\n// deliver() anyone may spend it — in a transaction that mints the agreed\n// certificate to the buyer and publishes the agreed registration.\n// \"Took the money and did not register\" is not a risk the buyer\n// has to weigh; it is a transaction that cannot be built.\n// refund() the buyer takes it back with their signature once it is\n// `refundAfter` blocks old.\n//\n// What deliver() pins down, output by output:\n// 0 the certificate — a NEW token category created by this transaction\n// (its id is input 0's outpoint), an NFT with no capability, commitment =\n// the name, no fungible amount, locked to the buyer's lock\n// 1 the registration payload, byte for byte as agreed (OP_RETURN)\n// 2 the discovery beacon, at least its dust\n// 3 optional: the deliverer's change — no token, and not a data output\n// and nothing else. Two things are being kept out:\n// · a second token of the certificate's category, which its holder could\n// later use to update the buyer's name;\n// · a second data output. A transaction is read as carrying ONE protocol\n// message; a later OP_RETURN would replace the agreed registration in\n// every resolver, and the deliverer would be paid for a certificate\n// that registers nothing.\n//\n// It cannot deliver under a TLD that requires its owner's co-signature: that\n// rule wants the TLD's certificate in an output of the registration, and no\n// extra token is allowed here. The library refuses to build an escrow for\n// such a name (escrow-covenant.js assertTldAllowsEscrow).\n//\n// The escrow must be input 1 (input 0 is the genesis outpoint). That makes it\n// one escrow per transaction: two payments for the same name could otherwise\n// both be collected against a single certificate.\n//\n// WHAT IT CANNOT PROMISE. Script sees this transaction, not the registry. If\n// the name was registered by someone else between payment and delivery, a\n// deliverer can still mint a certificate that satisfies every line here and\n// that no resolver will honour (\"first valid registration wins\" i s a r e s o l v e r \ n // rule). The window is the buyer's to keep short: check the name is free, pay,\n// and refund if delivery does not come.\ncontract DeliveryEscrow(\n bytes20 buyerPkh,\n bytes certLock, // where the certificate must go (the buyer's token address, or their covenant)\n bytes nameCommitment, // the on-chain name, as the certificate's commitment\n bytes payloadLock, // the full OP_RETURN locking bytecode of the agreed REG payload\n bytes beaconLock,\n int beaconDust,\n int refundAfter\n) {\n function deliver() {\n require(this.activeInputIndex == 1);\n require(tx.inputs[0].outpointIndex == 0);\n bytes category = tx.inputs[0].outpointTransactionHash;\n\n require(tx.outputs[0].lockingBytecode == certLock);\n require(tx.outputs[0].tokenCategory == category);\n require(tx.outputs[0].nftCommitment == nameCommitment);\n require(tx.outputs[0].tokenAmount == 0);\n\n require(tx.outputs[1].lockingBytecode == payloadLock);\n require(tx.outputs[1].tokenCategory == 0x);\n\n require(tx.outputs[2].lockingBytecode == beaconLock);\n require(tx.outputs[2].value >= beaconDust);\n require(tx.outputs[2].tokenCategory == 0x);\n\n require(tx.outputs.length <= 4);\n if (tx.outputs.length > 3) {\n require(tx.outputs[3].tokenCategory == 0x);\n require(tx.outputs[3].lockingBytecode.split(1)[0] !
"fingerprint" : "4f43d98c69ef538b7c7588fda9b49c1f18c4f712a6ea3a5e98c7cc6d24a36b1f" ,
covenants: the subscription and the delivery escrow, on one shared base (draft)
The roadmap asks for the covenant capability to be built once and used three
times. covenant.js is the shared part: artifact to bytecode, redeem script and
lock, signing a covenant input, an unlocking script for any function, and
assembling a transaction around covenant inputs. The registry library now
sits on it, and so do the two new contracts.
Subscription: the buyer funds a balance. Anyone may send one period's price
to the host once per period, the rest going back to the same script; the
buyer may take the balance back at any time with only their signature. A
draw spends its input alone, because with two inputs one payment and one
return could satisfy both and the host would keep a balance.
Delivery escrow: a payment that can be collected only by the transaction
that mints the agreed certificate to the buyer and publishes the agreed
registration, or refunded by the buyer after a wait. It forbids any other
token in the transaction: resolvers accept an update from any token of a
name's category, so a deliverer who minted a second one alongside the
certificate could later rewrite the buyer's name. It also sits at a fixed
input, so two payments cannot be collected against one certificate.
Neither can see the registry: an escrow cannot know the name was taken
between payment and delivery. The contract says so.
Drafts, not reviewed. The tests run every path in the VM under the 2025 and
2026 rules and count that the VM itself refused the tampered ones.
2026-10-04 16:08:10 +02:00
"debug" : {
2026-10-04 16:53:56 +02:00
"bytecode" : "5779009c63c0519d00c9009d00c800cd537a8800d18800d27b8800d3009d51cd7b8851d1008852cd7b8852cc7ba26952d10088c454a169c453a06353d1008853cd517f75016a879169686d755167577a519d5779a988577a577aad55795103000001a569557ab26d6d6d5168" ,
"sourceMap" : "59:4:81:5;;;;;60:16:60:37;:41::42;:8::44:1;61:26:61:27:0;:16::42:1;:46::47:0;:8::49:1;62:35:62:36:0;:25::61:1;64:27:64:28:0;:16::45:1;:49::57:0;;:8::59:1;65:27:65:28:0;:16::43:1;:8::57;66:27:66:28:0;:16::43:1;:47::61:0;:8::63:1;67:27:67:28:0;:16::41:1;:45::46:0;:8::48:1;69:27:69:28:0;:16::45:1;:49::60:0;:8::62:1;70:27:70:28:0;:16::43:1;:47::49:0;:8::51:1;72:27:72:28:0;:16::45:1;:49::59:0;:8::61:1;73:27:73:28:0;:16::35:1;:39::49:0;:16:::1;:8::51;74:27:74:28:0;:16::43:1;:47::49:0;:8::51:1;76:16:76:33:0;:37::38;:16:::1;:8::40;77:12:77:29:0;:32::33;:12:::1;:35:80:9:0;78:31:78:32;:20::47:1;:51::53:0;:12::55:1;79:31:79:32:0;:20::49:1;:56::57:0;:20::58:1;:::61;:65::69:0;:20:::1;;:12::71;77:35:80:9;59:23:81:5;;;:4;83::88::0;;;;84:24:84:26;;:16::27:1;:8::41;85:25:85:26:0;;:28::30;;:8::33:1;86:23:86:34:0;;:36::37;:39::44;:16::45:1;:8::47;87:28:87:39:0;;:8::41:1;83:38:88:5;;;;50:0:89:1" ,
covenants: the subscription and the delivery escrow, on one shared base (draft)
The roadmap asks for the covenant capability to be built once and used three
times. covenant.js is the shared part: artifact to bytecode, redeem script and
lock, signing a covenant input, an unlocking script for any function, and
assembling a transaction around covenant inputs. The registry library now
sits on it, and so do the two new contracts.
Subscription: the buyer funds a balance. Anyone may send one period's price
to the host once per period, the rest going back to the same script; the
buyer may take the balance back at any time with only their signature. A
draw spends its input alone, because with two inputs one payment and one
return could satisfy both and the host would keep a balance.
Delivery escrow: a payment that can be collected only by the transaction
that mints the agreed certificate to the buyer and publishes the agreed
registration, or refunded by the buyer after a wait. It forbids any other
token in the transaction: resolvers accept an update from any token of a
name's category, so a deliverer who minted a second one alongside the
certificate could later rewrite the buyer's name. It also sits at a fixed
input, so two payments cannot be collected against one certificate.
Neither can see the registry: an escrow cannot know the name was taken
between payment and delivery. The contract says so.
Drafts, not reviewed. The tests run every path in the VM under the 2025 and
2026 rules and count that the VM itself refused the tampered ones.
2026-10-04 16:08:10 +02:00
"logs" : [ ] ,
"requires" : [
2026-10-04 16:53:56 +02:00
{ "ip" : 14 , "line" : 60 } ,
{ "ip" : 18 , "line" : 61 } ,
{ "ip" : 25 , "line" : 64 } ,
{ "ip" : 28 , "line" : 65 } ,
{ "ip" : 32 , "line" : 66 } ,
{ "ip" : 36 , "line" : 67 } ,
{ "ip" : 40 , "line" : 69 } ,
{ "ip" : 44 , "line" : 70 } ,
{ "ip" : 48 , "line" : 72 } ,
{ "ip" : 53 , "line" : 73 } ,
{ "ip" : 57 , "line" : 74 } ,
{ "ip" : 61 , "line" : 76 } ,
{ "ip" : 69 , "line" : 78 } ,
{ "ip" : 78 , "line" : 79 } ,
{ "ip" : 91 , "line" : 84 } ,
{ "ip" : 96 , "line" : 85 } ,
{ "ip" : 102 , "line" : 86 } ,
{ "ip" : 105 , "line" : 87 }
covenants: the subscription and the delivery escrow, on one shared base (draft)
The roadmap asks for the covenant capability to be built once and used three
times. covenant.js is the shared part: artifact to bytecode, redeem script and
lock, signing a covenant input, an unlocking script for any function, and
assembling a transaction around covenant inputs. The registry library now
sits on it, and so do the two new contracts.
Subscription: the buyer funds a balance. Anyone may send one period's price
to the host once per period, the rest going back to the same script; the
buyer may take the balance back at any time with only their signature. A
draw spends its input alone, because with two inputs one payment and one
return could satisfy both and the host would keep a balance.
Delivery escrow: a payment that can be collected only by the transaction
that mints the agreed certificate to the buyer and publishes the agreed
registration, or refunded by the buyer after a wait. It forbids any other
token in the transaction: resolvers accept an update from any token of a
name's category, so a deliverer who minted a second one alongside the
certificate could later rewrite the buyer's name. It also sits at a fixed
input, so two payments cannot be collected against one certificate.
Neither can see the registry: an escrow cannot know the name was taken
between payment and delivery. The contract says so.
Drafts, not reviewed. The tests run every path in the VM under the 2025 and
2026 rules and count that the VM itself refused the tampered ones.
2026-10-04 16:08:10 +02:00
]
} ,
"compiler" : {
"name" : "cashc" ,
"version" : "0.13.3" ,
"options" : {
"enforceFunctionParameterTypes" : true ,
"enforceLocktimeGuard" : true
}
} ,
2026-10-04 16:53:56 +02:00
"updatedAt" : "2026-10-04T14:37:29.033Z"
covenants: the subscription and the delivery escrow, on one shared base (draft)
The roadmap asks for the covenant capability to be built once and used three
times. covenant.js is the shared part: artifact to bytecode, redeem script and
lock, signing a covenant input, an unlocking script for any function, and
assembling a transaction around covenant inputs. The registry library now
sits on it, and so do the two new contracts.
Subscription: the buyer funds a balance. Anyone may send one period's price
to the host once per period, the rest going back to the same script; the
buyer may take the balance back at any time with only their signature. A
draw spends its input alone, because with two inputs one payment and one
return could satisfy both and the host would keep a balance.
Delivery escrow: a payment that can be collected only by the transaction
that mints the agreed certificate to the buyer and publishes the agreed
registration, or refunded by the buyer after a wait. It forbids any other
token in the transaction: resolvers accept an update from any token of a
name's category, so a deliverer who minted a second one alongside the
certificate could later rewrite the buyer's name. It also sits at a fixed
input, so two payments cannot be collected against one certificate.
Neither can see the registry: an escrow cannot know the name was taken
between payment and delivery. The contract says so.
Drafts, not reviewed. The tests run every path in the VM under the 2025 and
2026 rules and count that the VM itself refused the tampered ones.
2026-10-04 16:08:10 +02:00
}