Expiry was always going to be the chain refusing, not resolvers agreeing. This is that contract: a certificate sits in a covenant whose address encodes its owner and expiry, and five paths move it. The owner renews, transfers, releases or migrates; anyone takes over an expired name at a price that glides from a premium to a floor, paying the previous owner a share while the grace period lasts and committing to the name a block ahead. The two changing values are the last constructor arguments, so they sit first in the redeem script and the contract re-creates itself by swapping 26 bytes. A resolver that knows the code can check any claimed owner and expiry against the address. Every number comes from registry-lifecycle.js, which was written as the fixture for this. The tests run each path in libauth's VM under the 2025 and 2026 rules, compare price and split to that model along the glide, and then break one rule at a time with valid signatures; the suite counts that the VM itself refused them. Draft, not reviewed, and not wired into any resolver. REGISTRY-COVENANT-v1.md says where it departs from the design: script cannot bound a height from above, so reclaim has no deadline and a commit cannot expire, which leaves commit hoarding open. That is the first thing a reviewer should read.
39 lines
No EOL
2.3 KiB
JSON
39 lines
No EOL
2.3 KiB
JSON
{
|
||
"contractName": "CommitBox",
|
||
"constructorInputs": [
|
||
{ "name": "commitHash", "type": "bytes32" },
|
||
{ "name": "ownerPkh", "type": "bytes20" }
|
||
],
|
||
"abi": [
|
||
{
|
||
"name": "spend",
|
||
"inputs": [
|
||
{ "name": "pk", "type": "pubkey" },
|
||
{ "name": "s", "type": "sig" }
|
||
]
|
||
}
|
||
],
|
||
"bytecode": "OP_2 OP_PICK OP_HASH160 OP_ROT OP_EQUALVERIFY OP_ROT OP_ROT OP_CHECKSIGVERIFY OP_1 OP_CHECKSEQUENCEVERIFY OP_DROP OP_SIZE OP_NIP 20 OP_NUMEQUAL",
|
||
"source": "pragma cashscript ^0.13.0;\n\n// CommitBox — the \"commit\" of a commit–reveal takeover\n// (Decentralized.DNS/DESIGN-covenant-registry.md §6.3).\n//\n// A taker creates one of these a block or more BEFORE taking a name over. Its\n// address reveals nothing: commitHash = hash256(name ‖ salt). The registry\n// covenant rebuilds this script from the taker's key hash and the revealed\n// salt, and requires input 1 of the takeover to be locked to it.\n//\n// The box enforces its own age (this.age), so a takeover cannot be assembled in\n// the same block as its commit, and it needs the taker's signature, so nobody\n// else can spend it out from under them.\n//\n// STATUS: chipnet draft, NOT REVIEWED — see name-registry.cash.\ncontract CommitBox(bytes32 commitHash, bytes20 ownerPkh) {\n function spend(pubkey pk, sig s) {\n require(hash160(pk) == ownerPkh);\n require(checkSig(s, pk));\n require(this.age >= 1);\n // The commitment is data, not logic: it only has to be part of this\n // script so that it is part of the address. (The compiler rejects an\n // unused constructor argument.)\n require(commitHash.length == 32);\n }\n}\n",
|
||
"fingerprint": "37cd443c35ce338bfe5e76055c161118d5a57a6d056f3cfd9484a571bb641d88",
|
||
"debug": {
|
||
"bytecode": "5279a97b887b7bad51b275827701209c",
|
||
"sourceMap": "18:24:18:26;;:16::27:1;:31::39:0;:8::41:1;19:25:19:26:0;:28::30;:8::33:1;20:28:20:29:0;:8::31:1;;24:16:24:33;;:37::39:0;:8::41:1",
|
||
"logs": [],
|
||
"requires": [
|
||
{ "ip": 6, "line": 18 },
|
||
{ "ip": 9, "line": 19 },
|
||
{ "ip": 11, "line": 20 },
|
||
{ "ip": 17, "line": 24 }
|
||
]
|
||
},
|
||
"compiler": {
|
||
"name": "cashc",
|
||
"version": "0.13.3",
|
||
"options": {
|
||
"enforceFunctionParameterTypes": true,
|
||
"enforceLocktimeGuard": true
|
||
}
|
||
},
|
||
"updatedAt": "2026-10-04T13:37:02.552Z"
|
||
} |