argus/contracts/name-registry.json
Local Dev e0eca1190e covenants: close the holes an adversarial review found
migrate let the owner supply the new state, so an owner could put a script
of their own in front of the approved code and take the certificate out of
the covenant, or rewrite owner and expiry on the way. The contract now
carries its own state over and the owner supplies only the code. The
steward's approval covers source and destination code, so it cannot be
replayed in another tier or network.

The delivery escrow could be collected with a second protocol message after
the agreed one; it now allows at most four outputs, the fourth plain change.
A subscription draw could pay its fee allowance to a third output; it now
has one or two outputs and pays the host exactly the price.

Smaller: the commit salt is exactly 32 bytes (one box could serve several
names), expiry stays a block height, and relative-lock terms are range
checked in script. Escrow quotes are refused for co-sign TLDs, where a
delivery would satisfy the contract and register nothing.
2026-10-04 16:53:56 +02:00

123 lines
No EOL
23 KiB
JSON

{
"contractName": "NameRegistry",
"constructorInputs": [
{ "name": "fundLock", "type": "bytes" },
{ "name": "stewardPk", "type": "pubkey" },
{ "name": "commitBoxCode", "type": "bytes" },
{ "name": "renewalSats", "type": "int" },
{ "name": "premiumSats", "type": "int" },
{ "name": "floorSats", "type": "int" },
{ "name": "graceBlocks", "type": "int" },
{ "name": "blocksPerYear", "type": "int" },
{ "name": "ownerPercentIdle", "type": "int" },
{ "name": "expiry", "type": "bytes4" },
{ "name": "ownerPkh", "type": "bytes20" }
],
"abi": [
{
"name": "renew",
"inputs": [
{ "name": "pk", "type": "pubkey" },
{ "name": "s", "type": "sig" },
{ "name": "years", "type": "int" }
]
},
{
"name": "transfer",
"inputs": [
{ "name": "pk", "type": "pubkey" },
{ "name": "s", "type": "sig" },
{ "name": "newOwnerPkh", "type": "bytes20" }
]
},
{
"name": "takeover",
"inputs": [
{ "name": "newOwnerPkh", "type": "bytes20" },
{ "name": "salt", "type": "bytes" }
]
},
{
"name": "release",
"inputs": [
{ "name": "pk", "type": "pubkey" },
{ "name": "s", "type": "sig" }
]
},
{
"name": "migrate",
"inputs": [
{ "name": "pk", "type": "pubkey" },
{ "name": "s", "type": "sig" },
{ "name": "approval", "type": "datasig" },
{ "name": "newCode", "type": "bytes" }
]
}
],
"bytecode": "OP_11 OP_PICK OP_0 OP_NUMEQUAL OP_IF OP_12 OP_PICK OP_HASH160 OP_11 OP_PICK OP_EQUALVERIFY OP_13 OP_ROLL OP_13 OP_ROLL OP_CHECKSIGVERIFY OP_12 OP_PICK OP_1 OP_GREATERTHANOREQUAL OP_VERIFY OP_9 OP_ROLL OP_BIN2NUM OP_12 OP_PICK OP_9 OP_ROLL OP_MUL OP_ADD OP_DUP 0065cd1d OP_LESSTHAN OP_VERIFY 14 OP_10 OP_ROLL OP_CAT OP_4 OP_CAT OP_SWAP OP_4 OP_NUM2BIN OP_CAT OP_ACTIVEBYTECODE 1a OP_SPLIT OP_NIP OP_CAT OP_HASH256 OP_0 OP_OUTPUTBYTECODE aa20 OP_ROT OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCOMMITMENT OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_0 OP_OUTPUTVALUE OP_INPUTINDEX OP_UTXOVALUE OP_GREATERTHANOREQUAL OP_VERIFY OP_1 OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_1 OP_OUTPUTVALUE OP_3 OP_ROLL OP_9 OP_ROLL OP_MUL OP_GREATERTHANOREQUAL OP_VERIFY OP_1 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_2DROP OP_2DROP OP_2DROP OP_DROP OP_1 OP_ELSE OP_11 OP_PICK OP_1 OP_NUMEQUAL OP_IF OP_14 OP_ROLL OP_SIZE 14 OP_EQUALVERIFY OP_13 OP_PICK OP_HASH160 OP_12 OP_ROLL OP_EQUALVERIFY OP_13 OP_ROLL OP_13 OP_ROLL OP_CHECKSIGVERIFY 14 OP_SWAP OP_CAT OP_4 OP_CAT OP_10 OP_ROLL OP_CAT OP_ACTIVEBYTECODE 1a OP_SPLIT OP_NIP OP_CAT OP_HASH256 OP_0 OP_OUTPUTBYTECODE aa20 OP_ROT OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCOMMITMENT OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_0 OP_OUTPUTVALUE OP_INPUTINDEX OP_UTXOVALUE OP_GREATERTHANOREQUAL OP_VERIFY OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_1 OP_ELSE OP_11 OP_PICK OP_2 OP_NUMEQUAL OP_IF OP_12 OP_ROLL OP_SIZE 14 OP_EQUALVERIFY OP_10 OP_ROLL OP_BIN2NUM OP_DUP OP_CHECKLOCKTIMEVERIFY OP_DROP OP_TXLOCKTIME OP_DUP 0065cd1d OP_LESSTHAN OP_VERIFY OP_SWAP OP_9 OP_PICK OP_ADD OP_8 OP_PICK OP_0 OP_2OVER OP_LESSTHAN OP_IF OP_10 OP_PICK OP_10 OP_PICK OP_12 OP_PICK OP_SUB OP_4 OP_PICK OP_6 OP_PICK OP_SUB OP_MUL OP_13 OP_PICK OP_DIV OP_ADD OP_ROT OP_DROP OP_SWAP OP_OVER OP_14 OP_PICK OP_MUL 64 OP_DIV OP_NIP OP_ENDIF OP_16 OP_PICK OP_SIZE OP_NIP 20 OP_NUMEQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT 11 OP_ROLL OP_CAT OP_HASH256 14 OP_6 OP_PICK OP_CAT 20 OP_CAT OP_SWAP OP_CAT OP_8 OP_ROLL OP_CAT OP_1 OP_UTXOBYTECODE aa20 OP_ROT OP_HASH256 OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_3 OP_PICK OP_12 OP_PICK OP_ADD 0065cd1d OP_LESSTHAN OP_VERIFY 14 OP_5 OP_ROLL OP_CAT OP_4 OP_CAT OP_4 OP_ROLL OP_11 OP_ROLL OP_ADD OP_4 OP_NUM2BIN OP_CAT OP_ACTIVEBYTECODE 1a OP_SPLIT OP_NIP OP_CAT OP_HASH256 OP_0 OP_OUTPUTBYTECODE aa20 OP_ROT OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCOMMITMENT OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_0 OP_OUTPUTVALUE OP_INPUTINDEX OP_UTXOVALUE OP_GREATERTHANOREQUAL OP_VERIFY OP_1 OP_OUTPUTBYTECODE OP_4 OP_ROLL OP_EQUALVERIFY OP_1 OP_OUTPUTVALUE OP_ROT OP_2 OP_PICK OP_SUB OP_GREATERTHANOREQUAL OP_VERIFY OP_1 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_DUP OP_0 OP_GREATERTHAN OP_IF OP_2 OP_OUTPUTBYTECODE 76a914 OP_10 OP_PICK OP_CAT 88ac OP_CAT OP_EQUALVERIFY OP_2 OP_OUTPUTVALUE OP_OVER OP_GREATERTHANOREQUAL OP_VERIFY OP_2 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_ENDIF OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_1 OP_ELSE OP_11 OP_PICK OP_3 OP_NUMEQUAL OP_IF OP_12 OP_PICK OP_HASH160 OP_11 OP_ROLL OP_EQUALVERIFY OP_12 OP_ROLL OP_12 OP_ROLL OP_CHECKSIGVERIFY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_TXOUTPUTCOUNT OP_4 OP_LESSTHANOREQUAL OP_VERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_OVER OP_EQUAL OP_NOT OP_VERIFY OP_TXOUTPUTCOUNT OP_1 OP_GREATERTHAN OP_IF OP_1 OP_OUTPUTTOKENCATEGORY OP_OVER OP_EQUAL OP_NOT OP_VERIFY OP_ENDIF OP_TXOUTPUTCOUNT OP_2 OP_GREATERTHAN OP_IF OP_2 OP_OUTPUTTOKENCATEGORY OP_OVER OP_EQUAL OP_NOT OP_VERIFY OP_ENDIF OP_TXOUTPUTCOUNT OP_3 OP_GREATERTHAN OP_IF OP_3 OP_OUTPUTTOKENCATEGORY OP_OVER OP_EQUAL OP_NOT OP_VERIFY OP_ENDIF OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_1 OP_ELSE OP_11 OP_ROLL OP_4 OP_NUMEQUALVERIFY OP_11 OP_PICK OP_HASH160 OP_11 OP_PICK OP_EQUALVERIFY OP_12 OP_ROLL OP_12 OP_ROLL OP_CHECKSIGVERIFY OP_ACTIVEBYTECODE 1a OP_SPLIT OP_NIP OP_HASH256 OP_12 OP_ROLL OP_SWAP OP_13 OP_PICK OP_HASH256 OP_CAT OP_HASH256 OP_3 OP_ROLL OP_CHECKDATASIGVERIFY 14 OP_10 OP_ROLL OP_CAT OP_4 OP_CAT OP_9 OP_ROLL OP_CAT OP_9 OP_ROLL OP_CAT OP_HASH256 OP_0 OP_OUTPUTBYTECODE aa20 OP_ROT OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCATEGORY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENCOMMITMENT OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT OP_EQUALVERIFY OP_0 OP_OUTPUTVALUE OP_INPUTINDEX OP_UTXOVALUE OP_GREATERTHANOREQUAL OP_VERIFY OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_1 OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF",
"source": "pragma cashscript ^0.13.0;\n\n// NameRegistry v1 — the covenant that holds a name certificate and enforces\n// its lifecycle (Decentralized.DNS/DESIGN-covenant-registry.md).\n//\n// STATUS: chipnet draft. NOT REVIEWED. A flaw here either locks every name\n// forever or lets anyone take one; nothing built from this file may hold a\n// mainnet name until someone who did not write it has reviewed it.\n//\n// The certificate (an immutable NFT whose commitment is the name) sits in an\n// output locked by this script. Two values change over a name's life — who\n// owns it and when it expires — and they are the LAST two constructor\n// arguments, which CashScript pushes FIRST. The redeem script therefore begins\n//\n// 0x14 <ownerPkh:20> 0x04 <expiry:4> <everything else>\n//\n// and every path that keeps the name re-creates the covenant by replacing\n// those 26 bytes and requiring output 0 to be locked to the result. One\n// contract, one code hash per price tier; the state is in the address.\n//\n// Numbers must match Argus/src/lib/registry-lifecycle.js, which is the\n// reference: integer arithmetic, multiply before dividing.\n//\n// What script cannot do, stated once: it can prove a block height has been\n// REACHED (tx.time), never that one has NOT. So \"the owner may reclaim only\n// until the grace period ends\" is not enforceable; an owner can renew for as\n// long as nobody has taken the name over. The takeover price is safe against\n// this: a taker can only claim a height that is already past, and a later\n// height means a lower price they are entitled to anyway.\ncontract NameRegistry(\n // ---- fixed for this covenant version and price tier ----\n bytes fundLock, // locking bytecode the fund's payments must go to\n pubkey stewardPk, // approves moving from this code to a newer version's (migrate)\n bytes commitBoxCode, // redeem-script body of the CommitBox contract\n int renewalSats, // price of one year, for the owner\n int premiumSats, // takeover price at the moment of expiry\n int floorSats, // takeover price once the grace period has run out\n int graceBlocks, // length of the grace period\n int blocksPerYear,\n int ownerPercentIdle, // previous owner's share of a takeover during grace\n // ---- state: keep these LAST, in this order ----\n bytes4 expiry, // block height the paid period ends at\n bytes20 ownerPkh\n) {\n // Keep the name: pay for `years` more. Also the reclaim path — an expired\n // name renews exactly the same way, from its old expiry.\n function renew(pubkey pk, sig s, int years) {\n require(hash160(pk) == ownerPkh);\n require(checkSig(s, pk));\n require(years >= 1);\n\n int newExpiry = int(expiry) + years * blocksPerYear;\n // Stay a block height. At 500,000,000 a locktime is read as a\n // timestamp, takeover could never satisfy its height check, and the\n // name would be untakeable for ever.\n require(newExpiry < 500000000);\n bytes newState = 0x14 + ownerPkh + 0x04 + toPaddedBytes(newExpiry, 4);\n bytes32 newHash = hash256(newState + this.activeBytecode.split(26)[1]);\n\n require(tx.outputs[0].lockingBytecode == new LockingBytecodeP2SH32(newHash));\n require(tx.outputs[0].tokenCategory == tx.inputs[this.activeInputIndex].tokenCategory);\n require(tx.outputs[0].nftCommitment == tx.inputs[this.activeInputIndex].nftCommitment);\n require(tx.outputs[0].value >= tx.inputs[this.activeInputIndex].value);\n\n require(tx.outputs[1].lockingBytecode == fundLock);\n require(tx.outputs[1].value >= renewalSats * years);\n require(tx.outputs[1].tokenCategory == 0x);\n }\n\n // Hand the name to another key (a sale, a gift), or re-create it for the\n // same key — which is how records are updated: the certificate has to move\n // for a resolver to accept an UPD. Expiry is untouched.\n function transfer(pubkey pk, sig s, bytes20 newOwnerPkh) {\n require(hash160(pk) == ownerPkh);\n require(checkSig(s, pk));\n\n bytes newState = 0x14 + newOwnerPkh + 0x04 + expiry;\n bytes32 newHash = hash256(newState + this.activeBytecode.split(26)[1]);\n\n require(tx.outputs[0].lockingBytecode == new LockingBytecodeP2SH32(newHash));\n require(tx.outputs[0].tokenCategory == tx.inputs[this.activeInputIndex].tokenCategory);\n require(tx.outputs[0].nftCommitment == tx.inputs[this.activeInputIndex].nftCommitment);\n require(tx.outputs[0].value >= tx.inputs[this.activeInputIndex].value);\n }\n\n // Take an expired name. No owner signature: anyone may, at a price that\n // glides from premiumSats at expiry down to floorSats at the end of the\n // grace period and stays there. During grace the previous owner is paid\n // ownerPercentIdle of the price; afterwards the fund receives all of it.\n //\n // Input 1 must be a CommitBox the taker created at least a block earlier,\n // committing to this name and to their own key. It hides which name is\n // wanted until the takeover itself, so the transaction cannot be copied\n // from the mempool by someone who had not already committed.\n function takeover(bytes20 newOwnerPkh, bytes salt) {\n int expiryHeight = int(expiry);\n require(tx.time >= expiryHeight);\n int height = tx.locktime;\n require(height < 500000000); // a block height, not a timestamp\n\n int idleEnd = expiryHeight + graceBlocks;\n int price = floorSats;\n int ownerSats = 0;\n if (height < idleEnd) {\n price = floorSats + (premiumSats - floorSats) * (idleEnd - height) / graceBlocks;\n ownerSats = price * ownerPercentIdle / 100;\n }\n\n // the commit. The salt has a fixed size: the name and the salt are\n // hashed end to end, so with a free-length salt a commit for \"pay\"\n // would also be a commit for \"payroll\" (the rest of the name passed\n // off as the start of the salt).\n require(salt.length == 32);\n bytes32 commitHash = hash256(tx.inputs[this.activeInputIndex].nftCommitment + salt);\n bytes boxRedeem = 0x14 + newOwnerPkh + 0x20 + commitHash + commitBoxCode;\n require(tx.inputs[1].lockingBytecode == new LockingBytecodeP2SH32(hash256(boxRedeem)));\n\n // the name, under its new owner, for one fresh year\n require(height + blocksPerYear < 500000000);\n bytes newState = 0x14 + newOwnerPkh + 0x04 + toPaddedBytes(height + blocksPerYear, 4);\n bytes32 newHash = hash256(newState + this.activeBytecode.split(26)[1]);\n require(tx.outputs[0].lockingBytecode == new LockingBytecodeP2SH32(newHash));\n require(tx.outputs[0].tokenCategory == tx.inputs[this.activeInputIndex].tokenCategory);\n require(tx.outputs[0].nftCommitment == tx.inputs[this.activeInputIndex].nftCommitment);\n require(tx.outputs[0].value >= tx.inputs[this.activeInputIndex].value);\n\n // the money\n require(tx.outputs[1].lockingBytecode == fundLock);\n require(tx.outputs[1].value >= price - ownerSats);\n require(tx.outputs[1].tokenCategory == 0x);\n if (ownerSats > 0) {\n require(tx.outputs[2].lockingBytecode == new LockingBytecodeP2PKH(ownerPkh));\n require(tx.outputs[2].value >= ownerSats);\n require(tx.outputs[2].tokenCategory == 0x);\n }\n }\n\n // Give the name back: the certificate is destroyed. At most four outputs,\n // none of which may carry it — the owner cannot use this path to walk the\n // certificate out of the covenant into a plain wallet.\n function release(pubkey pk, sig s) {\n require(hash160(pk) == ownerPkh);\n require(checkSig(s, pk));\n\n bytes category = tx.inputs[this.activeInputIndex].tokenCategory;\n require(tx.outputs.length <= 4);\n require(tx.outputs[0].tokenCategory != category);\n if (tx.outputs.length > 1) { require(tx.outputs[1].tokenCategory != category); }\n if (tx.outputs.length > 2) { require(tx.outputs[2].tokenCategory != category); }\n if (tx.outputs.length > 3) { require(tx.outputs[3].tokenCategory != category); }\n }\n\n // Move to a newer covenant version. The owner chooses to; the steward has\n // approved moving from THIS code to the new code, once, for everyone in\n // this covenant. Neither can act alone.\n //\n // The owner and the expiry carry over unchanged, in the same 26 bytes, in\n // front of the new code. Nothing here is free for the owner to choose:\n // · the state is rebuilt by the contract, so the owner cannot put a\n // script of their own in front of the approved code (which would turn\n // that code into inert data behind their own signature check), and\n // cannot give themselves a later expiry on the way;\n // · the approval is over (this code, new code), so a signature made for\n // one covenant — another tier, another network's fund — is worthless\n // in any other.\n // A newer version must therefore keep this state layout.\n function migrate(pubkey pk, sig s, datasig approval, bytes newCode) {\n require(hash160(pk) == ownerPkh);\n require(checkSig(s, pk));\n\n bytes32 fromCode = hash256(this.activeBytecode.split(26)[1]);\n require(checkDataSig(approval, hash256(fromCode + hash256(newCode)), stewardPk));\n\n bytes32 newHash = hash256(0x14 + ownerPkh + 0x04 + expiry + newCode);\n require(tx.outputs[0].lockingBytecode == new LockingBytecodeP2SH32(newHash));\n require(tx.outputs[0].tokenCategory == tx.inputs[this.activeInputIndex].tokenCategory);\n require(tx.outputs[0].nftCommitment == tx.inputs[this.activeInputIndex].nftCommitment);\n require(tx.outputs[0].value >= tx.inputs[this.activeInputIndex].value);\n }\n}\n",
"fingerprint": "c48440f8b9d46a8183c4c2326a691a281963febd642858667f3343fabc792736",
"debug": {
"bytecode": "5b79009c635c79a95b79885d7a5d7aad5c7951a269597a815c79597a959376040065cd1d9f6901145a7a7e547e7c54807ec1011a7f777eaa00cd02aa207b7e01877e8800d1c0ce8800d2c0cf8800ccc0c6a26951cd8851cc537a597a95a26951d100886d6d6d7551675b79519c635e7a820114885d79a95c7a885d7a5d7aad01147c7e547e5a7a7ec1011a7f777eaa00cd02aa207b7e01877e8800d1c0ce8800d2c0cf8800ccc0c6a2696d6d6d6d6d51675b79529c635c7a820114885a7a8176b175c576040065cd1d9f697c597993587900709f635a795a795c79945479567994955d7996937b757c785e799501649677686079827701209dc0cf01117a7eaa011456797e01207e7c7e587a7e51c702aa207baa7e01877e8853795c7993040065cd1d9f690114557a7e547e547a5b7a9354807ec1011a7f777eaa00cd02aa207b7e01877e8800d1c0ce8800d2c0cf8800ccc0c6a26951cd547a8851cc7b527994a26951d100887600a06352cd0376a9145a797e0288ac7e8852cc78a26952d10088686d6d6d6d6d51675b79539c635c79a95b7a885c7a5c7aadc0cec454a16900d178879169c451a06351d17887916968c452a06352d17887916968c453a06353d178879169686d6d6d6d6d6d51675b7a549d5b79a95b79885c7a5c7aadc1011a7f77aa5c7a7c5d79aa7eaa537abb01145a7a7e547e597a7e597a7eaa00cd02aa207b7e01877e8800d1c0ce8800d2c0cf8800ccc0c6a2696d6d6d6d5168686868",
"sourceMap": "47:4:68:5;;;;;48:24:48:26;;:16::27:1;:31::39:0;;:8::41:1;49:25:49:26:0;;:28::30;;:8::33:1;50:16:50:21:0;;:25::26;:16:::1;:8::28;52:28:52:34:0;;:24::35:1;:38::43:0;;:46::59;;:38:::1;:24;56:16:56:25:0;:28::37;:16:::1;:8::39;57:25:57:29:0;:32::40;;:25:::1;:43::47:0;:25:::1;:64::73:0;:75::76;:50::77:1;:25;58:45:58:64:0;:71::73;:45::74:1;:::77;:34;:26::78;60:27:60:28:0;:16::45:1;:49::83:0;:75::82;:49::83:1;;;:8::85;61:27:61:28:0;:16::43:1;:57::78:0;:47::93:1;:8::95;62:27:62:28:0;:16::43:1;:57::78:0;:47::93:1;:8::95;63:27:63:28:0;:16::35:1;:49::70:0;:39::77:1;:16;:8::79;65:27:65:28:0;:16::45:1;:8::59;66:27:66:28:0;:16::35:1;:39::50:0;;:53::58;;:39:::1;:16;:8::60;67:27:67:28:0;:16::43:1;:47::49:0;:8::51:1;47:48:68:5;;;;;:4;73::84::0;;;;;:40:73:59;;;;;74:24:74:26;;:16::27:1;:31::39:0;;:8::41:1;75:25:75:26:0;;:28::30;;:8::33:1;77:25:77:29:0;:32::43;:25:::1;:46::50:0;:25:::1;:53::59:0;;:25:::1;78:45:78:64:0;:71::73;:45::74:1;:::77;:34;:26::78;80:27:80:28:0;:16::45:1;:49::83:0;:75::82;:49::83:1;;;:8::85;81:27:81:28:0;:16::43:1;:57::78:0;:47::93:1;:8::95;82:27:82:28:0;:16::43:1;:57::78:0;:47::93:1;:8::95;83:27:83:28:0;:16::35:1;:49::70:0;:39::77:1;:16;:8::79;73:61:84:5;;;;;;:4;95::136::0;;;;;:22:95:41;;;;;96:31:96:37;;:27::38:1;97::97:39:0;:8::41:1;;98:21:98:32:0;99:16:99:22;:25::34;:16:::1;:8::36;101:22:101:34:0;:37::48;;:22:::1;102:20:102:29:0;;103:24:103:25;104:12:104:28;::::1;:30:107:9:0;105:20:105:29;;:33::44;;:47::56;;:33:::1;:61::68:0;;:71::77;;:61:::1;:32::78;:81::92:0;;:32:::1;:20;:12::93;;;106:24:106:29:0;:32::48;;:24:::1;:51::54:0;:24:::1;:12::55;104:30:107:9;113:16:113:20:0;;:::27:1;;:31::33:0;:8::35:1;114:47:114:68:0;:37::83:1;:86::90:0;;:37:::1;:29::91;115:26:115:30:0;:33::44;;:26:::1;:47::51:0;:26:::1;:54::64:0;:26:::1;:67::80:0;;:26:::1;116::116:27:0;:16::44:1;:48::93:0;:82::91;:74::92:1;:48::93;;;:8::95;119:16:119:22:0;;:25::38;;:16:::1;:41::50:0;:16:::1;:8::52;120:25:120:29:0;:32::43;;:25:::1;:46::50:0;:25:::1;:67::73:0;;:76::89;;:67:::1;:91::92:0;:53::93:1;:25;121:45:121:64:0;:71::73;:45::74:1;:::77;:34;:26::78;122:27:122:28:0;:16::45:1;:49::83:0;:75::82;:49::83:1;;;:8::85;123:27:123:28:0;:16::43:1;:57::78:0;:47::93:1;:8::95;124:27:124:28:0;:16::43:1;:57::78:0;:47::93:1;:8::95;125:27:125:28:0;:16::35:1;:49::70:0;:39::77:1;:16;:8::79;128:27:128:28:0;:16::45:1;:49::57:0;;:8::59:1;129:27:129:28:0;:16::35:1;:39::44:0;:47::56;;:39:::1;:16;:8::58;130:27:130:28:0;:16::43:1;:47::49:0;:8::51:1;131:12:131:21:0;:24::25;:12:::1;:27:135:9:0;132:31:132:32;:20::49:1;:53::87:0;:78::86;;:53::87:1;;;:12::89;133:31:133:32:0;:20::39:1;:43::52:0;:20:::1;:12::54;134:31:134:32:0;:20::47:1;:51::53:0;:12::55:1;131:27:135:9;95:55:136:5;;;;;;:4;141::151::0;;;;;142:24:142:26;;:16::27:1;:31::39:0;;:8::41:1;143:25:143:26:0;;:28::30;;:8::33:1;145:35:145:56:0;:25::71:1;146:16:146:33:0;:37::38;:16:::1;:8::40;147:27:147:28:0;:16::43:1;:47::55:0;:16:::1;;:8::57;148:12:148:29:0;:32::33;:12:::1;:35::88:0;:56::57;:45::72:1;:76::84:0;:45:::1;;:37::86;:35::88;149:12:149:29:0;:32::33;:12:::1;:35::88:0;:56::57;:45::72:1;:76::84:0;:45:::1;;:37::86;:35::88;150:12:150:29:0;:32::33;:12:::1;:35::88:0;:56::57;:45::72:1;:76::84:0;:45:::1;;:37::86;:35::88;141:39:151:5;;;;;;;:4;167::179::0;;;;168:24:168:26;;:16::27:1;:31::39:0;;:8::41:1;169:25:169:26:0;;:28::30;;:8::33:1;171:35:171:54:0;:61::63;:35::64:1;:::67;:27::68;172:29:172:37:0;;:47::55;:66::73;;:58::74:1;:47;:39::75;:77::86:0;;:8::89:1;174:34:174:38:0;:41::49;;:34:::1;:52::56:0;:34:::1;:59::65:0;;:34:::1;:68::75:0;;:34:::1;:26::76;175:27:175:28:0;:16::45:1;:49::83:0;:75::82;:49::83:1;;;:8::85;176:27:176:28:0;:16::43:1;:57::78:0;:47::93:1;:8::95;177:27:177:28:0;:16::43:1;:57::78:0;:47::93:1;:8::95;178:27:178:28:0;:16::35:1;:49::70:0;:39::77:1;:16;:8::79;167:72:179:5;;;;;30:0:180:1;;;",
"logs": [],
"requires": [
{ "ip": 21, "line": 48 },
{ "ip": 26, "line": 49 },
{ "ip": 31, "line": 50 },
{ "ip": 44, "line": 56 },
{ "ip": 68, "line": 60 },
{ "ip": 73, "line": 61 },
{ "ip": 78, "line": 62 },
{ "ip": 84, "line": 63 },
{ "ip": 87, "line": 65 },
{ "ip": 96, "line": 66 },
{ "ip": 100, "line": 67 },
{ "ip": 122, "line": 74 },
{ "ip": 127, "line": 75 },
{ "ip": 149, "line": 80 },
{ "ip": 154, "line": 81 },
{ "ip": 159, "line": 82 },
{ "ip": 165, "line": 83 },
{ "ip": 187, "line": 97 },
{ "ip": 193, "line": 99 },
{ "ip": 237, "line": 113 },
{ "ip": 263, "line": 116 },
{ "ip": 271, "line": 119 },
{ "ip": 299, "line": 122 },
{ "ip": 304, "line": 123 },
{ "ip": 309, "line": 124 },
{ "ip": 315, "line": 125 },
{ "ip": 320, "line": 128 },
{ "ip": 328, "line": 129 },
{ "ip": 332, "line": 130 },
{ "ip": 345, "line": 132 },
{ "ip": 350, "line": 133 },
{ "ip": 354, "line": 134 },
{ "ip": 373, "line": 142 },
{ "ip": 378, "line": 143 },
{ "ip": 384, "line": 146 },
{ "ip": 390, "line": 147 },
{ "ip": 400, "line": 148 },
{ "ip": 411, "line": 149 },
{ "ip": 422, "line": 150 },
{ "ip": 441, "line": 168 },
{ "ip": 446, "line": 169 },
{ "ip": 462, "line": 172 },
{ "ip": 483, "line": 175 },
{ "ip": 488, "line": 176 },
{ "ip": 493, "line": 177 },
{ "ip": 499, "line": 178 }
],
"sourceTags": "101:105:pv;167:171:pv"
},
"compiler": {
"name": "cashc",
"version": "0.13.3",
"options": {
"enforceFunctionParameterTypes": true,
"enforceLocktimeGuard": true
}
},
"updatedAt": "2026-10-04T14:37:27.164Z"
}