@fundtokens/builders 0.1.0-rc5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FundTokenTransactionBuilder.js +384 -0
- package/LICENSE +1 -0
- package/PublicFundTransactionBuilder.js +336 -0
- package/art/asset.json +52 -0
- package/art/authhead_vault.json +47 -0
- package/art/fee.json +97 -0
- package/art/fee_minter.json +82 -0
- package/art/fund.json +96 -0
- package/art/manager.json +202 -0
- package/art/mint_inflow.json +84 -0
- package/art/mint_outflow.json +84 -0
- package/art/public.json +149 -0
- package/art/public_vault.json +122 -0
- package/art/simple_minter.json +73 -0
- package/art/simple_vault.json +37 -0
- package/art/startup.json +109 -0
- package/constants.js +1 -0
- package/index.js +17 -0
- package/package.json +13 -0
- package/utils.js +201 -0
package/art/fund.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractName": "FundManager",
|
|
3
|
+
"constructorInputs": [
|
|
4
|
+
{
|
|
5
|
+
"name": "inflowToken",
|
|
6
|
+
"type": "bytes32"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"name": "outflowToken",
|
|
10
|
+
"type": "bytes32"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "fundCategory",
|
|
14
|
+
"type": "bytes"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "fundHash",
|
|
18
|
+
"type": "bytes"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"abi": [
|
|
22
|
+
{
|
|
23
|
+
"name": "mint",
|
|
24
|
+
"inputs": []
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "redeem",
|
|
28
|
+
"inputs": []
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"bytecode": "OP_4 OP_PICK OP_0 OP_NUMEQUAL OP_IF OP_INPUTINDEX OP_1SUB OP_UTXOTOKENCATEGORY OP_EQUALVERIFY OP_INPUTINDEX OP_1SUB OP_UTXOTOKENCOMMITMENT OP_2 OP_PICK OP_4 OP_ROLL OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOBYTECODE OP_INPUTINDEX OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENAMOUNT OP_INPUTINDEX OP_OUTPUTTOKENAMOUNT OP_GREATERTHAN OP_VERIFY OP_INPUTINDEX OP_OUTPUTTOKENAMOUNT OP_0 OP_GREATERTHAN OP_IF OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_2 OP_PICK OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_INPUTINDEX OP_OUTPUTTOKENCATEGORY OP_EQUALVERIFY OP_ELSE OP_INPUTINDEX OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUALVERIFY OP_ENDIF OP_2DROP OP_DROP OP_1 OP_ELSE OP_4 OP_ROLL OP_1 OP_NUMEQUALVERIFY OP_INPUTINDEX OP_1SUB OP_UTXOTOKENCATEGORY OP_ROT OP_EQUALVERIFY OP_INPUTINDEX OP_1SUB OP_UTXOTOKENCOMMITMENT OP_2 OP_PICK OP_4 OP_ROLL OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOBYTECODE OP_INPUTINDEX OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_INPUTINDEX OP_OUTPUTTOKENCATEGORY OP_ROT OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENAMOUNT OP_INPUTINDEX OP_OUTPUTTOKENAMOUNT OP_LESSTHAN OP_NIP OP_ENDIF",
|
|
32
|
+
"source": "pragma cashscript ~0.13.0;\r\n\r\n/**\r\n * FundManager (Fund): Holds and releases fund tokens\r\n * \r\n * Core accounting contract for fund tokens. Maintains the supply of fund tokens\r\n * and enforces token conservation during inflow/outflow operations.\r\n * \r\n * During mint (inflow/deposit):\r\n * - Input has fund tokens (current supply)\r\n * - Output has fewer tokens (tokens released to user)\r\n * - Release amount = (input - output)\r\n * \r\n * During redeem (outflow/withdrawal):\r\n * - Input has fund tokens (current supply)\r\n * - Output has more tokens (tokens returned from user)\r\n * - Collection amount = (output - input)\r\n * \r\n * Parameters:\r\n * inflowToken: Inflow token category (signals minting operation)\r\n * outflowToken: Outflow token category (signals redemption operation)\r\n * fundCategory: Fund token category held in this contract\r\n * fundHash: Hash of fund parameters (ensures correct fund)\r\n */\r\ncontract FundManager(bytes32 inflowToken, bytes32 outflowToken, bytes fundCategory, bytes fundHash)\r\n{ \r\n /**\r\n * mint(): Release fund tokens during inflow (user deposit)\r\n * \r\n * Ensures:\r\n * - Fund tokens are reduced (tokens released to user)\r\n * - If no tokens remain, output has no token (ready for next redeem)\r\n */\r\n function mint() {\r\n // Previous input must be inflow manager signaling this mint operation\r\n require(tx.inputs[this.activeInputIndex - 1].tokenCategory == inflowToken);\r\n require(tx.inputs[this.activeInputIndex - 1].nftCommitment == bytes(fundCategory + fundHash));\r\n\r\n // This contract returns to itself (fund UTXO stays alive)\r\n require(tx.inputs[this.activeInputIndex].lockingBytecode == tx.outputs[this.activeInputIndex].lockingBytecode);\r\n // Fund token amount must decrease (tokens released to user)\r\n require(tx.inputs[this.activeInputIndex].tokenAmount > tx.outputs[this.activeInputIndex].tokenAmount);\r\n\r\n // Verify token output or empty\r\n if(tx.outputs[this.activeInputIndex].tokenAmount > 0) {\r\n // If tokens remain, they must be the same fund token category\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == fundCategory);\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == tx.outputs[this.activeInputIndex].tokenCategory);\r\n } else {\r\n // If no tokens remain, output has no token (stay hydrated for next redeem)\r\n require(tx.outputs[this.activeInputIndex].tokenCategory == 0x);\r\n }\r\n }\r\n\r\n /**\r\n * redeem(): Collect fund tokens during outflow (user withdrawal)\r\n * \r\n * Ensures:\r\n * - Fund tokens are increased (tokens collected from user)\r\n * - Output amount > input amount (collecting tokens)\r\n */\r\n function redeem() {\r\n // Previous input must be outflow manager signaling this redeem operation\r\n require(tx.inputs[this.activeInputIndex - 1].tokenCategory == outflowToken);\r\n require(tx.inputs[this.activeInputIndex - 1].nftCommitment == bytes(fundCategory + fundHash));\r\n\r\n // This contract returns to itself\r\n require(tx.inputs[this.activeInputIndex].lockingBytecode == tx.outputs[this.activeInputIndex].lockingBytecode);\r\n // Output must have the fund token category (collecting tokens)\r\n require(tx.outputs[this.activeInputIndex].tokenCategory == fundCategory);\r\n // Fund token amount must increase (collecting from user)\r\n require(tx.inputs[this.activeInputIndex].tokenAmount < tx.outputs[this.activeInputIndex].tokenAmount);\r\n }\r\n}",
|
|
33
|
+
"debug": {
|
|
34
|
+
"bytecode": "5479009c63c08cce88c08ccf5279547a7e88c0c7c0cd88c0d0c0d3a069c0d300a063c0ce527988c0cec0d18867c0d10088686d755167547a519dc08cce7b88c08ccf5279547a7e88c0c7c0cd88c0d17b88c0d0c0d39f7768",
|
|
35
|
+
"sourceMap": "34:4:53:5;;;;;36:26:36:47;:::51:1;:16::66;:8::83;37:26:37:47:0;:::51:1;:16::66;:76::88:0;;:91::99;;:76:::1;:8::102;40:26:40:47:0;:16::64:1;:79::100:0;:68::117:1;:8::119;42:26:42:47:0;:16::60:1;:74::95:0;:63::108:1;:16;:8::110;45:22:45:43:0;:11::56:1;:59::60:0;:11:::1;:62:49:9:0;47:30:47:51;:20::66:1;:70::82:0;;:12::84:1;48:30:48:51:0;:20::66:1;:81::102:0;:70::117:1;:12::119;49:15:52:9:0;51:31:51:52;:20::67:1;:71::73:0;:12::75:1;49:15:52:9;34:4:53:5;;;;62::73::0;;;;64:26:64:47;:::51:1;:16::66;:70::82:0;:8::84:1;65:26:65:47:0;:::51:1;:16::66;:76::88:0;;:91::99;;:76:::1;:8::102;68:26:68:47:0;:16::64:1;:79::100:0;:68::117:1;:8::119;70:27:70:48:0;:16::63:1;:67::79:0;:8::81:1;72:26:72:47:0;:16::60:1;:74::95:0;:63::108:1;:8::110;62:4:73:5;25:0:74:1",
|
|
36
|
+
"logs": [],
|
|
37
|
+
"requires": [
|
|
38
|
+
{
|
|
39
|
+
"ip": 12,
|
|
40
|
+
"line": 36
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"ip": 21,
|
|
44
|
+
"line": 37
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"ip": 26,
|
|
48
|
+
"line": 40
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"ip": 32,
|
|
52
|
+
"line": 42
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"ip": 42,
|
|
56
|
+
"line": 47
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"ip": 47,
|
|
60
|
+
"line": 48
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"ip": 52,
|
|
64
|
+
"line": 51
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"ip": 66,
|
|
68
|
+
"line": 64
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"ip": 75,
|
|
72
|
+
"line": 65
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"ip": 80,
|
|
76
|
+
"line": 68
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"ip": 84,
|
|
80
|
+
"line": 70
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"ip": 90,
|
|
84
|
+
"line": 72
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
},
|
|
88
|
+
"compiler": {
|
|
89
|
+
"name": "cashc",
|
|
90
|
+
"version": "0.13.0-next.6",
|
|
91
|
+
"options": {
|
|
92
|
+
"enforceFunctionParameterTypes": true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"updatedAt": "2026-04-21T19:21:04.017Z"
|
|
96
|
+
}
|
package/art/manager.json
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractName": "TransactionManager",
|
|
3
|
+
"constructorInputs": [
|
|
4
|
+
{
|
|
5
|
+
"name": "fee",
|
|
6
|
+
"type": "bytes32"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"name": "inflowToken",
|
|
10
|
+
"type": "bytes32"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "outflowToken",
|
|
14
|
+
"type": "bytes32"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "fundCategory",
|
|
18
|
+
"type": "bytes32"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "fundHash",
|
|
22
|
+
"type": "bytes32"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "fundContract",
|
|
26
|
+
"type": "bytes"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "assetContract",
|
|
30
|
+
"type": "bytes"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"abi": [
|
|
34
|
+
{
|
|
35
|
+
"name": "inflow",
|
|
36
|
+
"inputs": [
|
|
37
|
+
{
|
|
38
|
+
"name": "fund",
|
|
39
|
+
"type": "bytes"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "outflow",
|
|
45
|
+
"inputs": [
|
|
46
|
+
{
|
|
47
|
+
"name": "fund",
|
|
48
|
+
"type": "bytes"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "densityPadding",
|
|
52
|
+
"type": "bytes"
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"bytecode": "OP_7 OP_PICK OP_0 OP_NUMEQUAL OP_IF OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_2 OP_PICK OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOBYTECODE OP_INPUTINDEX OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_INPUTINDEX OP_OUTPUTTOKENCATEGORY OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT OP_INPUTINDEX OP_OUTPUTTOKENCOMMITMENT OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT OP_4 OP_PICK OP_6 OP_PICK OP_CAT OP_EQUALVERIFY OP_8 OP_PICK OP_HASH256 OP_5 OP_PICK OP_EQUALVERIFY OP_INPUTINDEX OP_1ADD OP_DUP OP_UTXOBYTECODE aa20 20 OP_8 OP_PICK OP_CAT 20 OP_CAT OP_7 OP_PICK OP_CAT 20 OP_CAT OP_6 OP_PICK OP_CAT 20 OP_CAT OP_5 OP_ROLL OP_CAT OP_8 OP_ROLL OP_CAT OP_HASH256 OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_7 OP_ROLL 20 OP_SPLIT OP_SWAP OP_5 OP_ROLL OP_EQUALVERIFY OP_8 OP_SPLIT OP_SWAP OP_BIN2NUM OP_2 OP_PICK OP_UTXOTOKENAMOUNT OP_3 OP_PICK OP_OUTPUTTOKENAMOUNT OP_SUB OP_2DUP OP_SWAP OP_MOD OP_0 OP_NUMEQUALVERIFY OP_DUP OP_ROT OP_DIV OP_3 OP_PICK OP_1ADD OP_UTXOBYTECODE aa20 OP_6 OP_ROLL OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_ROT OP_8 OP_SPLIT OP_SWAP OP_BIN2NUM OP_4 OP_ROLL OP_2 OP_ADD OP_OVER OP_0 OP_GREATERTHAN OP_IF OP_DUP OP_1ADD OP_NIP 0000000000000000000000000000000000000000000000000000000000000000 OP_OVER OP_OUTPUTBYTECODE aa20 20 OP_3 OP_PICK OP_CAT 20 OP_CAT OP_10 OP_PICK OP_CAT 20 OP_CAT OP_9 OP_PICK OP_CAT OP_11 OP_PICK OP_CAT OP_HASH256 OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_OVER OP_OUTPUTVALUE OP_3 OP_PICK OP_MOD OP_0 OP_NUMEQUALVERIFY OP_OVER OP_OUTPUTVALUE OP_3 OP_PICK OP_DIV OP_DUP OP_6 OP_PICK OP_NUMEQUALVERIFY OP_2DROP OP_ENDIF OP_ROT OP_DUP OP_SIZE OP_NIP OP_0 OP_GREATERTHAN OP_IF OP_0 OP_BEGIN OP_OVER 20 OP_SPLIT OP_DUP OP_8 OP_SPLIT OP_OVER OP_BIN2NUM OP_7 OP_PICK OP_1ADD OP_6 OP_PICK OP_ADD OP_DUP OP_OUTPUTBYTECODE aa20 20 OP_8 OP_PICK OP_CAT 20 OP_CAT OP_16 OP_PICK OP_CAT 20 OP_CAT OP_15 OP_PICK OP_CAT 11 OP_PICK OP_CAT OP_HASH256 OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_DUP OP_OUTPUTTOKENCATEGORY OP_6 OP_PICK OP_EQUALVERIFY OP_DUP OP_OUTPUTTOKENAMOUNT OP_2 OP_PICK OP_MOD OP_0 OP_NUMEQUALVERIFY OP_DUP OP_OUTPUTTOKENAMOUNT OP_2 OP_PICK OP_DIV OP_DUP OP_12 OP_PICK OP_NUMEQUALVERIFY OP_3 OP_PICK OP_9 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_7 OP_PICK OP_1ADD OP_8 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_2DROP OP_2DROP OP_2DROP OP_DROP OP_OVER OP_SIZE OP_NIP OP_0 OP_LESSTHANOREQUAL OP_UNTIL OP_DROP OP_ENDIF OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_DROP OP_1 OP_ELSE OP_7 OP_ROLL OP_1 OP_NUMEQUALVERIFY OP_8 OP_ROLL OP_SIZE OP_NIP OP_0 OP_GREATERTHANOREQUAL OP_VERIFY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_3 OP_PICK OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOBYTECODE OP_INPUTINDEX OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_INPUTINDEX OP_OUTPUTTOKENCATEGORY OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT OP_INPUTINDEX OP_OUTPUTTOKENCOMMITMENT OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCOMMITMENT OP_4 OP_PICK OP_6 OP_PICK OP_CAT OP_EQUALVERIFY OP_7 OP_PICK OP_HASH256 OP_5 OP_PICK OP_EQUALVERIFY OP_INPUTINDEX OP_1ADD OP_DUP OP_UTXOBYTECODE aa20 20 OP_8 OP_PICK OP_CAT 20 OP_CAT OP_7 OP_PICK OP_CAT 20 OP_CAT OP_6 OP_PICK OP_CAT 20 OP_CAT OP_5 OP_ROLL OP_CAT OP_8 OP_ROLL OP_CAT OP_HASH256 OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_6 OP_ROLL 20 OP_SPLIT OP_SWAP OP_5 OP_ROLL OP_EQUALVERIFY OP_8 OP_SPLIT OP_SWAP OP_BIN2NUM OP_2 OP_PICK OP_OUTPUTTOKENAMOUNT OP_3 OP_PICK OP_UTXOTOKENAMOUNT OP_SUB OP_2DUP OP_SWAP OP_MOD OP_0 OP_NUMEQUALVERIFY OP_DUP OP_ROT OP_DIV OP_ROT OP_8 OP_SPLIT OP_4 OP_ROLL OP_1ADD OP_UTXOBYTECODE aa20 OP_6 OP_ROLL OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_SWAP OP_BIN2NUM OP_DUP OP_0 OP_GREATERTHAN OP_IF OP_0 0000000000000000000000000000000000000000000000000000000000000000 aa20 20 OP_2 OP_PICK OP_CAT 20 OP_CAT OP_9 OP_PICK OP_CAT 20 OP_CAT OP_8 OP_PICK OP_CAT OP_10 OP_PICK OP_CAT OP_HASH256 OP_CAT 87 OP_CAT OP_0 OP_BEGIN OP_DUP OP_UTXOBYTECODE OP_2 OP_PICK OP_EQUAL OP_OVER OP_UTXOTOKENCATEGORY OP_0 OP_EQUAL OP_BOOLAND OP_IF OP_3 OP_PICK OP_OVER OP_UTXOVALUE OP_ADD OP_4 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_FROMALTSTACK OP_ENDIF OP_DUP OP_1ADD OP_NIP OP_DUP OP_TXINPUTCOUNT OP_GREATERTHANOREQUAL OP_UNTIL OP_0 OP_BEGIN OP_DUP OP_OUTPUTBYTECODE OP_3 OP_PICK OP_EQUAL OP_OVER OP_OUTPUTTOKENCATEGORY OP_0 OP_EQUAL OP_BOOLAND OP_IF OP_4 OP_PICK OP_OVER OP_OUTPUTVALUE OP_SUB OP_5 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_ENDIF OP_DUP OP_1ADD OP_NIP OP_DUP OP_TXOUTPUTCOUNT OP_GREATERTHANOREQUAL OP_UNTIL OP_4 OP_PICK OP_6 OP_PICK OP_MOD OP_0 OP_NUMEQUALVERIFY OP_4 OP_PICK OP_6 OP_PICK OP_DIV OP_8 OP_PICK OP_NUMEQUALVERIFY OP_2DROP OP_2DROP OP_DROP OP_ENDIF OP_SWAP OP_BEGIN OP_DUP OP_SIZE OP_NIP OP_0 OP_GREATERTHAN OP_DUP OP_TOALTSTACK OP_IF OP_DUP 20 OP_SPLIT aa20 20 OP_3 OP_PICK OP_CAT 20 OP_CAT OP_9 OP_PICK OP_CAT 20 OP_CAT OP_8 OP_PICK OP_CAT OP_10 OP_PICK OP_CAT OP_HASH256 OP_CAT 87 OP_CAT OP_0 OP_0 OP_BEGIN OP_OVER OP_UTXOBYTECODE OP_3 OP_PICK OP_EQUAL OP_2 OP_PICK OP_UTXOTOKENCATEGORY OP_6 OP_PICK OP_EQUAL OP_BOOLAND OP_IF OP_2DUP OP_SWAP OP_UTXOTOKENAMOUNT OP_ADD OP_NIP OP_ENDIF OP_OVER OP_1ADD OP_ROT OP_DROP OP_SWAP OP_OVER OP_TXINPUTCOUNT OP_GREATERTHANOREQUAL OP_UNTIL OP_0 OP_BEGIN OP_DUP OP_OUTPUTBYTECODE OP_4 OP_PICK OP_EQUAL OP_OVER OP_OUTPUTTOKENCATEGORY OP_7 OP_PICK OP_EQUAL OP_BOOLAND OP_IF OP_2DUP OP_OUTPUTTOKENAMOUNT OP_SUB OP_ROT OP_DROP OP_SWAP OP_ENDIF OP_DUP OP_1ADD OP_NIP OP_DUP OP_TXOUTPUTCOUNT OP_GREATERTHANOREQUAL OP_UNTIL OP_4 OP_PICK OP_8 OP_SPLIT OP_OVER OP_BIN2NUM OP_4 OP_PICK OP_OVER OP_MOD OP_0 OP_NUMEQUALVERIFY OP_4 OP_PICK OP_OVER OP_DIV OP_12 OP_PICK OP_NUMEQUALVERIFY OP_OVER OP_10 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_FROMALTSTACK OP_2DROP OP_2DROP OP_2DROP OP_2DROP OP_DROP OP_ENDIF OP_FROMALTSTACK OP_NOT OP_UNTIL OP_2DROP OP_2DROP OP_2DROP OP_DROP OP_1 OP_ENDIF",
|
|
58
|
+
"source": "pragma cashscript ~0.13.0;\r\n\r\n/**\r\n * TransactionManager: Orchestrates inflow (deposits) and outflow (withdrawals)\r\n * \r\n * The most complex contract in FundTokens. Validates:\r\n * - Fund token accounting (release/locking amounts)\r\n * - Asset custody correctness per fund configuration\r\n * - Satoshi backing (if fund supports Bitcoin asset)\r\n * \r\n * NFT Commitment Format:\r\n * [fundCategory (32) | fundHash (32)]\r\n * \r\n * Fund Hash decodes to:\r\n * [fundCategory (32) | fundAmount (8) | satoshis (8) | \r\n * asset1Category (32) | asset1Amount (8) | ... | assetNCategory (32) | assetNAmount (8)]\r\n * \r\n * Threading Model:\r\n * - Multiple independent inflow/outflow threads possible (different asset chains)\r\n * - Each thread validates its asset amounts independently\r\n * - Fund token accounting aggregates across all threads\r\n * \r\n * Parameters:\r\n * fee: Fee contract hash (validates fees paid)\r\n * inflowToken: Inflow token category (deposit signal)\r\n * outflowToken: Outflow token category (withdrawal signal)\r\n * fundCategory: Fund identifier (comes from fund creation)\r\n * fundHash: Hash of complete fund specification\r\n * fundContract: Fund manager bytecode (for hashing per-fund instance)\r\n * assetContract: Asset manager bytecode (for hashing per-fund asset instances)\r\n */\r\ncontract TransactionManager(bytes32 fee, bytes32 inflowToken, bytes32 outflowToken, bytes32 fundCategory, bytes32 fundHash, bytes fundContract, bytes assetContract)\r\n{\r\n /**\r\n * inflow(bytes fund): Release fund tokens during user deposits\r\n * \r\n * Validates fund accounting:\r\n * - Fund tokens released = (input amount - output amount) / fundAmount\r\n * - Amount is whole multiple of fundAmount (prevents fractional tokens)\r\n * - Same release amount across all assets (atomicity across asset threads)\r\n * \r\n * Transaction Structure:\r\n * Input[activeInputIndex]: Inflow token (signal: deposit occurred)\r\n * Input[activeInputIndex+1]: Fund manager (contains fund tokens)\r\n * Input[activeInputIndex+2]: Fee contract (proves fees paid)\r\n * Input[activeInputIndex+3]: Optional satoshi asset inputs\r\n * Input[activeInputIndex+3+N]: Optional asset inputs\r\n * \r\n * Output[activeInputIndex]: Inflow token (returned to signal processor)\r\n * Output[activeInputIndex+1]: Fund manager (updated fund tokens)\r\n * Output[activeInputIndex+2+]: Asset custody outputs (satoshi/tokens released)\r\n * \r\n * Validates:\r\n * - Fund tokens released consistently across operation\r\n * - Satoshi backing matches if configured\r\n * - Each asset release equals fund release amount\r\n */\r\n function inflow(bytes fund) {\r\n // Verify this input carries inflow signal token\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == inflowToken);\r\n // Spend signal token back to self\r\n require(tx.inputs[this.activeInputIndex].lockingBytecode == tx.outputs[this.activeInputIndex].lockingBytecode);\r\n // Signal token category preserved (maintains state)\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == tx.outputs[this.activeInputIndex].tokenCategory);\r\n // Signal token NFT commitment must match fund parameters\r\n require(tx.inputs[this.activeInputIndex].nftCommitment == tx.outputs[this.activeInputIndex].nftCommitment);\r\n require(tx.inputs[this.activeInputIndex].nftCommitment == bytes(fundCategory + fundHash));\r\n // Fund parameter hash must match (prevents fund substitution)\r\n require(hash256(fund) == fundHash);\r\n\r\n // Fund manager contract is next input (index activeInputIndex + 1)\r\n // Fund manager holds fund tokens that get released or locked\r\n int fundInputIndex = this.activeInputIndex + 1;\r\n // Verify fund manager contract address matches expected hash\r\n require(tx.inputs[fundInputIndex].lockingBytecode == new LockingBytecodeP2SH32(hash256(0x20 + fundHash + 0x20 + fundCategory + 0x20 + outflowToken + 0x20 + inflowToken + fundContract)));\r\n\r\n // Parse fund parameters\r\n bytes nft_fundCategory, bytes nft_next1 = fund.split(32);\r\n // Fund category must match (prevents fund mixing)\r\n require(nft_fundCategory == fundCategory);\r\n\r\n // Fund amount: divisor determining whole token units\r\n bytes nft_fundAmount, bytes nft_next2 = nft_next1.split(8);\r\n\r\n int fundAmount = int(nft_fundAmount);\r\n // Calculate released fund tokens\r\n // Release = (input tokens - output tokens) / fundAmount\r\n // Division ensures whole token units (no fractional tokens)\r\n int fundReleasedAmount = tx.inputs[fundInputIndex].tokenAmount - tx.outputs[fundInputIndex].tokenAmount;\r\n // Ensure release is whole multiple of fund amount\r\n require(fundReleasedAmount % fundAmount == 0);\r\n // Convert raw token change to \"whole\" fund units\r\n fundReleasedAmount = fundReleasedAmount / fundAmount;\r\n\r\n // Fee contract input must follow fund manager (validates fees paid)\r\n require(tx.inputs[fundInputIndex + 1].lockingBytecode == new LockingBytecodeP2SH32(fee));\r\n\r\n // Parse satoshi configuration\r\n bytes nft_sats, bytes nft_next3 = nft_next2.split(8);\r\n int fundSats = int(nft_sats);\r\n int satoshiOutputIndex = fundInputIndex + 2;\r\n \r\n // If fund supports satoshi backing\r\n if(fundSats > 0) {\r\n satoshiOutputIndex = satoshiOutputIndex + 1;\r\n // Satoshi assets use special category (all zeros)\r\n bytes32 satoshiAsset = 0x0000000000000000000000000000000000000000000000000000000000000000;\r\n // Verify satoshi custody output to correct asset manager\r\n require(tx.outputs[satoshiOutputIndex].lockingBytecode == new LockingBytecodeP2SH32(hash256(0x20 + satoshiAsset + 0x20 + fundHash + 0x20 + outflowToken + assetContract)));\r\n // Satoshi value must be whole multiple of fundSats\r\n require(tx.outputs[satoshiOutputIndex].value % fundSats == 0);\r\n // Calculate collected satoshis\r\n int satoshiCollectedAmount = tx.outputs[satoshiOutputIndex].value / fundSats;\r\n // Satoshi release must equal fund token release (atomic consistency)\r\n require(satoshiCollectedAmount == fundReleasedAmount);\r\n }\r\n\r\n // Validate assets\r\n bytes nft_assetData = nft_next3;\r\n if(nft_assetData.length > 0) {\r\n int assetIndex = 0;\r\n // Iterate through each asset type in fund\r\n do {\r\n bytes nft_assetCategory, bytes nft_assetNext = nft_assetData.split(32);\r\n bytes nft_assetAmount, bytes nft_remaining = nft_assetNext.split(8);\r\n int assetAmount = int(nft_assetAmount);\r\n\r\n // Calculate output index for this asset (after satoshi asset if present)\r\n int assetOutputIndex = satoshiOutputIndex + 1 + assetIndex;\r\n // Verify asset custody output to correct asset manager\r\n require(tx.outputs[assetOutputIndex].lockingBytecode == new LockingBytecodeP2SH32(hash256(0x20 + nft_assetCategory + 0x20 + fundHash + 0x20 + outflowToken + assetContract)));\r\n // Verify asset tokens are of correct category\r\n require(tx.outputs[assetOutputIndex].tokenCategory == nft_assetCategory);\r\n \r\n // Asset tokens must be whole multiple of assetAmount\r\n require(tx.outputs[assetOutputIndex].tokenAmount % assetAmount == 0);\r\n // Calculate collected asset units\r\n int assetCollectedAmount = tx.outputs[assetOutputIndex].tokenAmount / assetAmount;\r\n // Asset release must equal fund release (maintains atomicity across assets)\r\n require(assetCollectedAmount == fundReleasedAmount);\r\n \r\n nft_assetData = nft_remaining;\r\n assetIndex = assetIndex + 1;\r\n } while(nft_assetData.length > 0);\r\n }\r\n }\r\n\r\n /**\r\n * outflow(bytes fund, bytes densityPadding): Lock fund tokens during user withdrawals\r\n * \r\n * Validates fund accounting:\r\n * - Fund tokens locked = (output amount - input amount) / fundAmount\r\n * - Amount is whole multiple of fundAmount (prevents fractional tokens)\r\n * - Same lock amount across all assets (atomicity across asset threads)\r\n * - Asset amounts released match fund lock amount\r\n * - Satoshi amounts released match fund lock amount\r\n * \r\n * Similar to inflow() but:\r\n * - Uses outflowToken instead of inflowToken\r\n * - Fund tokens INCREASE (locking) instead of DECREASE (releasing)\r\n * - Scans all inputs/outputs for asset amounts (threading tolerance)\r\n * \r\n * Transaction Structure:\r\n * Input[activeInputIndex]: Outflow token (signal: withdrawal occurred)\r\n * Input[activeInputIndex+1]: Fund manager (will receive fund tokens)\r\n * Input[activeInputIndex+2]: Fee contract (proves fees paid)\r\n * Input[activeInputIndex+3]: Asset inputs from all threads\r\n * \r\n * Output[activeInputIndex]: Outflow token (returned to signal processor)\r\n * Output[activeInputIndex+1]: Fund manager (updated fund tokens)\r\n * Output[activeInputIndex+2]: Asset custody outputs (change amounts)\r\n * \r\n * densityPadding: Pad tx size if fund uses many assets (allows flexible transaction building)\r\n */\r\n function outflow(bytes fund, bytes densityPadding) {\r\n // Redeeming funds w/ many assets can trigger computation density limits\r\n // Add padding to reduce tx density\r\n require(densityPadding.length >= 0);\r\n \r\n // Verify this input carries outflow signal token\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == outflowToken);\r\n // Spend signal token back to self\r\n require(tx.inputs[this.activeInputIndex].lockingBytecode == tx.outputs[this.activeInputIndex].lockingBytecode);\r\n // Signal token category preserved (maintains state)\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == tx.outputs[this.activeInputIndex].tokenCategory);\r\n // Signal token NFT commitment must match fund parameters\r\n require(tx.inputs[this.activeInputIndex].nftCommitment == tx.outputs[this.activeInputIndex].nftCommitment);\r\n require(tx.inputs[this.activeInputIndex].nftCommitment == bytes(fundCategory + fundHash));\r\n // Fund parameter hash must match (prevents fund substitution)\r\n require(hash256(fund) == fundHash);\r\n\r\n // Fund manager contract is next input\r\n int fundInputIndex = this.activeInputIndex + 1;\r\n // Verify fund manager contract address\r\n require(tx.inputs[fundInputIndex].lockingBytecode == new LockingBytecodeP2SH32(hash256(0x20 + fundHash + 0x20 + fundCategory + 0x20 + outflowToken + 0x20 + inflowToken + fundContract)));\r\n\r\n // Parse fund parameters\r\n bytes nft_fundCategory, bytes nft_next1 = fund.split(32);\r\n require(nft_fundCategory == fundCategory);\r\n\r\n bytes nft_fundAmount, bytes nft_next2 = nft_next1.split(8);\r\n\r\n int fundAmount = int(nft_fundAmount);\r\n // Calculate locked (collected) fund tokens\r\n // Lock = (output tokens - input tokens) / fundAmount\r\n // Positive when tokens are collected (withdrawal creates fund share)\r\n int fundLockingAmount = tx.outputs[fundInputIndex].tokenAmount - tx.inputs[fundInputIndex].tokenAmount;\r\n require(fundLockingAmount % fundAmount == 0);\r\n fundLockingAmount = fundLockingAmount / fundAmount;\r\n\r\n // Fee contract input must follow fund manager\r\n bytes nft_sats, bytes nft_next3 = nft_next2.split(8);\r\n require(tx.inputs[fundInputIndex + 1].lockingBytecode == new LockingBytecodeP2SH32(fee));\r\n\r\n int fundSats = int(nft_sats);\r\n if(fundSats > 0) {\r\n int satoshiReleaseAmount = 0;\r\n bytes32 satoshiAsset = 0x0000000000000000000000000000000000000000000000000000000000000000;\r\n bytes satoshiLockingBytecode = new LockingBytecodeP2SH32(hash256(0x20 + satoshiAsset + 0x20 + fundHash + 0x20 + outflowToken + assetContract));\r\n\r\n // Scan all inputs for satoshi assets (handles multiple threads)\r\n int fundSatoshiInput = 0;\r\n do {\r\n if(tx.inputs[fundSatoshiInput].lockingBytecode == satoshiLockingBytecode && tx.inputs[fundSatoshiInput].tokenCategory == 0x) {\r\n // Sum up all satoshi inputs from asset custody\r\n satoshiReleaseAmount = satoshiReleaseAmount + tx.inputs[fundSatoshiInput].value;\r\n }\r\n fundSatoshiInput = fundSatoshiInput + 1;\r\n } while(fundSatoshiInput < tx.inputs.length);\r\n\r\n // Scan all outputs for satoshi change (assets returned to custody)\r\n int fundSatoshiOutput = 0;\r\n do {\r\n if(tx.outputs[fundSatoshiOutput].lockingBytecode == satoshiLockingBytecode && tx.outputs[fundSatoshiOutput].tokenCategory == 0x) {\r\n // Subtract any satoshi change (net release calculation)\r\n satoshiReleaseAmount = satoshiReleaseAmount - tx.outputs[fundSatoshiOutput].value;\r\n }\r\n fundSatoshiOutput = fundSatoshiOutput + 1;\r\n } while(fundSatoshiOutput < tx.outputs.length);\r\n\r\n // Net satoshi release must be whole multiple of fundSats\r\n require((satoshiReleaseAmount % fundSats) == 0);\r\n // Net satoshi release must equal fund token lock (atomic consistency)\r\n require((satoshiReleaseAmount / fundSats) == fundLockingAmount);\r\n }\r\n\r\n // Validate all assets\r\n bytes nft_assetData = nft_next3;\r\n while(nft_assetData.length > 0) {\r\n bytes nft_assetCategory, bytes nft_assetNext = nft_assetData.split(32);\r\n // Calculate asset custody contract address\r\n bytes assetLockingBytecode = new LockingBytecodeP2SH32(hash256(0x20 + nft_assetCategory + 0x20 + fundHash + 0x20 + outflowToken + assetContract));\r\n\r\n // Scan all inputs for this asset type (handles multiple threads)\r\n int inputIndex = 0;\r\n int assetReleaseAmount = 0;\r\n do {\r\n if(tx.inputs[inputIndex].lockingBytecode == assetLockingBytecode && tx.inputs[inputIndex].tokenCategory == nft_assetCategory) {\r\n // Sum all asset tokens from this asset custody\r\n assetReleaseAmount = assetReleaseAmount + tx.inputs[inputIndex].tokenAmount;\r\n }\r\n inputIndex = inputIndex + 1;\r\n } while(inputIndex < tx.inputs.length);\r\n\r\n // Scan all outputs for this asset type (change amounts)\r\n int outputIndex = 0;\r\n do {\r\n if(tx.outputs[outputIndex].lockingBytecode == assetLockingBytecode && tx.outputs[outputIndex].tokenCategory == nft_assetCategory) {\r\n // Subtract asset change (net asset release)\r\n assetReleaseAmount = assetReleaseAmount - tx.outputs[outputIndex].tokenAmount;\r\n }\r\n outputIndex = outputIndex + 1;\r\n } while(outputIndex < tx.outputs.length);\r\n\r\n // Parse asset amount divisor\r\n bytes nft_assetAmount, bytes nft_remaining = nft_assetNext.split(8);\r\n int assetAmount = int(nft_assetAmount);\r\n \r\n // Net asset release must be whole multiple of assetAmount\r\n require((assetReleaseAmount % assetAmount) == 0);\r\n // Net asset release must equal fund token lock (maintains atomicity)\r\n require((assetReleaseAmount / assetAmount) == fundLockingAmount);\r\n nft_assetData = nft_remaining;\r\n }\r\n }\r\n}\r\n",
|
|
59
|
+
"debug": {
|
|
60
|
+
"bytecode": "5779009c63c0ce527988c0c7c0cd88c0cec0d188c0cfc0d288c0cf547956797e885879aa557988c08b76c702aa20012058797e01207e57797e01207e56797e01207e557a7e587a7eaa7e01877e88577a01207f7c557a88587f7c815279d05379d3946e7c97009d767b9653798bc702aa20567a7e01877e887b587f7c81547a52937800a063768b7720000000000000000000000000000000000000000000000000000000000000000078cd02aa20012053797e01207e5a797e01207e59797e5b797eaa7e01877e8878cc537997009d78cc5379967656799d6d687b76827700a06300657801207f76587f788157798b56799376cd02aa20012058797e01207e60797e01207e5f797e0111797eaa7e01877e8876d156798876d3527997009d76d3527996765c799d5379597a757c6b7c6b7c6b7c6b7c6b7c6b7c6b7c6c6c6c6c6c6c6c57798b587a757c6b7c6b7c6b7c6b7c6b7c6b7c6c6c6c6c6c6c6d6d6d7578827700a16675686d6d6d6d755167577a519d587a827700a269c0ce537988c0c7c0cd88c0cec0d188c0cfc0d288c0cf547956797e885779aa557988c08b76c702aa20012058797e01207e57797e01207e56797e01207e557a7e587a7eaa7e01877e88567a01207f7c557a88587f7c815279d35379d0946e7c97009d767b967b587f547a8bc702aa20567a7e01877e887c817600a0630020000000000000000000000000000000000000000000000000000000000000000002aa20012052797e01207e59797e01207e58797e5a797eaa7e01877e006576c752798778ce00879a63537978c693547a757c6b7c6b7c6c6c68768b7776c3a266006576cd53798778d100879a63547978cc94557a757c6b7c6b7c6b7c6c6c6c68768b7776c4a2665479567997009d547956799658799d6d6d75687c6576827700a0766b637601207f02aa20012053797e01207e59797e01207e58797e5a797eaa7e01877e00006578c75379875279ce5679879a636e7cd0937768788b7b757c78c3a266006576cd54798778d15779879a636ed3947b757c68768b7776c4a2665479587f788154797897009d547978965c799d785a7a757c6b7c6b7c6b7c6b7c6b7c6b7c6b7c6b7c6c6c6c6c6c6c6c6c6d6d6d6d75686c91666d6d6d755168",
|
|
61
|
+
"sourceMap": "58:4:146:5;;;;;60:26:60:47;:16::62:1;:66::77:0;;:8::79:1;62:26:62:47:0;:16::64:1;:79::100:0;:68::117:1;:8::119;64:26:64:47:0;:16::62:1;:77::98:0;:66::113:1;:8::115;66:26:66:47:0;:16::62:1;:77::98:0;:66::113:1;:8::115;67:26:67:47:0;:16::62:1;:72::84:0;;:87::95;;:72:::1;:8::98;69:24:69:28:0;;:16::29:1;:33::41:0;;:8::43:1;73:29:73:50:0;:::54:1;75:26:75:40:0;:16::57:1;:61::192:0;:95::99;:102::110;;:95:::1;:113::117:0;:95:::1;:120::132:0;;:95:::1;:135::139:0;:95:::1;:142::154:0;;:95:::1;:157::161:0;:95:::1;:164::175:0;;:95:::1;:178::190:0;;:95:::1;:87::191;:61::192;;;:8::194;78:50:78:54:0;;:61::63;:50::64:1;80:16:80:32:0;:36::48;;:8::50:1;83:64:83:65:0;:48::66:1;85:29:85:43:0;:25::44:1;89:43:89:57:0;;:33::70:1;:84::98:0;;:73::111:1;:33;91:16:91:47:0;;::::1;:51::52:0;:8::54:1;93:29:93:47:0;:50::60;:29:::1;96:26:96:40:0;;:::44:1;:16::61;:65::95:0;:91::94;;:65::95:1;;;:8::97;99:42:99:51:0;:58::59;:42::60:1;100:27:100:35:0;:23::36:1;101:33:101:47:0;;:50::51;:33:::1;104:11:104:19:0;:22::23;:11:::1;:25:116:9:0;105:33:105:51;:::55:1;:12::56;107:35:107:101:0;109:31:109:49;:20::66:1;:70::181:0;:104::108;:111::123;;:104:::1;:126::130:0;:104:::1;:133::141:0;;:104:::1;:144::148:0;:104:::1;:151::163:0;;:104:::1;:166::179:0;;:104:::1;:96::180;:70::181;;;:12::183;111:31:111:49:0;:20::56:1;:59::67:0;;:20:::1;:71::72:0;:12::74:1;113:52:113:70:0;:41::77:1;:80::88:0;;:41:::1;115:20:115:42:0;:46::64;;:12::66:1;104:25:116:9;;119:30:119:39:0;120:11:120:24;:::31:1;;:34::35:0;:11:::1;:37:145:9:0;121:29:121:30;123:12:144:46;124:63:124:76;:83::85;:63::86:1;125:61:125:74:0;:81::82;:61::83:1;126:38:126:53:0;:34::54:1;129:39:129:57:0;;:::61:1;:64::74:0;;:39:::1;131:35:131:51:0;:24::68:1;:72::188:0;:106::110;:113::130;;:106:::1;:133::137:0;:106:::1;:140::148:0;;:106:::1;:151::155:0;:106:::1;:158::170:0;;:106:::1;:173::186:0;;:106:::1;:98::187;:72::188;;;:16::190;133:35:133:51:0;:24::66:1;:70::87:0;;:16::89:1;136:35:136:51:0;:24::64:1;:67::78:0;;:24:::1;:82::83:0;:16::85:1;138:54:138:70:0;:43::83:1;:86::97:0;;:43:::1;140:24:140:44:0;:48::66;;:16::68:1;142:32:142:45:0;;:16::46:1;;;;;;;;;;;;;;;;;;;;;;;;;143:29:143:39:0;;:::43:1;:16::44;;;;;;;;;;;;;;;;;;;;;;123:15:144:13;;;;144:20::33:0;:::40:1;;:43::44:0;123:12::46:1;;120:37:145:9;;58:4:146:5;;;;;;;175::285::0;;;;178:16:178:30;;:::37:1;;:41::42:0;:16:::1;:8::44;181:26:181:47:0;:16::62:1;:66::78:0;;:8::80:1;183:26:183:47:0;:16::64:1;:79::100:0;:68::117:1;:8::119;185:26:185:47:0;:16::62:1;:77::98:0;:66::113:1;:8::115;187:26:187:47:0;:16::62:1;:77::98:0;:66::113:1;:8::115;188:26:188:47:0;:16::62:1;:72::84:0;;:87::95;;:72:::1;:8::98;190:24:190:28:0;;:16::29:1;:33::41:0;;:8::43:1;193:29:193:50:0;:::54:1;195:26:195:40:0;:16::57:1;:61::192:0;:95::99;:102::110;;:95:::1;:113::117:0;:95:::1;:120::132:0;;:95:::1;:135::139:0;:95:::1;:142::154:0;;:95:::1;:157::161:0;:95:::1;:164::175:0;;:95:::1;:178::190:0;;:95:::1;:87::191;:61::192;;;:8::194;198:50:198:54:0;;:61::63;:50::64:1;199:16:199:32:0;:36::48;;:8::50:1;201:64:201:65:0;:48::66:1;203:29:203:43:0;:25::44:1;207:43:207:57:0;;:32::70:1;:83::97:0;;:73::110:1;:32;208:16:208:46:0;;::::1;:50::51:0;:8::53:1;209:28:209:45:0;:48::58;:28:::1;212:42:212:51:0;:58::59;:42::60:1;213:26:213:40:0;;:::44:1;:16::61;:65::95:0;:91::94;;:65::95:1;;;:8::97;215:27:215:35:0;:23::36:1;216:11:216:19:0;:22::23;:11:::1;:25:245:9:0;217:39:217:40;218:35:218:101;219:43:219:154;:77::81;:84::96;;:77:::1;:99::103:0;:77:::1;:106::114:0;;:77:::1;:117::121:0;:77:::1;:124::136:0;;:77:::1;:139::152:0;;:77:::1;:69::153;:43::154;;;222:35:222:36:0;223:12:229:57;224:29:224:45;:19::62:1;:66::88:0;;:19:::1;:102::118:0;:92::133:1;:137::139:0;:92:::1;:19;:141:227:17:0;226:43:226:63;;:76::92;:66::99:1;:43;:20::100;;;;;;;;;;224:141:227:17;228:35:228:51:0;:::55:1;:16::56;229:20:229:36:0;:39::55;223:12::57:1;;232:36:232:37:0;233:12:239:59;234:30:234:47;:19::64:1;:68::90:0;;:19:::1;:105::122:0;:94::137:1;:141::143:0;:94:::1;:19;:145:237:17:0;236:43:236:63;;:77::94;:66::101:1;:43;:20::102;;;;;;;;;;;;;234:145:237:17;238:36:238:53:0;:::57:1;:16::58;239:20:239:37:0;:40::57;233:12::59:1;;242:21:242:41:0;;:44::52;;:21:::1;:57::58:0;:12::60:1;244:21:244:41:0;;:44::52;;:21:::1;:57::74:0;;:12::76:1;216:25:245:9;;;;248:30:248:39:0;249:8:284:9;:14:249:27;:::34:1;;:37::38:0;:14:::1;;;:40:284:9:0;250:59:250:72;:79::81;:59::82:1;252:41:252:157:0;:75::79;:82::99;;:75:::1;:102::106:0;:75:::1;:109::117:0;;:75:::1;:120::124:0;:75:::1;:127::139:0;;:75:::1;:142::155:0;;:75:::1;:67::156;:41::157;;;255:29:255:30:0;256:37:256:38;257:12:263:51;258:29:258:39;:19::56:1;:60::80:0;;:19:::1;:94::104:0;;:84::119:1;:123::140:0;;:84:::1;:19;:142:261:17:0;260:41:260:82;;:62::95:1;:41;:20::96;258:142:261:17;262:29:262:39:0;:::43:1;:16::44;;;263:20:263:30:0;:33::49;257:12::51:1;;266:30:266:31:0;267:12:273:53;268:30:268:41;:19::58:1;:62::82:0;;:19:::1;:97::108:0;:86::123:1;:127::144:0;;:86:::1;:19;:146:271:17:0;270:41:270:84;:62::97:1;:41;:20::98;;;268:146:271:17;272:30:272:41:0;:::45:1;:16::46;273:20:273:31:0;:34::51;267:12::53:1;;276:57:276:70:0;;:77::78;:57::79:1;277:34:277:49:0;:30::50:1;280:21:280:39:0;;:42::53;:21:::1;:58::59:0;:12::61:1;282:21:282:39:0;;:42::53;:21:::1;:58::75:0;;:12::77:1;283:28:283:41:0;:12::42:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;249:40:284:9;;;;;;;:8;;175:4:285:5;;;;;32:0:286:1",
|
|
62
|
+
"logs": [],
|
|
63
|
+
"requires": [
|
|
64
|
+
{
|
|
65
|
+
"ip": 16,
|
|
66
|
+
"line": 60
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"ip": 21,
|
|
70
|
+
"line": 62
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"ip": 26,
|
|
74
|
+
"line": 64
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"ip": 31,
|
|
78
|
+
"line": 66
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"ip": 39,
|
|
82
|
+
"line": 67
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"ip": 45,
|
|
86
|
+
"line": 69
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"ip": 77,
|
|
90
|
+
"line": 75
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"ip": 85,
|
|
94
|
+
"line": 80
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"ip": 101,
|
|
98
|
+
"line": 91
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"ip": 115,
|
|
102
|
+
"line": 96
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"ip": 157,
|
|
106
|
+
"line": 109
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"ip": 164,
|
|
110
|
+
"line": 111
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"ip": 173,
|
|
114
|
+
"line": 115
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"ip": 223,
|
|
118
|
+
"line": 131
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"ip": 228,
|
|
122
|
+
"line": 133
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"ip": 235,
|
|
126
|
+
"line": 136
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"ip": 244,
|
|
130
|
+
"line": 140
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"ip": 326,
|
|
134
|
+
"line": 178
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"ip": 331,
|
|
138
|
+
"line": 181
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"ip": 336,
|
|
142
|
+
"line": 183
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"ip": 341,
|
|
146
|
+
"line": 185
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"ip": 346,
|
|
150
|
+
"line": 187
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"ip": 354,
|
|
154
|
+
"line": 188
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"ip": 360,
|
|
158
|
+
"line": 190
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"ip": 392,
|
|
162
|
+
"line": 195
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"ip": 400,
|
|
166
|
+
"line": 199
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"ip": 416,
|
|
170
|
+
"line": 208
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"ip": 433,
|
|
174
|
+
"line": 213
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"ip": 545,
|
|
178
|
+
"line": 242
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"ip": 553,
|
|
182
|
+
"line": 244
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"ip": 663,
|
|
186
|
+
"line": 280
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"ip": 670,
|
|
190
|
+
"line": 282
|
|
191
|
+
}
|
|
192
|
+
]
|
|
193
|
+
},
|
|
194
|
+
"compiler": {
|
|
195
|
+
"name": "cashc",
|
|
196
|
+
"version": "0.13.0-next.6",
|
|
197
|
+
"options": {
|
|
198
|
+
"enforceFunctionParameterTypes": true
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"updatedAt": "2026-04-21T19:21:03.764Z"
|
|
202
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractName": "FundInflowMint",
|
|
3
|
+
"constructorInputs": [
|
|
4
|
+
{
|
|
5
|
+
"name": "validator",
|
|
6
|
+
"type": "bytes32"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"name": "inflowToken",
|
|
10
|
+
"type": "bytes32"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "outflowToken",
|
|
14
|
+
"type": "bytes32"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "fee",
|
|
18
|
+
"type": "bytes32"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "managerContract",
|
|
22
|
+
"type": "bytes"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "fundContract",
|
|
26
|
+
"type": "bytes"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "assetContract",
|
|
30
|
+
"type": "bytes"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"abi": [
|
|
34
|
+
{
|
|
35
|
+
"name": "mint",
|
|
36
|
+
"inputs": []
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"bytecode": "OP_INPUTINDEX OP_1SUB OP_UTXOBYTECODE aa20 OP_ROT OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOBYTECODE OP_INPUTINDEX OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_OVER OP_2 OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_INPUTINDEX OP_OUTPUTTOKENCATEGORY OP_EQUALVERIFY OP_INPUTINDEX OP_1ADD OP_UTXOTOKENCATEGORY OP_2 OP_PICK OP_2 OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_4 OP_ADD OP_OUTPUTTOKENCOMMITMENT 20 OP_SPLIT OP_0 OP_DUP OP_9 OP_ROLL OP_SIZE OP_NIP OP_ADD OP_2 OP_ADD OP_ACTIVEBYTECODE OP_OVER OP_SPLIT OP_DROP OP_ROT OP_SPLIT OP_NIP OP_SWAP OP_DUP OP_9 OP_ROLL OP_SIZE OP_NIP OP_ADD OP_2 OP_ADD OP_ACTIVEBYTECODE OP_SWAP OP_SPLIT OP_DROP OP_SWAP OP_SPLIT OP_NIP OP_INPUTINDEX OP_4 OP_ADD OP_OUTPUTBYTECODE aa20 OP_2SWAP OP_CAT 20 OP_CAT OP_3 OP_ROLL OP_CAT 20 OP_CAT OP_3 OP_ROLL OP_CAT 20 OP_CAT OP_4 OP_ROLL OP_CAT 20 OP_CAT OP_3 OP_PICK OP_CAT 20 OP_CAT OP_4 OP_ROLL OP_CAT OP_4 OP_ROLL OP_CAT OP_HASH256 OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_4 OP_ADD OP_OUTPUTTOKENCATEGORY OP_EQUAL",
|
|
40
|
+
"source": "pragma cashscript ~0.13.0;\r\n\r\n/**\r\n * FundMint: Creates per-fund contract instances via bytecode extraction and hashing\r\n * \r\n * Mints both inflow and outflow tokens with carefully calculated contract addresses.\r\n * Each fund gets unique Asset and Fund manager contract instances derived from:\r\n * - Fund category and hash (fund identity)\r\n * - Inflow/outflow token categories\r\n * - Fee contract hash\r\n * - Manager contract bytecode\r\n * - Asset and Fund contract templates (extracted from activation bytecode)\r\n * \r\n * Contract structure in activation bytecode:\r\n * [assetContract bytes (push bytecode) | fundContract bytes (push bytecode)]\r\n * Push bytecodes include the CashScript push opcode (overhead ~2 bytes for >75 bytes)\r\n * \r\n * Parameters (all provided to FundMint at creation):\r\n * validator: Validator contract hash (initial authorizer)\r\n * inflowToken: Inflow token category (minting capability)\r\n * outflowToken: Outflow token category (minting capability)\r\n * fee: Fee contract hash\r\n * managerContract: TransactionManager bytecode template\r\n * fundContract: Fund contract bytecode template\r\n * assetContract: Asset contract bytecode template\r\n */\r\ncontract FundInflowMint(bytes32 validator, bytes32 inflowToken, bytes32 outflowToken, bytes32 fee, bytes managerContract, bytes fundContract, bytes assetContract)\r\n{\r\n /**\r\n * mintInflow(): Create Asset contract instance for inflow operations\r\n * \r\n * Mints inflow token to newly calculated Asset contract address.\r\n * This asset manager controls fund deposits and token releases.\r\n * \r\n * Validates:\r\n * - Validator input precedes this mint\r\n * - This FundMint UTXO returns to itself with minting token\r\n * - Outflow token input present with minting capability\r\n * - Both inputs from same contract (prevents cross-fund confusion)\r\n * - Output receives correct Asset contract address and inflow token\r\n * \r\n * Contract calculation by hashing:\r\n * hash256(assetContractParam + fundContractParam + fundHash + fundCategory + \r\n * outflowToken + inflowToken + fee + managerContract)\r\n * \r\n * This ensures Asset contract is unique per fund and cannot be reused.\r\n */\r\n function mint() {\r\n // Validator must immediately precede this mint (sequence control)\r\n require(tx.inputs[this.activeInputIndex - 1].lockingBytecode == new LockingBytecodeP2SH32(validator));\r\n\r\n // This FundMint UTXO returns to itself (self-contained minting)\r\n require(tx.inputs[this.activeInputIndex].lockingBytecode == tx.outputs[this.activeInputIndex].lockingBytecode);\r\n // Must have inflow token with minting capability (0x02 flag)\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == (inflowToken + 0x02));\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == tx.outputs[this.activeInputIndex].tokenCategory);\r\n\r\n // Outflow token input must be present with minting capability\r\n require(tx.inputs[this.activeInputIndex + 1].tokenCategory == (outflowToken + 0x02));\r\n // Both tokens must come from same FundMint instance\r\n // require(tx.inputs[this.activeInputIndex + 1].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);\r\n\r\n // Extract fund parameters from output NFT commitment\r\n bytes fundCategory, bytes fundHash = tx.outputs[this.activeInputIndex + 4].nftCommitment.split(32);\r\n\r\n // Extract asset contract bytecode from this contract's activation bytecode\r\n // Push opcodes add ~2 bytes of overhead for >75 byte push\r\n int assetContractStart = 0;\r\n int assetContractStop = assetContractStart + assetContract.length + 2;\r\n bytes assetContractParam = this.activeBytecode.slice(assetContractStart, assetContractStop);\r\n\r\n // Extract fund contract bytecode from this contract's activation bytecode\r\n // Positioned immediately after asset contract\r\n int fundContractStart = assetContractStop;\r\n int fundContractStop = fundContractStart + fundContract.length + 2;\r\n bytes fundContractParam = this.activeBytecode.slice(fundContractStart, fundContractStop);\r\n\r\n // Compute Asset contract address by hashing:\r\n // [asset_bytecode | fund_bytecode | fundHash | fundCategory | outflows | inflows | fees | manager_bytecode]\r\n // This calculation must match the per-fund Asset instance created elsewhere\r\n require(tx.outputs[this.activeInputIndex + 4].lockingBytecode == new LockingBytecodeP2SH32(hash256(assetContractParam + fundContractParam + 0x20 + fundHash + 0x20 + fundCategory + 0x20 + outflowToken + 0x20 + inflowToken + 0x20 + fee + managerContract)));\r\n // Asset receives inflow token to control inflow operations\r\n require(tx.outputs[this.activeInputIndex + 4].tokenCategory == inflowToken);\r\n }\r\n}",
|
|
41
|
+
"debug": {
|
|
42
|
+
"bytecode": "c08cc702aa207b7e01877e88c0c7c0cd88c0ce78527e88c0cec0d188c08bce5279527e88c05493d201207f0076597a8277935293c1787f757b7f777c76597a8277935293c17c7f757c7f77c05493cd02aa20727e01207e537a7e01207e537a7e01207e547a7e01207e53797e01207e547a7e547a7eaa7e01877e88c05493d187",
|
|
43
|
+
"sourceMap": "50:26:50:47;:::51:1;:16::68;:72::108:0;:98::107;:72::108:1;;;:8::110;53:26:53:47:0;:16::64:1;:79::100:0;:68::117:1;:8::119;55:26:55:47:0;:16::62:1;:67::78:0;:81::85;:67:::1;:8::88;56:26:56:47:0;:16::62:1;:77::98:0;:66::113:1;:8::115;59:26:59:47:0;:::51:1;:16::66;:71::83:0;;:86::90;:71:::1;:8::93;64:56:64:77:0;:80::81;:56:::1;:45::96;:103::105:0;:45::106:1;68:33:68:34:0;69:32:69:50;:53::66;;:::73:1;;:32;:76::77:0;:32:::1;70:35:70:54:0;:81::98;:35::99:1;;:61::79:0;:35::99:1;;74:32:74:49:0;75:31:75:48;:51::63;;:::70:1;;:31;:73::74:0;:31:::1;76:34:76:53:0;:79::95;:34::96:1;;:60::77:0;:34::96:1;;81:27:81:48:0;:51::52;:27:::1;:16::69;:73::261:0;:107::145;::::1;:148::152:0;:107:::1;:155::163:0;;:107:::1;:166::170:0;:107:::1;:173::185:0;;:107:::1;:188::192:0;:107:::1;:195::207:0;;:107:::1;:210::214:0;:107:::1;:217::228:0;;:107:::1;:231::235:0;:107:::1;:238::241:0;;:107:::1;:244::259:0;;:107:::1;:99::260;:73::261;;;:8::263;83:27:83:48:0;:51::52;:27:::1;:16::67;:8::84",
|
|
44
|
+
"logs": [],
|
|
45
|
+
"requires": [
|
|
46
|
+
{
|
|
47
|
+
"ip": 15,
|
|
48
|
+
"line": 50
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"ip": 20,
|
|
52
|
+
"line": 53
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"ip": 26,
|
|
56
|
+
"line": 55
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"ip": 31,
|
|
60
|
+
"line": 56
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"ip": 39,
|
|
64
|
+
"line": 59
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"ip": 117,
|
|
68
|
+
"line": 81
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"ip": 123,
|
|
72
|
+
"line": 83
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"compiler": {
|
|
77
|
+
"name": "cashc",
|
|
78
|
+
"version": "0.13.0-next.6",
|
|
79
|
+
"options": {
|
|
80
|
+
"enforceFunctionParameterTypes": true
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"updatedAt": "2026-04-21T19:21:05.475Z"
|
|
84
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contractName": "FundOutflowMint",
|
|
3
|
+
"constructorInputs": [
|
|
4
|
+
{
|
|
5
|
+
"name": "validator",
|
|
6
|
+
"type": "bytes32"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"name": "inflowToken",
|
|
10
|
+
"type": "bytes32"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"name": "outflowToken",
|
|
14
|
+
"type": "bytes32"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "fee",
|
|
18
|
+
"type": "bytes32"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"name": "managerContract",
|
|
22
|
+
"type": "bytes"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "fundContract",
|
|
26
|
+
"type": "bytes"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "assetContract",
|
|
30
|
+
"type": "bytes"
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"abi": [
|
|
34
|
+
{
|
|
35
|
+
"name": "mint",
|
|
36
|
+
"inputs": []
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"bytecode": "OP_INPUTINDEX OP_2 OP_SUB OP_UTXOBYTECODE aa20 OP_ROT OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_1SUB OP_UTXOTOKENCATEGORY OP_OVER OP_2 OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_2 OP_PICK OP_2 OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOBYTECODE OP_INPUTINDEX OP_OUTPUTBYTECODE OP_EQUALVERIFY OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_INPUTINDEX OP_OUTPUTTOKENCATEGORY OP_EQUALVERIFY OP_INPUTINDEX OP_4 OP_ADD OP_OUTPUTTOKENCOMMITMENT 20 OP_SPLIT OP_0 OP_DUP OP_9 OP_ROLL OP_SIZE OP_NIP OP_ADD OP_2 OP_ADD OP_ACTIVEBYTECODE OP_OVER OP_SPLIT OP_DROP OP_ROT OP_SPLIT OP_NIP OP_SWAP OP_DUP OP_9 OP_ROLL OP_SIZE OP_NIP OP_ADD OP_2 OP_ADD OP_ACTIVEBYTECODE OP_SWAP OP_SPLIT OP_DROP OP_SWAP OP_SPLIT OP_NIP OP_INPUTINDEX OP_4 OP_ADD OP_OUTPUTBYTECODE aa20 OP_2SWAP OP_CAT 20 OP_CAT OP_3 OP_ROLL OP_CAT 20 OP_CAT OP_3 OP_ROLL OP_CAT 20 OP_CAT OP_4 OP_PICK OP_CAT 20 OP_CAT OP_3 OP_ROLL OP_CAT 20 OP_CAT OP_4 OP_ROLL OP_CAT OP_4 OP_ROLL OP_CAT OP_HASH256 OP_CAT 87 OP_CAT OP_EQUALVERIFY OP_INPUTINDEX OP_4 OP_ADD OP_OUTPUTTOKENCATEGORY OP_EQUAL",
|
|
40
|
+
"source": "pragma cashscript ~0.13.0;\r\n\r\n/**\r\n * FundMint: Creates per-fund contract instances via bytecode extraction and hashing\r\n * \r\n * Mints both inflow and outflow tokens with carefully calculated contract addresses.\r\n * Each fund gets unique Asset and Fund manager contract instances derived from:\r\n * - Fund category and hash (fund identity)\r\n * - Inflow/outflow token categories\r\n * - Fee contract hash\r\n * - Manager contract bytecode\r\n * - Asset and Fund contract templates (extracted from activation bytecode)\r\n * \r\n * Contract structure in activation bytecode:\r\n * [assetContract bytes (push bytecode) | fundContract bytes (push bytecode)]\r\n * Push bytecodes include the CashScript push opcode (overhead ~2 bytes for >75 bytes)\r\n * \r\n * Parameters (all provided to FundMint at creation):\r\n * validator: Validator contract hash (initial authorizer)\r\n * inflowToken: Inflow token category (minting capability)\r\n * outflowToken: Outflow token category (minting capability)\r\n * fee: Fee contract hash\r\n * managerContract: TransactionManager bytecode template\r\n * fundContract: Fund contract bytecode template\r\n * assetContract: Asset contract bytecode template\r\n */\r\ncontract FundOutflowMint(bytes32 validator, bytes32 inflowToken, bytes32 outflowToken, bytes32 fee, bytes managerContract, bytes fundContract, bytes assetContract)\r\n{\r\n /**\r\n * mintOutflow(): Create Fund contract instance for fund account management\r\n * \r\n * Mints outflow token to newly calculated Fund contract address.\r\n * This fund manager controls token accounting and redemption.\r\n * \r\n * Validates:\r\n * - Validator input 2 positions before this mint (sequence control)\r\n * - Inflow token input immediately before this mint with minting capability\r\n * - This FundMint UTXO holds outflow token with minting capability\r\n * - This UTXO returns to itself\r\n * - Output receives correct Fund contract address and outflow token\r\n * \r\n * Contract calculation uses same formula as mintInflow but different output token.\r\n * Fund contract is unique per fund and handles token accounting.\r\n */\r\n function mint() {\r\n // Validator must be 2 positions before this mint (part of sequence)\r\n require(tx.inputs[this.activeInputIndex - 2].lockingBytecode == new LockingBytecodeP2SH32(validator));\r\n\r\n // Inflow token input must be immediately before (handles sequencing)\r\n require(tx.inputs[this.activeInputIndex - 1].tokenCategory == (inflowToken + 0x02));\r\n // Inflow input must also be same FundMint instance\r\n // require(tx.inputs[this.activeInputIndex - 1].lockingBytecode == tx.inputs[this.activeInputIndex].lockingBytecode);\r\n\r\n // This FundMint holds outflow token with minting capability\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == outflowToken + 0x02);\r\n\r\n // This FundMint returns to itself\r\n require(tx.inputs[this.activeInputIndex].lockingBytecode == tx.outputs[this.activeInputIndex].lockingBytecode);\r\n require(tx.inputs[this.activeInputIndex].tokenCategory == tx.outputs[this.activeInputIndex].tokenCategory);\r\n\r\n // Extract fund parameters from output NFT commitment\r\n bytes fundCategory, bytes fundHash = tx.outputs[this.activeInputIndex + 4].nftCommitment.split(32);\r\n \r\n // Extract asset contract bytecode from activation bytecode\r\n int assetContractStart = 0;\r\n int assetContractStop = assetContractStart + assetContract.length + 2;\r\n bytes assetContractParam = this.activeBytecode.slice(assetContractStart, assetContractStop);\r\n\r\n // Extract fund contract bytecode from activation bytecode\r\n int fundContractStart = assetContractStop;\r\n int fundContractStop = fundContractStart + fundContract.length + 2;\r\n bytes fundContractParam = this.activeBytecode.slice(fundContractStart, fundContractStop);\r\n\r\n // Compute Fund contract address using same hash as Asset contract\r\n // This will differ only in the output token category\r\n require(tx.outputs[this.activeInputIndex + 4].lockingBytecode == new LockingBytecodeP2SH32(hash256(assetContractParam + fundContractParam + 0x20 + fundHash + 0x20 + fundCategory + 0x20 + outflowToken + 0x20 + inflowToken + 0x20 + fee + managerContract)));\r\n // Fund receives outflow token to control outflow (redemption) operations\r\n require(tx.outputs[this.activeInputIndex + 4].tokenCategory == outflowToken);\r\n }\r\n}",
|
|
41
|
+
"debug": {
|
|
42
|
+
"bytecode": "c05294c702aa207b7e01877e88c08cce78527e88c0ce5279527e88c0c7c0cd88c0cec0d188c05493d201207f0076597a8277935293c1787f757b7f777c76597a8277935293c17c7f757c7f77c05493cd02aa20727e01207e537a7e01207e537a7e01207e54797e01207e537a7e01207e547a7e547a7eaa7e01877e88c05493d187",
|
|
43
|
+
"sourceMap": "47:26:47:47;:50::51;:26:::1;:16::68;:72::108:0;:98::107;:72::108:1;;;:8::110;50:26:50:47:0;:::51:1;:16::66;:71::82:0;:85::89;:71:::1;:8::92;55:26:55:47:0;:16::62:1;:66::78:0;;:81::85;:66:::1;:8::87;58:26:58:47:0;:16::64:1;:79::100:0;:68::117:1;:8::119;59:26:59:47:0;:16::62:1;:77::98:0;:66::113:1;:8::115;62:56:62:77:0;:80::81;:56:::1;:45::96;:103::105:0;:45::106:1;65:33:65:34:0;66:32:66:50;:53::66;;:::73:1;;:32;:76::77:0;:32:::1;67:35:67:54:0;:81::98;:35::99:1;;:61::79:0;:35::99:1;;70:32:70:49:0;71:31:71:48;:51::63;;:::70:1;;:31;:73::74:0;:31:::1;72:34:72:53:0;:79::95;:34::96:1;;:60::77:0;:34::96:1;;76:27:76:48:0;:51::52;:27:::1;:16::69;:73::261:0;:107::145;::::1;:148::152:0;:107:::1;:155::163:0;;:107:::1;:166::170:0;:107:::1;:173::185:0;;:107:::1;:188::192:0;:107:::1;:195::207:0;;:107:::1;:210::214:0;:107:::1;:217::228:0;;:107:::1;:231::235:0;:107:::1;:238::241:0;;:107:::1;:244::259:0;;:107:::1;:99::260;:73::261;;;:8::263;78:27:78:48:0;:51::52;:27:::1;:16::67;:8::85",
|
|
44
|
+
"logs": [],
|
|
45
|
+
"requires": [
|
|
46
|
+
{
|
|
47
|
+
"ip": 16,
|
|
48
|
+
"line": 47
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"ip": 23,
|
|
52
|
+
"line": 50
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"ip": 30,
|
|
56
|
+
"line": 55
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"ip": 35,
|
|
60
|
+
"line": 58
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"ip": 40,
|
|
64
|
+
"line": 59
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"ip": 118,
|
|
68
|
+
"line": 76
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"ip": 124,
|
|
72
|
+
"line": 78
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"compiler": {
|
|
77
|
+
"name": "cashc",
|
|
78
|
+
"version": "0.13.0-next.6",
|
|
79
|
+
"options": {
|
|
80
|
+
"enforceFunctionParameterTypes": true
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"updatedAt": "2026-04-21T19:21:05.726Z"
|
|
84
|
+
}
|