@secondlayer/stacks 6.1.0 → 6.1.2
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/dist/shared/stacks-esm-0pc6tmf0.js +50 -0
- package/dist/shared/{stacks-esm-743jfh10.js.map → stacks-esm-0pc6tmf0.js.map} +2 -2
- package/dist/shared/{stacks-esm-0rdxcta7.js → stacks-esm-16d82wyc.js} +10 -10
- package/dist/shared/{stacks-esm-0rdxcta7.js.map → stacks-esm-16d82wyc.js.map} +2 -2
- package/dist/shared/{stacks-esm-cvhazvhd.js → stacks-esm-7a0ehykf.js} +43 -43
- package/dist/shared/{stacks-esm-cvhazvhd.js.map → stacks-esm-7a0ehykf.js.map} +2 -2
- package/dist/shared/{stacks-esm-1jae0a3r.js → stacks-esm-7v18h5dk.js} +4 -4
- package/dist/shared/{stacks-esm-1jae0a3r.js.map → stacks-esm-7v18h5dk.js.map} +2 -2
- package/dist/shared/{stacks-esm-9rnx0zxr.js → stacks-esm-8f5catbf.js} +126 -126
- package/dist/shared/{stacks-esm-9rnx0zxr.js.map → stacks-esm-8f5catbf.js.map} +2 -2
- package/dist/shared/{stacks-esm-7fpqgtyx.js → stacks-esm-8jt6k8p3.js} +13 -13
- package/dist/shared/{stacks-esm-7fpqgtyx.js.map → stacks-esm-8jt6k8p3.js.map} +2 -2
- package/dist/shared/{stacks-esm-hr7fpxtj.js → stacks-esm-a20wyky3.js} +92 -92
- package/dist/shared/{stacks-esm-hr7fpxtj.js.map → stacks-esm-a20wyky3.js.map} +2 -2
- package/dist/shared/{stacks-esm-3pv5avgr.js → stacks-esm-b54n1jdx.js} +54 -54
- package/dist/shared/{stacks-esm-3pv5avgr.js.map → stacks-esm-b54n1jdx.js.map} +2 -2
- package/dist/shared/{stacks-esm-r9q4wnyw.js → stacks-esm-cmtj5vky.js} +162 -162
- package/dist/shared/{stacks-esm-r9q4wnyw.js.map → stacks-esm-cmtj5vky.js.map} +2 -2
- package/dist/shared/{stacks-esm-wv67m4g6.js → stacks-esm-e2qhfgke.js} +36 -36
- package/dist/shared/{stacks-esm-wv67m4g6.js.map → stacks-esm-e2qhfgke.js.map} +2 -2
- package/dist/shared/{stacks-esm-qk0p9fr6.js → stacks-esm-ea4m4bk7.js} +117 -117
- package/dist/shared/{stacks-esm-qk0p9fr6.js.map → stacks-esm-ea4m4bk7.js.map} +2 -2
- package/dist/shared/{stacks-esm-fcfdn2zx.js → stacks-esm-hkw1kvd4.js} +140 -140
- package/dist/shared/{stacks-esm-fcfdn2zx.js.map → stacks-esm-hkw1kvd4.js.map} +2 -2
- package/dist/shared/{stacks-esm-qkj67g80.js → stacks-esm-k108pemv.js} +4 -4
- package/dist/shared/{stacks-esm-qkj67g80.js.map → stacks-esm-k108pemv.js.map} +2 -2
- package/dist/shared/stacks-esm-kbz5s6v8.js +84 -0
- package/dist/shared/{stacks-esm-2mc7ebrm.js.map → stacks-esm-kbz5s6v8.js.map} +2 -2
- package/dist/shared/{stacks-esm-n53kvwmt.js → stacks-esm-mt1thm7k.js} +9 -9
- package/dist/shared/{stacks-esm-n53kvwmt.js.map → stacks-esm-mt1thm7k.js.map} +2 -2
- package/dist/shared/{stacks-esm-v45990hx.js → stacks-esm-n1mekwnb.js} +9 -9
- package/dist/shared/{stacks-esm-v45990hx.js.map → stacks-esm-n1mekwnb.js.map} +2 -2
- package/dist/shared/{stacks-esm-r6dejrgr.js → stacks-esm-nt5hf8ht.js} +34 -34
- package/dist/shared/{stacks-esm-r6dejrgr.js.map → stacks-esm-nt5hf8ht.js.map} +2 -2
- package/dist/shared/{stacks-esm-skmcf5n2.js → stacks-esm-phgy8yqf.js} +210 -210
- package/dist/shared/{stacks-esm-skmcf5n2.js.map → stacks-esm-phgy8yqf.js.map} +2 -2
- package/dist/shared/{stacks-esm-kds4n82p.js → stacks-esm-pxv6ny92.js} +116 -116
- package/dist/shared/{stacks-esm-kds4n82p.js.map → stacks-esm-pxv6ny92.js.map} +2 -2
- package/dist/shared/{stacks-esm-3g33bqsm.js → stacks-esm-qfzxhdqz.js} +19 -19
- package/dist/shared/{stacks-esm-3g33bqsm.js.map → stacks-esm-qfzxhdqz.js.map} +2 -2
- package/dist/shared/{stacks-esm-aw2mj3sj.js → stacks-esm-snj9s2q8.js} +43 -43
- package/dist/shared/{stacks-esm-aw2mj3sj.js.map → stacks-esm-snj9s2q8.js.map} +2 -2
- package/dist/shared/{stacks-esm-q19a17fd.js → stacks-esm-ss9ap75h.js} +28 -28
- package/dist/shared/{stacks-esm-q19a17fd.js.map → stacks-esm-ss9ap75h.js.map} +2 -2
- package/dist/shared/{stacks-esm-x1r01353.js → stacks-esm-t88hc019.js} +18 -18
- package/dist/shared/{stacks-esm-x1r01353.js.map → stacks-esm-t88hc019.js.map} +2 -2
- package/dist/shared/stacks-esm-tdrdye4y.js +48 -0
- package/dist/shared/{stacks-esm-pxhfqfff.js.map → stacks-esm-tdrdye4y.js.map} +2 -2
- package/dist/src/accounts/index.cjs +15 -13
- package/dist/src/accounts/index.cjs.map +2 -2
- package/dist/src/accounts/index.d.cts +1 -1
- package/dist/src/accounts/index.d.ts +1 -1
- package/dist/src/accounts/index.js +26 -26
- package/dist/src/accounts/index.js.map +2 -2
- package/dist/src/actions/index.cjs +83 -81
- package/dist/src/actions/index.cjs.map +2 -2
- package/dist/src/actions/index.d.cts +1 -1
- package/dist/src/actions/index.d.ts +1 -1
- package/dist/src/actions/index.js +102 -103
- package/dist/src/actions/index.js.map +1 -1
- package/dist/src/bitcoin/index.cjs +2035 -2036
- package/dist/src/bitcoin/index.cjs.map +8 -8
- package/dist/src/bitcoin/index.d.cts +92 -92
- package/dist/src/bitcoin/index.d.ts +92 -92
- package/dist/src/bitcoin/index.js +88 -90
- package/dist/src/bitcoin/index.js.map +2 -2
- package/dist/src/bns/index.cjs +3313 -3310
- package/dist/src/bns/index.cjs.map +13 -13
- package/dist/src/bns/index.d.cts +1 -1
- package/dist/src/bns/index.d.ts +1 -1
- package/dist/src/bns/index.js +39 -41
- package/dist/src/bns/index.js.map +2 -2
- package/dist/src/chains/index.cjs +14 -12
- package/dist/src/chains/index.cjs.map +2 -2
- package/dist/src/chains/index.d.cts +1 -1
- package/dist/src/chains/index.d.ts +1 -1
- package/dist/src/chains/index.js +12 -12
- package/dist/src/chains/index.js.map +1 -1
- package/dist/src/clarity/index.cjs +98 -96
- package/dist/src/clarity/index.cjs.map +2 -2
- package/dist/src/clarity/index.d.cts +1 -1
- package/dist/src/clarity/index.d.ts +1 -1
- package/dist/src/clarity/index.js +170 -171
- package/dist/src/clarity/index.js.map +1 -1
- package/dist/src/connect/index.cjs +27 -20
- package/dist/src/connect/index.cjs.map +3 -3
- package/dist/src/connect/index.d.cts +1 -1
- package/dist/src/connect/index.d.ts +1 -1
- package/dist/src/connect/index.js +27 -20
- package/dist/src/connect/index.js.map +3 -3
- package/dist/src/connect/walletconnect/index.cjs +6 -46
- package/dist/src/connect/walletconnect/index.cjs.map +3 -4
- package/dist/src/connect/walletconnect/index.d.cts +1 -1
- package/dist/src/connect/walletconnect/index.d.ts +1 -1
- package/dist/src/connect/walletconnect/index.js +6 -46
- package/dist/src/connect/walletconnect/index.js.map +3 -4
- package/dist/src/filters/index.cjs +22 -20
- package/dist/src/filters/index.cjs.map +2 -2
- package/dist/src/filters/index.d.cts +1 -1
- package/dist/src/filters/index.d.ts +1 -1
- package/dist/src/filters/index.js +30 -30
- package/dist/src/filters/index.js.map +1 -1
- package/dist/src/index.cjs +1411 -1410
- package/dist/src/index.cjs.map +11 -11
- package/dist/src/index.d.cts +724 -724
- package/dist/src/index.d.ts +724 -724
- package/dist/src/index.js +219 -219
- package/dist/src/index.js.map +2 -2
- package/dist/src/postconditions/index.cjs +26 -24
- package/dist/src/postconditions/index.cjs.map +2 -2
- package/dist/src/postconditions/index.d.cts +1 -1
- package/dist/src/postconditions/index.d.ts +1 -1
- package/dist/src/postconditions/index.js +16 -17
- package/dist/src/postconditions/index.js.map +1 -1
- package/dist/src/pox/index.cjs +722 -721
- package/dist/src/pox/index.cjs.map +9 -9
- package/dist/src/pox/index.d.cts +1 -1
- package/dist/src/pox/index.d.ts +1 -1
- package/dist/src/pox/index.js +40 -41
- package/dist/src/pox/index.js.map +2 -2
- package/dist/src/pox5/index.cjs +141 -137
- package/dist/src/pox5/index.cjs.map +3 -3
- package/dist/src/pox5/index.d.cts +9 -1
- package/dist/src/pox5/index.d.ts +9 -1
- package/dist/src/pox5/index.js +210 -209
- package/dist/src/pox5/index.js.map +3 -3
- package/dist/src/sbtc/index.cjs +71 -69
- package/dist/src/sbtc/index.cjs.map +2 -2
- package/dist/src/sbtc/index.d.cts +1 -1
- package/dist/src/sbtc/index.d.ts +1 -1
- package/dist/src/sbtc/index.js +39 -40
- package/dist/src/sbtc/index.js.map +2 -2
- package/dist/src/simnet/index.cjs +16 -16
- package/dist/src/simnet/index.cjs.map +2 -2
- package/dist/src/simnet/index.d.cts +1 -1
- package/dist/src/simnet/index.d.ts +1 -1
- package/dist/src/simnet/index.js +16 -16
- package/dist/src/simnet/index.js.map +2 -2
- package/dist/src/stackingdao/index.cjs +716 -715
- package/dist/src/stackingdao/index.cjs.map +9 -9
- package/dist/src/stackingdao/index.d.cts +1 -1
- package/dist/src/stackingdao/index.d.ts +1 -1
- package/dist/src/stackingdao/index.js +26 -27
- package/dist/src/stackingdao/index.js.map +2 -2
- package/dist/src/subscriptions/index.cjs +15 -13
- package/dist/src/subscriptions/index.cjs.map +2 -2
- package/dist/src/subscriptions/index.d.cts +1 -1
- package/dist/src/subscriptions/index.d.ts +1 -1
- package/dist/src/subscriptions/index.js +14 -15
- package/dist/src/subscriptions/index.js.map +1 -1
- package/dist/src/transactions/index.cjs +79 -77
- package/dist/src/transactions/index.cjs.map +2 -2
- package/dist/src/transactions/index.d.cts +1 -1
- package/dist/src/transactions/index.d.ts +1 -1
- package/dist/src/transactions/index.js +104 -105
- package/dist/src/transactions/index.js.map +1 -1
- package/dist/src/utils/index.cjs +76 -74
- package/dist/src/utils/index.cjs.map +2 -2
- package/dist/src/utils/index.d.cts +1 -1
- package/dist/src/utils/index.d.ts +1 -1
- package/dist/src/utils/index.js +131 -131
- package/dist/src/utils/index.js.map +2 -2
- package/package.json +1 -1
- package/dist/shared/stacks-esm-2mc7ebrm.js +0 -84
- package/dist/shared/stacks-esm-743jfh10.js +0 -50
- package/dist/shared/stacks-esm-pxhfqfff.js +0 -48
|
@@ -19,13 +19,15 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
19
19
|
return cached;
|
|
20
20
|
}
|
|
21
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
const to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
24
|
+
for (let key of __getOwnPropNames(mod))
|
|
25
|
+
if (!__hasOwnProp.call(to, key))
|
|
26
|
+
__defProp(to, key, {
|
|
27
|
+
get: __accessProp.bind(mod, key),
|
|
28
|
+
enumerable: true
|
|
29
|
+
});
|
|
30
|
+
}
|
|
29
31
|
if (canCache)
|
|
30
32
|
cache.set(mod, to);
|
|
31
33
|
return to;
|
|
@@ -61,120 +63,42 @@ var __export = (target, all) => {
|
|
|
61
63
|
});
|
|
62
64
|
};
|
|
63
65
|
|
|
64
|
-
// src/
|
|
65
|
-
var
|
|
66
|
-
__export(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
isTraitReference: () => isTraitReference,
|
|
99
|
-
isString: () => isString,
|
|
100
|
-
isStandardPrincipal: () => isStandardPrincipal,
|
|
101
|
-
isResponse: () => isResponse,
|
|
102
|
-
isPrincipal: () => isPrincipal,
|
|
103
|
-
isOptional: () => isOptional,
|
|
104
|
-
isOkResponse: () => isOkResponse,
|
|
105
|
-
isInt128: () => isInt128,
|
|
106
|
-
isErrResponse: () => isErrResponse,
|
|
107
|
-
isContractPrincipal: () => isContractPrincipal,
|
|
108
|
-
isClarityValue: () => isClarityValue,
|
|
109
|
-
isBool: () => isBool,
|
|
110
|
-
isArray: () => isArray,
|
|
111
|
-
isAbiTuple: () => isAbiTuple,
|
|
112
|
-
isAbiTraitReference: () => isAbiTraitReference,
|
|
113
|
-
isAbiStringUtf8: () => isAbiStringUtf8,
|
|
114
|
-
isAbiStringAscii: () => isAbiStringAscii,
|
|
115
|
-
isAbiResponse: () => isAbiResponse,
|
|
116
|
-
isAbiOptional: () => isAbiOptional,
|
|
117
|
-
isAbiList: () => isAbiList,
|
|
118
|
-
isAbiBuffer: () => isAbiBuffer,
|
|
119
|
-
intCV: () => intCV,
|
|
120
|
-
hashStructuredData: () => hashStructuredData,
|
|
121
|
-
falseCV: () => falseCV,
|
|
122
|
-
encodeStructuredData: () => encodeStructuredData,
|
|
123
|
-
deserializeCVBytes: () => deserializeCVBytes,
|
|
124
|
-
deserializeCV: () => deserializeCV,
|
|
125
|
-
cvToValue: () => cvToValue,
|
|
126
|
-
cvToString: () => cvToString,
|
|
127
|
-
cvToPrincipal: () => cvToPrincipal,
|
|
128
|
-
cvToJSON: () => cvToJSON,
|
|
129
|
-
cvToBuffer: () => cvToBuffer,
|
|
130
|
-
cvToBoolean: () => cvToBoolean,
|
|
131
|
-
cvToBigInt: () => cvToBigInt,
|
|
132
|
-
contractPrincipalCV: () => contractPrincipalCV,
|
|
133
|
-
classifyContract: () => classifyContract,
|
|
134
|
-
clarityValueToJSUntyped: () => clarityValueToJSUntyped,
|
|
135
|
-
clarityValueToJS: () => clarityValueToJS,
|
|
136
|
-
clarityTypeFromByte: () => clarityTypeFromByte,
|
|
137
|
-
bufferCV: () => bufferCV,
|
|
138
|
-
boolCV: () => boolCV,
|
|
139
|
-
TRAIT_STANDARDS: () => TRAIT_STANDARDS,
|
|
140
|
-
SIP018_PREFIX: () => SIP018_PREFIX,
|
|
141
|
-
SIP013_ABI: () => SIP013_ABI,
|
|
142
|
-
SIP010_ABI: () => SIP010_ABI,
|
|
143
|
-
SIP009_ABI: () => SIP009_ABI,
|
|
144
|
-
ClarityWireType: () => ClarityWireType,
|
|
145
|
-
ClarityConversionError: () => ClarityConversionError,
|
|
146
|
-
Cl: () => Cl,
|
|
147
|
-
CONTRACT_NAME_REGEX: () => CONTRACT_NAME_REGEX
|
|
66
|
+
// src/bitcoin/index.ts
|
|
67
|
+
var exports_bitcoin = {};
|
|
68
|
+
__export(exports_bitcoin, {
|
|
69
|
+
BtcReader: () => BtcReader,
|
|
70
|
+
EPOCH_4_ACTIVATION_BURN_HEIGHT_MAINNET: () => EPOCH_4_ACTIVATION_BURN_HEIGHT_MAINNET,
|
|
71
|
+
SPV_ADAPTER_ABI: () => SPV_ADAPTER_ABI,
|
|
72
|
+
SPV_ADAPTER_CONTRACTS: () => SPV_ADAPTER_CONTRACTS,
|
|
73
|
+
bitcoinRpcSource: () => bitcoinRpcSource,
|
|
74
|
+
bitcoinTxid: () => bitcoinTxid,
|
|
75
|
+
bitcoinVerifier: () => bitcoinVerifier,
|
|
76
|
+
blockHash: () => blockHash,
|
|
77
|
+
buildMerkleProof: () => buildMerkleProof,
|
|
78
|
+
buildTxProof: () => buildTxProof,
|
|
79
|
+
decodeTxOutput: () => decodeTxOutput,
|
|
80
|
+
doubleSha256: () => doubleSha256,
|
|
81
|
+
encodeMerkleProofArgs: () => encodeMerkleProofArgs,
|
|
82
|
+
esploraSource: () => esploraSource,
|
|
83
|
+
fallbackProofSource: () => fallbackProofSource,
|
|
84
|
+
formatBitcoinAddress: () => formatBitcoinAddress,
|
|
85
|
+
getBurnBlockHeight: () => getBurnBlockHeight,
|
|
86
|
+
getSpvAdapter: () => getSpvAdapter,
|
|
87
|
+
isClarity6Active: () => isClarity6Active,
|
|
88
|
+
merkleRoot: () => merkleRoot,
|
|
89
|
+
parseBitcoinTx: () => parseBitcoinTx,
|
|
90
|
+
parseBlockHeader: () => parseBlockHeader,
|
|
91
|
+
parseOutputScript: () => parseOutputScript,
|
|
92
|
+
publicKeyToP2trAddress: () => publicKeyToP2trAddress,
|
|
93
|
+
publicKeyToP2wpkhAddress: () => publicKeyToP2wpkhAddress,
|
|
94
|
+
reverseBytes: () => reverseBytes,
|
|
95
|
+
rootFromProof: () => rootFromProof,
|
|
96
|
+
spvAdapterPrincipal: () => spvAdapterPrincipal,
|
|
97
|
+
stripWitness: () => stripWitness,
|
|
98
|
+
taprootTweakPubkey: () => taprootTweakPubkey,
|
|
99
|
+
verifyBitcoinPayment: () => verifyBitcoinPayment
|
|
148
100
|
});
|
|
149
|
-
module.exports = __toCommonJS(
|
|
150
|
-
|
|
151
|
-
// src/clarity/types.ts
|
|
152
|
-
var ClarityWireType = {
|
|
153
|
-
int: 0,
|
|
154
|
-
uint: 1,
|
|
155
|
-
buffer: 2,
|
|
156
|
-
true: 3,
|
|
157
|
-
false: 4,
|
|
158
|
-
address: 5,
|
|
159
|
-
contract: 6,
|
|
160
|
-
ok: 7,
|
|
161
|
-
err: 8,
|
|
162
|
-
none: 9,
|
|
163
|
-
some: 10,
|
|
164
|
-
list: 11,
|
|
165
|
-
tuple: 12,
|
|
166
|
-
ascii: 13,
|
|
167
|
-
utf8: 14
|
|
168
|
-
};
|
|
169
|
-
var wireTypeToClarity = Object.fromEntries(Object.entries(ClarityWireType).map(([k, v]) => [v, k]));
|
|
170
|
-
function clarityTypeFromByte(byte) {
|
|
171
|
-
const type = wireTypeToClarity[byte];
|
|
172
|
-
if (!type)
|
|
173
|
-
throw new Error(`Unknown clarity wire type: ${byte}`);
|
|
174
|
-
return type;
|
|
175
|
-
}
|
|
176
|
-
// src/utils/c32.ts
|
|
177
|
-
var import_sha2 = require("@noble/hashes/sha2.js");
|
|
101
|
+
module.exports = __toCommonJS(exports_bitcoin);
|
|
178
102
|
|
|
179
103
|
// src/utils/encoding.ts
|
|
180
104
|
var hexes = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
@@ -307,2112 +231,2187 @@ function writeUInt8(value) {
|
|
|
307
231
|
return new Uint8Array([value & 255]);
|
|
308
232
|
}
|
|
309
233
|
|
|
310
|
-
// src/utils/
|
|
311
|
-
var
|
|
312
|
-
var
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
function c32encode(inputHex) {
|
|
317
|
-
let hex = inputHex;
|
|
318
|
-
if (hex.length % 2 !== 0)
|
|
319
|
-
hex = `0${hex}`;
|
|
320
|
-
hex = hex.toLowerCase();
|
|
321
|
-
const res = [];
|
|
322
|
-
let carry = 0;
|
|
323
|
-
for (let i = hex.length - 1;i >= 0; i--) {
|
|
324
|
-
if (carry < 4) {
|
|
325
|
-
const currentCode = HEX.indexOf(hex[i]) >> carry;
|
|
326
|
-
const nextCode = i !== 0 ? HEX.indexOf(hex[i - 1]) : 0;
|
|
327
|
-
const nextBits = 1 + carry;
|
|
328
|
-
const nextLowBits = nextCode % (1 << nextBits) << 5 - nextBits;
|
|
329
|
-
res.unshift(C32[currentCode + nextLowBits]);
|
|
330
|
-
carry = nextBits;
|
|
331
|
-
} else {
|
|
332
|
-
carry = 0;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
let leadingZeros = 0;
|
|
336
|
-
while (leadingZeros < res.length && res[leadingZeros] === "0")
|
|
337
|
-
leadingZeros++;
|
|
338
|
-
const stripped = res.slice(leadingZeros);
|
|
339
|
-
const bytes = hexToBytes(hex);
|
|
340
|
-
let zeroBytesCount = 0;
|
|
341
|
-
while (zeroBytesCount < bytes.length && bytes[zeroBytesCount] === 0)
|
|
342
|
-
zeroBytesCount++;
|
|
343
|
-
const prefix = Array(zeroBytesCount).fill(C32[0]);
|
|
344
|
-
return [...prefix, ...stripped].join("");
|
|
234
|
+
// src/utils/hash.ts
|
|
235
|
+
var import_legacy = require("@noble/hashes/legacy.js");
|
|
236
|
+
var import_sha2 = require("@noble/hashes/sha2.js");
|
|
237
|
+
var import_sha22 = require("@noble/hashes/sha2.js");
|
|
238
|
+
function hash160(input) {
|
|
239
|
+
return import_legacy.ripemd160(import_sha2.sha256(input));
|
|
345
240
|
}
|
|
346
|
-
function
|
|
347
|
-
|
|
348
|
-
if (!input.match(`^[${C32}]*$`))
|
|
349
|
-
throw new Error("Not a c32-encoded string");
|
|
350
|
-
const zeroPrefix = input.match(`^${C32[0]}*`);
|
|
351
|
-
const numLeadingZeroBytes = zeroPrefix ? zeroPrefix[0]?.length : 0;
|
|
352
|
-
const res = [];
|
|
353
|
-
let carry = 0;
|
|
354
|
-
let carryBits = 0;
|
|
355
|
-
for (let i = input.length - 1;i >= 0; i--) {
|
|
356
|
-
if (carryBits === 4) {
|
|
357
|
-
res.unshift(HEX[carry]);
|
|
358
|
-
carryBits = 0;
|
|
359
|
-
carry = 0;
|
|
360
|
-
}
|
|
361
|
-
const currentValue = (C32.indexOf(input[i]) << carryBits) + carry;
|
|
362
|
-
res.unshift(HEX[currentValue % 16]);
|
|
363
|
-
carryBits += 1;
|
|
364
|
-
carry = currentValue >> 4;
|
|
365
|
-
if (carry > 1 << carryBits)
|
|
366
|
-
throw new Error("Panic error in c32 decoding");
|
|
367
|
-
}
|
|
368
|
-
res.unshift(HEX[carry]);
|
|
369
|
-
if (res.length % 2 === 1)
|
|
370
|
-
res.unshift("0");
|
|
371
|
-
let hexLeadingZeros = 0;
|
|
372
|
-
while (hexLeadingZeros < res.length && res[hexLeadingZeros] === "0")
|
|
373
|
-
hexLeadingZeros++;
|
|
374
|
-
let hexStr = res.slice(hexLeadingZeros - hexLeadingZeros % 2).join("");
|
|
375
|
-
for (let i = 0;i < numLeadingZeroBytes; i++)
|
|
376
|
-
hexStr = `00${hexStr}`;
|
|
377
|
-
return hexStr;
|
|
241
|
+
function txidFromBytes(data) {
|
|
242
|
+
return bytesToHex(import_sha22.sha512_256(data));
|
|
378
243
|
}
|
|
379
|
-
function
|
|
380
|
-
return bytesToHex(
|
|
244
|
+
function hashP2PKH(input) {
|
|
245
|
+
return bytesToHex(hash160(input));
|
|
381
246
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
throw new Error("Invalid data (not a hex string)");
|
|
387
|
-
let d = data.toLowerCase();
|
|
388
|
-
if (d.length % 2 !== 0)
|
|
389
|
-
d = `0${d}`;
|
|
390
|
-
let versionHex = version.toString(16);
|
|
391
|
-
if (versionHex.length === 1)
|
|
392
|
-
versionHex = `0${versionHex}`;
|
|
393
|
-
const checksumHex = c32checksum(`${versionHex}${d}`);
|
|
394
|
-
return `${C32[version]}${c32encode(`${d}${checksumHex}`)}`;
|
|
247
|
+
|
|
248
|
+
// src/bitcoin/serialize.ts
|
|
249
|
+
function doubleSha256(bytes) {
|
|
250
|
+
return import_sha2.sha256(import_sha2.sha256(bytes));
|
|
395
251
|
}
|
|
396
|
-
function
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
const checksum = dataHex.slice(-8);
|
|
401
|
-
let versionHex = version.toString(16);
|
|
402
|
-
if (versionHex.length === 1)
|
|
403
|
-
versionHex = `0${versionHex}`;
|
|
404
|
-
if (c32checksum(`${versionHex}${dataHex.substring(0, dataHex.length - 8)}`) !== checksum) {
|
|
405
|
-
throw new Error("Invalid c32check string: checksum mismatch");
|
|
252
|
+
function reverseBytes(bytes) {
|
|
253
|
+
const out = new Uint8Array(bytes.length);
|
|
254
|
+
for (let i = 0;i < bytes.length; i++) {
|
|
255
|
+
out[i] = bytes[bytes.length - 1 - i];
|
|
406
256
|
}
|
|
407
|
-
return
|
|
408
|
-
}
|
|
409
|
-
function c32address(version, hash160hex) {
|
|
410
|
-
if (!hash160hex.match(/^[0-9a-fA-F]{40}$/)) {
|
|
411
|
-
throw new Error("Invalid argument: not a hash160 hex string");
|
|
412
|
-
}
|
|
413
|
-
return `S${c32checkEncode(version, hash160hex)}`;
|
|
414
|
-
}
|
|
415
|
-
function c32addressDecode(c32addr) {
|
|
416
|
-
if (c32addr.length <= 5)
|
|
417
|
-
throw new Error("Invalid c32 address: invalid length");
|
|
418
|
-
if (c32addr[0] !== "S")
|
|
419
|
-
throw new Error('Invalid c32 address: must start with "S"');
|
|
420
|
-
return c32checkDecode(c32addr.slice(1));
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// src/utils/constants.ts
|
|
424
|
-
var MAX_U128 = (1n << 128n) - 1n;
|
|
425
|
-
var MAX_I128 = (1n << 127n) - 1n;
|
|
426
|
-
var MIN_I128 = -(1n << 127n);
|
|
427
|
-
var AddressVersion = {
|
|
428
|
-
MainnetSingleSig: 22,
|
|
429
|
-
MainnetMultiSig: 20,
|
|
430
|
-
TestnetSingleSig: 26,
|
|
431
|
-
TestnetMultiSig: 21
|
|
432
|
-
};
|
|
433
|
-
var ZERO_ADDRESS = "SP000000000000000000002Q6VF78";
|
|
434
|
-
var TESTNET_ZERO_ADDRESS = "ST000000000000000000002AMW42H";
|
|
435
|
-
var MICROSTX_PER_STX = 1000000n;
|
|
436
|
-
|
|
437
|
-
// src/utils/hash.ts
|
|
438
|
-
var import_legacy = require("@noble/hashes/legacy.js");
|
|
439
|
-
var import_sha22 = require("@noble/hashes/sha2.js");
|
|
440
|
-
var import_sha23 = require("@noble/hashes/sha2.js");
|
|
441
|
-
function hash160(input) {
|
|
442
|
-
return import_legacy.ripemd160(import_sha22.sha256(input));
|
|
443
|
-
}
|
|
444
|
-
function txidFromBytes(data) {
|
|
445
|
-
return bytesToHex(import_sha23.sha512_256(data));
|
|
446
|
-
}
|
|
447
|
-
function hashP2PKH(input) {
|
|
448
|
-
return bytesToHex(hash160(input));
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
// src/utils/address.ts
|
|
452
|
-
function publicKeyToAddress(publicKey, network = "mainnet") {
|
|
453
|
-
const bytes = typeof publicKey === "string" ? hexToBytes(without0x(publicKey)) : publicKey;
|
|
454
|
-
const version = network === "mainnet" ? AddressVersion.MainnetSingleSig : AddressVersion.TestnetSingleSig;
|
|
455
|
-
return c32address(version, bytesToHex(hash160(bytes)));
|
|
456
|
-
}
|
|
457
|
-
var CONTRACT_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/;
|
|
458
|
-
function validateStacksAddress(address) {
|
|
459
|
-
try {
|
|
460
|
-
c32addressDecode(address);
|
|
461
|
-
return true;
|
|
462
|
-
} catch {
|
|
463
|
-
return false;
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
var isValidAddress = validateStacksAddress;
|
|
467
|
-
function parsePrincipal(value) {
|
|
468
|
-
const parts = value.split(".");
|
|
469
|
-
if (parts.length > 2)
|
|
470
|
-
return null;
|
|
471
|
-
const [address, contractName] = parts;
|
|
472
|
-
if (!validateStacksAddress(address))
|
|
473
|
-
return null;
|
|
474
|
-
if (contractName === undefined)
|
|
475
|
-
return { address };
|
|
476
|
-
if (!CONTRACT_NAME_REGEX.test(contractName))
|
|
477
|
-
return null;
|
|
478
|
-
return { address, contractName };
|
|
479
|
-
}
|
|
480
|
-
function parseContractId(contractId) {
|
|
481
|
-
const parsed = parsePrincipal(contractId);
|
|
482
|
-
if (!parsed?.contractName)
|
|
483
|
-
throw new Error(`Invalid contract identifier: ${contractId}`);
|
|
484
|
-
return [parsed.address, parsed.contractName];
|
|
485
|
-
}
|
|
486
|
-
function isClarityName(name) {
|
|
487
|
-
const regex = /^[a-zA-Z]([a-zA-Z0-9]|[-_!?+<>=/*])*$|^[-+=/*]$|^[<>]=?$/;
|
|
488
|
-
return regex.test(name) && name.length < 128;
|
|
489
|
-
}
|
|
490
|
-
function isAddressEqual(a, b) {
|
|
491
|
-
const [versionA, hashA] = c32addressDecode(a);
|
|
492
|
-
const [versionB, hashB] = c32addressDecode(b);
|
|
493
|
-
return versionA === versionB && hashA.toLowerCase() === hashB.toLowerCase();
|
|
494
|
-
}
|
|
495
|
-
function addressToVersion(address) {
|
|
496
|
-
return c32addressDecode(address)[0];
|
|
497
|
-
}
|
|
498
|
-
function getContractAddress(deployer, contractName) {
|
|
499
|
-
if (!validateStacksAddress(deployer)) {
|
|
500
|
-
throw new Error(`Invalid deployer address: ${deployer}`);
|
|
501
|
-
}
|
|
502
|
-
if (!isClarityName(contractName)) {
|
|
503
|
-
throw new Error(`Invalid contract name: ${contractName}`);
|
|
504
|
-
}
|
|
505
|
-
return `${deployer}.${contractName}`;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
// src/errors/base.ts
|
|
509
|
-
function codeFromName(name) {
|
|
510
|
-
return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toUpperCase();
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
class BaseError extends Error {
|
|
514
|
-
name = "StacksError";
|
|
515
|
-
#code;
|
|
516
|
-
shortMessage;
|
|
517
|
-
details;
|
|
518
|
-
constructor(shortMessage, options) {
|
|
519
|
-
const message = [
|
|
520
|
-
shortMessage,
|
|
521
|
-
options?.details ? `
|
|
522
|
-
${options.details}` : ""
|
|
523
|
-
].join("");
|
|
524
|
-
super(message, { cause: options?.cause });
|
|
525
|
-
if (options?.code !== undefined)
|
|
526
|
-
this.#code = options.code;
|
|
527
|
-
this.shortMessage = shortMessage;
|
|
528
|
-
this.details = options?.details;
|
|
529
|
-
}
|
|
530
|
-
get code() {
|
|
531
|
-
return this.#code ?? codeFromName(this.name);
|
|
532
|
-
}
|
|
533
|
-
set code(value) {
|
|
534
|
-
this.#code = value;
|
|
535
|
-
}
|
|
536
|
-
toJSON() {
|
|
537
|
-
return {
|
|
538
|
-
name: this.name,
|
|
539
|
-
code: this.code,
|
|
540
|
-
message: this.message,
|
|
541
|
-
shortMessage: this.shortMessage,
|
|
542
|
-
details: this.details,
|
|
543
|
-
cause: this.cause instanceof Error ? this.cause.message : undefined
|
|
544
|
-
};
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// src/errors/transaction.ts
|
|
549
|
-
class TransactionError extends BaseError {
|
|
550
|
-
name = "TransactionError";
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
class BroadcastError extends BaseError {
|
|
554
|
-
name = "BroadcastError";
|
|
555
|
-
txid;
|
|
556
|
-
reason;
|
|
557
|
-
reasonData;
|
|
558
|
-
constructor(message, options) {
|
|
559
|
-
super(message, options);
|
|
560
|
-
this.txid = options?.txid;
|
|
561
|
-
this.reason = options?.reason;
|
|
562
|
-
this.reasonData = options?.reasonData;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
class TransactionAbortedError extends BaseError {
|
|
567
|
-
name = "TransactionAbortedError";
|
|
568
|
-
receipt;
|
|
569
|
-
constructor(message, options) {
|
|
570
|
-
super(message, options);
|
|
571
|
-
this.receipt = options.receipt;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
class TransactionDroppedError extends BaseError {
|
|
576
|
-
name = "TransactionDroppedError";
|
|
577
|
-
txid;
|
|
578
|
-
constructor(message, options) {
|
|
579
|
-
super(message, options);
|
|
580
|
-
this.txid = options.txid;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
class WaitForTransactionTimeoutError extends BaseError {
|
|
585
|
-
name = "WaitForTransactionTimeoutError";
|
|
586
|
-
txid;
|
|
587
|
-
constructor(message, options) {
|
|
588
|
-
super(message, options);
|
|
589
|
-
this.txid = options.txid;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
class SerializationError extends BaseError {
|
|
594
|
-
name = "SerializationError";
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
class SigningError extends BaseError {
|
|
598
|
-
name = "SigningError";
|
|
257
|
+
return out;
|
|
599
258
|
}
|
|
600
259
|
|
|
601
|
-
|
|
602
|
-
class BytesReader {
|
|
260
|
+
class BtcReader {
|
|
603
261
|
data;
|
|
262
|
+
view;
|
|
604
263
|
offset = 0;
|
|
605
264
|
constructor(data) {
|
|
606
265
|
this.data = data;
|
|
266
|
+
this.view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
607
267
|
}
|
|
608
|
-
|
|
609
|
-
return this.data.length
|
|
610
|
-
}
|
|
611
|
-
ensure(length) {
|
|
612
|
-
if (this.offset + length > this.data.length) {
|
|
613
|
-
throw new SerializationError(`Buffer underflow: need ${length} bytes at offset ${this.offset}, have ${this.data.length}`);
|
|
614
|
-
}
|
|
268
|
+
get length() {
|
|
269
|
+
return this.data.length;
|
|
615
270
|
}
|
|
616
271
|
readUInt8() {
|
|
617
|
-
this.
|
|
618
|
-
|
|
272
|
+
const v = this.view.getUint8(this.offset);
|
|
273
|
+
this.offset += 1;
|
|
274
|
+
return v;
|
|
619
275
|
}
|
|
620
|
-
|
|
621
|
-
this.
|
|
622
|
-
const val = (this.data[this.offset] << 8 | this.data[this.offset + 1]) >>> 0;
|
|
623
|
-
this.offset += 2;
|
|
624
|
-
return val;
|
|
276
|
+
peekUInt8() {
|
|
277
|
+
return this.view.getUint8(this.offset);
|
|
625
278
|
}
|
|
626
|
-
|
|
627
|
-
this.
|
|
628
|
-
const val = (this.data[this.offset] << 24 | this.data[this.offset + 1] << 16 | this.data[this.offset + 2] << 8 | this.data[this.offset + 3]) >>> 0;
|
|
279
|
+
readUInt32LE() {
|
|
280
|
+
const v = this.view.getUint32(this.offset, true);
|
|
629
281
|
this.offset += 4;
|
|
630
|
-
return
|
|
282
|
+
return v;
|
|
631
283
|
}
|
|
632
|
-
|
|
633
|
-
this.
|
|
634
|
-
|
|
635
|
-
|
|
284
|
+
readUInt64LE() {
|
|
285
|
+
const v = this.view.getBigUint64(this.offset, true);
|
|
286
|
+
this.offset += 8;
|
|
287
|
+
return v;
|
|
288
|
+
}
|
|
289
|
+
readBytes(n) {
|
|
290
|
+
if (this.offset + n > this.data.length) {
|
|
291
|
+
throw new Error(`Bitcoin tx underflow: need ${n} bytes at offset ${this.offset}, have ${this.data.length}`);
|
|
292
|
+
}
|
|
293
|
+
const slice = this.data.slice(this.offset, this.offset + n);
|
|
294
|
+
this.offset += n;
|
|
636
295
|
return slice;
|
|
637
296
|
}
|
|
638
|
-
|
|
639
|
-
const
|
|
640
|
-
|
|
297
|
+
readVarInt() {
|
|
298
|
+
const first = this.readUInt8();
|
|
299
|
+
if (first < 253)
|
|
300
|
+
return first;
|
|
301
|
+
if (first === 253) {
|
|
302
|
+
const v = this.view.getUint16(this.offset, true);
|
|
303
|
+
this.offset += 2;
|
|
304
|
+
return v;
|
|
305
|
+
}
|
|
306
|
+
if (first === 254) {
|
|
307
|
+
return this.readUInt32LE();
|
|
308
|
+
}
|
|
309
|
+
const big = this.readUInt64LE();
|
|
310
|
+
if (big > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
311
|
+
throw new Error("Bitcoin varint exceeds safe integer range");
|
|
312
|
+
}
|
|
313
|
+
return Number(big);
|
|
641
314
|
}
|
|
642
315
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
316
|
+
function scanTx(rawTx) {
|
|
317
|
+
const r = new BtcReader(rawTx);
|
|
318
|
+
const version = r.readUInt32LE();
|
|
319
|
+
let hasWitness = false;
|
|
320
|
+
if (r.peekUInt8() === 0) {
|
|
321
|
+
r.readUInt8();
|
|
322
|
+
const flag = r.readUInt8();
|
|
323
|
+
if (flag !== 1) {
|
|
324
|
+
throw new Error(`Unexpected SegWit flag 0x${flag.toString(16)}`);
|
|
325
|
+
}
|
|
326
|
+
hasWitness = true;
|
|
654
327
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
328
|
+
const bodyStart = r.offset;
|
|
329
|
+
const inputCount = r.readVarInt();
|
|
330
|
+
const inputs = [];
|
|
331
|
+
for (let i = 0;i < inputCount; i++) {
|
|
332
|
+
const prevTxid = r.readBytes(32);
|
|
333
|
+
const vout = r.readUInt32LE();
|
|
334
|
+
const scriptSig = r.readBytes(r.readVarInt());
|
|
335
|
+
const sequence = r.readUInt32LE();
|
|
336
|
+
inputs.push({ prevTxid, vout, scriptSig, sequence });
|
|
663
337
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
338
|
+
const outputCount = r.readVarInt();
|
|
339
|
+
const outputs = [];
|
|
340
|
+
for (let i = 0;i < outputCount; i++) {
|
|
341
|
+
const value = r.readUInt64LE();
|
|
342
|
+
const scriptPubKey = r.readBytes(r.readVarInt());
|
|
343
|
+
outputs.push({ value, scriptPubKey });
|
|
668
344
|
}
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
return uintCV(reader.readBytes(16));
|
|
676
|
-
case "true":
|
|
677
|
-
return trueCV();
|
|
678
|
-
case "false":
|
|
679
|
-
return falseCV();
|
|
680
|
-
case "buffer": {
|
|
681
|
-
const len = reader.readUInt32BE();
|
|
682
|
-
return bufferCV(reader.readBytes(len));
|
|
683
|
-
}
|
|
684
|
-
case "none":
|
|
685
|
-
return noneCV();
|
|
686
|
-
case "some":
|
|
687
|
-
return someCV(readCV(reader, depth + 1));
|
|
688
|
-
case "ok":
|
|
689
|
-
return responseOkCV(readCV(reader, depth + 1));
|
|
690
|
-
case "err":
|
|
691
|
-
return responseErrorCV(readCV(reader, depth + 1));
|
|
692
|
-
case "address":
|
|
693
|
-
return standardPrincipalCV(readAddress(reader));
|
|
694
|
-
case "contract": {
|
|
695
|
-
const addr = readAddress(reader);
|
|
696
|
-
const name = readLPString(reader);
|
|
697
|
-
return contractPrincipalCV(addr, name);
|
|
698
|
-
}
|
|
699
|
-
case "list": {
|
|
700
|
-
const len = reader.readUInt32BE();
|
|
701
|
-
checkCount(reader, len, MIN_LIST_ITEM_BYTES);
|
|
702
|
-
const items = [];
|
|
703
|
-
for (let i = 0;i < len; i++) {
|
|
704
|
-
items.push(readCV(reader, depth + 1));
|
|
705
|
-
}
|
|
706
|
-
return listCV(items);
|
|
707
|
-
}
|
|
708
|
-
case "tuple": {
|
|
709
|
-
const len = reader.readUInt32BE();
|
|
710
|
-
checkCount(reader, len, MIN_TUPLE_ENTRY_BYTES);
|
|
711
|
-
const data = {};
|
|
712
|
-
for (let i = 0;i < len; i++) {
|
|
713
|
-
const key = readLPString(reader);
|
|
714
|
-
data[key] = readCV(reader, depth + 1);
|
|
345
|
+
const bodyEnd = r.offset;
|
|
346
|
+
if (hasWitness) {
|
|
347
|
+
for (let i = 0;i < inputCount; i++) {
|
|
348
|
+
const itemCount = r.readVarInt();
|
|
349
|
+
for (let j = 0;j < itemCount; j++) {
|
|
350
|
+
r.readBytes(r.readVarInt());
|
|
715
351
|
}
|
|
716
|
-
return tupleCV(data);
|
|
717
|
-
}
|
|
718
|
-
case "ascii": {
|
|
719
|
-
const len = reader.readUInt32BE();
|
|
720
|
-
return stringAsciiCV(bytesToAscii(reader.readBytes(len)));
|
|
721
|
-
}
|
|
722
|
-
case "utf8": {
|
|
723
|
-
const len = reader.readUInt32BE();
|
|
724
|
-
return stringUtf8CV(bytesToUtf8(reader.readBytes(len)));
|
|
725
352
|
}
|
|
726
|
-
default:
|
|
727
|
-
throw new SerializationError(`Cannot deserialize unknown clarity type: ${type}`);
|
|
728
353
|
}
|
|
354
|
+
const locktime = r.readUInt32LE();
|
|
355
|
+
const legacy = concatBytes(rawTx.slice(0, 4), rawTx.slice(bodyStart, bodyEnd), rawTx.slice(r.offset - 4, r.offset));
|
|
356
|
+
return { version, hasWitness, inputs, outputs, locktime, legacy };
|
|
729
357
|
}
|
|
730
|
-
function
|
|
731
|
-
const
|
|
732
|
-
return
|
|
358
|
+
function parseBitcoinTx(rawTx) {
|
|
359
|
+
const s = scanTx(rawTx);
|
|
360
|
+
return {
|
|
361
|
+
version: s.version,
|
|
362
|
+
hasWitness: s.hasWitness,
|
|
363
|
+
inputs: s.inputs,
|
|
364
|
+
outputs: s.outputs,
|
|
365
|
+
locktime: s.locktime,
|
|
366
|
+
txidInternal: doubleSha256(s.legacy)
|
|
367
|
+
};
|
|
733
368
|
}
|
|
734
|
-
function
|
|
735
|
-
return
|
|
369
|
+
function stripWitness(rawTx) {
|
|
370
|
+
return scanTx(rawTx).legacy;
|
|
736
371
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
var CLARITY_INT_BYTE_SIZE = 16;
|
|
741
|
-
function typeIdByte(type) {
|
|
742
|
-
return ClarityWireType[type];
|
|
372
|
+
function bitcoinTxid(rawTx, { display = false } = {}) {
|
|
373
|
+
const txid = doubleSha256(scanTx(rawTx).legacy);
|
|
374
|
+
return display ? reverseBytes(txid) : txid;
|
|
743
375
|
}
|
|
744
|
-
function
|
|
745
|
-
|
|
376
|
+
function parseBlockHeader(header) {
|
|
377
|
+
if (header.length !== 80) {
|
|
378
|
+
throw new Error(`Bitcoin block header must be 80 bytes, got ${header.length}`);
|
|
379
|
+
}
|
|
380
|
+
const r = new BtcReader(header);
|
|
381
|
+
const version = r.readUInt32LE();
|
|
382
|
+
const prevBlock = r.readBytes(32);
|
|
383
|
+
const merkleRoot = r.readBytes(32);
|
|
384
|
+
const timestamp = r.readUInt32LE();
|
|
385
|
+
const bits = r.readUInt32LE();
|
|
386
|
+
const nonce = r.readUInt32LE();
|
|
387
|
+
return { version, prevBlock, merkleRoot, timestamp, bits, nonce };
|
|
746
388
|
}
|
|
747
|
-
function
|
|
748
|
-
const
|
|
749
|
-
return
|
|
389
|
+
function blockHash(header, { display = false } = {}) {
|
|
390
|
+
const hash = doubleSha256(header);
|
|
391
|
+
return display ? reverseBytes(hash) : hash;
|
|
750
392
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
return concatBytes(lengthPrefix, content);
|
|
393
|
+
// src/bitcoin/merkle.ts
|
|
394
|
+
function hashPair(left, right) {
|
|
395
|
+
return doubleSha256(concatBytes(left, right));
|
|
755
396
|
}
|
|
756
|
-
function
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
}
|
|
765
|
-
case "uint": {
|
|
766
|
-
const bytes = bigIntToBytes(BigInt(value.value), CLARITY_INT_BYTE_SIZE);
|
|
767
|
-
return withTypeId(value.type, bytes);
|
|
768
|
-
}
|
|
769
|
-
case "buffer": {
|
|
770
|
-
const bufBytes = hexToBytes(value.value);
|
|
771
|
-
return withTypeId(value.type, concatBytes(writeUInt32BE(bufBytes.length), bufBytes));
|
|
772
|
-
}
|
|
773
|
-
case "none":
|
|
774
|
-
return new Uint8Array([typeIdByte(value.type)]);
|
|
775
|
-
case "some":
|
|
776
|
-
return withTypeId(value.type, serializeCVBytes(value.value));
|
|
777
|
-
case "ok":
|
|
778
|
-
case "err":
|
|
779
|
-
return withTypeId(value.type, serializeCVBytes(value.value));
|
|
780
|
-
case "address":
|
|
781
|
-
return withTypeId(value.type, serializeAddress(value.value));
|
|
782
|
-
case "contract": {
|
|
783
|
-
const [addr, name] = value.value.split(".");
|
|
784
|
-
if (!addr || !name)
|
|
785
|
-
throw new Error(`Invalid contract principal: ${value.value}`);
|
|
786
|
-
return withTypeId(value.type, concatBytes(serializeAddress(addr), serializeLPString(name)));
|
|
787
|
-
}
|
|
788
|
-
case "list": {
|
|
789
|
-
const parts = [writeUInt32BE(value.value.length)];
|
|
790
|
-
for (const item of value.value) {
|
|
791
|
-
parts.push(serializeCVBytes(item));
|
|
792
|
-
}
|
|
793
|
-
return withTypeId(value.type, concatBytes(...parts));
|
|
794
|
-
}
|
|
795
|
-
case "tuple": {
|
|
796
|
-
const keys = Object.keys(value.value).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
797
|
-
const parts = [writeUInt32BE(keys.length)];
|
|
798
|
-
for (const key of keys) {
|
|
799
|
-
parts.push(serializeLPString(key));
|
|
800
|
-
parts.push(serializeCVBytes(value.value[key]));
|
|
801
|
-
}
|
|
802
|
-
return withTypeId(value.type, concatBytes(...parts));
|
|
803
|
-
}
|
|
804
|
-
case "ascii": {
|
|
805
|
-
const strBytes = asciiToBytes(value.value);
|
|
806
|
-
return withTypeId(value.type, concatBytes(writeUInt32BE(strBytes.length), strBytes));
|
|
807
|
-
}
|
|
808
|
-
case "utf8": {
|
|
809
|
-
const strBytes = utf8ToBytes(value.value);
|
|
810
|
-
return withTypeId(value.type, concatBytes(writeUInt32BE(strBytes.length), strBytes));
|
|
811
|
-
}
|
|
812
|
-
default:
|
|
813
|
-
throw new Error("Cannot serialize unknown clarity type");
|
|
397
|
+
function nextLevel(level) {
|
|
398
|
+
const next = [];
|
|
399
|
+
for (let i = 0;i < level.length; i += 2) {
|
|
400
|
+
const left = level[i];
|
|
401
|
+
if (left === undefined)
|
|
402
|
+
throw new Error("merkle: missing left node");
|
|
403
|
+
const right = level[i + 1] ?? left;
|
|
404
|
+
next.push(hashPair(left, right));
|
|
814
405
|
}
|
|
406
|
+
return next;
|
|
815
407
|
}
|
|
816
|
-
function
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
// src/clarity/values.ts
|
|
821
|
-
var MAX_U1282 = BigInt("0xffffffffffffffffffffffffffffffff");
|
|
822
|
-
var MIN_I1282 = BigInt("-170141183460469231731687303715884105728");
|
|
823
|
-
var MAX_I1282 = BigInt("0x7fffffffffffffffffffffffffffffff");
|
|
824
|
-
function intCV(value) {
|
|
825
|
-
let v = value;
|
|
826
|
-
if (typeof v === "string" && v.toLowerCase().startsWith("0x")) {
|
|
827
|
-
v = bytesToTwosBigInt(hexToBytes(v));
|
|
408
|
+
function merkleRoot(txidsInternal) {
|
|
409
|
+
if (txidsInternal.length === 0) {
|
|
410
|
+
throw new Error("merkleRoot: empty tx list");
|
|
828
411
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
if (n > MAX_I1282)
|
|
833
|
-
throw new RangeError(`Int exceeds max i128: ${MAX_I1282}`);
|
|
834
|
-
if (n < MIN_I1282)
|
|
835
|
-
throw new RangeError(`Int below min i128: ${MIN_I1282}`);
|
|
836
|
-
return { type: "int", value: n };
|
|
837
|
-
}
|
|
838
|
-
function uintCV(value) {
|
|
839
|
-
const n = intToBigInt(value);
|
|
840
|
-
if (n < 0n)
|
|
841
|
-
throw new RangeError("Cannot construct unsigned int from negative value");
|
|
842
|
-
if (n > MAX_U1282)
|
|
843
|
-
throw new RangeError(`UInt exceeds max u128: ${MAX_U1282}`);
|
|
844
|
-
return { type: "uint", value: n };
|
|
845
|
-
}
|
|
846
|
-
var trueCV = () => ({ type: "true" });
|
|
847
|
-
var falseCV = () => ({ type: "false" });
|
|
848
|
-
var boolCV = (v) => v ? trueCV() : falseCV();
|
|
849
|
-
function bufferCV(buffer) {
|
|
850
|
-
if (buffer.byteLength > 1048576) {
|
|
851
|
-
throw new Error("Buffer exceeds max size of 1MB");
|
|
412
|
+
let level = txidsInternal.slice();
|
|
413
|
+
while (level.length > 1) {
|
|
414
|
+
level = nextLevel(level);
|
|
852
415
|
}
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
const normalized = c32address(version, hash1602);
|
|
858
|
-
return { type: "address", value: normalized };
|
|
416
|
+
const root = level[0];
|
|
417
|
+
if (root === undefined)
|
|
418
|
+
throw new Error("merkleRoot: no root");
|
|
419
|
+
return root;
|
|
859
420
|
}
|
|
860
|
-
function
|
|
861
|
-
const
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
throw new Error("Contract name must be less than 128 bytes");
|
|
421
|
+
function buildMerkleProof(txidsInternal, txIndex) {
|
|
422
|
+
const txCount = txidsInternal.length;
|
|
423
|
+
if (txCount === 0) {
|
|
424
|
+
throw new Error("buildMerkleProof: empty tx list");
|
|
865
425
|
}
|
|
866
|
-
|
|
867
|
-
}
|
|
868
|
-
function noneCV() {
|
|
869
|
-
return { type: "none" };
|
|
870
|
-
}
|
|
871
|
-
function someCV(value) {
|
|
872
|
-
return { type: "some", value };
|
|
873
|
-
}
|
|
874
|
-
function responseOkCV(value) {
|
|
875
|
-
return { type: "ok", value };
|
|
876
|
-
}
|
|
877
|
-
function responseErrorCV(value) {
|
|
878
|
-
return { type: "err", value };
|
|
879
|
-
}
|
|
880
|
-
function listCV(values) {
|
|
881
|
-
return { type: "list", value: values };
|
|
882
|
-
}
|
|
883
|
-
function tupleCV(data) {
|
|
884
|
-
for (const key in data) {
|
|
885
|
-
if (!isClarityName(key)) {
|
|
886
|
-
throw new Error(`"${key}" is not a valid Clarity name`);
|
|
887
|
-
}
|
|
426
|
+
if (txIndex < 0 || txIndex >= txCount) {
|
|
427
|
+
throw new Error(`buildMerkleProof: txIndex ${txIndex} out of range for ${txCount} txs`);
|
|
888
428
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
429
|
+
const siblings = [];
|
|
430
|
+
let index = txIndex;
|
|
431
|
+
let level = txidsInternal.slice();
|
|
432
|
+
while (level.length > 1) {
|
|
433
|
+
const isRight = index % 2 === 1;
|
|
434
|
+
const siblingIndex = isRight ? index - 1 : index + 1;
|
|
435
|
+
const self = level[index];
|
|
436
|
+
if (self === undefined)
|
|
437
|
+
throw new Error("buildMerkleProof: missing node");
|
|
438
|
+
siblings.push(level[siblingIndex] ?? self);
|
|
439
|
+
level = nextLevel(level);
|
|
440
|
+
index = Math.floor(index / 2);
|
|
441
|
+
}
|
|
442
|
+
return { siblings, txIndex, txCount };
|
|
896
443
|
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
return parsed.contractName ? contractPrincipalCV(parsed.address, parsed.contractName) : standardPrincipalCV(parsed.address);
|
|
906
|
-
},
|
|
907
|
-
address(address) {
|
|
908
|
-
return Cl.principal(address);
|
|
909
|
-
},
|
|
910
|
-
contractPrincipal: contractPrincipalCV,
|
|
911
|
-
standardPrincipal: standardPrincipalCV,
|
|
912
|
-
buffer: bufferCV,
|
|
913
|
-
bufferFromHex: (hex) => bufferCV(hexToBytes(hex)),
|
|
914
|
-
bufferFromAscii: (ascii) => bufferCV(asciiToBytes(ascii)),
|
|
915
|
-
bufferFromUtf8: (utf8) => bufferCV(utf8ToBytes(utf8)),
|
|
916
|
-
none: noneCV,
|
|
917
|
-
some: someCV,
|
|
918
|
-
ok: responseOkCV,
|
|
919
|
-
error: responseErrorCV,
|
|
920
|
-
list: listCV,
|
|
921
|
-
tuple: tupleCV,
|
|
922
|
-
stringAscii: stringAsciiCV,
|
|
923
|
-
stringUtf8: stringUtf8CV,
|
|
924
|
-
serialize(value) {
|
|
925
|
-
return bytesToHex(serializeCVBytes(value));
|
|
926
|
-
},
|
|
927
|
-
deserialize: deserializeCVBytes
|
|
928
|
-
};
|
|
929
|
-
// src/clarity/structuredData.ts
|
|
930
|
-
var import_sha24 = require("@noble/hashes/sha2.js");
|
|
931
|
-
var SIP018_PREFIX = new Uint8Array([
|
|
932
|
-
83,
|
|
933
|
-
73,
|
|
934
|
-
80,
|
|
935
|
-
48,
|
|
936
|
-
49,
|
|
937
|
-
56
|
|
938
|
-
]);
|
|
939
|
-
function hashStructuredData(structuredData) {
|
|
940
|
-
return import_sha24.sha256(serializeCVBytes(structuredData));
|
|
444
|
+
function rootFromProof(leafInternal, proof) {
|
|
445
|
+
let hash = leafInternal;
|
|
446
|
+
let index = proof.txIndex;
|
|
447
|
+
for (const sibling of proof.siblings) {
|
|
448
|
+
hash = index % 2 === 1 ? hashPair(sibling, hash) : hashPair(hash, sibling);
|
|
449
|
+
index = Math.floor(index / 2);
|
|
450
|
+
}
|
|
451
|
+
return hash;
|
|
941
452
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
return name?.type === "ascii" && version?.type === "ascii" && chainId?.type === "uint";
|
|
453
|
+
|
|
454
|
+
// src/bitcoin/proof.ts
|
|
455
|
+
function normalizeTxid(txid) {
|
|
456
|
+
return without0x(txid).toLowerCase();
|
|
947
457
|
}
|
|
948
|
-
function
|
|
949
|
-
|
|
950
|
-
|
|
458
|
+
function assembleBlockForTx(args) {
|
|
459
|
+
const txIndex = args.txidsDisplay.indexOf(normalizeTxid(args.txid));
|
|
460
|
+
if (txIndex < 0) {
|
|
461
|
+
throw new Error(`tx ${args.txid} not found in block ${args.blockId}`);
|
|
951
462
|
}
|
|
952
|
-
return
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
463
|
+
return {
|
|
464
|
+
header: hexToBytes(args.headerHex),
|
|
465
|
+
height: args.height,
|
|
466
|
+
txidsInternal: args.txidsDisplay.map((t) => reverseBytes(hexToBytes(t))),
|
|
467
|
+
txIndex
|
|
468
|
+
};
|
|
956
469
|
}
|
|
957
|
-
async function
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
470
|
+
async function buildTxProof(source, params) {
|
|
471
|
+
const { txid, vout } = params;
|
|
472
|
+
const want = normalizeTxid(txid);
|
|
473
|
+
const [rawTx, block] = await Promise.all([
|
|
474
|
+
source.getRawTx(txid),
|
|
475
|
+
source.getBlockForTx(txid)
|
|
476
|
+
]);
|
|
477
|
+
const parsed = parseBitcoinTx(rawTx);
|
|
478
|
+
const gotDisplay = bytesToHex(reverseBytes(parsed.txidInternal));
|
|
479
|
+
if (gotDisplay !== want) {
|
|
480
|
+
throw new Error(`source returned a tx whose id ${gotDisplay} does not match requested ${want}`);
|
|
961
481
|
}
|
|
962
|
-
|
|
482
|
+
const atIndex = block.txidsInternal[block.txIndex];
|
|
483
|
+
if (!atIndex || bytesToHex(atIndex) !== bytesToHex(parsed.txidInternal)) {
|
|
484
|
+
throw new Error(`source txIndex ${block.txIndex} does not point at tx ${want}`);
|
|
485
|
+
}
|
|
486
|
+
const merkle = buildMerkleProof(block.txidsInternal, block.txIndex);
|
|
487
|
+
const headerRoot = parseBlockHeader(block.header).merkleRoot;
|
|
488
|
+
const computed = rootFromProof(parsed.txidInternal, merkle);
|
|
489
|
+
if (bytesToHex(computed) !== bytesToHex(headerRoot)) {
|
|
490
|
+
throw new Error("constructed merkle proof does not reconcile with the block header merkle root");
|
|
491
|
+
}
|
|
492
|
+
return {
|
|
493
|
+
rawTx,
|
|
494
|
+
txidInternal: parsed.txidInternal,
|
|
495
|
+
vout,
|
|
496
|
+
merkle,
|
|
497
|
+
header: block.header,
|
|
498
|
+
height: block.height
|
|
499
|
+
};
|
|
963
500
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
case "buffer":
|
|
976
|
-
if (encoding === "tryAscii") {
|
|
977
|
-
const str = bytesToAscii(hexToBytes(val.value));
|
|
978
|
-
if (/^[ -~]*$/.test(str))
|
|
979
|
-
return JSON.stringify(str);
|
|
501
|
+
function fallbackProofSource(sources) {
|
|
502
|
+
if (sources.length === 0) {
|
|
503
|
+
throw new Error("fallbackProofSource: at least one source is required");
|
|
504
|
+
}
|
|
505
|
+
async function firstSuccess(fn) {
|
|
506
|
+
let lastError;
|
|
507
|
+
for (const source of sources) {
|
|
508
|
+
try {
|
|
509
|
+
return await fn(source);
|
|
510
|
+
} catch (error) {
|
|
511
|
+
lastError = error;
|
|
980
512
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
return "none";
|
|
984
|
-
case "some":
|
|
985
|
-
return `(some ${prettyPrint(val.value, encoding)})`;
|
|
986
|
-
case "ok":
|
|
987
|
-
return `(ok ${prettyPrint(val.value, encoding)})`;
|
|
988
|
-
case "err":
|
|
989
|
-
return `(err ${prettyPrint(val.value, encoding)})`;
|
|
990
|
-
case "address":
|
|
991
|
-
case "contract":
|
|
992
|
-
return val.value;
|
|
993
|
-
case "list":
|
|
994
|
-
return `(list ${val.value.map((v) => prettyPrint(v, encoding)).join(" ")})`;
|
|
995
|
-
case "tuple":
|
|
996
|
-
return `(tuple ${Object.keys(val.value).map((key) => `(${key} ${prettyPrint(val.value[key], encoding)})`).join(" ")})`;
|
|
997
|
-
case "ascii":
|
|
998
|
-
return `"${val.value}"`;
|
|
999
|
-
case "utf8":
|
|
1000
|
-
return `u"${val.value}"`;
|
|
513
|
+
}
|
|
514
|
+
throw lastError;
|
|
1001
515
|
}
|
|
516
|
+
return {
|
|
517
|
+
getRawTx: (txid) => firstSuccess((s) => s.getRawTx(txid)),
|
|
518
|
+
getBlockForTx: (txid) => firstSuccess((s) => s.getBlockForTx(txid))
|
|
519
|
+
};
|
|
1002
520
|
}
|
|
1003
|
-
function
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
return { type: "uint", value: val.value.toString() };
|
|
1013
|
-
case "buffer": {
|
|
1014
|
-
const hex = without0x(val.value);
|
|
1015
|
-
return {
|
|
1016
|
-
type: `(buff ${Math.ceil(hex.length / 2)})`,
|
|
1017
|
-
value: `0x${hex}`
|
|
1018
|
-
};
|
|
521
|
+
function bitcoinRpcSource(config) {
|
|
522
|
+
const doFetch = config.fetch ?? fetch;
|
|
523
|
+
async function rpc(method, rpcParams) {
|
|
524
|
+
const headers = {
|
|
525
|
+
"content-type": "application/json"
|
|
526
|
+
};
|
|
527
|
+
if (config.auth) {
|
|
528
|
+
const basic = typeof config.auth === "string" ? config.auth : btoa(`${config.auth.username}:${config.auth.password}`);
|
|
529
|
+
headers.authorization = `Basic ${basic}`;
|
|
1019
530
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
return { type: "(list)", value: val.value.map(cvToJSON) };
|
|
1033
|
-
case "tuple": {
|
|
1034
|
-
const result = {};
|
|
1035
|
-
for (const key of Object.keys(val.value)) {
|
|
1036
|
-
result[key] = cvToJSON(val.value[key]);
|
|
1037
|
-
}
|
|
1038
|
-
return { type: "(tuple)", value: result };
|
|
531
|
+
const res = await doFetch(config.url, {
|
|
532
|
+
method: "POST",
|
|
533
|
+
headers,
|
|
534
|
+
body: JSON.stringify({
|
|
535
|
+
jsonrpc: "1.0",
|
|
536
|
+
id: "secondlayer",
|
|
537
|
+
method,
|
|
538
|
+
params: rpcParams
|
|
539
|
+
})
|
|
540
|
+
});
|
|
541
|
+
if (!res.ok) {
|
|
542
|
+
throw new Error(`bitcoin rpc ${method} failed: HTTP ${res.status}`);
|
|
1039
543
|
}
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
case "utf8":
|
|
1046
|
-
return {
|
|
1047
|
-
type: `(string-utf8 ${utf8ToBytes(val.value).length})`,
|
|
1048
|
-
value: val.value
|
|
1049
|
-
};
|
|
544
|
+
const json = await res.json();
|
|
545
|
+
if (json.error) {
|
|
546
|
+
throw new Error(`bitcoin rpc ${method} error: ${json.error.message}`);
|
|
547
|
+
}
|
|
548
|
+
return json.result;
|
|
1050
549
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
return `0x${val.value}`;
|
|
1063
|
-
case "none":
|
|
1064
|
-
return null;
|
|
1065
|
-
case "some":
|
|
1066
|
-
return cvToValue(val.value);
|
|
1067
|
-
case "ok":
|
|
1068
|
-
case "err":
|
|
1069
|
-
return cvToValue(val.value);
|
|
1070
|
-
case "address":
|
|
1071
|
-
case "contract":
|
|
1072
|
-
return val.value;
|
|
1073
|
-
case "list":
|
|
1074
|
-
return val.value.map(cvToValue);
|
|
1075
|
-
case "tuple": {
|
|
1076
|
-
const result = {};
|
|
1077
|
-
for (const key of Object.keys(val.value)) {
|
|
1078
|
-
result[key] = cvToValue(val.value[key]);
|
|
550
|
+
return {
|
|
551
|
+
async getRawTx(txid) {
|
|
552
|
+
return hexToBytes(await rpc("getrawtransaction", [txid, false]));
|
|
553
|
+
},
|
|
554
|
+
async getBlockForTx(txid) {
|
|
555
|
+
const tx = await rpc("getrawtransaction", [
|
|
556
|
+
txid,
|
|
557
|
+
true
|
|
558
|
+
]);
|
|
559
|
+
if (!tx.blockhash) {
|
|
560
|
+
throw new Error(`tx ${txid} is not in a block (node needs -txindex, or the tx is unconfirmed)`);
|
|
1079
561
|
}
|
|
1080
|
-
|
|
562
|
+
const block = await rpc("getblock", [
|
|
563
|
+
tx.blockhash,
|
|
564
|
+
1
|
|
565
|
+
]);
|
|
566
|
+
const header = await rpc("getblockheader", [tx.blockhash, false]);
|
|
567
|
+
return assembleBlockForTx({
|
|
568
|
+
txid,
|
|
569
|
+
blockId: tx.blockhash,
|
|
570
|
+
headerHex: header,
|
|
571
|
+
height: block.height,
|
|
572
|
+
txidsDisplay: block.tx
|
|
573
|
+
});
|
|
1081
574
|
}
|
|
1082
|
-
|
|
1083
|
-
case "utf8":
|
|
1084
|
-
return val.value;
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
function cvToBigInt(val) {
|
|
1088
|
-
if (val.type !== "int" && val.type !== "uint") {
|
|
1089
|
-
throw new Error(`cvToBigInt: expected int or uint, got ${val.type}`);
|
|
1090
|
-
}
|
|
1091
|
-
return val.value;
|
|
1092
|
-
}
|
|
1093
|
-
function cvToString(val) {
|
|
1094
|
-
if (val.type !== "ascii" && val.type !== "utf8") {
|
|
1095
|
-
throw new Error(`cvToString: expected ascii or utf8, got ${val.type}`);
|
|
1096
|
-
}
|
|
1097
|
-
return val.value;
|
|
1098
|
-
}
|
|
1099
|
-
function cvToBuffer(val) {
|
|
1100
|
-
if (val.type !== "buffer") {
|
|
1101
|
-
throw new Error(`cvToBuffer: expected buffer, got ${val.type}`);
|
|
1102
|
-
}
|
|
1103
|
-
return val.value;
|
|
1104
|
-
}
|
|
1105
|
-
function cvToBoolean(val) {
|
|
1106
|
-
if (val.type !== "true" && val.type !== "false") {
|
|
1107
|
-
throw new Error(`cvToBoolean: expected bool, got ${val.type}`);
|
|
1108
|
-
}
|
|
1109
|
-
return val.type === "true";
|
|
575
|
+
};
|
|
1110
576
|
}
|
|
1111
|
-
function
|
|
1112
|
-
|
|
1113
|
-
|
|
577
|
+
function esploraSource(config) {
|
|
578
|
+
const doFetch = config.fetch ?? fetch;
|
|
579
|
+
const base = config.url.replace(/\/+$/, "");
|
|
580
|
+
async function get(path) {
|
|
581
|
+
const res = await doFetch(`${base}${path}`);
|
|
582
|
+
if (!res.ok) {
|
|
583
|
+
throw new Error(`esplora GET ${path} failed: HTTP ${res.status}`);
|
|
584
|
+
}
|
|
585
|
+
return res;
|
|
1114
586
|
}
|
|
1115
|
-
return
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
}
|
|
1136
|
-
function isContractPrincipal(value) {
|
|
1137
|
-
if (typeof value !== "string")
|
|
1138
|
-
return false;
|
|
1139
|
-
const parsed = parsePrincipal(value);
|
|
1140
|
-
return parsed !== null && parsed.contractName !== undefined;
|
|
1141
|
-
}
|
|
1142
|
-
function isTraitReference(value) {
|
|
1143
|
-
return isContractPrincipal(value);
|
|
1144
|
-
}
|
|
1145
|
-
function isString(value) {
|
|
1146
|
-
return typeof value === "string";
|
|
1147
|
-
}
|
|
1148
|
-
function isUint8Array(value) {
|
|
1149
|
-
return value instanceof Uint8Array;
|
|
1150
|
-
}
|
|
1151
|
-
function isArray(value, itemGuard) {
|
|
1152
|
-
return Array.isArray(value) && value.every(itemGuard);
|
|
1153
|
-
}
|
|
1154
|
-
function isOptional(value, guard) {
|
|
1155
|
-
return value === null || guard(value);
|
|
1156
|
-
}
|
|
1157
|
-
function isOkResponse(response) {
|
|
1158
|
-
return "ok" in response && !("err" in response);
|
|
1159
|
-
}
|
|
1160
|
-
function isErrResponse(response) {
|
|
1161
|
-
return "err" in response && !("ok" in response);
|
|
1162
|
-
}
|
|
1163
|
-
function isResponse(value, okGuard, errGuard) {
|
|
1164
|
-
if (typeof value !== "object" || value === null)
|
|
1165
|
-
return false;
|
|
1166
|
-
const obj = value;
|
|
1167
|
-
if ("ok" in value && !("err" in value))
|
|
1168
|
-
return okGuard(obj.ok);
|
|
1169
|
-
if ("err" in value && !("ok" in value))
|
|
1170
|
-
return errGuard(obj.err);
|
|
1171
|
-
return false;
|
|
1172
|
-
}
|
|
1173
|
-
function isAbiList(type) {
|
|
1174
|
-
return typeof type === "object" && type !== null && "list" in type;
|
|
1175
|
-
}
|
|
1176
|
-
function isAbiTuple(type) {
|
|
1177
|
-
return typeof type === "object" && type !== null && "tuple" in type;
|
|
1178
|
-
}
|
|
1179
|
-
function isAbiOptional(type) {
|
|
1180
|
-
return typeof type === "object" && type !== null && "optional" in type;
|
|
1181
|
-
}
|
|
1182
|
-
function isAbiResponse(type) {
|
|
1183
|
-
return typeof type === "object" && type !== null && "response" in type;
|
|
1184
|
-
}
|
|
1185
|
-
function isAbiBuffer(type) {
|
|
1186
|
-
return typeof type === "object" && type !== null && "buff" in type;
|
|
1187
|
-
}
|
|
1188
|
-
function isAbiStringAscii(type) {
|
|
1189
|
-
return typeof type === "object" && type !== null && "string-ascii" in type;
|
|
1190
|
-
}
|
|
1191
|
-
function isAbiStringUtf8(type) {
|
|
1192
|
-
return typeof type === "object" && type !== null && "string-utf8" in type;
|
|
1193
|
-
}
|
|
1194
|
-
function isAbiTraitReference(type) {
|
|
1195
|
-
return type === "trait_reference";
|
|
1196
|
-
}
|
|
1197
|
-
// src/clarity/abi/utils.ts
|
|
1198
|
-
function toCamelCase(str) {
|
|
1199
|
-
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()).replace(/-([A-Z])/g, (_, letter) => letter).replace(/-(\d)/g, (_, digit) => digit).replace(/-/g, "").replace(/^\d/, "_$&");
|
|
587
|
+
return {
|
|
588
|
+
async getRawTx(txid) {
|
|
589
|
+
return hexToBytes((await (await get(`/tx/${txid}/hex`)).text()).trim());
|
|
590
|
+
},
|
|
591
|
+
async getBlockForTx(txid) {
|
|
592
|
+
const status = await (await get(`/tx/${txid}`)).json();
|
|
593
|
+
if (!status.status.confirmed) {
|
|
594
|
+
throw new Error(`tx ${txid} is unconfirmed`);
|
|
595
|
+
}
|
|
596
|
+
const blockHashHex = status.status.block_hash;
|
|
597
|
+
const header = (await (await get(`/block/${blockHashHex}/header`)).text()).trim();
|
|
598
|
+
const txids = await (await get(`/block/${blockHashHex}/txids`)).json();
|
|
599
|
+
return assembleBlockForTx({
|
|
600
|
+
txid,
|
|
601
|
+
blockId: blockHashHex,
|
|
602
|
+
headerHex: header,
|
|
603
|
+
height: status.status.block_height,
|
|
604
|
+
txidsDisplay: txids
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
};
|
|
1200
608
|
}
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
609
|
+
// src/clarity/index.ts
|
|
610
|
+
var exports_clarity = {};
|
|
611
|
+
__export(exports_clarity, {
|
|
612
|
+
CONTRACT_NAME_REGEX: () => CONTRACT_NAME_REGEX,
|
|
613
|
+
Cl: () => Cl,
|
|
614
|
+
ClarityConversionError: () => ClarityConversionError,
|
|
615
|
+
ClarityWireType: () => ClarityWireType,
|
|
616
|
+
SIP009_ABI: () => SIP009_ABI,
|
|
617
|
+
SIP010_ABI: () => SIP010_ABI,
|
|
618
|
+
SIP013_ABI: () => SIP013_ABI,
|
|
619
|
+
SIP018_PREFIX: () => SIP018_PREFIX,
|
|
620
|
+
TRAIT_STANDARDS: () => TRAIT_STANDARDS,
|
|
621
|
+
boolCV: () => boolCV,
|
|
622
|
+
bufferCV: () => bufferCV,
|
|
623
|
+
clarityTypeFromByte: () => clarityTypeFromByte,
|
|
624
|
+
clarityValueToJS: () => clarityValueToJS,
|
|
625
|
+
clarityValueToJSUntyped: () => clarityValueToJSUntyped,
|
|
626
|
+
classifyContract: () => classifyContract,
|
|
627
|
+
contractPrincipalCV: () => contractPrincipalCV,
|
|
628
|
+
cvToBigInt: () => cvToBigInt,
|
|
629
|
+
cvToBoolean: () => cvToBoolean,
|
|
630
|
+
cvToBuffer: () => cvToBuffer,
|
|
631
|
+
cvToJSON: () => cvToJSON,
|
|
632
|
+
cvToPrincipal: () => cvToPrincipal,
|
|
633
|
+
cvToString: () => cvToString,
|
|
634
|
+
cvToValue: () => cvToValue,
|
|
635
|
+
deserializeCV: () => deserializeCV,
|
|
636
|
+
deserializeCVBytes: () => deserializeCVBytes,
|
|
637
|
+
encodeStructuredData: () => encodeStructuredData,
|
|
638
|
+
falseCV: () => falseCV,
|
|
639
|
+
hashStructuredData: () => hashStructuredData,
|
|
640
|
+
intCV: () => intCV,
|
|
641
|
+
isAbiBuffer: () => isAbiBuffer,
|
|
642
|
+
isAbiList: () => isAbiList,
|
|
643
|
+
isAbiOptional: () => isAbiOptional,
|
|
644
|
+
isAbiResponse: () => isAbiResponse,
|
|
645
|
+
isAbiStringAscii: () => isAbiStringAscii,
|
|
646
|
+
isAbiStringUtf8: () => isAbiStringUtf8,
|
|
647
|
+
isAbiTraitReference: () => isAbiTraitReference,
|
|
648
|
+
isAbiTuple: () => isAbiTuple,
|
|
649
|
+
isArray: () => isArray,
|
|
650
|
+
isBool: () => isBool,
|
|
651
|
+
isClarityValue: () => isClarityValue,
|
|
652
|
+
isContractPrincipal: () => isContractPrincipal,
|
|
653
|
+
isErrResponse: () => isErrResponse,
|
|
654
|
+
isInt128: () => isInt128,
|
|
655
|
+
isOkResponse: () => isOkResponse,
|
|
656
|
+
isOptional: () => isOptional,
|
|
657
|
+
isPrincipal: () => isPrincipal,
|
|
658
|
+
isResponse: () => isResponse,
|
|
659
|
+
isStandardPrincipal: () => isStandardPrincipal,
|
|
660
|
+
isString: () => isString,
|
|
661
|
+
isTraitReference: () => isTraitReference,
|
|
662
|
+
isUint128: () => isUint128,
|
|
663
|
+
isUint8Array: () => isUint8Array,
|
|
664
|
+
jsToClarity: () => jsToClarity,
|
|
665
|
+
jsToClarityValue: () => jsToClarityValue,
|
|
666
|
+
listCV: () => listCV,
|
|
667
|
+
noneCV: () => noneCV,
|
|
668
|
+
normalizeAbi: () => normalizeAbi,
|
|
669
|
+
normalizeAccess: () => normalizeAccess,
|
|
670
|
+
normalizeType: () => normalizeType,
|
|
671
|
+
parseDeclaredStandards: () => parseDeclaredStandards,
|
|
672
|
+
prepareArgs: () => prepareArgs,
|
|
673
|
+
prettyPrint: () => prettyPrint,
|
|
674
|
+
responseErrorCV: () => responseErrorCV,
|
|
675
|
+
responseOkCV: () => responseOkCV,
|
|
676
|
+
serializeCV: () => serializeCV,
|
|
677
|
+
serializeCVBytes: () => serializeCVBytes,
|
|
678
|
+
signStructuredData: () => signStructuredData,
|
|
679
|
+
sip009Abi: () => sip009Abi,
|
|
680
|
+
sip010Abi: () => sip010Abi,
|
|
681
|
+
sip013Abi: () => sip013Abi,
|
|
682
|
+
someCV: () => someCV,
|
|
683
|
+
standardPrincipalCV: () => standardPrincipalCV,
|
|
684
|
+
stringAsciiCV: () => stringAsciiCV,
|
|
685
|
+
stringUtf8CV: () => stringUtf8CV,
|
|
686
|
+
structuredDataHash: () => structuredDataHash,
|
|
687
|
+
toCamelCase: () => toCamelCase,
|
|
688
|
+
trueCV: () => trueCV,
|
|
689
|
+
tupleCV: () => tupleCV,
|
|
690
|
+
uintCV: () => uintCV,
|
|
691
|
+
validateArgs: () => validateArgs,
|
|
692
|
+
validateArgsArray: () => validateArgsArray
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// src/clarity/types.ts
|
|
696
|
+
var ClarityWireType = {
|
|
697
|
+
int: 0,
|
|
698
|
+
uint: 1,
|
|
699
|
+
buffer: 2,
|
|
700
|
+
true: 3,
|
|
701
|
+
false: 4,
|
|
702
|
+
address: 5,
|
|
703
|
+
contract: 6,
|
|
704
|
+
ok: 7,
|
|
705
|
+
err: 8,
|
|
706
|
+
none: 9,
|
|
707
|
+
some: 10,
|
|
708
|
+
list: 11,
|
|
709
|
+
tuple: 12,
|
|
710
|
+
ascii: 13,
|
|
711
|
+
utf8: 14
|
|
712
|
+
};
|
|
713
|
+
var wireTypeToClarity = Object.fromEntries(Object.entries(ClarityWireType).map(([k, v]) => [v, k]));
|
|
714
|
+
function clarityTypeFromByte(byte) {
|
|
715
|
+
const type = wireTypeToClarity[byte];
|
|
716
|
+
if (!type)
|
|
717
|
+
throw new Error(`Unknown clarity wire type: ${byte}`);
|
|
718
|
+
return type;
|
|
719
|
+
}
|
|
720
|
+
// src/utils/c32.ts
|
|
721
|
+
var import_sha23 = require("@noble/hashes/sha2.js");
|
|
722
|
+
var C32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
723
|
+
var HEX = "0123456789abcdef";
|
|
724
|
+
function c32normalize(input) {
|
|
725
|
+
return input.toUpperCase().replace(/O/g, "0").replace(/L|I/g, "1");
|
|
726
|
+
}
|
|
727
|
+
function c32encode(inputHex) {
|
|
728
|
+
let hex = inputHex;
|
|
729
|
+
if (hex.length % 2 !== 0)
|
|
730
|
+
hex = `0${hex}`;
|
|
731
|
+
hex = hex.toLowerCase();
|
|
732
|
+
const res = [];
|
|
733
|
+
let carry = 0;
|
|
734
|
+
for (let i = hex.length - 1;i >= 0; i--) {
|
|
735
|
+
if (carry < 4) {
|
|
736
|
+
const currentCode = HEX.indexOf(hex[i]) >> carry;
|
|
737
|
+
const nextCode = i !== 0 ? HEX.indexOf(hex[i - 1]) : 0;
|
|
738
|
+
const nextBits = 1 + carry;
|
|
739
|
+
const nextLowBits = nextCode % (1 << nextBits) << 5 - nextBits;
|
|
740
|
+
res.unshift(C32[currentCode + nextLowBits]);
|
|
741
|
+
carry = nextBits;
|
|
742
|
+
} else {
|
|
743
|
+
carry = 0;
|
|
744
|
+
}
|
|
1211
745
|
}
|
|
746
|
+
let leadingZeros = 0;
|
|
747
|
+
while (leadingZeros < res.length && res[leadingZeros] === "0")
|
|
748
|
+
leadingZeros++;
|
|
749
|
+
const stripped = res.slice(leadingZeros);
|
|
750
|
+
const bytes = hexToBytes(hex);
|
|
751
|
+
let zeroBytesCount = 0;
|
|
752
|
+
while (zeroBytesCount < bytes.length && bytes[zeroBytesCount] === 0)
|
|
753
|
+
zeroBytesCount++;
|
|
754
|
+
const prefix = Array(zeroBytesCount).fill(C32[0]);
|
|
755
|
+
return [...prefix, ...stripped].join("");
|
|
1212
756
|
}
|
|
1213
|
-
function
|
|
1214
|
-
|
|
757
|
+
function c32decode(c32input) {
|
|
758
|
+
const input = c32normalize(c32input);
|
|
759
|
+
if (!input.match(`^[${C32}]*$`))
|
|
760
|
+
throw new Error("Not a c32-encoded string");
|
|
761
|
+
const zeroPrefix = input.match(`^${C32[0]}*`);
|
|
762
|
+
const numLeadingZeroBytes = zeroPrefix ? zeroPrefix[0]?.length : 0;
|
|
763
|
+
const res = [];
|
|
764
|
+
let carry = 0;
|
|
765
|
+
let carryBits = 0;
|
|
766
|
+
for (let i = input.length - 1;i >= 0; i--) {
|
|
767
|
+
if (carryBits === 4) {
|
|
768
|
+
res.unshift(HEX[carry]);
|
|
769
|
+
carryBits = 0;
|
|
770
|
+
carry = 0;
|
|
771
|
+
}
|
|
772
|
+
const currentValue = (C32.indexOf(input[i]) << carryBits) + carry;
|
|
773
|
+
res.unshift(HEX[currentValue % 16]);
|
|
774
|
+
carryBits += 1;
|
|
775
|
+
carry = currentValue >> 4;
|
|
776
|
+
if (carry > 1 << carryBits)
|
|
777
|
+
throw new Error("Panic error in c32 decoding");
|
|
778
|
+
}
|
|
779
|
+
res.unshift(HEX[carry]);
|
|
780
|
+
if (res.length % 2 === 1)
|
|
781
|
+
res.unshift("0");
|
|
782
|
+
let hexLeadingZeros = 0;
|
|
783
|
+
while (hexLeadingZeros < res.length && res[hexLeadingZeros] === "0")
|
|
784
|
+
hexLeadingZeros++;
|
|
785
|
+
let hexStr = res.slice(hexLeadingZeros - hexLeadingZeros % 2).join("");
|
|
786
|
+
for (let i = 0;i < numLeadingZeroBytes; i++)
|
|
787
|
+
hexStr = `00${hexStr}`;
|
|
788
|
+
return hexStr;
|
|
789
|
+
}
|
|
790
|
+
function c32checksum(dataHex) {
|
|
791
|
+
return bytesToHex(import_sha23.sha256(import_sha23.sha256(hexToBytes(dataHex))).slice(0, 4));
|
|
792
|
+
}
|
|
793
|
+
function c32checkEncode(version, data) {
|
|
794
|
+
if (version < 0 || version >= 32)
|
|
795
|
+
throw new Error("Invalid version (must be between 0 and 31)");
|
|
796
|
+
if (!data.match(/^[0-9a-fA-F]*$/))
|
|
797
|
+
throw new Error("Invalid data (not a hex string)");
|
|
798
|
+
let d = data.toLowerCase();
|
|
799
|
+
if (d.length % 2 !== 0)
|
|
800
|
+
d = `0${d}`;
|
|
801
|
+
let versionHex = version.toString(16);
|
|
802
|
+
if (versionHex.length === 1)
|
|
803
|
+
versionHex = `0${versionHex}`;
|
|
804
|
+
const checksumHex = c32checksum(`${versionHex}${d}`);
|
|
805
|
+
return `${C32[version]}${c32encode(`${d}${checksumHex}`)}`;
|
|
806
|
+
}
|
|
807
|
+
function c32checkDecode(c32data) {
|
|
808
|
+
const normalized = c32normalize(c32data);
|
|
809
|
+
const dataHex = c32decode(normalized.slice(1));
|
|
810
|
+
const version = C32.indexOf(normalized[0]);
|
|
811
|
+
const checksum = dataHex.slice(-8);
|
|
812
|
+
let versionHex = version.toString(16);
|
|
813
|
+
if (versionHex.length === 1)
|
|
814
|
+
versionHex = `0${versionHex}`;
|
|
815
|
+
if (c32checksum(`${versionHex}${dataHex.substring(0, dataHex.length - 8)}`) !== checksum) {
|
|
816
|
+
throw new Error("Invalid c32check string: checksum mismatch");
|
|
817
|
+
}
|
|
818
|
+
return [version, dataHex.substring(0, dataHex.length - 8)];
|
|
819
|
+
}
|
|
820
|
+
function c32address(version, hash160hex) {
|
|
821
|
+
if (!hash160hex.match(/^[0-9a-fA-F]{40}$/)) {
|
|
822
|
+
throw new Error("Invalid argument: not a hash160 hex string");
|
|
823
|
+
}
|
|
824
|
+
return `S${c32checkEncode(version, hash160hex)}`;
|
|
825
|
+
}
|
|
826
|
+
function c32addressDecode(c32addr) {
|
|
827
|
+
if (c32addr.length <= 5)
|
|
828
|
+
throw new Error("Invalid c32 address: invalid length");
|
|
829
|
+
if (c32addr[0] !== "S")
|
|
830
|
+
throw new Error('Invalid c32 address: must start with "S"');
|
|
831
|
+
return c32checkDecode(c32addr.slice(1));
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// src/utils/constants.ts
|
|
835
|
+
var MAX_U128 = (1n << 128n) - 1n;
|
|
836
|
+
var MAX_I128 = (1n << 127n) - 1n;
|
|
837
|
+
var MIN_I128 = -(1n << 127n);
|
|
838
|
+
var AddressVersion = {
|
|
839
|
+
MainnetSingleSig: 22,
|
|
840
|
+
MainnetMultiSig: 20,
|
|
841
|
+
TestnetSingleSig: 26,
|
|
842
|
+
TestnetMultiSig: 21
|
|
843
|
+
};
|
|
844
|
+
var ZERO_ADDRESS = "SP000000000000000000002Q6VF78";
|
|
845
|
+
var TESTNET_ZERO_ADDRESS = "ST000000000000000000002AMW42H";
|
|
846
|
+
var MICROSTX_PER_STX = 1000000n;
|
|
847
|
+
|
|
848
|
+
// src/utils/address.ts
|
|
849
|
+
function publicKeyToAddress(publicKey, network = "mainnet") {
|
|
850
|
+
const bytes = typeof publicKey === "string" ? hexToBytes(without0x(publicKey)) : publicKey;
|
|
851
|
+
const version = network === "mainnet" ? AddressVersion.MainnetSingleSig : AddressVersion.TestnetSingleSig;
|
|
852
|
+
return c32address(version, bytesToHex(hash160(bytes)));
|
|
853
|
+
}
|
|
854
|
+
var CONTRACT_NAME_REGEX = /^[a-zA-Z][a-zA-Z0-9_-]{0,127}$/;
|
|
855
|
+
function validateStacksAddress(address) {
|
|
856
|
+
try {
|
|
857
|
+
c32addressDecode(address);
|
|
858
|
+
return true;
|
|
859
|
+
} catch {
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
var isValidAddress = validateStacksAddress;
|
|
864
|
+
function parsePrincipal(value) {
|
|
865
|
+
const parts = value.split(".");
|
|
866
|
+
if (parts.length > 2)
|
|
1215
867
|
return null;
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
868
|
+
const [address, contractName] = parts;
|
|
869
|
+
if (!validateStacksAddress(address))
|
|
870
|
+
return null;
|
|
871
|
+
if (contractName === undefined)
|
|
872
|
+
return { address };
|
|
873
|
+
if (!CONTRACT_NAME_REGEX.test(contractName))
|
|
874
|
+
return null;
|
|
875
|
+
return { address, contractName };
|
|
876
|
+
}
|
|
877
|
+
function parseContractId(contractId) {
|
|
878
|
+
const parsed = parsePrincipal(contractId);
|
|
879
|
+
if (!parsed?.contractName)
|
|
880
|
+
throw new Error(`Invalid contract identifier: ${contractId}`);
|
|
881
|
+
return [parsed.address, parsed.contractName];
|
|
882
|
+
}
|
|
883
|
+
function isClarityName(name) {
|
|
884
|
+
const regex = /^[a-zA-Z]([a-zA-Z0-9]|[-_!?+<>=/*])*$|^[-+=/*]$|^[<>]=?$/;
|
|
885
|
+
return regex.test(name) && name.length < 128;
|
|
886
|
+
}
|
|
887
|
+
function isAddressEqual(a, b) {
|
|
888
|
+
const [versionA, hashA] = c32addressDecode(a);
|
|
889
|
+
const [versionB, hashB] = c32addressDecode(b);
|
|
890
|
+
return versionA === versionB && hashA.toLowerCase() === hashB.toLowerCase();
|
|
891
|
+
}
|
|
892
|
+
function addressToVersion(address) {
|
|
893
|
+
return c32addressDecode(address)[0];
|
|
894
|
+
}
|
|
895
|
+
function getContractAddress(deployer, contractName) {
|
|
896
|
+
if (!validateStacksAddress(deployer)) {
|
|
897
|
+
throw new Error(`Invalid deployer address: ${deployer}`);
|
|
1220
898
|
}
|
|
1221
|
-
if (
|
|
1222
|
-
|
|
1223
|
-
throw new ClarityConversionError("Invalid int128 value", type, value);
|
|
1224
|
-
return value;
|
|
899
|
+
if (!isClarityName(contractName)) {
|
|
900
|
+
throw new Error(`Invalid contract name: ${contractName}`);
|
|
1225
901
|
}
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
902
|
+
return `${deployer}.${contractName}`;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// src/errors/base.ts
|
|
906
|
+
function codeFromName(name) {
|
|
907
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").toUpperCase();
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
class BaseError extends Error {
|
|
911
|
+
name = "StacksError";
|
|
912
|
+
#code;
|
|
913
|
+
shortMessage;
|
|
914
|
+
details;
|
|
915
|
+
constructor(shortMessage, options) {
|
|
916
|
+
const message = [
|
|
917
|
+
shortMessage,
|
|
918
|
+
options?.details ? `
|
|
919
|
+
${options.details}` : ""
|
|
920
|
+
].join("");
|
|
921
|
+
super(message, { cause: options?.cause });
|
|
922
|
+
if (options?.code !== undefined)
|
|
923
|
+
this.#code = options.code;
|
|
924
|
+
this.shortMessage = shortMessage;
|
|
925
|
+
this.details = options?.details;
|
|
926
|
+
}
|
|
927
|
+
get code() {
|
|
928
|
+
return this.#code ?? codeFromName(this.name);
|
|
929
|
+
}
|
|
930
|
+
set code(value) {
|
|
931
|
+
this.#code = value;
|
|
932
|
+
}
|
|
933
|
+
toJSON() {
|
|
934
|
+
return {
|
|
935
|
+
name: this.name,
|
|
936
|
+
code: this.code,
|
|
937
|
+
message: this.message,
|
|
938
|
+
shortMessage: this.shortMessage,
|
|
939
|
+
details: this.details,
|
|
940
|
+
cause: this.cause instanceof Error ? this.cause.message : undefined
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// src/errors/transaction.ts
|
|
946
|
+
class TransactionError extends BaseError {
|
|
947
|
+
name = "TransactionError";
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
class BroadcastError extends BaseError {
|
|
951
|
+
name = "BroadcastError";
|
|
952
|
+
txid;
|
|
953
|
+
reason;
|
|
954
|
+
reasonData;
|
|
955
|
+
constructor(message, options) {
|
|
956
|
+
super(message, options);
|
|
957
|
+
this.txid = options?.txid;
|
|
958
|
+
this.reason = options?.reason;
|
|
959
|
+
this.reasonData = options?.reasonData;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
class TransactionAbortedError extends BaseError {
|
|
964
|
+
name = "TransactionAbortedError";
|
|
965
|
+
receipt;
|
|
966
|
+
constructor(message, options) {
|
|
967
|
+
super(message, options);
|
|
968
|
+
this.receipt = options.receipt;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
class TransactionDroppedError extends BaseError {
|
|
973
|
+
name = "TransactionDroppedError";
|
|
974
|
+
txid;
|
|
975
|
+
constructor(message, options) {
|
|
976
|
+
super(message, options);
|
|
977
|
+
this.txid = options.txid;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
class WaitForTransactionTimeoutError extends BaseError {
|
|
982
|
+
name = "WaitForTransactionTimeoutError";
|
|
983
|
+
txid;
|
|
984
|
+
constructor(message, options) {
|
|
985
|
+
super(message, options);
|
|
986
|
+
this.txid = options.txid;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
class SerializationError extends BaseError {
|
|
991
|
+
name = "SerializationError";
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
class SigningError extends BaseError {
|
|
995
|
+
name = "SigningError";
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// src/utils/bytes-reader.ts
|
|
999
|
+
class BytesReader {
|
|
1000
|
+
data;
|
|
1001
|
+
offset = 0;
|
|
1002
|
+
constructor(data) {
|
|
1003
|
+
this.data = data;
|
|
1004
|
+
}
|
|
1005
|
+
remaining() {
|
|
1006
|
+
return this.data.length - this.offset;
|
|
1007
|
+
}
|
|
1008
|
+
ensure(length) {
|
|
1009
|
+
if (this.offset + length > this.data.length) {
|
|
1010
|
+
throw new SerializationError(`Buffer underflow: need ${length} bytes at offset ${this.offset}, have ${this.data.length}`);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
readUInt8() {
|
|
1014
|
+
this.ensure(1);
|
|
1015
|
+
return this.data[this.offset++];
|
|
1016
|
+
}
|
|
1017
|
+
readUInt16BE() {
|
|
1018
|
+
this.ensure(2);
|
|
1019
|
+
const val = (this.data[this.offset] << 8 | this.data[this.offset + 1]) >>> 0;
|
|
1020
|
+
this.offset += 2;
|
|
1021
|
+
return val;
|
|
1022
|
+
}
|
|
1023
|
+
readUInt32BE() {
|
|
1024
|
+
this.ensure(4);
|
|
1025
|
+
const val = (this.data[this.offset] << 24 | this.data[this.offset + 1] << 16 | this.data[this.offset + 2] << 8 | this.data[this.offset + 3]) >>> 0;
|
|
1026
|
+
this.offset += 4;
|
|
1027
|
+
return val;
|
|
1028
|
+
}
|
|
1029
|
+
readBytes(length) {
|
|
1030
|
+
this.ensure(length);
|
|
1031
|
+
const slice = this.data.slice(this.offset, this.offset + length);
|
|
1032
|
+
this.offset += length;
|
|
1033
|
+
return slice;
|
|
1230
1034
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
return value;
|
|
1035
|
+
readBigUInt64BE() {
|
|
1036
|
+
const hex = bytesToHex(this.readBytes(8));
|
|
1037
|
+
return hex.length > 0 ? BigInt(`0x${hex}`) : 0n;
|
|
1235
1038
|
}
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// src/clarity/deserialize.ts
|
|
1042
|
+
function readAddress(reader) {
|
|
1043
|
+
const version = reader.readUInt8();
|
|
1044
|
+
const hash160 = bytesToHex(reader.readBytes(20));
|
|
1045
|
+
return c32address(version, hash160);
|
|
1046
|
+
}
|
|
1047
|
+
function readLPString(reader, prefixBytes = 1) {
|
|
1048
|
+
let length = 0;
|
|
1049
|
+
for (let i = 0;i < prefixBytes; i++) {
|
|
1050
|
+
length = length << 8 | reader.readUInt8();
|
|
1240
1051
|
}
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
}
|
|
1250
|
-
if (str.length > type["string-ascii"].length) {
|
|
1251
|
-
throw new ClarityConversionError(`String length ${str.length} exceeds max ${type["string-ascii"].length}`, type, value);
|
|
1252
|
-
}
|
|
1253
|
-
return value;
|
|
1052
|
+
return bytesToUtf8(reader.readBytes(length));
|
|
1053
|
+
}
|
|
1054
|
+
var MAX_CV_DEPTH = 64;
|
|
1055
|
+
var MIN_LIST_ITEM_BYTES = 1;
|
|
1056
|
+
var MIN_TUPLE_ENTRY_BYTES = 2;
|
|
1057
|
+
function checkCount(reader, count, minBytes) {
|
|
1058
|
+
if (count * minBytes > reader.remaining()) {
|
|
1059
|
+
throw new SerializationError(`Clarity value declares ${count} elements but only ${reader.remaining()} bytes remain`);
|
|
1254
1060
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
const byteLength = new TextEncoder().encode(str).length;
|
|
1260
|
-
if (byteLength > type["string-utf8"].length) {
|
|
1261
|
-
throw new ClarityConversionError(`String byte length ${byteLength} exceeds max ${type["string-utf8"].length}`, type, value);
|
|
1262
|
-
}
|
|
1263
|
-
return value;
|
|
1061
|
+
}
|
|
1062
|
+
function readCV(reader, depth = 0) {
|
|
1063
|
+
if (depth > MAX_CV_DEPTH) {
|
|
1064
|
+
throw new SerializationError(`Clarity value nests deeper than ${MAX_CV_DEPTH} levels`);
|
|
1264
1065
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1066
|
+
const typeByte = reader.readUInt8();
|
|
1067
|
+
const type = clarityTypeFromByte(typeByte);
|
|
1068
|
+
switch (type) {
|
|
1069
|
+
case "int":
|
|
1070
|
+
return intCV(bytesToTwosBigInt(reader.readBytes(16)));
|
|
1071
|
+
case "uint":
|
|
1072
|
+
return uintCV(reader.readBytes(16));
|
|
1073
|
+
case "true":
|
|
1074
|
+
return trueCV();
|
|
1075
|
+
case "false":
|
|
1076
|
+
return falseCV();
|
|
1077
|
+
case "buffer": {
|
|
1078
|
+
const len = reader.readUInt32BE();
|
|
1079
|
+
return bufferCV(reader.readBytes(len));
|
|
1271
1080
|
}
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1081
|
+
case "none":
|
|
1082
|
+
return noneCV();
|
|
1083
|
+
case "some":
|
|
1084
|
+
return someCV(readCV(reader, depth + 1));
|
|
1085
|
+
case "ok":
|
|
1086
|
+
return responseOkCV(readCV(reader, depth + 1));
|
|
1087
|
+
case "err":
|
|
1088
|
+
return responseErrorCV(readCV(reader, depth + 1));
|
|
1089
|
+
case "address":
|
|
1090
|
+
return standardPrincipalCV(readAddress(reader));
|
|
1091
|
+
case "contract": {
|
|
1092
|
+
const addr = readAddress(reader);
|
|
1093
|
+
const name = readLPString(reader);
|
|
1094
|
+
return contractPrincipalCV(addr, name);
|
|
1279
1095
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
for (const field of type.tuple) {
|
|
1287
|
-
const camelKey = toCamelCase(field.name);
|
|
1288
|
-
const hasOriginal = field.name in value;
|
|
1289
|
-
const hasCamel = camelKey in value;
|
|
1290
|
-
if (!hasOriginal && !hasCamel) {
|
|
1291
|
-
throw new ClarityConversionError(`Missing tuple field: ${field.name}`, type, value);
|
|
1096
|
+
case "list": {
|
|
1097
|
+
const len = reader.readUInt32BE();
|
|
1098
|
+
checkCount(reader, len, MIN_LIST_ITEM_BYTES);
|
|
1099
|
+
const items = [];
|
|
1100
|
+
for (let i = 0;i < len; i++) {
|
|
1101
|
+
items.push(readCV(reader, depth + 1));
|
|
1292
1102
|
}
|
|
1293
|
-
|
|
1294
|
-
result[field.name] = jsToClarity(field.type, fieldValue);
|
|
1103
|
+
return listCV(items);
|
|
1295
1104
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
throw new ClarityConversionError("Expected object for response type", type, value);
|
|
1306
|
-
const hasOk = "ok" in value;
|
|
1307
|
-
const hasErr = "err" in value;
|
|
1308
|
-
if (hasOk && !hasErr) {
|
|
1309
|
-
return {
|
|
1310
|
-
ok: jsToClarity(type.response.ok, value.ok)
|
|
1311
|
-
};
|
|
1105
|
+
case "tuple": {
|
|
1106
|
+
const len = reader.readUInt32BE();
|
|
1107
|
+
checkCount(reader, len, MIN_TUPLE_ENTRY_BYTES);
|
|
1108
|
+
const data = {};
|
|
1109
|
+
for (let i = 0;i < len; i++) {
|
|
1110
|
+
const key = readLPString(reader);
|
|
1111
|
+
data[key] = readCV(reader, depth + 1);
|
|
1112
|
+
}
|
|
1113
|
+
return tupleCV(data);
|
|
1312
1114
|
}
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
};
|
|
1115
|
+
case "ascii": {
|
|
1116
|
+
const len = reader.readUInt32BE();
|
|
1117
|
+
return stringAsciiCV(bytesToAscii(reader.readBytes(len)));
|
|
1317
1118
|
}
|
|
1318
|
-
|
|
1119
|
+
case "utf8": {
|
|
1120
|
+
const len = reader.readUInt32BE();
|
|
1121
|
+
return stringUtf8CV(bytesToUtf8(reader.readBytes(len)));
|
|
1122
|
+
}
|
|
1123
|
+
default:
|
|
1124
|
+
throw new SerializationError(`Cannot deserialize unknown clarity type: ${type}`);
|
|
1319
1125
|
}
|
|
1320
|
-
throw new ClarityConversionError("Unknown Clarity type", type, value);
|
|
1321
1126
|
}
|
|
1322
|
-
function
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
throw new ClarityConversionError(`Missing argument: ${arg.name}`, arg.type, undefined);
|
|
1326
|
-
}
|
|
1327
|
-
return jsToClarity(arg.type, args[arg.name]);
|
|
1328
|
-
});
|
|
1127
|
+
function deserializeCVBytes(input) {
|
|
1128
|
+
const bytes = typeof input === "string" ? hexToBytes(without0x(input)) : input;
|
|
1129
|
+
return readCV(new BytesReader(bytes));
|
|
1329
1130
|
}
|
|
1330
|
-
function
|
|
1331
|
-
|
|
1332
|
-
if (!(arg.name in args)) {
|
|
1333
|
-
throw new ClarityConversionError(`Missing argument: ${arg.name}`, arg.type, undefined);
|
|
1334
|
-
}
|
|
1335
|
-
jsToClarity(arg.type, args[arg.name]);
|
|
1336
|
-
}
|
|
1131
|
+
function deserializeCV(input) {
|
|
1132
|
+
return deserializeCVBytes(input);
|
|
1337
1133
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
});
|
|
1134
|
+
|
|
1135
|
+
// src/clarity/serialize.ts
|
|
1136
|
+
var CLARITY_INT_SIZE = 128n;
|
|
1137
|
+
var CLARITY_INT_BYTE_SIZE = 16;
|
|
1138
|
+
function typeIdByte(type) {
|
|
1139
|
+
return ClarityWireType[type];
|
|
1345
1140
|
}
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
{
|
|
1367
|
-
name: "get-total-supply",
|
|
1368
|
-
access: "read-only",
|
|
1369
|
-
args: [],
|
|
1370
|
-
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1371
|
-
},
|
|
1372
|
-
{
|
|
1373
|
-
name: "get-name",
|
|
1374
|
-
access: "read-only",
|
|
1375
|
-
args: [],
|
|
1376
|
-
outputs: {
|
|
1377
|
-
response: {
|
|
1378
|
-
ok: { "string-ascii": { length: 32 } },
|
|
1379
|
-
error: "uint128"
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
},
|
|
1383
|
-
{
|
|
1384
|
-
name: "get-symbol",
|
|
1385
|
-
access: "read-only",
|
|
1386
|
-
args: [],
|
|
1387
|
-
outputs: {
|
|
1388
|
-
response: {
|
|
1389
|
-
ok: { "string-ascii": { length: 10 } },
|
|
1390
|
-
error: "uint128"
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
},
|
|
1394
|
-
{
|
|
1395
|
-
name: "get-decimals",
|
|
1396
|
-
access: "read-only",
|
|
1397
|
-
args: [],
|
|
1398
|
-
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1399
|
-
},
|
|
1400
|
-
{
|
|
1401
|
-
name: "get-token-uri",
|
|
1402
|
-
access: "read-only",
|
|
1403
|
-
args: [],
|
|
1404
|
-
outputs: {
|
|
1405
|
-
response: {
|
|
1406
|
-
ok: { optional: { "string-utf8": { length: 256 } } },
|
|
1407
|
-
error: "uint128"
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1141
|
+
function withTypeId(type, bytes) {
|
|
1142
|
+
return concatBytes(new Uint8Array([typeIdByte(type)]), bytes);
|
|
1143
|
+
}
|
|
1144
|
+
function serializeAddress(c32Address) {
|
|
1145
|
+
const [version, hash160] = c32addressDecode(c32Address);
|
|
1146
|
+
return concatBytes(new Uint8Array([version]), hexToBytes(hash160));
|
|
1147
|
+
}
|
|
1148
|
+
function serializeLPString(str, prefixBytes = 1) {
|
|
1149
|
+
const content = utf8ToBytes(str);
|
|
1150
|
+
const lengthPrefix = hexToBytes(intToHex(content.byteLength, prefixBytes));
|
|
1151
|
+
return concatBytes(lengthPrefix, content);
|
|
1152
|
+
}
|
|
1153
|
+
function serializeCVBytes(value) {
|
|
1154
|
+
switch (value.type) {
|
|
1155
|
+
case "true":
|
|
1156
|
+
case "false":
|
|
1157
|
+
return new Uint8Array([typeIdByte(value.type)]);
|
|
1158
|
+
case "int": {
|
|
1159
|
+
const bytes = bigIntToBytes(toTwos(BigInt(value.value), CLARITY_INT_SIZE), CLARITY_INT_BYTE_SIZE);
|
|
1160
|
+
return withTypeId(value.type, bytes);
|
|
1410
1161
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
}
|
|
1434
|
-
{
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1439
|
-
},
|
|
1440
|
-
{
|
|
1441
|
-
name: "get-token-uri",
|
|
1442
|
-
access: "read-only",
|
|
1443
|
-
args: [{ name: "id", type: "uint128" }],
|
|
1444
|
-
outputs: {
|
|
1445
|
-
response: {
|
|
1446
|
-
ok: { optional: { "string-utf8": { length: 256 } } },
|
|
1447
|
-
error: "uint128"
|
|
1448
|
-
}
|
|
1162
|
+
case "uint": {
|
|
1163
|
+
const bytes = bigIntToBytes(BigInt(value.value), CLARITY_INT_BYTE_SIZE);
|
|
1164
|
+
return withTypeId(value.type, bytes);
|
|
1165
|
+
}
|
|
1166
|
+
case "buffer": {
|
|
1167
|
+
const bufBytes = hexToBytes(value.value);
|
|
1168
|
+
return withTypeId(value.type, concatBytes(writeUInt32BE(bufBytes.length), bufBytes));
|
|
1169
|
+
}
|
|
1170
|
+
case "none":
|
|
1171
|
+
return new Uint8Array([typeIdByte(value.type)]);
|
|
1172
|
+
case "some":
|
|
1173
|
+
return withTypeId(value.type, serializeCVBytes(value.value));
|
|
1174
|
+
case "ok":
|
|
1175
|
+
case "err":
|
|
1176
|
+
return withTypeId(value.type, serializeCVBytes(value.value));
|
|
1177
|
+
case "address":
|
|
1178
|
+
return withTypeId(value.type, serializeAddress(value.value));
|
|
1179
|
+
case "contract": {
|
|
1180
|
+
const [addr, name] = value.value.split(".");
|
|
1181
|
+
if (!addr || !name)
|
|
1182
|
+
throw new Error(`Invalid contract principal: ${value.value}`);
|
|
1183
|
+
return withTypeId(value.type, concatBytes(serializeAddress(addr), serializeLPString(name)));
|
|
1184
|
+
}
|
|
1185
|
+
case "list": {
|
|
1186
|
+
const parts = [writeUInt32BE(value.value.length)];
|
|
1187
|
+
for (const item of value.value) {
|
|
1188
|
+
parts.push(serializeCVBytes(item));
|
|
1449
1189
|
}
|
|
1190
|
+
return withTypeId(value.type, concatBytes(...parts));
|
|
1450
1191
|
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
name: "transfer",
|
|
1458
|
-
access: "public",
|
|
1459
|
-
args: [
|
|
1460
|
-
{ name: "token-id", type: "uint128" },
|
|
1461
|
-
{ name: "amount", type: "uint128" },
|
|
1462
|
-
{ name: "sender", type: "principal" },
|
|
1463
|
-
{ name: "recipient", type: "principal" }
|
|
1464
|
-
],
|
|
1465
|
-
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1466
|
-
},
|
|
1467
|
-
{
|
|
1468
|
-
name: "transfer-memo",
|
|
1469
|
-
access: "public",
|
|
1470
|
-
args: [
|
|
1471
|
-
{ name: "token-id", type: "uint128" },
|
|
1472
|
-
{ name: "amount", type: "uint128" },
|
|
1473
|
-
{ name: "sender", type: "principal" },
|
|
1474
|
-
{ name: "recipient", type: "principal" },
|
|
1475
|
-
{ name: "memo", type: { buff: { length: 34 } } }
|
|
1476
|
-
],
|
|
1477
|
-
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1478
|
-
},
|
|
1479
|
-
{
|
|
1480
|
-
name: "transfer-many",
|
|
1481
|
-
access: "public",
|
|
1482
|
-
args: [
|
|
1483
|
-
{
|
|
1484
|
-
name: "transfers",
|
|
1485
|
-
type: {
|
|
1486
|
-
list: {
|
|
1487
|
-
type: {
|
|
1488
|
-
tuple: [
|
|
1489
|
-
{ name: "token-id", type: "uint128" },
|
|
1490
|
-
{ name: "amount", type: "uint128" },
|
|
1491
|
-
{ name: "sender", type: "principal" },
|
|
1492
|
-
{ name: "recipient", type: "principal" }
|
|
1493
|
-
]
|
|
1494
|
-
},
|
|
1495
|
-
length: 200
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
],
|
|
1500
|
-
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1501
|
-
},
|
|
1502
|
-
{
|
|
1503
|
-
name: "transfer-many-memo",
|
|
1504
|
-
access: "public",
|
|
1505
|
-
args: [
|
|
1506
|
-
{
|
|
1507
|
-
name: "transfers",
|
|
1508
|
-
type: {
|
|
1509
|
-
list: {
|
|
1510
|
-
type: {
|
|
1511
|
-
tuple: [
|
|
1512
|
-
{ name: "token-id", type: "uint128" },
|
|
1513
|
-
{ name: "amount", type: "uint128" },
|
|
1514
|
-
{ name: "sender", type: "principal" },
|
|
1515
|
-
{ name: "recipient", type: "principal" },
|
|
1516
|
-
{ name: "memo", type: { buff: { length: 34 } } }
|
|
1517
|
-
]
|
|
1518
|
-
},
|
|
1519
|
-
length: 200
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
],
|
|
1524
|
-
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1525
|
-
},
|
|
1526
|
-
{
|
|
1527
|
-
name: "get-balance",
|
|
1528
|
-
access: "read-only",
|
|
1529
|
-
args: [
|
|
1530
|
-
{ name: "token-id", type: "uint128" },
|
|
1531
|
-
{ name: "account", type: "principal" }
|
|
1532
|
-
],
|
|
1533
|
-
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1534
|
-
},
|
|
1535
|
-
{
|
|
1536
|
-
name: "get-overall-balance",
|
|
1537
|
-
access: "read-only",
|
|
1538
|
-
args: [{ name: "account", type: "principal" }],
|
|
1539
|
-
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1540
|
-
},
|
|
1541
|
-
{
|
|
1542
|
-
name: "get-total-supply",
|
|
1543
|
-
access: "read-only",
|
|
1544
|
-
args: [{ name: "token-id", type: "uint128" }],
|
|
1545
|
-
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1546
|
-
},
|
|
1547
|
-
{
|
|
1548
|
-
name: "get-overall-supply",
|
|
1549
|
-
access: "read-only",
|
|
1550
|
-
args: [],
|
|
1551
|
-
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1552
|
-
},
|
|
1553
|
-
{
|
|
1554
|
-
name: "get-decimals",
|
|
1555
|
-
access: "read-only",
|
|
1556
|
-
args: [{ name: "token-id", type: "uint128" }],
|
|
1557
|
-
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1558
|
-
},
|
|
1559
|
-
{
|
|
1560
|
-
name: "get-token-uri",
|
|
1561
|
-
access: "read-only",
|
|
1562
|
-
args: [{ name: "token-id", type: "uint128" }],
|
|
1563
|
-
outputs: {
|
|
1564
|
-
response: {
|
|
1565
|
-
ok: { optional: { "string-utf8": { length: 256 } } },
|
|
1566
|
-
error: "uint128"
|
|
1567
|
-
}
|
|
1192
|
+
case "tuple": {
|
|
1193
|
+
const keys = Object.keys(value.value).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
1194
|
+
const parts = [writeUInt32BE(keys.length)];
|
|
1195
|
+
for (const key of keys) {
|
|
1196
|
+
parts.push(serializeLPString(key));
|
|
1197
|
+
parts.push(serializeCVBytes(value.value[key]));
|
|
1568
1198
|
}
|
|
1199
|
+
return withTypeId(value.type, concatBytes(...parts));
|
|
1569
1200
|
}
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
{ id: "sip-010", abi: SIP010_ABI, optional: new Set(["get-token-uri"]) },
|
|
1581
|
-
{ id: "sip-009", abi: SIP009_ABI, optional: new Set(["get-token-uri"]) },
|
|
1582
|
-
{
|
|
1583
|
-
id: "sip-013",
|
|
1584
|
-
abi: SIP013_ABI,
|
|
1585
|
-
optional: new Set([
|
|
1586
|
-
"transfer-memo",
|
|
1587
|
-
"transfer-many",
|
|
1588
|
-
"transfer-many-memo",
|
|
1589
|
-
"get-token-uri",
|
|
1590
|
-
"get-overall-balance",
|
|
1591
|
-
"get-overall-supply"
|
|
1592
|
-
])
|
|
1201
|
+
case "ascii": {
|
|
1202
|
+
const strBytes = asciiToBytes(value.value);
|
|
1203
|
+
return withTypeId(value.type, concatBytes(writeUInt32BE(strBytes.length), strBytes));
|
|
1204
|
+
}
|
|
1205
|
+
case "utf8": {
|
|
1206
|
+
const strBytes = utf8ToBytes(value.value);
|
|
1207
|
+
return withTypeId(value.type, concatBytes(writeUInt32BE(strBytes.length), strBytes));
|
|
1208
|
+
}
|
|
1209
|
+
default:
|
|
1210
|
+
throw new Error("Cannot serialize unknown clarity type");
|
|
1593
1211
|
}
|
|
1594
|
-
];
|
|
1595
|
-
function indexByName(abi) {
|
|
1596
|
-
const m = new Map;
|
|
1597
|
-
for (const f of abi.functions)
|
|
1598
|
-
m.set(f.name, f);
|
|
1599
|
-
return m;
|
|
1600
1212
|
}
|
|
1601
|
-
function
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1213
|
+
function serializeCV(value) {
|
|
1214
|
+
return bytesToHex(serializeCVBytes(value));
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// src/clarity/values.ts
|
|
1218
|
+
var MAX_U1282 = BigInt("0xffffffffffffffffffffffffffffffff");
|
|
1219
|
+
var MIN_I1282 = BigInt("-170141183460469231731687303715884105728");
|
|
1220
|
+
var MAX_I1282 = BigInt("0x7fffffffffffffffffffffffffffffff");
|
|
1221
|
+
function intCV(value) {
|
|
1222
|
+
let v = value;
|
|
1223
|
+
if (typeof v === "string" && v.toLowerCase().startsWith("0x")) {
|
|
1224
|
+
v = bytesToTwosBigInt(hexToBytes(v));
|
|
1225
|
+
}
|
|
1226
|
+
if (v instanceof Uint8Array)
|
|
1227
|
+
v = bytesToTwosBigInt(v);
|
|
1228
|
+
const n = intToBigInt(v);
|
|
1229
|
+
if (n > MAX_I1282)
|
|
1230
|
+
throw new RangeError(`Int exceeds max i128: ${MAX_I1282}`);
|
|
1231
|
+
if (n < MIN_I1282)
|
|
1232
|
+
throw new RangeError(`Int below min i128: ${MIN_I1282}`);
|
|
1233
|
+
return { type: "int", value: n };
|
|
1234
|
+
}
|
|
1235
|
+
function uintCV(value) {
|
|
1236
|
+
const n = intToBigInt(value);
|
|
1237
|
+
if (n < 0n)
|
|
1238
|
+
throw new RangeError("Cannot construct unsigned int from negative value");
|
|
1239
|
+
if (n > MAX_U1282)
|
|
1240
|
+
throw new RangeError(`UInt exceeds max u128: ${MAX_U1282}`);
|
|
1241
|
+
return { type: "uint", value: n };
|
|
1242
|
+
}
|
|
1243
|
+
var trueCV = () => ({ type: "true" });
|
|
1244
|
+
var falseCV = () => ({ type: "false" });
|
|
1245
|
+
var boolCV = (v) => v ? trueCV() : falseCV();
|
|
1246
|
+
function bufferCV(buffer) {
|
|
1247
|
+
if (buffer.byteLength > 1048576) {
|
|
1248
|
+
throw new Error("Buffer exceeds max size of 1MB");
|
|
1613
1249
|
}
|
|
1614
|
-
return
|
|
1250
|
+
return { type: "buffer", value: bytesToHex(buffer) };
|
|
1615
1251
|
}
|
|
1616
|
-
function
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
return
|
|
1252
|
+
function standardPrincipalCV(address) {
|
|
1253
|
+
const [version, hash160] = c32addressDecode(address);
|
|
1254
|
+
const normalized = c32address(version, hash160);
|
|
1255
|
+
return { type: "address", value: normalized };
|
|
1620
1256
|
}
|
|
1621
|
-
function
|
|
1622
|
-
const
|
|
1623
|
-
const
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
if (ref.includes("sip-010") || ref.includes(".ft-trait"))
|
|
1627
|
-
out.add("sip-010");
|
|
1628
|
-
if (ref.includes("sip-009") || ref.includes("nft-trait"))
|
|
1629
|
-
out.add("sip-009");
|
|
1630
|
-
if (ref.includes("sip-013") || ref.includes("semi-fungible"))
|
|
1631
|
-
out.add("sip-013");
|
|
1257
|
+
function contractPrincipalCV(address, contractName) {
|
|
1258
|
+
const [version, hash160] = c32addressDecode(address);
|
|
1259
|
+
const normalized = c32address(version, hash160);
|
|
1260
|
+
if (utf8ToBytes(contractName).byteLength >= 128) {
|
|
1261
|
+
throw new Error("Contract name must be less than 128 bytes");
|
|
1632
1262
|
}
|
|
1633
|
-
return
|
|
1263
|
+
return { type: "contract", value: `${normalized}.${contractName}` };
|
|
1634
1264
|
}
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
if (access === "read_only")
|
|
1638
|
-
return "read-only";
|
|
1639
|
-
return access;
|
|
1265
|
+
function noneCV() {
|
|
1266
|
+
return { type: "none" };
|
|
1640
1267
|
}
|
|
1641
|
-
function
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1268
|
+
function someCV(value) {
|
|
1269
|
+
return { type: "some", value };
|
|
1270
|
+
}
|
|
1271
|
+
function responseOkCV(value) {
|
|
1272
|
+
return { type: "ok", value };
|
|
1273
|
+
}
|
|
1274
|
+
function responseErrorCV(value) {
|
|
1275
|
+
return { type: "err", value };
|
|
1276
|
+
}
|
|
1277
|
+
function listCV(values) {
|
|
1278
|
+
return { type: "list", value: values };
|
|
1279
|
+
}
|
|
1280
|
+
function tupleCV(data) {
|
|
1281
|
+
for (const key in data) {
|
|
1282
|
+
if (!isClarityName(key)) {
|
|
1283
|
+
throw new Error(`"${key}" is not a valid Clarity name`);
|
|
1652
1284
|
}
|
|
1653
1285
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
1286
|
+
return { type: "tuple", value: data };
|
|
1287
|
+
}
|
|
1288
|
+
function stringAsciiCV(value) {
|
|
1289
|
+
return { type: "ascii", value };
|
|
1290
|
+
}
|
|
1291
|
+
function stringUtf8CV(value) {
|
|
1292
|
+
return { type: "utf8", value };
|
|
1293
|
+
}
|
|
1294
|
+
var Cl = {
|
|
1295
|
+
int: intCV,
|
|
1296
|
+
uint: uintCV,
|
|
1297
|
+
bool: boolCV,
|
|
1298
|
+
principal(address) {
|
|
1299
|
+
const parsed = parsePrincipal(address);
|
|
1300
|
+
if (!parsed)
|
|
1301
|
+
throw new Error(`Invalid principal: ${address}`);
|
|
1302
|
+
return parsed.contractName ? contractPrincipalCV(parsed.address, parsed.contractName) : standardPrincipalCV(parsed.address);
|
|
1303
|
+
},
|
|
1304
|
+
address(address) {
|
|
1305
|
+
return Cl.principal(address);
|
|
1306
|
+
},
|
|
1307
|
+
contractPrincipal: contractPrincipalCV,
|
|
1308
|
+
standardPrincipal: standardPrincipalCV,
|
|
1309
|
+
buffer: bufferCV,
|
|
1310
|
+
bufferFromHex: (hex) => bufferCV(hexToBytes(hex)),
|
|
1311
|
+
bufferFromAscii: (ascii) => bufferCV(asciiToBytes(ascii)),
|
|
1312
|
+
bufferFromUtf8: (utf8) => bufferCV(utf8ToBytes(utf8)),
|
|
1313
|
+
none: noneCV,
|
|
1314
|
+
some: someCV,
|
|
1315
|
+
ok: responseOkCV,
|
|
1316
|
+
error: responseErrorCV,
|
|
1317
|
+
list: listCV,
|
|
1318
|
+
tuple: tupleCV,
|
|
1319
|
+
stringAscii: stringAsciiCV,
|
|
1320
|
+
stringUtf8: stringUtf8CV,
|
|
1321
|
+
serialize(value) {
|
|
1322
|
+
return bytesToHex(serializeCVBytes(value));
|
|
1323
|
+
},
|
|
1324
|
+
deserialize: deserializeCVBytes
|
|
1325
|
+
};
|
|
1326
|
+
// src/clarity/structuredData.ts
|
|
1327
|
+
var import_sha24 = require("@noble/hashes/sha2.js");
|
|
1328
|
+
var SIP018_PREFIX = new Uint8Array([
|
|
1329
|
+
83,
|
|
1330
|
+
73,
|
|
1331
|
+
80,
|
|
1332
|
+
48,
|
|
1333
|
+
49,
|
|
1334
|
+
56
|
|
1335
|
+
]);
|
|
1336
|
+
function hashStructuredData(structuredData) {
|
|
1337
|
+
return import_sha24.sha256(serializeCVBytes(structuredData));
|
|
1338
|
+
}
|
|
1339
|
+
function isDomain(value) {
|
|
1340
|
+
if (value.type !== "tuple")
|
|
1341
|
+
return false;
|
|
1342
|
+
const { name, version, "chain-id": chainId } = value.value;
|
|
1343
|
+
return name?.type === "ascii" && version?.type === "ascii" && chainId?.type === "uint";
|
|
1344
|
+
}
|
|
1345
|
+
function encodeStructuredData(opts) {
|
|
1346
|
+
if (!isDomain(opts.domain)) {
|
|
1347
|
+
throw new Error("domain must be a tuple { name: ascii, version: ascii, chain-id: uint }");
|
|
1656
1348
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1349
|
+
return concatBytes(SIP018_PREFIX, hashStructuredData(opts.domain), hashStructuredData(opts.message));
|
|
1350
|
+
}
|
|
1351
|
+
function structuredDataHash(opts) {
|
|
1352
|
+
return import_sha24.sha256(encodeStructuredData(opts));
|
|
1353
|
+
}
|
|
1354
|
+
async function signStructuredData(account, opts) {
|
|
1355
|
+
const vrs = await account.sign(structuredDataHash(opts));
|
|
1356
|
+
if (vrs.length !== 65) {
|
|
1357
|
+
throw new Error(`Expected 65-byte recoverable signature, got ${vrs.length}`);
|
|
1665
1358
|
}
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1359
|
+
return bytesToHex(concatBytes(vrs.slice(1), vrs.slice(0, 1)));
|
|
1360
|
+
}
|
|
1361
|
+
// src/clarity/prettyPrint.ts
|
|
1362
|
+
function prettyPrint(val, encoding = "hex") {
|
|
1363
|
+
switch (val.type) {
|
|
1364
|
+
case "true":
|
|
1365
|
+
return "true";
|
|
1366
|
+
case "false":
|
|
1367
|
+
return "false";
|
|
1368
|
+
case "int":
|
|
1369
|
+
return val.value.toString();
|
|
1370
|
+
case "uint":
|
|
1371
|
+
return `u${val.value.toString()}`;
|
|
1372
|
+
case "buffer":
|
|
1373
|
+
if (encoding === "tryAscii") {
|
|
1374
|
+
const str = bytesToAscii(hexToBytes(val.value));
|
|
1375
|
+
if (/^[ -~]*$/.test(str))
|
|
1376
|
+
return JSON.stringify(str);
|
|
1671
1377
|
}
|
|
1672
|
-
|
|
1378
|
+
return `0x${val.value}`;
|
|
1379
|
+
case "none":
|
|
1380
|
+
return "none";
|
|
1381
|
+
case "some":
|
|
1382
|
+
return `(some ${prettyPrint(val.value, encoding)})`;
|
|
1383
|
+
case "ok":
|
|
1384
|
+
return `(ok ${prettyPrint(val.value, encoding)})`;
|
|
1385
|
+
case "err":
|
|
1386
|
+
return `(err ${prettyPrint(val.value, encoding)})`;
|
|
1387
|
+
case "address":
|
|
1388
|
+
case "contract":
|
|
1389
|
+
return val.value;
|
|
1390
|
+
case "list":
|
|
1391
|
+
return `(list ${val.value.map((v) => prettyPrint(v, encoding)).join(" ")})`;
|
|
1392
|
+
case "tuple":
|
|
1393
|
+
return `(tuple ${Object.keys(val.value).map((key) => `(${key} ${prettyPrint(val.value[key], encoding)})`).join(" ")})`;
|
|
1394
|
+
case "ascii":
|
|
1395
|
+
return `"${val.value}"`;
|
|
1396
|
+
case "utf8":
|
|
1397
|
+
return `u"${val.value}"`;
|
|
1673
1398
|
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1399
|
+
}
|
|
1400
|
+
function cvToJSON(val) {
|
|
1401
|
+
switch (val.type) {
|
|
1402
|
+
case "true":
|
|
1403
|
+
return { type: "bool", value: true };
|
|
1404
|
+
case "false":
|
|
1405
|
+
return { type: "bool", value: false };
|
|
1406
|
+
case "int":
|
|
1407
|
+
return { type: "int", value: val.value.toString() };
|
|
1408
|
+
case "uint":
|
|
1409
|
+
return { type: "uint", value: val.value.toString() };
|
|
1410
|
+
case "buffer": {
|
|
1411
|
+
const hex = without0x(val.value);
|
|
1412
|
+
return {
|
|
1413
|
+
type: `(buff ${Math.ceil(hex.length / 2)})`,
|
|
1414
|
+
value: `0x${hex}`
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
case "none":
|
|
1418
|
+
return { type: "(optional none)", value: null };
|
|
1419
|
+
case "some":
|
|
1420
|
+
return { type: "(optional)", value: cvToJSON(val.value) };
|
|
1421
|
+
case "ok":
|
|
1422
|
+
return { type: "(response)", value: cvToJSON(val.value), success: true };
|
|
1423
|
+
case "err":
|
|
1424
|
+
return { type: "(response)", value: cvToJSON(val.value), success: false };
|
|
1425
|
+
case "address":
|
|
1426
|
+
case "contract":
|
|
1427
|
+
return { type: "principal", value: val.value };
|
|
1428
|
+
case "list":
|
|
1429
|
+
return { type: "(list)", value: val.value.map(cvToJSON) };
|
|
1430
|
+
case "tuple": {
|
|
1431
|
+
const result = {};
|
|
1432
|
+
for (const key of Object.keys(val.value)) {
|
|
1433
|
+
result[key] = cvToJSON(val.value[key]);
|
|
1679
1434
|
}
|
|
1680
|
-
|
|
1435
|
+
return { type: "(tuple)", value: result };
|
|
1436
|
+
}
|
|
1437
|
+
case "ascii":
|
|
1438
|
+
return {
|
|
1439
|
+
type: `(string-ascii ${asciiToBytes(val.value).length})`,
|
|
1440
|
+
value: val.value
|
|
1441
|
+
};
|
|
1442
|
+
case "utf8":
|
|
1443
|
+
return {
|
|
1444
|
+
type: `(string-utf8 ${utf8ToBytes(val.value).length})`,
|
|
1445
|
+
value: val.value
|
|
1446
|
+
};
|
|
1681
1447
|
}
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1448
|
+
}
|
|
1449
|
+
function cvToValue(val) {
|
|
1450
|
+
switch (val.type) {
|
|
1451
|
+
case "true":
|
|
1452
|
+
return true;
|
|
1453
|
+
case "false":
|
|
1454
|
+
return false;
|
|
1455
|
+
case "int":
|
|
1456
|
+
case "uint":
|
|
1457
|
+
return val.value;
|
|
1458
|
+
case "buffer":
|
|
1459
|
+
return `0x${val.value}`;
|
|
1460
|
+
case "none":
|
|
1461
|
+
return null;
|
|
1462
|
+
case "some":
|
|
1463
|
+
return cvToValue(val.value);
|
|
1464
|
+
case "ok":
|
|
1465
|
+
case "err":
|
|
1466
|
+
return cvToValue(val.value);
|
|
1467
|
+
case "address":
|
|
1468
|
+
case "contract":
|
|
1469
|
+
return val.value;
|
|
1470
|
+
case "list":
|
|
1471
|
+
return val.value.map(cvToValue);
|
|
1472
|
+
case "tuple": {
|
|
1473
|
+
const result = {};
|
|
1474
|
+
for (const key of Object.keys(val.value)) {
|
|
1475
|
+
result[key] = cvToValue(val.value[key]);
|
|
1687
1476
|
}
|
|
1688
|
-
|
|
1477
|
+
return result;
|
|
1478
|
+
}
|
|
1479
|
+
case "ascii":
|
|
1480
|
+
case "utf8":
|
|
1481
|
+
return val.value;
|
|
1689
1482
|
}
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
ok: normalizeType(response?.ok ?? "bool"),
|
|
1695
|
-
error: normalizeType(response?.error ?? "uint128")
|
|
1696
|
-
}
|
|
1697
|
-
};
|
|
1483
|
+
}
|
|
1484
|
+
function cvToBigInt(val) {
|
|
1485
|
+
if (val.type !== "int" && val.type !== "uint") {
|
|
1486
|
+
throw new Error(`cvToBigInt: expected int or uint, got ${val.type}`);
|
|
1698
1487
|
}
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1488
|
+
return val.value;
|
|
1489
|
+
}
|
|
1490
|
+
function cvToString(val) {
|
|
1491
|
+
if (val.type !== "ascii" && val.type !== "utf8") {
|
|
1492
|
+
throw new Error(`cvToString: expected ascii or utf8, got ${val.type}`);
|
|
1703
1493
|
}
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
length: list?.length ?? 100
|
|
1710
|
-
}
|
|
1711
|
-
};
|
|
1494
|
+
return val.value;
|
|
1495
|
+
}
|
|
1496
|
+
function cvToBuffer(val) {
|
|
1497
|
+
if (val.type !== "buffer") {
|
|
1498
|
+
throw new Error(`cvToBuffer: expected buffer, got ${val.type}`);
|
|
1712
1499
|
}
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
type: normalizeType(field.type)
|
|
1719
|
-
}))
|
|
1720
|
-
};
|
|
1500
|
+
return val.value;
|
|
1501
|
+
}
|
|
1502
|
+
function cvToBoolean(val) {
|
|
1503
|
+
if (val.type !== "true" && val.type !== "false") {
|
|
1504
|
+
throw new Error(`cvToBoolean: expected bool, got ${val.type}`);
|
|
1721
1505
|
}
|
|
1722
|
-
|
|
1506
|
+
return val.type === "true";
|
|
1723
1507
|
}
|
|
1724
|
-
function
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
return
|
|
1729
|
-
name: func.name,
|
|
1730
|
-
access,
|
|
1731
|
-
args: args.map((arg) => ({
|
|
1732
|
-
name: arg.name,
|
|
1733
|
-
type: normalizeType(arg.type)
|
|
1734
|
-
})),
|
|
1735
|
-
outputs: normalizeType(typeof outputs === "object" && outputs !== null && "type" in outputs ? outputs.type : outputs)
|
|
1736
|
-
};
|
|
1508
|
+
function cvToPrincipal(val) {
|
|
1509
|
+
if (val.type !== "address" && val.type !== "contract") {
|
|
1510
|
+
throw new Error(`cvToPrincipal: expected principal or contract, got ${val.type}`);
|
|
1511
|
+
}
|
|
1512
|
+
return val.value;
|
|
1737
1513
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
key: normalizeType(map.key),
|
|
1742
|
-
value: normalizeType(map.value)
|
|
1743
|
-
};
|
|
1514
|
+
// src/clarity/abi/guards.ts
|
|
1515
|
+
function isUint128(value) {
|
|
1516
|
+
return typeof value === "bigint" && value >= 0n && value <= MAX_U128;
|
|
1744
1517
|
}
|
|
1745
|
-
function
|
|
1746
|
-
return
|
|
1747
|
-
name: variable.name,
|
|
1748
|
-
type: normalizeType(variable.type),
|
|
1749
|
-
access: variable.access
|
|
1750
|
-
};
|
|
1518
|
+
function isInt128(value) {
|
|
1519
|
+
return typeof value === "bigint" && value >= MIN_I128 && value <= MAX_I128;
|
|
1751
1520
|
}
|
|
1752
|
-
function
|
|
1753
|
-
return
|
|
1521
|
+
function isBool(value) {
|
|
1522
|
+
return typeof value === "boolean";
|
|
1754
1523
|
}
|
|
1755
|
-
function
|
|
1756
|
-
return
|
|
1524
|
+
function isPrincipal(value) {
|
|
1525
|
+
return typeof value === "string" && parsePrincipal(value) !== null;
|
|
1757
1526
|
}
|
|
1758
|
-
function
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1527
|
+
function isStandardPrincipal(value) {
|
|
1528
|
+
if (typeof value !== "string")
|
|
1529
|
+
return false;
|
|
1530
|
+
const parsed = parsePrincipal(value);
|
|
1531
|
+
return parsed !== null && parsed.contractName === undefined;
|
|
1532
|
+
}
|
|
1533
|
+
function isContractPrincipal(value) {
|
|
1534
|
+
if (typeof value !== "string")
|
|
1535
|
+
return false;
|
|
1536
|
+
const parsed = parsePrincipal(value);
|
|
1537
|
+
return parsed !== null && parsed.contractName !== undefined;
|
|
1538
|
+
}
|
|
1539
|
+
function isTraitReference(value) {
|
|
1540
|
+
return isContractPrincipal(value);
|
|
1541
|
+
}
|
|
1542
|
+
function isString(value) {
|
|
1543
|
+
return typeof value === "string";
|
|
1544
|
+
}
|
|
1545
|
+
function isUint8Array(value) {
|
|
1546
|
+
return value instanceof Uint8Array;
|
|
1547
|
+
}
|
|
1548
|
+
function isArray(value, itemGuard) {
|
|
1549
|
+
return Array.isArray(value) && value.every(itemGuard);
|
|
1550
|
+
}
|
|
1551
|
+
function isOptional(value, guard) {
|
|
1552
|
+
return value === null || guard(value);
|
|
1553
|
+
}
|
|
1554
|
+
function isOkResponse(response) {
|
|
1555
|
+
return "ok" in response && !("err" in response);
|
|
1556
|
+
}
|
|
1557
|
+
function isErrResponse(response) {
|
|
1558
|
+
return "err" in response && !("ok" in response);
|
|
1559
|
+
}
|
|
1560
|
+
function isResponse(value, okGuard, errGuard) {
|
|
1561
|
+
if (typeof value !== "object" || value === null)
|
|
1562
|
+
return false;
|
|
1563
|
+
const obj = value;
|
|
1564
|
+
if ("ok" in value && !("err" in value))
|
|
1565
|
+
return okGuard(obj.ok);
|
|
1566
|
+
if ("err" in value && !("ok" in value))
|
|
1567
|
+
return errGuard(obj.err);
|
|
1568
|
+
return false;
|
|
1569
|
+
}
|
|
1570
|
+
function isAbiList(type) {
|
|
1571
|
+
return typeof type === "object" && type !== null && "list" in type;
|
|
1572
|
+
}
|
|
1573
|
+
function isAbiTuple(type) {
|
|
1574
|
+
return typeof type === "object" && type !== null && "tuple" in type;
|
|
1575
|
+
}
|
|
1576
|
+
function isAbiOptional(type) {
|
|
1577
|
+
return typeof type === "object" && type !== null && "optional" in type;
|
|
1578
|
+
}
|
|
1579
|
+
function isAbiResponse(type) {
|
|
1580
|
+
return typeof type === "object" && type !== null && "response" in type;
|
|
1581
|
+
}
|
|
1582
|
+
function isAbiBuffer(type) {
|
|
1583
|
+
return typeof type === "object" && type !== null && "buff" in type;
|
|
1584
|
+
}
|
|
1585
|
+
function isAbiStringAscii(type) {
|
|
1586
|
+
return typeof type === "object" && type !== null && "string-ascii" in type;
|
|
1587
|
+
}
|
|
1588
|
+
function isAbiStringUtf8(type) {
|
|
1589
|
+
return typeof type === "object" && type !== null && "string-utf8" in type;
|
|
1590
|
+
}
|
|
1591
|
+
function isAbiTraitReference(type) {
|
|
1592
|
+
return type === "trait_reference";
|
|
1593
|
+
}
|
|
1594
|
+
// src/clarity/abi/utils.ts
|
|
1595
|
+
function toCamelCase(str) {
|
|
1596
|
+
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()).replace(/-([A-Z])/g, (_, letter) => letter).replace(/-(\d)/g, (_, digit) => digit).replace(/-/g, "").replace(/^\d/, "_$&");
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
// src/clarity/abi/converters.ts
|
|
1600
|
+
class ClarityConversionError extends Error {
|
|
1601
|
+
type;
|
|
1602
|
+
value;
|
|
1603
|
+
constructor(message, type, value) {
|
|
1604
|
+
super(message);
|
|
1605
|
+
this.type = type;
|
|
1606
|
+
this.value = value;
|
|
1607
|
+
this.name = "ClarityConversionError";
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
function jsToClarity(type, value) {
|
|
1611
|
+
if (type === "none")
|
|
1612
|
+
return null;
|
|
1613
|
+
if (type === "uint128") {
|
|
1614
|
+
if (!isUint128(value))
|
|
1615
|
+
throw new ClarityConversionError("Invalid uint128 value", type, value);
|
|
1616
|
+
return value;
|
|
1617
|
+
}
|
|
1618
|
+
if (type === "int128") {
|
|
1619
|
+
if (!isInt128(value))
|
|
1620
|
+
throw new ClarityConversionError("Invalid int128 value", type, value);
|
|
1621
|
+
return value;
|
|
1622
|
+
}
|
|
1623
|
+
if (type === "bool") {
|
|
1624
|
+
if (!isBool(value))
|
|
1625
|
+
throw new ClarityConversionError("Invalid bool value", type, value);
|
|
1626
|
+
return value;
|
|
1768
1627
|
}
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
return { functions: [] };
|
|
1628
|
+
if (type === "principal") {
|
|
1629
|
+
if (!isPrincipal(value))
|
|
1630
|
+
throw new ClarityConversionError("Invalid principal value", type, value);
|
|
1631
|
+
return value;
|
|
1774
1632
|
}
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
for (
|
|
1785
|
-
if (
|
|
1786
|
-
|
|
1633
|
+
if (type === "trait_reference") {
|
|
1634
|
+
if (!isPrincipal(value))
|
|
1635
|
+
throw new ClarityConversionError("Invalid trait_reference value", type, value);
|
|
1636
|
+
return value;
|
|
1637
|
+
}
|
|
1638
|
+
if (isAbiStringAscii(type)) {
|
|
1639
|
+
if (!isString(value))
|
|
1640
|
+
throw new ClarityConversionError("Invalid string-ascii value", type, value);
|
|
1641
|
+
const str = value;
|
|
1642
|
+
for (let i = 0;i < str.length; i++) {
|
|
1643
|
+
if (str.charCodeAt(i) > 127) {
|
|
1644
|
+
throw new ClarityConversionError(`Non-ASCII character at position ${i}: '${str[i]}' (code ${str.charCodeAt(i)})`, type, value);
|
|
1787
1645
|
}
|
|
1788
1646
|
}
|
|
1647
|
+
if (str.length > type["string-ascii"].length) {
|
|
1648
|
+
throw new ClarityConversionError(`String length ${str.length} exceeds max ${type["string-ascii"].length}`, type, value);
|
|
1649
|
+
}
|
|
1650
|
+
return value;
|
|
1789
1651
|
}
|
|
1790
|
-
if (
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1652
|
+
if (isAbiStringUtf8(type)) {
|
|
1653
|
+
if (!isString(value))
|
|
1654
|
+
throw new ClarityConversionError("Invalid string-utf8 value", type, value);
|
|
1655
|
+
const str = value;
|
|
1656
|
+
const byteLength = new TextEncoder().encode(str).length;
|
|
1657
|
+
if (byteLength > type["string-utf8"].length) {
|
|
1658
|
+
throw new ClarityConversionError(`String byte length ${byteLength} exceeds max ${type["string-utf8"].length}`, type, value);
|
|
1795
1659
|
}
|
|
1660
|
+
return value;
|
|
1796
1661
|
}
|
|
1797
|
-
if (
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1662
|
+
if (isAbiBuffer(type)) {
|
|
1663
|
+
if (!isUint8Array(value))
|
|
1664
|
+
throw new ClarityConversionError("Invalid buffer value", type, value);
|
|
1665
|
+
const buff = value;
|
|
1666
|
+
if (buff.length > type.buff.length) {
|
|
1667
|
+
throw new ClarityConversionError(`Buffer length ${buff.length} exceeds max ${type.buff.length}`, type, value);
|
|
1802
1668
|
}
|
|
1669
|
+
return value;
|
|
1803
1670
|
}
|
|
1804
|
-
if (
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
}
|
|
1671
|
+
if (isAbiList(type)) {
|
|
1672
|
+
if (!Array.isArray(value))
|
|
1673
|
+
throw new ClarityConversionError("Expected array for list type", type, value);
|
|
1674
|
+
if (value.length > type.list.length) {
|
|
1675
|
+
throw new ClarityConversionError(`List length ${value.length} exceeds max ${type.list.length}`, type, value);
|
|
1809
1676
|
}
|
|
1677
|
+
return value.map((item) => jsToClarity(type.list.type, item));
|
|
1810
1678
|
}
|
|
1811
|
-
if (
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1679
|
+
if (isAbiTuple(type)) {
|
|
1680
|
+
if (typeof value !== "object" || value === null)
|
|
1681
|
+
throw new ClarityConversionError("Expected object for tuple type", type, value);
|
|
1682
|
+
const result = {};
|
|
1683
|
+
for (const field of type.tuple) {
|
|
1684
|
+
const camelKey = toCamelCase(field.name);
|
|
1685
|
+
const hasOriginal = field.name in value;
|
|
1686
|
+
const hasCamel = camelKey in value;
|
|
1687
|
+
if (!hasOriginal && !hasCamel) {
|
|
1688
|
+
throw new ClarityConversionError(`Missing tuple field: ${field.name}`, type, value);
|
|
1815
1689
|
}
|
|
1690
|
+
const fieldValue = hasOriginal ? value[field.name] : value[camelKey];
|
|
1691
|
+
result[field.name] = jsToClarity(field.type, fieldValue);
|
|
1816
1692
|
}
|
|
1693
|
+
return result;
|
|
1817
1694
|
}
|
|
1818
|
-
if (
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1695
|
+
if (isAbiOptional(type)) {
|
|
1696
|
+
if (value === null || value === undefined)
|
|
1697
|
+
return null;
|
|
1698
|
+
return jsToClarity(type.optional, value);
|
|
1699
|
+
}
|
|
1700
|
+
if (isAbiResponse(type)) {
|
|
1701
|
+
if (typeof value !== "object" || value === null)
|
|
1702
|
+
throw new ClarityConversionError("Expected object for response type", type, value);
|
|
1703
|
+
const hasOk = "ok" in value;
|
|
1704
|
+
const hasErr = "err" in value;
|
|
1705
|
+
if (hasOk && !hasErr) {
|
|
1706
|
+
return {
|
|
1707
|
+
ok: jsToClarity(type.response.ok, value.ok)
|
|
1708
|
+
};
|
|
1709
|
+
}
|
|
1710
|
+
if (hasErr && !hasOk) {
|
|
1711
|
+
return {
|
|
1712
|
+
err: jsToClarity(type.response.error, value.err)
|
|
1713
|
+
};
|
|
1822
1714
|
}
|
|
1715
|
+
throw new ClarityConversionError("Response must have exactly 'ok' or 'err' property", type, value);
|
|
1823
1716
|
}
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1717
|
+
throw new ClarityConversionError("Unknown Clarity type", type, value);
|
|
1718
|
+
}
|
|
1719
|
+
function prepareArgs(func, args) {
|
|
1720
|
+
return func.args.map((arg) => {
|
|
1721
|
+
if (!(arg.name in args)) {
|
|
1722
|
+
throw new ClarityConversionError(`Missing argument: ${arg.name}`, arg.type, undefined);
|
|
1723
|
+
}
|
|
1724
|
+
return jsToClarity(arg.type, args[arg.name]);
|
|
1725
|
+
});
|
|
1726
|
+
}
|
|
1727
|
+
function validateArgs(func, args) {
|
|
1728
|
+
for (const arg of func.args) {
|
|
1729
|
+
if (!(arg.name in args)) {
|
|
1730
|
+
throw new ClarityConversionError(`Missing argument: ${arg.name}`, arg.type, undefined);
|
|
1829
1731
|
}
|
|
1732
|
+
jsToClarity(arg.type, args[arg.name]);
|
|
1830
1733
|
}
|
|
1831
|
-
return {
|
|
1832
|
-
functions,
|
|
1833
|
-
maps: maps.length > 0 ? maps : undefined,
|
|
1834
|
-
variables: variables.length > 0 ? variables : undefined,
|
|
1835
|
-
fungible_tokens: fungibleTokens.length > 0 ? fungibleTokens : undefined,
|
|
1836
|
-
non_fungible_tokens: nonFungibleTokens.length > 0 ? nonFungibleTokens : undefined,
|
|
1837
|
-
implemented_traits: implementedTraits.length > 0 ? implementedTraits : undefined,
|
|
1838
|
-
defined_traits: definedTraits.length > 0 ? definedTraits : undefined
|
|
1839
|
-
};
|
|
1840
1734
|
}
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
"contract",
|
|
1849
|
-
"ascii",
|
|
1850
|
-
"utf8",
|
|
1851
|
-
"buffer",
|
|
1852
|
-
"list",
|
|
1853
|
-
"tuple",
|
|
1854
|
-
"none",
|
|
1855
|
-
"some",
|
|
1856
|
-
"ok",
|
|
1857
|
-
"err"
|
|
1858
|
-
]);
|
|
1859
|
-
function isClarityValue(value) {
|
|
1860
|
-
if (typeof value !== "object" || value === null)
|
|
1861
|
-
return false;
|
|
1862
|
-
const type = value.type;
|
|
1863
|
-
if (typeof type !== "string" || !CV_TYPE_TAGS.has(type))
|
|
1864
|
-
return false;
|
|
1865
|
-
if (type === "true" || type === "false" || type === "none")
|
|
1866
|
-
return true;
|
|
1867
|
-
return "value" in value;
|
|
1735
|
+
function validateArgsArray(func, args) {
|
|
1736
|
+
if (args.length !== func.args.length) {
|
|
1737
|
+
throw new ClarityConversionError(`Expected ${func.args.length} arguments, got ${args.length}`, func.args[0]?.type ?? "bool", args);
|
|
1738
|
+
}
|
|
1739
|
+
func.args.forEach((arg, i) => {
|
|
1740
|
+
jsToClarity(arg.type, args[i]);
|
|
1741
|
+
});
|
|
1868
1742
|
}
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1743
|
+
// src/clarity/abi/standards.ts
|
|
1744
|
+
var SIP010_ABI = {
|
|
1745
|
+
functions: [
|
|
1746
|
+
{
|
|
1747
|
+
name: "transfer",
|
|
1748
|
+
access: "public",
|
|
1749
|
+
args: [
|
|
1750
|
+
{ name: "amount", type: "uint128" },
|
|
1751
|
+
{ name: "sender", type: "principal" },
|
|
1752
|
+
{ name: "recipient", type: "principal" },
|
|
1753
|
+
{ name: "memo", type: { optional: { buff: { length: 34 } } } }
|
|
1754
|
+
],
|
|
1755
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1756
|
+
},
|
|
1757
|
+
{
|
|
1758
|
+
name: "get-balance",
|
|
1759
|
+
access: "read-only",
|
|
1760
|
+
args: [{ name: "account", type: "principal" }],
|
|
1761
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1762
|
+
},
|
|
1763
|
+
{
|
|
1764
|
+
name: "get-total-supply",
|
|
1765
|
+
access: "read-only",
|
|
1766
|
+
args: [],
|
|
1767
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1768
|
+
},
|
|
1769
|
+
{
|
|
1770
|
+
name: "get-name",
|
|
1771
|
+
access: "read-only",
|
|
1772
|
+
args: [],
|
|
1773
|
+
outputs: {
|
|
1774
|
+
response: {
|
|
1775
|
+
ok: { "string-ascii": { length: 32 } },
|
|
1776
|
+
error: "uint128"
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
},
|
|
1780
|
+
{
|
|
1781
|
+
name: "get-symbol",
|
|
1782
|
+
access: "read-only",
|
|
1783
|
+
args: [],
|
|
1784
|
+
outputs: {
|
|
1785
|
+
response: {
|
|
1786
|
+
ok: { "string-ascii": { length: 10 } },
|
|
1787
|
+
error: "uint128"
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
},
|
|
1791
|
+
{
|
|
1792
|
+
name: "get-decimals",
|
|
1793
|
+
access: "read-only",
|
|
1794
|
+
args: [],
|
|
1795
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1796
|
+
},
|
|
1797
|
+
{
|
|
1798
|
+
name: "get-token-uri",
|
|
1799
|
+
access: "read-only",
|
|
1800
|
+
args: [],
|
|
1801
|
+
outputs: {
|
|
1802
|
+
response: {
|
|
1803
|
+
ok: { optional: { "string-utf8": { length: 256 } } },
|
|
1804
|
+
error: "uint128"
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1884
1807
|
}
|
|
1885
|
-
|
|
1886
|
-
}
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
const fieldValue = hasOriginal ? obj[field.name] : hasCamel ? obj[camelKey] : undefined;
|
|
1924
|
-
if (fieldValue === undefined && !isAbiOptional(field.type)) {
|
|
1925
|
-
throw new Error(`Missing tuple field: ${field.name}`);
|
|
1808
|
+
],
|
|
1809
|
+
fungible_tokens: [{ name: "token" }]
|
|
1810
|
+
};
|
|
1811
|
+
var SIP009_ABI = {
|
|
1812
|
+
functions: [
|
|
1813
|
+
{
|
|
1814
|
+
name: "transfer",
|
|
1815
|
+
access: "public",
|
|
1816
|
+
args: [
|
|
1817
|
+
{ name: "id", type: "uint128" },
|
|
1818
|
+
{ name: "sender", type: "principal" },
|
|
1819
|
+
{ name: "recipient", type: "principal" }
|
|
1820
|
+
],
|
|
1821
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1822
|
+
},
|
|
1823
|
+
{
|
|
1824
|
+
name: "get-owner",
|
|
1825
|
+
access: "read-only",
|
|
1826
|
+
args: [{ name: "id", type: "uint128" }],
|
|
1827
|
+
outputs: {
|
|
1828
|
+
response: { ok: { optional: "principal" }, error: "uint128" }
|
|
1829
|
+
}
|
|
1830
|
+
},
|
|
1831
|
+
{
|
|
1832
|
+
name: "get-last-token-id",
|
|
1833
|
+
access: "read-only",
|
|
1834
|
+
args: [],
|
|
1835
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1836
|
+
},
|
|
1837
|
+
{
|
|
1838
|
+
name: "get-token-uri",
|
|
1839
|
+
access: "read-only",
|
|
1840
|
+
args: [{ name: "id", type: "uint128" }],
|
|
1841
|
+
outputs: {
|
|
1842
|
+
response: {
|
|
1843
|
+
ok: { optional: { "string-utf8": { length: 256 } } },
|
|
1844
|
+
error: "uint128"
|
|
1845
|
+
}
|
|
1926
1846
|
}
|
|
1927
|
-
data[field.name] = jsToClarityValue(field.type, fieldValue);
|
|
1928
1847
|
}
|
|
1929
|
-
|
|
1930
|
-
}
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1848
|
+
],
|
|
1849
|
+
non_fungible_tokens: [{ name: "nft", type: "uint128" }]
|
|
1850
|
+
};
|
|
1851
|
+
var SIP013_ABI = {
|
|
1852
|
+
functions: [
|
|
1853
|
+
{
|
|
1854
|
+
name: "transfer",
|
|
1855
|
+
access: "public",
|
|
1856
|
+
args: [
|
|
1857
|
+
{ name: "token-id", type: "uint128" },
|
|
1858
|
+
{ name: "amount", type: "uint128" },
|
|
1859
|
+
{ name: "sender", type: "principal" },
|
|
1860
|
+
{ name: "recipient", type: "principal" }
|
|
1861
|
+
],
|
|
1862
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
name: "transfer-memo",
|
|
1866
|
+
access: "public",
|
|
1867
|
+
args: [
|
|
1868
|
+
{ name: "token-id", type: "uint128" },
|
|
1869
|
+
{ name: "amount", type: "uint128" },
|
|
1870
|
+
{ name: "sender", type: "principal" },
|
|
1871
|
+
{ name: "recipient", type: "principal" },
|
|
1872
|
+
{ name: "memo", type: { buff: { length: 34 } } }
|
|
1873
|
+
],
|
|
1874
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
name: "transfer-many",
|
|
1878
|
+
access: "public",
|
|
1879
|
+
args: [
|
|
1880
|
+
{
|
|
1881
|
+
name: "transfers",
|
|
1882
|
+
type: {
|
|
1883
|
+
list: {
|
|
1884
|
+
type: {
|
|
1885
|
+
tuple: [
|
|
1886
|
+
{ name: "token-id", type: "uint128" },
|
|
1887
|
+
{ name: "amount", type: "uint128" },
|
|
1888
|
+
{ name: "sender", type: "principal" },
|
|
1889
|
+
{ name: "recipient", type: "principal" }
|
|
1890
|
+
]
|
|
1891
|
+
},
|
|
1892
|
+
length: 200
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
],
|
|
1897
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1898
|
+
},
|
|
1899
|
+
{
|
|
1900
|
+
name: "transfer-many-memo",
|
|
1901
|
+
access: "public",
|
|
1902
|
+
args: [
|
|
1903
|
+
{
|
|
1904
|
+
name: "transfers",
|
|
1905
|
+
type: {
|
|
1906
|
+
list: {
|
|
1907
|
+
type: {
|
|
1908
|
+
tuple: [
|
|
1909
|
+
{ name: "token-id", type: "uint128" },
|
|
1910
|
+
{ name: "amount", type: "uint128" },
|
|
1911
|
+
{ name: "sender", type: "principal" },
|
|
1912
|
+
{ name: "recipient", type: "principal" },
|
|
1913
|
+
{ name: "memo", type: { buff: { length: 34 } } }
|
|
1914
|
+
]
|
|
1915
|
+
},
|
|
1916
|
+
length: 200
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
],
|
|
1921
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1922
|
+
},
|
|
1923
|
+
{
|
|
1924
|
+
name: "get-balance",
|
|
1925
|
+
access: "read-only",
|
|
1926
|
+
args: [
|
|
1927
|
+
{ name: "token-id", type: "uint128" },
|
|
1928
|
+
{ name: "account", type: "principal" }
|
|
1929
|
+
],
|
|
1930
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1931
|
+
},
|
|
1932
|
+
{
|
|
1933
|
+
name: "get-overall-balance",
|
|
1934
|
+
access: "read-only",
|
|
1935
|
+
args: [{ name: "account", type: "principal" }],
|
|
1936
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1937
|
+
},
|
|
1938
|
+
{
|
|
1939
|
+
name: "get-total-supply",
|
|
1940
|
+
access: "read-only",
|
|
1941
|
+
args: [{ name: "token-id", type: "uint128" }],
|
|
1942
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1943
|
+
},
|
|
1944
|
+
{
|
|
1945
|
+
name: "get-overall-supply",
|
|
1946
|
+
access: "read-only",
|
|
1947
|
+
args: [],
|
|
1948
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1949
|
+
},
|
|
1950
|
+
{
|
|
1951
|
+
name: "get-decimals",
|
|
1952
|
+
access: "read-only",
|
|
1953
|
+
args: [{ name: "token-id", type: "uint128" }],
|
|
1954
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1955
|
+
},
|
|
1956
|
+
{
|
|
1957
|
+
name: "get-token-uri",
|
|
1958
|
+
access: "read-only",
|
|
1959
|
+
args: [{ name: "token-id", type: "uint128" }],
|
|
1960
|
+
outputs: {
|
|
1961
|
+
response: {
|
|
1962
|
+
ok: { optional: { "string-utf8": { length: 256 } } },
|
|
1963
|
+
error: "uint128"
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
],
|
|
1968
|
+
fungible_tokens: [],
|
|
1969
|
+
non_fungible_tokens: []
|
|
1970
|
+
};
|
|
1971
|
+
var sip010Abi = SIP010_ABI;
|
|
1972
|
+
var sip009Abi = SIP009_ABI;
|
|
1973
|
+
var sip013Abi = SIP013_ABI;
|
|
1974
|
+
// src/clarity/abi/classify.ts
|
|
1975
|
+
var TRAIT_STANDARDS = ["sip-009", "sip-010", "sip-013"];
|
|
1976
|
+
var STANDARDS = [
|
|
1977
|
+
{ id: "sip-010", abi: SIP010_ABI, optional: new Set(["get-token-uri"]) },
|
|
1978
|
+
{ id: "sip-009", abi: SIP009_ABI, optional: new Set(["get-token-uri"]) },
|
|
1979
|
+
{
|
|
1980
|
+
id: "sip-013",
|
|
1981
|
+
abi: SIP013_ABI,
|
|
1982
|
+
optional: new Set([
|
|
1983
|
+
"transfer-memo",
|
|
1984
|
+
"transfer-many",
|
|
1985
|
+
"transfer-many-memo",
|
|
1986
|
+
"get-token-uri",
|
|
1987
|
+
"get-overall-balance",
|
|
1988
|
+
"get-overall-supply"
|
|
1989
|
+
])
|
|
1935
1990
|
}
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1991
|
+
];
|
|
1992
|
+
function indexByName(abi) {
|
|
1993
|
+
const m = new Map;
|
|
1994
|
+
for (const f of abi.functions)
|
|
1995
|
+
m.set(f.name, f);
|
|
1996
|
+
return m;
|
|
1997
|
+
}
|
|
1998
|
+
function conformsTo(candidate, spec) {
|
|
1999
|
+
const fns = indexByName(candidate);
|
|
2000
|
+
for (const required of spec.abi.functions) {
|
|
2001
|
+
if (spec.optional.has(required.name))
|
|
2002
|
+
continue;
|
|
2003
|
+
const got = fns.get(required.name);
|
|
2004
|
+
if (!got)
|
|
2005
|
+
return false;
|
|
2006
|
+
if (got.access !== required.access)
|
|
2007
|
+
return false;
|
|
2008
|
+
if (got.args.length !== required.args.length)
|
|
2009
|
+
return false;
|
|
1943
2010
|
}
|
|
1944
|
-
|
|
2011
|
+
return true;
|
|
1945
2012
|
}
|
|
1946
|
-
function
|
|
1947
|
-
|
|
2013
|
+
function classifyContract(abi) {
|
|
2014
|
+
if (!abi || !Array.isArray(abi.functions))
|
|
2015
|
+
return [];
|
|
2016
|
+
return STANDARDS.filter((s) => conformsTo(abi, s)).map((s) => s.id);
|
|
1948
2017
|
}
|
|
1949
|
-
function
|
|
1950
|
-
|
|
2018
|
+
function parseDeclaredStandards(claritySource) {
|
|
2019
|
+
const out = new Set;
|
|
2020
|
+
const matches = claritySource.matchAll(/\(impl-trait\s+[^)]+\)/gi);
|
|
2021
|
+
for (const m of matches) {
|
|
2022
|
+
const ref = m[0].toLowerCase();
|
|
2023
|
+
if (ref.includes("sip-010") || ref.includes(".ft-trait"))
|
|
2024
|
+
out.add("sip-010");
|
|
2025
|
+
if (ref.includes("sip-009") || ref.includes("nft-trait"))
|
|
2026
|
+
out.add("sip-009");
|
|
2027
|
+
if (ref.includes("sip-013") || ref.includes("semi-fungible"))
|
|
2028
|
+
out.add("sip-013");
|
|
2029
|
+
}
|
|
2030
|
+
return [...out];
|
|
1951
2031
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
2032
|
+
// src/clarity/abi/normalize.ts
|
|
2033
|
+
function normalizeAccess(access) {
|
|
2034
|
+
if (access === "read_only")
|
|
2035
|
+
return "read-only";
|
|
2036
|
+
return access;
|
|
2037
|
+
}
|
|
2038
|
+
function normalizeType(type) {
|
|
2039
|
+
if (typeof type === "string") {
|
|
2040
|
+
switch (type) {
|
|
2041
|
+
case "uint128":
|
|
2042
|
+
case "int128":
|
|
2043
|
+
case "bool":
|
|
2044
|
+
case "principal":
|
|
2045
|
+
case "trait_reference":
|
|
2046
|
+
return type;
|
|
2047
|
+
default:
|
|
2048
|
+
return type;
|
|
2049
|
+
}
|
|
1957
2050
|
}
|
|
1958
|
-
if (
|
|
1959
|
-
|
|
1960
|
-
return true;
|
|
1961
|
-
if (cv.type === "false")
|
|
1962
|
-
return false;
|
|
1963
|
-
throw new Error(`Expected bool CV, got ${cv.type}`);
|
|
2051
|
+
if (typeof type !== "object" || type === null) {
|
|
2052
|
+
throw new Error(`Invalid ABI type: expected object, got ${typeof type}`);
|
|
1964
2053
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
return
|
|
2054
|
+
const typeObj = type;
|
|
2055
|
+
if ("buffer" in typeObj) {
|
|
2056
|
+
const buffer = typeObj.buffer;
|
|
2057
|
+
return {
|
|
2058
|
+
buff: {
|
|
2059
|
+
length: buffer?.length ?? 32
|
|
2060
|
+
}
|
|
2061
|
+
};
|
|
1969
2062
|
}
|
|
1970
|
-
if (
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
2063
|
+
if ("buff" in typeObj) {
|
|
2064
|
+
const buff = typeObj.buff;
|
|
2065
|
+
return {
|
|
2066
|
+
buff: {
|
|
2067
|
+
length: buff?.length ?? 32
|
|
2068
|
+
}
|
|
2069
|
+
};
|
|
1974
2070
|
}
|
|
1975
|
-
if (
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
}
|
|
1983
|
-
return bytes;
|
|
2071
|
+
if ("string-ascii" in typeObj) {
|
|
2072
|
+
const strAscii = typeObj["string-ascii"];
|
|
2073
|
+
return {
|
|
2074
|
+
"string-ascii": {
|
|
2075
|
+
length: strAscii?.length ?? 256
|
|
2076
|
+
}
|
|
2077
|
+
};
|
|
1984
2078
|
}
|
|
1985
|
-
if (
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
2079
|
+
if ("string-utf8" in typeObj) {
|
|
2080
|
+
const strUtf8 = typeObj["string-utf8"];
|
|
2081
|
+
return {
|
|
2082
|
+
"string-utf8": {
|
|
2083
|
+
length: strUtf8?.length ?? 256
|
|
2084
|
+
}
|
|
2085
|
+
};
|
|
1989
2086
|
}
|
|
1990
|
-
if (
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
const camelKey = toCamelCase(field.name);
|
|
1999
|
-
result[camelKey] = clarityValueToJSInner(field.type, fieldCV);
|
|
2000
|
-
}
|
|
2001
|
-
return result;
|
|
2087
|
+
if ("response" in typeObj) {
|
|
2088
|
+
const response = typeObj.response;
|
|
2089
|
+
return {
|
|
2090
|
+
response: {
|
|
2091
|
+
ok: normalizeType(response?.ok ?? "bool"),
|
|
2092
|
+
error: normalizeType(response?.error ?? "uint128")
|
|
2093
|
+
}
|
|
2094
|
+
};
|
|
2002
2095
|
}
|
|
2003
|
-
if (
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
return clarityValueToJSInner(abiType.optional, cv.value);
|
|
2008
|
-
throw new Error(`Expected optional CV, got ${cv.type}`);
|
|
2096
|
+
if ("optional" in typeObj) {
|
|
2097
|
+
return {
|
|
2098
|
+
optional: normalizeType(typeObj.optional)
|
|
2099
|
+
};
|
|
2009
2100
|
}
|
|
2010
|
-
if (
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2101
|
+
if ("list" in typeObj) {
|
|
2102
|
+
const list = typeObj.list;
|
|
2103
|
+
return {
|
|
2104
|
+
list: {
|
|
2105
|
+
type: normalizeType(list?.type ?? "uint128"),
|
|
2106
|
+
length: list?.length ?? 100
|
|
2107
|
+
}
|
|
2108
|
+
};
|
|
2016
2109
|
}
|
|
2017
|
-
|
|
2110
|
+
if ("tuple" in typeObj) {
|
|
2111
|
+
const tuple = typeObj.tuple;
|
|
2112
|
+
return {
|
|
2113
|
+
tuple: tuple.map((field) => ({
|
|
2114
|
+
name: field.name,
|
|
2115
|
+
type: normalizeType(field.type)
|
|
2116
|
+
}))
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
throw new Error(`Unknown ABI type structure: ${JSON.stringify(type)}`);
|
|
2018
2120
|
}
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
parseBitcoinTx: () => parseBitcoinTx,
|
|
2033
|
-
merkleRoot: () => merkleRoot,
|
|
2034
|
-
isClarity6Active: () => isClarity6Active,
|
|
2035
|
-
getSpvAdapter: () => getSpvAdapter,
|
|
2036
|
-
getBurnBlockHeight: () => getBurnBlockHeight,
|
|
2037
|
-
formatBitcoinAddress: () => formatBitcoinAddress,
|
|
2038
|
-
fallbackProofSource: () => fallbackProofSource,
|
|
2039
|
-
esploraSource: () => esploraSource,
|
|
2040
|
-
encodeMerkleProofArgs: () => encodeMerkleProofArgs,
|
|
2041
|
-
doubleSha256: () => doubleSha256,
|
|
2042
|
-
decodeTxOutput: () => decodeTxOutput,
|
|
2043
|
-
buildTxProof: () => buildTxProof,
|
|
2044
|
-
buildMerkleProof: () => buildMerkleProof,
|
|
2045
|
-
blockHash: () => blockHash,
|
|
2046
|
-
bitcoinVerifier: () => bitcoinVerifier,
|
|
2047
|
-
bitcoinTxid: () => bitcoinTxid,
|
|
2048
|
-
bitcoinRpcSource: () => bitcoinRpcSource,
|
|
2049
|
-
SPV_ADAPTER_CONTRACTS: () => SPV_ADAPTER_CONTRACTS,
|
|
2050
|
-
SPV_ADAPTER_ABI: () => SPV_ADAPTER_ABI,
|
|
2051
|
-
EPOCH_4_ACTIVATION_BURN_HEIGHT_MAINNET: () => EPOCH_4_ACTIVATION_BURN_HEIGHT_MAINNET,
|
|
2052
|
-
BtcReader: () => BtcReader
|
|
2053
|
-
});
|
|
2054
|
-
module.exports = __toCommonJS(exports_bitcoin);
|
|
2055
|
-
|
|
2056
|
-
// src/bitcoin/serialize.ts
|
|
2057
|
-
function doubleSha256(bytes) {
|
|
2058
|
-
return import_sha22.sha256(import_sha22.sha256(bytes));
|
|
2121
|
+
function normalizeFunction(func) {
|
|
2122
|
+
const access = normalizeAccess(func.access);
|
|
2123
|
+
const args = func.args ?? [];
|
|
2124
|
+
const outputs = func.outputs;
|
|
2125
|
+
return {
|
|
2126
|
+
name: func.name,
|
|
2127
|
+
access,
|
|
2128
|
+
args: args.map((arg) => ({
|
|
2129
|
+
name: arg.name,
|
|
2130
|
+
type: normalizeType(arg.type)
|
|
2131
|
+
})),
|
|
2132
|
+
outputs: normalizeType(typeof outputs === "object" && outputs !== null && "type" in outputs ? outputs.type : outputs)
|
|
2133
|
+
};
|
|
2059
2134
|
}
|
|
2060
|
-
function
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2135
|
+
function normalizeMap(map) {
|
|
2136
|
+
return {
|
|
2137
|
+
name: map.name,
|
|
2138
|
+
key: normalizeType(map.key),
|
|
2139
|
+
value: normalizeType(map.value)
|
|
2140
|
+
};
|
|
2066
2141
|
}
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
}
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
}
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
return v;
|
|
2142
|
+
function normalizeVariable(variable) {
|
|
2143
|
+
return {
|
|
2144
|
+
name: variable.name,
|
|
2145
|
+
type: normalizeType(variable.type),
|
|
2146
|
+
access: variable.access
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
function normalizeFungibleToken(token) {
|
|
2150
|
+
return { name: token.name };
|
|
2151
|
+
}
|
|
2152
|
+
function normalizeNonFungibleToken(token) {
|
|
2153
|
+
return { name: token.name, type: normalizeType(token.type) };
|
|
2154
|
+
}
|
|
2155
|
+
function normalizeTraitDefinition(trait) {
|
|
2156
|
+
const rawFunctions = Array.isArray(trait.functions) ? trait.functions : [];
|
|
2157
|
+
const functions = [];
|
|
2158
|
+
for (const func of rawFunctions) {
|
|
2159
|
+
if (typeof func !== "object" || func === null)
|
|
2160
|
+
continue;
|
|
2161
|
+
const normalized = normalizeFunction(func);
|
|
2162
|
+
if (normalized.access === "private")
|
|
2163
|
+
continue;
|
|
2164
|
+
functions.push(normalized);
|
|
2091
2165
|
}
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2166
|
+
return { name: trait.name, functions };
|
|
2167
|
+
}
|
|
2168
|
+
function normalizeAbi(abi) {
|
|
2169
|
+
if (typeof abi !== "object" || abi === null) {
|
|
2170
|
+
return { functions: [] };
|
|
2096
2171
|
}
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2172
|
+
const abiObj = abi;
|
|
2173
|
+
const functions = [];
|
|
2174
|
+
const maps = [];
|
|
2175
|
+
const variables = [];
|
|
2176
|
+
const fungibleTokens = [];
|
|
2177
|
+
const nonFungibleTokens = [];
|
|
2178
|
+
const implementedTraits = [];
|
|
2179
|
+
const definedTraits = [];
|
|
2180
|
+
if (Array.isArray(abiObj.functions)) {
|
|
2181
|
+
for (const func of abiObj.functions) {
|
|
2182
|
+
if (typeof func === "object" && func !== null) {
|
|
2183
|
+
functions.push(normalizeFunction(func));
|
|
2184
|
+
}
|
|
2100
2185
|
}
|
|
2101
|
-
const slice = this.data.slice(this.offset, this.offset + n);
|
|
2102
|
-
this.offset += n;
|
|
2103
|
-
return slice;
|
|
2104
2186
|
}
|
|
2105
|
-
|
|
2106
|
-
const
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
const v = this.view.getUint16(this.offset, true);
|
|
2111
|
-
this.offset += 2;
|
|
2112
|
-
return v;
|
|
2113
|
-
}
|
|
2114
|
-
if (first === 254) {
|
|
2115
|
-
return this.readUInt32LE();
|
|
2187
|
+
if (Array.isArray(abiObj.maps)) {
|
|
2188
|
+
for (const map of abiObj.maps) {
|
|
2189
|
+
if (typeof map === "object" && map !== null) {
|
|
2190
|
+
maps.push(normalizeMap(map));
|
|
2191
|
+
}
|
|
2116
2192
|
}
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2193
|
+
}
|
|
2194
|
+
if (Array.isArray(abiObj.variables)) {
|
|
2195
|
+
for (const variable of abiObj.variables) {
|
|
2196
|
+
if (typeof variable === "object" && variable !== null) {
|
|
2197
|
+
variables.push(normalizeVariable(variable));
|
|
2198
|
+
}
|
|
2120
2199
|
}
|
|
2121
|
-
return Number(big);
|
|
2122
2200
|
}
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
if (r.peekUInt8() === 0) {
|
|
2129
|
-
r.readUInt8();
|
|
2130
|
-
const flag = r.readUInt8();
|
|
2131
|
-
if (flag !== 1) {
|
|
2132
|
-
throw new Error(`Unexpected SegWit flag 0x${flag.toString(16)}`);
|
|
2201
|
+
if (Array.isArray(abiObj.fungible_tokens)) {
|
|
2202
|
+
for (const token of abiObj.fungible_tokens) {
|
|
2203
|
+
if (typeof token === "object" && token !== null) {
|
|
2204
|
+
fungibleTokens.push(normalizeFungibleToken(token));
|
|
2205
|
+
}
|
|
2133
2206
|
}
|
|
2134
|
-
hasWitness = true;
|
|
2135
2207
|
}
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
const scriptSig = r.readBytes(r.readVarInt());
|
|
2143
|
-
const sequence = r.readUInt32LE();
|
|
2144
|
-
inputs.push({ prevTxid, vout, scriptSig, sequence });
|
|
2208
|
+
if (Array.isArray(abiObj.non_fungible_tokens)) {
|
|
2209
|
+
for (const token of abiObj.non_fungible_tokens) {
|
|
2210
|
+
if (typeof token === "object" && token !== null) {
|
|
2211
|
+
nonFungibleTokens.push(normalizeNonFungibleToken(token));
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2145
2214
|
}
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
outputs.push({ value, scriptPubKey });
|
|
2215
|
+
if (Array.isArray(abiObj.implemented_traits)) {
|
|
2216
|
+
for (const trait of abiObj.implemented_traits) {
|
|
2217
|
+
if (typeof trait === "string")
|
|
2218
|
+
implementedTraits.push(trait);
|
|
2219
|
+
}
|
|
2152
2220
|
}
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
for (let j = 0;j < itemCount; j++) {
|
|
2158
|
-
r.readBytes(r.readVarInt());
|
|
2221
|
+
if (Array.isArray(abiObj.defined_traits)) {
|
|
2222
|
+
for (const trait of abiObj.defined_traits) {
|
|
2223
|
+
if (typeof trait === "object" && trait !== null) {
|
|
2224
|
+
definedTraits.push(normalizeTraitDefinition(trait));
|
|
2159
2225
|
}
|
|
2160
2226
|
}
|
|
2161
2227
|
}
|
|
2162
|
-
const locktime = r.readUInt32LE();
|
|
2163
|
-
const legacy = concatBytes(rawTx.slice(0, 4), rawTx.slice(bodyStart, bodyEnd), rawTx.slice(r.offset - 4, r.offset));
|
|
2164
|
-
return { version, hasWitness, inputs, outputs, locktime, legacy };
|
|
2165
|
-
}
|
|
2166
|
-
function parseBitcoinTx(rawTx) {
|
|
2167
|
-
const s = scanTx(rawTx);
|
|
2168
2228
|
return {
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2229
|
+
functions,
|
|
2230
|
+
maps: maps.length > 0 ? maps : undefined,
|
|
2231
|
+
variables: variables.length > 0 ? variables : undefined,
|
|
2232
|
+
fungible_tokens: fungibleTokens.length > 0 ? fungibleTokens : undefined,
|
|
2233
|
+
non_fungible_tokens: nonFungibleTokens.length > 0 ? nonFungibleTokens : undefined,
|
|
2234
|
+
implemented_traits: implementedTraits.length > 0 ? implementedTraits : undefined,
|
|
2235
|
+
defined_traits: definedTraits.length > 0 ? definedTraits : undefined
|
|
2175
2236
|
};
|
|
2176
2237
|
}
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
const
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
return
|
|
2204
|
-
}
|
|
2205
|
-
function nextLevel(level) {
|
|
2206
|
-
const next = [];
|
|
2207
|
-
for (let i = 0;i < level.length; i += 2) {
|
|
2208
|
-
const left = level[i];
|
|
2209
|
-
if (left === undefined)
|
|
2210
|
-
throw new Error("merkle: missing left node");
|
|
2211
|
-
const right = level[i + 1] ?? left;
|
|
2212
|
-
next.push(hashPair(left, right));
|
|
2213
|
-
}
|
|
2214
|
-
return next;
|
|
2238
|
+
// src/clarity/bridge.ts
|
|
2239
|
+
var CV_TYPE_TAGS = new Set([
|
|
2240
|
+
"int",
|
|
2241
|
+
"uint",
|
|
2242
|
+
"true",
|
|
2243
|
+
"false",
|
|
2244
|
+
"address",
|
|
2245
|
+
"contract",
|
|
2246
|
+
"ascii",
|
|
2247
|
+
"utf8",
|
|
2248
|
+
"buffer",
|
|
2249
|
+
"list",
|
|
2250
|
+
"tuple",
|
|
2251
|
+
"none",
|
|
2252
|
+
"some",
|
|
2253
|
+
"ok",
|
|
2254
|
+
"err"
|
|
2255
|
+
]);
|
|
2256
|
+
function isClarityValue(value) {
|
|
2257
|
+
if (typeof value !== "object" || value === null)
|
|
2258
|
+
return false;
|
|
2259
|
+
const type = value.type;
|
|
2260
|
+
if (typeof type !== "string" || !CV_TYPE_TAGS.has(type))
|
|
2261
|
+
return false;
|
|
2262
|
+
if (type === "true" || type === "false" || type === "none")
|
|
2263
|
+
return true;
|
|
2264
|
+
return "value" in value;
|
|
2215
2265
|
}
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2266
|
+
var HEX_PAIRS_REGEX = /^(?:[0-9a-fA-F]{2})+$/;
|
|
2267
|
+
function coerceBuffer(value) {
|
|
2268
|
+
if (value instanceof Uint8Array)
|
|
2269
|
+
return bufferCV(value);
|
|
2270
|
+
if (typeof value === "object" && value !== null && "type" in value) {
|
|
2271
|
+
const tagged = value;
|
|
2272
|
+
if (tagged.type === "buffer" && isClarityValue(value))
|
|
2273
|
+
return value;
|
|
2274
|
+
if (typeof tagged.value === "string") {
|
|
2275
|
+
if (tagged.type === "ascii")
|
|
2276
|
+
return Cl.bufferFromAscii(tagged.value);
|
|
2277
|
+
if (tagged.type === "utf8")
|
|
2278
|
+
return Cl.bufferFromUtf8(tagged.value);
|
|
2279
|
+
if (tagged.type === "hex")
|
|
2280
|
+
return Cl.bufferFromHex(tagged.value);
|
|
2281
|
+
}
|
|
2282
|
+
throw new Error(`Unsupported buffer input: ${JSON.stringify(value)}`);
|
|
2219
2283
|
}
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2284
|
+
if (typeof value === "string") {
|
|
2285
|
+
const hex = value.startsWith("0x") ? value.slice(2) : value;
|
|
2286
|
+
if (HEX_PAIRS_REGEX.test(hex))
|
|
2287
|
+
return Cl.bufferFromHex(hex);
|
|
2288
|
+
return Cl.bufferFromUtf8(value);
|
|
2223
2289
|
}
|
|
2224
|
-
|
|
2225
|
-
if (root === undefined)
|
|
2226
|
-
throw new Error("merkleRoot: no root");
|
|
2227
|
-
return root;
|
|
2290
|
+
throw new Error("buffer arg expects Uint8Array, hex string, { type, value }, or BufferCV");
|
|
2228
2291
|
}
|
|
2229
|
-
function
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2292
|
+
function jsToClarityValue(abiType, value) {
|
|
2293
|
+
if (isAbiBuffer(abiType))
|
|
2294
|
+
return coerceBuffer(value);
|
|
2295
|
+
if (isClarityValue(value))
|
|
2296
|
+
return value;
|
|
2297
|
+
if (abiType === "uint128")
|
|
2298
|
+
return uintCV(value);
|
|
2299
|
+
if (abiType === "int128")
|
|
2300
|
+
return intCV(value);
|
|
2301
|
+
if (abiType === "bool")
|
|
2302
|
+
return boolCV(value);
|
|
2303
|
+
if (abiType === "principal" || abiType === "trait_reference")
|
|
2304
|
+
return Cl.principal(value);
|
|
2305
|
+
if (isAbiStringAscii(abiType))
|
|
2306
|
+
return stringAsciiCV(value);
|
|
2307
|
+
if (isAbiStringUtf8(abiType))
|
|
2308
|
+
return stringUtf8CV(value);
|
|
2309
|
+
if (isAbiList(abiType)) {
|
|
2310
|
+
const arr = value;
|
|
2311
|
+
return listCV(arr.map((item) => jsToClarityValue(abiType.list.type, item)));
|
|
2233
2312
|
}
|
|
2234
|
-
if (
|
|
2235
|
-
|
|
2313
|
+
if (isAbiTuple(abiType)) {
|
|
2314
|
+
const obj = value;
|
|
2315
|
+
const data = {};
|
|
2316
|
+
for (const field of abiType.tuple) {
|
|
2317
|
+
const camelKey = toCamelCase(field.name);
|
|
2318
|
+
const hasOriginal = field.name in obj;
|
|
2319
|
+
const hasCamel = camelKey in obj;
|
|
2320
|
+
const fieldValue = hasOriginal ? obj[field.name] : hasCamel ? obj[camelKey] : undefined;
|
|
2321
|
+
if (fieldValue === undefined && !isAbiOptional(field.type)) {
|
|
2322
|
+
throw new Error(`Missing tuple field: ${field.name}`);
|
|
2323
|
+
}
|
|
2324
|
+
data[field.name] = jsToClarityValue(field.type, fieldValue);
|
|
2325
|
+
}
|
|
2326
|
+
return tupleCV(data);
|
|
2236
2327
|
}
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
const isRight = index % 2 === 1;
|
|
2242
|
-
const siblingIndex = isRight ? index - 1 : index + 1;
|
|
2243
|
-
const self = level[index];
|
|
2244
|
-
if (self === undefined)
|
|
2245
|
-
throw new Error("buildMerkleProof: missing node");
|
|
2246
|
-
siblings.push(level[siblingIndex] ?? self);
|
|
2247
|
-
level = nextLevel(level);
|
|
2248
|
-
index = Math.floor(index / 2);
|
|
2328
|
+
if (isAbiOptional(abiType)) {
|
|
2329
|
+
if (value === null || value === undefined)
|
|
2330
|
+
return noneCV();
|
|
2331
|
+
return someCV(jsToClarityValue(abiType.optional, value));
|
|
2249
2332
|
}
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
index = Math.floor(index / 2);
|
|
2333
|
+
if (isAbiResponse(abiType)) {
|
|
2334
|
+
const obj = value;
|
|
2335
|
+
if ("ok" in obj && !("err" in obj))
|
|
2336
|
+
return responseOkCV(jsToClarityValue(abiType.response.ok, obj.ok));
|
|
2337
|
+
if ("err" in obj && !("ok" in obj))
|
|
2338
|
+
return responseErrorCV(jsToClarityValue(abiType.response.error, obj.err));
|
|
2339
|
+
throw new Error("Response must have exactly 'ok' or 'err' property");
|
|
2258
2340
|
}
|
|
2259
|
-
|
|
2341
|
+
throw new Error(`Unknown ABI type: ${JSON.stringify(abiType)}`);
|
|
2260
2342
|
}
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
function normalizeTxid(txid) {
|
|
2264
|
-
return without0x(txid).toLowerCase();
|
|
2343
|
+
function clarityValueToJS(abiType, cv) {
|
|
2344
|
+
return clarityValueToJSInner(abiType, cv);
|
|
2265
2345
|
}
|
|
2266
|
-
function
|
|
2267
|
-
|
|
2268
|
-
if (txIndex < 0) {
|
|
2269
|
-
throw new Error(`tx ${args.txid} not found in block ${args.blockId}`);
|
|
2270
|
-
}
|
|
2271
|
-
return {
|
|
2272
|
-
header: hexToBytes(args.headerHex),
|
|
2273
|
-
height: args.height,
|
|
2274
|
-
txidsInternal: args.txidsDisplay.map((t) => reverseBytes(hexToBytes(t))),
|
|
2275
|
-
txIndex
|
|
2276
|
-
};
|
|
2346
|
+
function clarityValueToJSUntyped(abiType, cv) {
|
|
2347
|
+
return clarityValueToJSInner(abiType, cv);
|
|
2277
2348
|
}
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
source.getBlockForTx(txid)
|
|
2284
|
-
]);
|
|
2285
|
-
const parsed = parseBitcoinTx(rawTx);
|
|
2286
|
-
const gotDisplay = bytesToHex(reverseBytes(parsed.txidInternal));
|
|
2287
|
-
if (gotDisplay !== want) {
|
|
2288
|
-
throw new Error(`source returned a tx whose id ${gotDisplay} does not match requested ${want}`);
|
|
2349
|
+
function clarityValueToJSInner(abiType, cv) {
|
|
2350
|
+
if (abiType === "uint128" || abiType === "int128") {
|
|
2351
|
+
if (cv.type !== "int" && cv.type !== "uint")
|
|
2352
|
+
throw new Error(`Expected int/uint CV, got ${cv.type}`);
|
|
2353
|
+
return cv.value;
|
|
2289
2354
|
}
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2355
|
+
if (abiType === "bool") {
|
|
2356
|
+
if (cv.type === "true")
|
|
2357
|
+
return true;
|
|
2358
|
+
if (cv.type === "false")
|
|
2359
|
+
return false;
|
|
2360
|
+
throw new Error(`Expected bool CV, got ${cv.type}`);
|
|
2293
2361
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
throw new Error("constructed merkle proof does not reconcile with the block header merkle root");
|
|
2362
|
+
if (abiType === "principal" || abiType === "trait_reference") {
|
|
2363
|
+
if (cv.type !== "address" && cv.type !== "contract")
|
|
2364
|
+
throw new Error(`Expected principal CV, got ${cv.type}`);
|
|
2365
|
+
return cv.value;
|
|
2299
2366
|
}
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
merkle,
|
|
2305
|
-
header: block.header,
|
|
2306
|
-
height: block.height
|
|
2307
|
-
};
|
|
2308
|
-
}
|
|
2309
|
-
function fallbackProofSource(sources) {
|
|
2310
|
-
if (sources.length === 0) {
|
|
2311
|
-
throw new Error("fallbackProofSource: at least one source is required");
|
|
2367
|
+
if (isAbiStringAscii(abiType) || isAbiStringUtf8(abiType)) {
|
|
2368
|
+
if (cv.type !== "ascii" && cv.type !== "utf8")
|
|
2369
|
+
throw new Error(`Expected string CV, got ${cv.type}`);
|
|
2370
|
+
return cv.value;
|
|
2312
2371
|
}
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
}
|
|
2372
|
+
if (isAbiBuffer(abiType)) {
|
|
2373
|
+
if (cv.type !== "buffer")
|
|
2374
|
+
throw new Error(`Expected buffer CV, got ${cv.type}`);
|
|
2375
|
+
const hex = cv.value;
|
|
2376
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
2377
|
+
for (let i = 0;i < bytes.length; i++) {
|
|
2378
|
+
bytes[i] = Number.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
|
|
2321
2379
|
}
|
|
2322
|
-
|
|
2380
|
+
return bytes;
|
|
2323
2381
|
}
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
}
|
|
2329
|
-
function bitcoinRpcSource(config) {
|
|
2330
|
-
const doFetch = config.fetch ?? fetch;
|
|
2331
|
-
async function rpc(method, rpcParams) {
|
|
2332
|
-
const headers = {
|
|
2333
|
-
"content-type": "application/json"
|
|
2334
|
-
};
|
|
2335
|
-
if (config.auth) {
|
|
2336
|
-
const basic = typeof config.auth === "string" ? config.auth : btoa(`${config.auth.username}:${config.auth.password}`);
|
|
2337
|
-
headers.authorization = `Basic ${basic}`;
|
|
2338
|
-
}
|
|
2339
|
-
const res = await doFetch(config.url, {
|
|
2340
|
-
method: "POST",
|
|
2341
|
-
headers,
|
|
2342
|
-
body: JSON.stringify({
|
|
2343
|
-
jsonrpc: "1.0",
|
|
2344
|
-
id: "secondlayer",
|
|
2345
|
-
method,
|
|
2346
|
-
params: rpcParams
|
|
2347
|
-
})
|
|
2348
|
-
});
|
|
2349
|
-
if (!res.ok) {
|
|
2350
|
-
throw new Error(`bitcoin rpc ${method} failed: HTTP ${res.status}`);
|
|
2351
|
-
}
|
|
2352
|
-
const json = await res.json();
|
|
2353
|
-
if (json.error) {
|
|
2354
|
-
throw new Error(`bitcoin rpc ${method} error: ${json.error.message}`);
|
|
2355
|
-
}
|
|
2356
|
-
return json.result;
|
|
2382
|
+
if (isAbiList(abiType)) {
|
|
2383
|
+
if (cv.type !== "list")
|
|
2384
|
+
throw new Error(`Expected list CV, got ${cv.type}`);
|
|
2385
|
+
return cv.value.map((item) => clarityValueToJSInner(abiType.list.type, item));
|
|
2357
2386
|
}
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
}
|
|
2362
|
-
|
|
2363
|
-
const
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
throw new Error(`tx ${txid} is not in a block (node needs -txindex, or the tx is unconfirmed)`);
|
|
2369
|
-
}
|
|
2370
|
-
const block = await rpc("getblock", [
|
|
2371
|
-
tx.blockhash,
|
|
2372
|
-
1
|
|
2373
|
-
]);
|
|
2374
|
-
const header = await rpc("getblockheader", [tx.blockhash, false]);
|
|
2375
|
-
return assembleBlockForTx({
|
|
2376
|
-
txid,
|
|
2377
|
-
blockId: tx.blockhash,
|
|
2378
|
-
headerHex: header,
|
|
2379
|
-
height: block.height,
|
|
2380
|
-
txidsDisplay: block.tx
|
|
2381
|
-
});
|
|
2382
|
-
}
|
|
2383
|
-
};
|
|
2384
|
-
}
|
|
2385
|
-
function esploraSource(config) {
|
|
2386
|
-
const doFetch = config.fetch ?? fetch;
|
|
2387
|
-
const base = config.url.replace(/\/+$/, "");
|
|
2388
|
-
async function get(path) {
|
|
2389
|
-
const res = await doFetch(`${base}${path}`);
|
|
2390
|
-
if (!res.ok) {
|
|
2391
|
-
throw new Error(`esplora GET ${path} failed: HTTP ${res.status}`);
|
|
2387
|
+
if (isAbiTuple(abiType)) {
|
|
2388
|
+
if (cv.type !== "tuple")
|
|
2389
|
+
throw new Error(`Expected tuple CV, got ${cv.type}`);
|
|
2390
|
+
const result = {};
|
|
2391
|
+
for (const field of abiType.tuple) {
|
|
2392
|
+
const fieldCV = cv.value[field.name];
|
|
2393
|
+
if (!fieldCV)
|
|
2394
|
+
throw new Error(`Missing tuple field in CV: ${field.name}`);
|
|
2395
|
+
const camelKey = toCamelCase(field.name);
|
|
2396
|
+
result[camelKey] = clarityValueToJSInner(field.type, fieldCV);
|
|
2392
2397
|
}
|
|
2393
|
-
return
|
|
2398
|
+
return result;
|
|
2394
2399
|
}
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
return
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
headerHex: header,
|
|
2411
|
-
height: status.status.block_height,
|
|
2412
|
-
txidsDisplay: txids
|
|
2413
|
-
});
|
|
2414
|
-
}
|
|
2415
|
-
};
|
|
2400
|
+
if (isAbiOptional(abiType)) {
|
|
2401
|
+
if (cv.type === "none")
|
|
2402
|
+
return null;
|
|
2403
|
+
if (cv.type === "some")
|
|
2404
|
+
return clarityValueToJSInner(abiType.optional, cv.value);
|
|
2405
|
+
throw new Error(`Expected optional CV, got ${cv.type}`);
|
|
2406
|
+
}
|
|
2407
|
+
if (isAbiResponse(abiType)) {
|
|
2408
|
+
if (cv.type === "ok")
|
|
2409
|
+
return { ok: clarityValueToJSInner(abiType.response.ok, cv.value) };
|
|
2410
|
+
if (cv.type === "err")
|
|
2411
|
+
return { err: clarityValueToJSInner(abiType.response.error, cv.value) };
|
|
2412
|
+
throw new Error(`Expected response CV, got ${cv.type}`);
|
|
2413
|
+
}
|
|
2414
|
+
throw new Error(`Unknown ABI type: ${JSON.stringify(abiType)}`);
|
|
2416
2415
|
}
|
|
2417
2416
|
// src/bitcoin/codec.ts
|
|
2418
2417
|
function merkleDepth(txCount) {
|
|
@@ -2799,5 +2798,5 @@ async function verifyBitcoinPayment(client, params) {
|
|
|
2799
2798
|
return { verified, mined, output, proof };
|
|
2800
2799
|
}
|
|
2801
2800
|
|
|
2802
|
-
//# debugId=
|
|
2801
|
+
//# debugId=A75A612053B8AE0464756E2164756E21
|
|
2803
2802
|
//# sourceMappingURL=index.cjs.map
|