@bitcann/contracts
Version:
Bitcoin Cash for Assigned Names and Numbers
110 lines • 11.1 kB
JavaScript
export default {
'contractName': 'OwnershipGuard',
'constructorInputs': [
{
'name': 'nameContractBytecode',
'type': 'bytes',
},
],
'abi': [
{
'name': 'call',
'inputs': [],
},
],
'bytecode': 'OP_TXINPUTCOUNT OP_4 OP_NUMEQUALVERIFY OP_TXOUTPUTCOUNT OP_4 OP_NUMEQUALVERIFY OP_INPUTINDEX OP_1 OP_NUMEQUALVERIFY OP_INPUTINDEX OP_UTXOBYTECODE OP_INPUTINDEX OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_INPUTINDEX OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_0 OP_UTXOBYTECODE OP_3 OP_UTXOBYTECODE OP_EQUALVERIFY OP_0 OP_UTXOTOKENCATEGORY OP_2 OP_UTXOTOKENCATEGORY OP_OVER OP_EQUALVERIFY OP_2 OP_OUTPUTTOKENCATEGORY OP_OVER OP_EQUALVERIFY OP_3 OP_UTXOTOKENCATEGORY 20 OP_SPLIT OP_SWAP OP_2 OP_PICK OP_EQUALVERIFY OP_1 OP_EQUALVERIFY OP_2 OP_UTXOTOKENCOMMITMENT OP_2 OP_OUTPUTTOKENCOMMITMENT OP_EQUALVERIFY OP_2 OP_UTXOTOKENCOMMITMENT OP_0 OP_EQUALVERIFY OP_3 OP_UTXOTOKENCOMMITMENT 14 OP_SPLIT OP_NIP OP_DUP OP_SIZE OP_NIP 2e626368 20 OP_4 OP_ROLL OP_CAT OP_OVER OP_SIZE OP_NIP OP_CAT OP_SWAP OP_CAT OP_SWAP OP_CAT OP_SWAP OP_CAT OP_SWAP OP_CAT OP_HASH256 aa20 OP_SWAP OP_CAT 87 OP_CAT OP_2 OP_UTXOBYTECODE OP_OVER OP_EQUALVERIFY OP_2 OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_0 OP_OUTPUTTOKENAMOUNT OP_0 OP_UTXOTOKENAMOUNT OP_3 OP_UTXOTOKENAMOUNT OP_ADD OP_NUMEQUALVERIFY OP_3 OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUAL',
'source': "pragma cashscript 0.11.5;\n\n/**\n * @param nameContractBytecode The the partial bytecode of the name contract that has an Owner.\n */\ncontract OwnershipGuard(bytes nameContractBytecode) {\n /**\n * If the name being auctioned already has an `externalAuthNFT` with the same category, then the auction is invalid.\n * Because it means that an owner still exists. If it is known that the name has been abandoned for > `inactivityExpiryTime`\n * then one must use the `burn` method of the name.cash to burn the internalAuthNFT and externalAuthNFT making the \n * name to be available for auction.\n *\n * Penalizes invalid name registrations by allowing anyone to burn the auctionNFT and claim the funds as a reward.\n * \n * @inputs\n * - Input0: Registry Contract's authorizedThreadNFT i.e immutable NFT with commitment that has the lockingBytecode of this contract\n * - Input1: Any input from this contract\n * - Input2: External Auth NFT from the Name Contract\n * - Input3: auctionNFT from Registry Contract\n * \n * @outputs\n * - Output0: Registry Contract's authorizedThreadNFT back to the Registry contract.\n * - Output1: Input1 back to this contract without any change\n * - Output2: External Auth NFT back to the Name Contract\n * - Output3: BCH change/reward to caller\n */\n function call(){\n require(tx.inputs.length == 4, \"Transaction: must have exactly 4 inputs\");\n require(tx.outputs.length == 4, \"Transaction: must have exactly 4 outputs\");\n \n // This contract can only be used at input1 and it should return the input1 back to itself.\n require(this.activeInputIndex == 1, \"Input 1: ownership guard contract UTXO must be at this index\");\n require(tx.inputs[this.activeInputIndex].lockingBytecode == tx.outputs[this.activeInputIndex].lockingBytecode, \"Input 1: locking bytecode must match output 1\");\n // Ensure that no tokenCategory is minted here.\n require(tx.outputs[this.activeInputIndex].tokenCategory == 0x, \"Output 1: must not have any token category (pure BCH only)\");\n\n // This contract can only be used with the 'lockingbytecode' used in the 0th input.\n // Note: This contract can be used with any contract that fulfills these conditions, and that is fine\n // because those contracts will not be manipulating the utxos of the Registry contract. Instead, they will\n // be manipulating their own utxos.\n bytes registryInputLockingBytecode = tx.inputs[0].lockingBytecode;\n require(tx.inputs[3].lockingBytecode == registryInputLockingBytecode, \"Input 3: auction NFT locking bytecode does not match registry input's locking bytecode\");\n\n bytes registryInputCategory = tx.inputs[0].tokenCategory;\n require(tx.inputs[2].tokenCategory == registryInputCategory, \"Input 2: external auth NFT token category prefix must match registry\");\n require(tx.outputs[2].tokenCategory == registryInputCategory, \"Output 2: external auth NFT token category prefix must match registry\");\n\n // AuctionNFT should be mutable and of the 'nameCategory' i.e registryInputCategory\n bytes auctionCategory, bytes auctionCapability = tx.inputs[3].tokenCategory.split(32);\n require(auctionCategory == registryInputCategory, \"Input 3: auction NFT token category prefix must match registry\");\n // Mutable\n require(auctionCapability == 0x01, \"Input 3: auction NFT capability must be mutable (0x01)\");\n\n // nftCommiment of the externalAuthNFT must stay the same\n require(tx.inputs[2].nftCommitment == tx.outputs[2].nftCommitment, \"Output 2: external auth NFT commitment must match input 2\");\n // Ensure that the externalAuth NFT is used and not the internalAuth NFT.\n require(tx.inputs[2].nftCommitment == 0x, \"Input 2: external auth NFT must have empty commitment\");\n\n // Get the name of the name from the auctionNFT\n bytes name = tx.inputs[3].nftCommitment.split(20)[1];\n // Get the name length to generate the complete bytecode of the name contract\n int nameLength = name.length;\n // category + name + bytecode.\n // Note: `inactivityExpiryTime` in the name is already added to the nameContractBytecode in the constructor.\n bytes constant tld = bytes('.bch');\n bytes nameBytecode = 0x20 + registryInputCategory + bytes(tld.length) + tld + bytes(nameLength) + name + nameContractBytecode;\n bytes32 scriptHash = hash256(nameBytecode);\n bytes35 nameLockingBytecode = new LockingBytecodeP2SH32(scriptHash);\n\n // Ensure that the externalAuthNFT is coming from the correct Name Contract\n require(tx.inputs[2].lockingBytecode == nameLockingBytecode, \"Input 2: external auth NFT locking bytecode must match name contract\");\n require(tx.outputs[2].lockingBytecode == nameLockingBytecode, \"Output 2: external auth NFT locking bytecode must match name contract\");\n\n // tokenAmount from the auctionNFT goes to the authorizedThreadNFT to be accumulated later\n // and merged back with the CounterNFT using the `Accumulator` Contract\n require(tx.outputs[0].tokenAmount == tx.inputs[0].tokenAmount + tx.inputs[3].tokenAmount, \"Output 0: token amount must equal input 0 + input 3 amounts (accumulation)\");\n\n // Reward Output\n require(tx.outputs[3].tokenCategory == 0x, \"Output 3: reward must be pure BCH (no token category)\");\n }\n}",
'debug': {
'bytecode': 'c3549dc4549dc0519dc0c7c0cd88c0d1008800c753c78800ce52ce788852d1788853ce01207f7c527988518852cf52d28852cf008853cf01147f77768277042e6263680120547a7e7882777e7c7e7c7e7c7e7c7eaa02aa207c7e01877e52c7788852cd8800d300d053d0939d53d10087',
'sourceMap': '28:12:28:28;:32::33;:4::78:1;29:12:29:29:0;:33::34;:4::80:1;32:12:32:33:0;:37::38;:4::104:1;33:22:33:43:0;:12::60:1;:75::96:0;:64::113:1;:4::164;35:23:35:44:0;:12::59:1;:63::65:0;:4::129:1;41:51:41:52:0;:41::69:1;42:22:42:23:0;:12::40:1;:4::164;44:44:44:45:0;:34::60:1;45:22:45:23:0;:12::38:1;:42::63:0;:4::137:1;46:23:46:24:0;:12::39:1;:43::64:0;:4::139:1;49:63:49:64:0;:53::79:1;:86::88:0;:53::89:1;50:12:50:27:0;:31::52;;:4::120:1;52:33:52:37:0;:4::97:1;55:22:55:23:0;:12::38:1;:53::54:0;:42::69:1;:4::132;57:22:57:23:0;:12::38:1;:42::44:0;:4::103:1;60:27:60:28:0;:17::43:1;:50::52:0;:17::53:1;:::56;62:21:62:25:0;:::32:1;;65:31:65:37:0;66:25:66:29;:32::53;;:25:::1;:62::65:0;:::72:1;;:25::73;:76::79:0;:25:::1;:88::98:0;:25::99:1;:102::106:0;:25:::1;:109::129:0;:25:::1;67::67:46;68:34:68:71:0;:60::70;:34::71:1;;;71:22:71:23:0;:12::40:1;:44::63:0;:4::137:1;72:23:72:24:0;:12::41:1;:4::139;76:23:76:24:0;:12::37:1;:51::52:0;:41::65:1;:78::79:0;:68::92:1;:41;:4::172;79:23:79:24:0;:12::39:1;:43::45:0;:4::104:1',
'logs': [],
'requires': [
{
'ip': 3,
'line': 28,
'message': 'Transaction: must have exactly 4 inputs',
},
{
'ip': 6,
'line': 29,
'message': 'Transaction: must have exactly 4 outputs',
},
{
'ip': 9,
'line': 32,
'message': 'Input 1: ownership guard contract UTXO must be at this index',
},
{
'ip': 14,
'line': 33,
'message': 'Input 1: locking bytecode must match output 1',
},
{
'ip': 18,
'line': 35,
'message': 'Output 1: must not have any token category (pure BCH only)',
},
{
'ip': 23,
'line': 42,
'message': "Input 3: auction NFT locking bytecode does not match registry input's locking bytecode",
},
{
'ip': 29,
'line': 45,
'message': 'Input 2: external auth NFT token category prefix must match registry',
},
{
'ip': 33,
'line': 46,
'message': 'Output 2: external auth NFT token category prefix must match registry',
},
{
'ip': 41,
'line': 50,
'message': 'Input 3: auction NFT token category prefix must match registry',
},
{
'ip': 43,
'line': 52,
'message': 'Input 3: auction NFT capability must be mutable (0x01)',
},
{
'ip': 48,
'line': 55,
'message': 'Output 2: external auth NFT commitment must match input 2',
},
{
'ip': 52,
'line': 57,
'message': 'Input 2: external auth NFT must have empty commitment',
},
{
'ip': 87,
'line': 71,
'message': 'Input 2: external auth NFT locking bytecode must match name contract',
},
{
'ip': 90,
'line': 72,
'message': 'Output 2: external auth NFT locking bytecode must match name contract',
},
{
'ip': 98,
'line': 76,
'message': 'Output 0: token amount must equal input 0 + input 3 amounts (accumulation)',
},
{
'ip': 103,
'line': 79,
'message': 'Output 3: reward must be pure BCH (no token category)',
},
],
},
'compiler': {
'name': 'cashc',
'version': '0.11.5',
},
'updatedAt': '2025-09-01T12:51:28.820Z',
};
//# sourceMappingURL=OwnershipGuard.js.map