@secondlayer/stacks 5.1.3 → 6.1.0
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/README.md +1 -8
- package/dist/shared/{stacks-qt8ehebn.js → stacks-esm-0rdxcta7.js} +2 -2
- package/dist/shared/{stacks-qt8ehebn.js.map → stacks-esm-0rdxcta7.js.map} +1 -1
- package/dist/shared/{stacks-4hs8r4q2.js → stacks-esm-1jae0a3r.js} +2 -2
- package/dist/shared/{stacks-xjkn3en1.cjs.map → stacks-esm-1jae0a3r.js.map} +1 -1
- package/dist/shared/{stacks-4d7c3x27.js → stacks-esm-2mc7ebrm.js} +3 -3
- package/dist/shared/{stacks-4d7c3x27.js.map → stacks-esm-2mc7ebrm.js.map} +1 -1
- package/dist/shared/{stacks-8brgfvqx.js → stacks-esm-3g33bqsm.js} +4 -4
- package/dist/shared/{stacks-8brgfvqx.js.map → stacks-esm-3g33bqsm.js.map} +1 -1
- package/dist/shared/{stacks-gjz26k6b.js → stacks-esm-3pv5avgr.js} +59 -15
- package/dist/shared/stacks-esm-3pv5avgr.js.map +12 -0
- package/dist/shared/{stacks-qex691bh.js → stacks-esm-743jfh10.js} +6 -6
- package/dist/shared/{stacks-qex691bh.js.map → stacks-esm-743jfh10.js.map} +1 -1
- package/dist/shared/{stacks-wxfd6r4b.js → stacks-esm-7fpqgtyx.js} +3 -3
- package/dist/shared/{stacks-wxfd6r4b.js.map → stacks-esm-7fpqgtyx.js.map} +1 -1
- package/dist/shared/{stacks-71k0vmct.js → stacks-esm-9rnx0zxr.js} +5 -5
- package/dist/shared/{stacks-71k0vmct.js.map → stacks-esm-9rnx0zxr.js.map} +1 -1
- package/dist/shared/{stacks-fd4rx56e.js → stacks-esm-aw2mj3sj.js} +7 -7
- package/dist/shared/{stacks-fd4rx56e.js.map → stacks-esm-aw2mj3sj.js.map} +1 -1
- package/dist/shared/{stacks-qs5fzts5.js → stacks-esm-cvhazvhd.js} +2 -2
- package/dist/shared/{stacks-qs5fzts5.js.map → stacks-esm-cvhazvhd.js.map} +1 -1
- package/dist/shared/{stacks-69nq48jp.js → stacks-esm-fcfdn2zx.js} +5 -5
- package/dist/shared/{stacks-69nq48jp.js.map → stacks-esm-fcfdn2zx.js.map} +1 -1
- package/dist/shared/{stacks-x0qqwrev.js → stacks-esm-hr7fpxtj.js} +4 -4
- package/dist/shared/{stacks-x0qqwrev.js.map → stacks-esm-hr7fpxtj.js.map} +1 -1
- package/dist/shared/{stacks-mbt36bzt.js → stacks-esm-kds4n82p.js} +11 -11
- package/dist/shared/{stacks-mbt36bzt.js.map → stacks-esm-kds4n82p.js.map} +1 -1
- package/dist/shared/{stacks-kg1npstf.js → stacks-esm-n53kvwmt.js} +2 -2
- package/dist/shared/{stacks-kg1npstf.js.map → stacks-esm-n53kvwmt.js.map} +1 -1
- package/dist/shared/{stacks-v2rfr46a.js → stacks-esm-pxhfqfff.js} +4 -4
- package/dist/shared/{stacks-v2rfr46a.js.map → stacks-esm-pxhfqfff.js.map} +1 -1
- package/dist/shared/{stacks-yajyej2y.js → stacks-esm-q19a17fd.js} +3 -3
- package/dist/shared/{stacks-yajyej2y.js.map → stacks-esm-q19a17fd.js.map} +1 -1
- package/dist/shared/{stacks-v03zef3g.js → stacks-esm-qk0p9fr6.js} +9 -9
- package/dist/shared/{stacks-v03zef3g.js.map → stacks-esm-qk0p9fr6.js.map} +1 -1
- package/dist/shared/{stacks-qcae5852.js → stacks-esm-qkj67g80.js} +2 -2
- package/dist/shared/{stacks-qcae5852.js.map → stacks-esm-qkj67g80.js.map} +1 -1
- package/dist/shared/{stacks-mftyrc60.js → stacks-esm-r6dejrgr.js} +4 -4
- package/dist/shared/{stacks-mftyrc60.js.map → stacks-esm-r6dejrgr.js.map} +1 -1
- package/dist/shared/{stacks-9c1yam8b.js → stacks-esm-r9q4wnyw.js} +5 -5
- package/dist/shared/{stacks-9c1yam8b.js.map → stacks-esm-r9q4wnyw.js.map} +1 -1
- package/dist/shared/{stacks-51ybf135.js → stacks-esm-skmcf5n2.js} +5 -5
- package/dist/shared/{stacks-51ybf135.js.map → stacks-esm-skmcf5n2.js.map} +1 -1
- package/dist/shared/{stacks-yvb7rvwk.js → stacks-esm-v45990hx.js} +2 -2
- package/dist/shared/{stacks-8vzxax5e.cjs.map → stacks-esm-v45990hx.js.map} +1 -1
- package/dist/shared/{stacks-z90xdr1x.js → stacks-esm-wv67m4g6.js} +3 -3
- package/dist/shared/{stacks-z90xdr1x.js.map → stacks-esm-wv67m4g6.js.map} +1 -1
- package/dist/shared/{stacks-1m3m1agc.js → stacks-esm-x1r01353.js} +5 -5
- package/dist/shared/{stacks-1m3m1agc.js.map → stacks-esm-x1r01353.js.map} +1 -1
- package/dist/src/accounts/index.cjs +558 -4
- package/dist/src/accounts/index.cjs.map +10 -4
- package/dist/src/accounts/index.js +3 -3
- package/dist/src/actions/index.cjs +3815 -1
- package/dist/src/actions/index.cjs.map +65 -3
- package/dist/src/actions/index.js +14 -14
- package/dist/src/bitcoin/index.cjs +2477 -1
- package/dist/src/bitcoin/index.cjs.map +31 -3
- package/dist/src/bitcoin/index.js +11 -11
- package/dist/src/bns/index.cjs +4439 -17
- package/dist/src/bns/index.cjs.map +50 -3
- package/dist/src/bns/index.js +14 -14
- package/dist/src/chains/index.cjs +135 -1
- package/dist/src/chains/index.cjs.map +5 -3
- package/dist/src/chains/index.js +1 -1
- package/dist/src/clarity/index.cjs +2019 -1
- package/dist/src/clarity/index.cjs.map +24 -3
- package/dist/src/clarity/index.js +8 -8
- package/dist/src/filters/index.cjs +725 -1
- package/dist/src/filters/index.cjs.map +11 -3
- package/dist/src/filters/index.d.cts +76 -13
- package/dist/src/filters/index.d.ts +76 -13
- package/dist/src/filters/index.js +8 -4
- package/dist/src/filters/index.js.map +1 -1
- package/dist/src/index.cjs +3935 -62
- package/dist/src/index.cjs.map +69 -4
- package/dist/src/index.d.cts +62 -11
- package/dist/src/index.d.ts +62 -11
- package/dist/src/index.js +16 -16
- package/dist/src/postconditions/index.cjs +1726 -1
- package/dist/src/postconditions/index.cjs.map +20 -3
- package/dist/src/postconditions/index.js +6 -6
- package/dist/src/pox/index.cjs +3855 -1
- package/dist/src/pox/index.cjs.map +48 -3
- package/dist/src/pox/index.js +13 -13
- package/dist/src/pox5/index.cjs +4054 -29
- package/dist/src/pox5/index.cjs.map +54 -3
- package/dist/src/pox5/index.js +15 -15
- package/dist/src/sbtc/index.cjs +3705 -4
- package/dist/src/sbtc/index.cjs.map +47 -3
- package/dist/src/sbtc/index.js +12 -12
- package/dist/src/stackingdao/index.cjs +3751 -8
- package/dist/src/stackingdao/index.cjs.map +45 -3
- package/dist/src/stackingdao/index.js +12 -12
- package/dist/src/subscriptions/index.cjs +153 -1
- package/dist/src/subscriptions/index.cjs.map +6 -3
- package/dist/src/subscriptions/index.js +2 -2
- package/dist/src/transactions/index.cjs +2139 -1
- package/dist/src/transactions/index.cjs.map +23 -3
- package/dist/src/transactions/index.js +6 -6
- package/dist/src/utils/index.cjs +435 -3
- package/dist/src/utils/index.cjs.map +9 -3
- package/dist/src/utils/index.js +3 -3
- package/package.json +3 -23
- package/dist/shared/stacks-02actsrx.cjs +0 -17
- package/dist/shared/stacks-02actsrx.cjs.map +0 -10
- package/dist/shared/stacks-03vfm21t.cjs +0 -222
- package/dist/shared/stacks-03vfm21t.cjs.map +0 -12
- package/dist/shared/stacks-24h5k94q.cjs +0 -74
- package/dist/shared/stacks-24h5k94q.cjs.map +0 -11
- package/dist/shared/stacks-37kz5t9f.cjs +0 -764
- package/dist/shared/stacks-37kz5t9f.cjs.map +0 -23
- package/dist/shared/stacks-3mt2q2na.cjs +0 -65
- package/dist/shared/stacks-3mt2q2na.cjs.map +0 -9
- package/dist/shared/stacks-4hs8r4q2.js.map +0 -10
- package/dist/shared/stacks-8vzxax5e.cjs +0 -45
- package/dist/shared/stacks-agk106zs.cjs +0 -267
- package/dist/shared/stacks-agk106zs.cjs.map +0 -12
- package/dist/shared/stacks-bdgh9n83.cjs +0 -212
- package/dist/shared/stacks-bdgh9n83.cjs.map +0 -11
- package/dist/shared/stacks-dpxnxhqb.cjs +0 -51
- package/dist/shared/stacks-dpxnxhqb.cjs.map +0 -11
- package/dist/shared/stacks-ee53k9j2.cjs +0 -651
- package/dist/shared/stacks-ee53k9j2.cjs.map +0 -13
- package/dist/shared/stacks-enpj9krt.cjs +0 -38
- package/dist/shared/stacks-enpj9krt.cjs.map +0 -10
- package/dist/shared/stacks-f35mnrmg.cjs +0 -164
- package/dist/shared/stacks-f35mnrmg.cjs.map +0 -10
- package/dist/shared/stacks-fhzwsn5d.cjs +0 -261
- package/dist/shared/stacks-fhzwsn5d.cjs.map +0 -12
- package/dist/shared/stacks-gjz26k6b.js.map +0 -12
- package/dist/shared/stacks-gza2n1zs.cjs +0 -73
- package/dist/shared/stacks-gza2n1zs.cjs.map +0 -11
- package/dist/shared/stacks-kem68d80.cjs +0 -156
- package/dist/shared/stacks-kem68d80.cjs.map +0 -10
- package/dist/shared/stacks-n98w7g57.cjs +0 -234
- package/dist/shared/stacks-n98w7g57.cjs.map +0 -10
- package/dist/shared/stacks-p337hp6m.cjs +0 -336
- package/dist/shared/stacks-p337hp6m.cjs.map +0 -25
- package/dist/shared/stacks-q34k4vnc.cjs +0 -286
- package/dist/shared/stacks-q34k4vnc.cjs.map +0 -12
- package/dist/shared/stacks-rryme9bv.cjs +0 -569
- package/dist/shared/stacks-rryme9bv.cjs.map +0 -13
- package/dist/shared/stacks-s5vej5z6.cjs +0 -410
- package/dist/shared/stacks-s5vej5z6.cjs.map +0 -15
- package/dist/shared/stacks-sdqkapct.cjs +0 -67
- package/dist/shared/stacks-sdqkapct.cjs.map +0 -12
- package/dist/shared/stacks-vea7nde7.cjs +0 -731
- package/dist/shared/stacks-vea7nde7.cjs.map +0 -13
- package/dist/shared/stacks-wk8yp13j.cjs +0 -33
- package/dist/shared/stacks-wk8yp13j.cjs.map +0 -11
- package/dist/shared/stacks-xjkn3en1.cjs +0 -42
- package/dist/shared/stacks-xnrywjf1.cjs +0 -131
- package/dist/shared/stacks-xnrywjf1.cjs.map +0 -11
- package/dist/shared/stacks-yvb7rvwk.js.map +0 -10
- package/dist/src/tools/btc/index.cjs +0 -131
- package/dist/src/tools/btc/index.cjs.map +0 -10
- package/dist/src/tools/btc/index.d.cts +0 -10
- package/dist/src/tools/btc/index.d.ts +0 -10
- package/dist/src/tools/btc/index.js +0 -90
- package/dist/src/tools/btc/index.js.map +0 -10
- package/dist/src/tools/index.cjs +0 -3865
- package/dist/src/tools/index.cjs.map +0 -80
- package/dist/src/tools/index.d.cts +0 -206
- package/dist/src/tools/index.d.ts +0 -206
- package/dist/src/tools/index.js +0 -3827
- package/dist/src/tools/index.js.map +0 -80
|
@@ -1,3 +1,2021 @@
|
|
|
1
|
+
var import_node_module = require("node:module");
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
13
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
21
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
+
for (let key of __getOwnPropNames(mod))
|
|
24
|
+
if (!__hasOwnProp.call(to, key))
|
|
25
|
+
__defProp(to, key, {
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
27
|
+
enumerable: true
|
|
28
|
+
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
31
|
+
return to;
|
|
32
|
+
};
|
|
33
|
+
var __toCommonJS = (from) => {
|
|
34
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
35
|
+
if (entry)
|
|
36
|
+
return entry;
|
|
37
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
38
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
39
|
+
for (var key of __getOwnPropNames(from))
|
|
40
|
+
if (!__hasOwnProp.call(entry, key))
|
|
41
|
+
__defProp(entry, key, {
|
|
42
|
+
get: __accessProp.bind(from, key),
|
|
43
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
__moduleCache.set(from, entry);
|
|
47
|
+
return entry;
|
|
48
|
+
};
|
|
49
|
+
var __moduleCache;
|
|
50
|
+
var __returnValue = (v) => v;
|
|
51
|
+
function __exportSetter(name, newValue) {
|
|
52
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
53
|
+
}
|
|
54
|
+
var __export = (target, all) => {
|
|
55
|
+
for (var name in all)
|
|
56
|
+
__defProp(target, name, {
|
|
57
|
+
get: all[name],
|
|
58
|
+
enumerable: true,
|
|
59
|
+
configurable: true,
|
|
60
|
+
set: __exportSetter.bind(all, name)
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// src/clarity/index.ts
|
|
65
|
+
var exports_clarity = {};
|
|
66
|
+
__export(exports_clarity, {
|
|
67
|
+
validateArgsArray: () => validateArgsArray,
|
|
68
|
+
validateArgs: () => validateArgs,
|
|
69
|
+
uintCV: () => uintCV,
|
|
70
|
+
tupleCV: () => tupleCV,
|
|
71
|
+
trueCV: () => trueCV,
|
|
72
|
+
toCamelCase: () => toCamelCase,
|
|
73
|
+
structuredDataHash: () => structuredDataHash,
|
|
74
|
+
stringUtf8CV: () => stringUtf8CV,
|
|
75
|
+
stringAsciiCV: () => stringAsciiCV,
|
|
76
|
+
standardPrincipalCV: () => standardPrincipalCV,
|
|
77
|
+
someCV: () => someCV,
|
|
78
|
+
sip013Abi: () => sip013Abi,
|
|
79
|
+
sip010Abi: () => sip010Abi,
|
|
80
|
+
sip009Abi: () => sip009Abi,
|
|
81
|
+
signStructuredData: () => signStructuredData,
|
|
82
|
+
serializeCVBytes: () => serializeCVBytes,
|
|
83
|
+
serializeCV: () => serializeCV,
|
|
84
|
+
responseOkCV: () => responseOkCV,
|
|
85
|
+
responseErrorCV: () => responseErrorCV,
|
|
86
|
+
prettyPrint: () => prettyPrint,
|
|
87
|
+
prepareArgs: () => prepareArgs,
|
|
88
|
+
parseDeclaredStandards: () => parseDeclaredStandards,
|
|
89
|
+
normalizeType: () => normalizeType,
|
|
90
|
+
normalizeAccess: () => normalizeAccess,
|
|
91
|
+
normalizeAbi: () => normalizeAbi,
|
|
92
|
+
noneCV: () => noneCV,
|
|
93
|
+
listCV: () => listCV,
|
|
94
|
+
jsToClarityValue: () => jsToClarityValue,
|
|
95
|
+
jsToClarity: () => jsToClarity,
|
|
96
|
+
isUint8Array: () => isUint8Array,
|
|
97
|
+
isUint128: () => isUint128,
|
|
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
|
|
148
|
+
});
|
|
149
|
+
module.exports = __toCommonJS(exports_clarity);
|
|
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");
|
|
178
|
+
|
|
179
|
+
// src/utils/encoding.ts
|
|
180
|
+
var hexes = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
181
|
+
function bytesToHex(bytes) {
|
|
182
|
+
let hex = "";
|
|
183
|
+
for (const b of bytes) {
|
|
184
|
+
hex += hexes[b];
|
|
185
|
+
}
|
|
186
|
+
return hex;
|
|
187
|
+
}
|
|
188
|
+
function hexToBytes(hex) {
|
|
189
|
+
let h = without0x(hex);
|
|
190
|
+
if (h.length % 2)
|
|
191
|
+
h = `0${h}`;
|
|
192
|
+
const array = new Uint8Array(h.length / 2);
|
|
193
|
+
for (let i = 0;i < array.length; i++) {
|
|
194
|
+
const j = i * 2;
|
|
195
|
+
const byte = Number.parseInt(h.slice(j, j + 2), 16);
|
|
196
|
+
if (Number.isNaN(byte) || byte < 0)
|
|
197
|
+
throw new Error("Invalid byte sequence");
|
|
198
|
+
array[i] = byte;
|
|
199
|
+
}
|
|
200
|
+
return array;
|
|
201
|
+
}
|
|
202
|
+
function with0x(value) {
|
|
203
|
+
return /^0x/i.test(value) ? value : `0x${value}`;
|
|
204
|
+
}
|
|
205
|
+
function without0x(value) {
|
|
206
|
+
return /^0x/i.test(value) ? value.slice(2) : value;
|
|
207
|
+
}
|
|
208
|
+
function utf8ToBytes(str) {
|
|
209
|
+
return new TextEncoder().encode(str);
|
|
210
|
+
}
|
|
211
|
+
function bytesToUtf8(bytes) {
|
|
212
|
+
return new TextDecoder().decode(bytes);
|
|
213
|
+
}
|
|
214
|
+
function asciiToBytes(str) {
|
|
215
|
+
const bytes = new Uint8Array(str.length);
|
|
216
|
+
for (let i = 0;i < str.length; i++) {
|
|
217
|
+
bytes[i] = str.charCodeAt(i) & 255;
|
|
218
|
+
}
|
|
219
|
+
return bytes;
|
|
220
|
+
}
|
|
221
|
+
function bytesToAscii(bytes) {
|
|
222
|
+
return String.fromCharCode(...bytes);
|
|
223
|
+
}
|
|
224
|
+
function concatBytes(...arrays) {
|
|
225
|
+
if (arrays.length === 1)
|
|
226
|
+
return arrays[0];
|
|
227
|
+
const length = arrays.reduce((a, arr) => a + arr.length, 0);
|
|
228
|
+
const result = new Uint8Array(length);
|
|
229
|
+
let pad = 0;
|
|
230
|
+
for (const arr of arrays) {
|
|
231
|
+
result.set(arr, pad);
|
|
232
|
+
pad += arr.length;
|
|
233
|
+
}
|
|
234
|
+
return result;
|
|
235
|
+
}
|
|
236
|
+
function intToBigInt(value) {
|
|
237
|
+
if (typeof value === "bigint")
|
|
238
|
+
return value;
|
|
239
|
+
if (typeof value === "string")
|
|
240
|
+
return BigInt(value);
|
|
241
|
+
if (typeof value === "number") {
|
|
242
|
+
if (!Number.isInteger(value))
|
|
243
|
+
throw new RangeError("Values of type 'number' must be an integer.");
|
|
244
|
+
if (value > Number.MAX_SAFE_INTEGER)
|
|
245
|
+
throw new RangeError(`Values of type 'number' must be <= ${Number.MAX_SAFE_INTEGER}. Use BigInt instead.`);
|
|
246
|
+
return BigInt(value);
|
|
247
|
+
}
|
|
248
|
+
if (value instanceof Uint8Array)
|
|
249
|
+
return BigInt(`0x${bytesToHex(value)}`);
|
|
250
|
+
throw new TypeError("Must be a number, bigint, string, or Uint8Array.");
|
|
251
|
+
}
|
|
252
|
+
function intToBytes(value, byteLength) {
|
|
253
|
+
return bigIntToBytes(intToBigInt(value), byteLength);
|
|
254
|
+
}
|
|
255
|
+
function bigIntToBytes(value, length = 16) {
|
|
256
|
+
const hex = value.toString(16).padStart(length * 2, "0");
|
|
257
|
+
return hexToBytes(hex);
|
|
258
|
+
}
|
|
259
|
+
function intToHex(integer, byteLength = 8) {
|
|
260
|
+
const value = typeof integer === "bigint" ? integer : intToBigInt(integer);
|
|
261
|
+
return value.toString(16).padStart(byteLength * 2, "0");
|
|
262
|
+
}
|
|
263
|
+
function toTwos(value, width) {
|
|
264
|
+
const limit = BigInt(1) << width - BigInt(1);
|
|
265
|
+
if (value < -limit || value > limit - BigInt(1)) {
|
|
266
|
+
throw new Error(`Unable to represent integer in width: ${width}`);
|
|
267
|
+
}
|
|
268
|
+
if (value >= BigInt(0))
|
|
269
|
+
return value;
|
|
270
|
+
return value + (BigInt(1) << width);
|
|
271
|
+
}
|
|
272
|
+
function fromTwos(value, width) {
|
|
273
|
+
if (value & BigInt(1) << width - BigInt(1)) {
|
|
274
|
+
return value - (BigInt(1) << width);
|
|
275
|
+
}
|
|
276
|
+
return value;
|
|
277
|
+
}
|
|
278
|
+
function bytesToTwosBigInt(bytes) {
|
|
279
|
+
if (bytes.length === 0)
|
|
280
|
+
return 0n;
|
|
281
|
+
const hex = bytesToHex(bytes);
|
|
282
|
+
if (hex.length === 0)
|
|
283
|
+
return 0n;
|
|
284
|
+
return fromTwos(BigInt(`0x${hex}`), BigInt(bytes.byteLength * 8));
|
|
285
|
+
}
|
|
286
|
+
function writeUInt32BE(value) {
|
|
287
|
+
const buf = new Uint8Array(4);
|
|
288
|
+
buf[0] = value >>> 24 & 255;
|
|
289
|
+
buf[1] = value >>> 16 & 255;
|
|
290
|
+
buf[2] = value >>> 8 & 255;
|
|
291
|
+
buf[3] = value & 255;
|
|
292
|
+
return buf;
|
|
293
|
+
}
|
|
294
|
+
function readUInt32BE(bytes, offset = 0) {
|
|
295
|
+
return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
|
|
296
|
+
}
|
|
297
|
+
function writeUInt16BE(value) {
|
|
298
|
+
const buf = new Uint8Array(2);
|
|
299
|
+
buf[0] = value >>> 8 & 255;
|
|
300
|
+
buf[1] = value & 255;
|
|
301
|
+
return buf;
|
|
302
|
+
}
|
|
303
|
+
function readUInt16BE(bytes, offset = 0) {
|
|
304
|
+
return (bytes[offset] << 8 | bytes[offset + 1]) >>> 0;
|
|
305
|
+
}
|
|
306
|
+
function writeUInt8(value) {
|
|
307
|
+
return new Uint8Array([value & 255]);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/utils/c32.ts
|
|
311
|
+
var C32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
312
|
+
var HEX = "0123456789abcdef";
|
|
313
|
+
function c32normalize(input) {
|
|
314
|
+
return input.toUpperCase().replace(/O/g, "0").replace(/L|I/g, "1");
|
|
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("");
|
|
345
|
+
}
|
|
346
|
+
function c32decode(c32input) {
|
|
347
|
+
const input = c32normalize(c32input);
|
|
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;
|
|
378
|
+
}
|
|
379
|
+
function c32checksum(dataHex) {
|
|
380
|
+
return bytesToHex(import_sha2.sha256(import_sha2.sha256(hexToBytes(dataHex))).slice(0, 4));
|
|
381
|
+
}
|
|
382
|
+
function c32checkEncode(version, data) {
|
|
383
|
+
if (version < 0 || version >= 32)
|
|
384
|
+
throw new Error("Invalid version (must be between 0 and 31)");
|
|
385
|
+
if (!data.match(/^[0-9a-fA-F]*$/))
|
|
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}`)}`;
|
|
395
|
+
}
|
|
396
|
+
function c32checkDecode(c32data) {
|
|
397
|
+
const normalized = c32normalize(c32data);
|
|
398
|
+
const dataHex = c32decode(normalized.slice(1));
|
|
399
|
+
const version = C32.indexOf(normalized[0]);
|
|
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");
|
|
406
|
+
}
|
|
407
|
+
return [version, dataHex.substring(0, dataHex.length - 8)];
|
|
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";
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// src/utils/bytes-reader.ts
|
|
602
|
+
class BytesReader {
|
|
603
|
+
data;
|
|
604
|
+
offset = 0;
|
|
605
|
+
constructor(data) {
|
|
606
|
+
this.data = data;
|
|
607
|
+
}
|
|
608
|
+
remaining() {
|
|
609
|
+
return this.data.length - this.offset;
|
|
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
|
+
}
|
|
615
|
+
}
|
|
616
|
+
readUInt8() {
|
|
617
|
+
this.ensure(1);
|
|
618
|
+
return this.data[this.offset++];
|
|
619
|
+
}
|
|
620
|
+
readUInt16BE() {
|
|
621
|
+
this.ensure(2);
|
|
622
|
+
const val = (this.data[this.offset] << 8 | this.data[this.offset + 1]) >>> 0;
|
|
623
|
+
this.offset += 2;
|
|
624
|
+
return val;
|
|
625
|
+
}
|
|
626
|
+
readUInt32BE() {
|
|
627
|
+
this.ensure(4);
|
|
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;
|
|
629
|
+
this.offset += 4;
|
|
630
|
+
return val;
|
|
631
|
+
}
|
|
632
|
+
readBytes(length) {
|
|
633
|
+
this.ensure(length);
|
|
634
|
+
const slice = this.data.slice(this.offset, this.offset + length);
|
|
635
|
+
this.offset += length;
|
|
636
|
+
return slice;
|
|
637
|
+
}
|
|
638
|
+
readBigUInt64BE() {
|
|
639
|
+
const hex = bytesToHex(this.readBytes(8));
|
|
640
|
+
return hex.length > 0 ? BigInt(`0x${hex}`) : 0n;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// src/clarity/deserialize.ts
|
|
645
|
+
function readAddress(reader) {
|
|
646
|
+
const version = reader.readUInt8();
|
|
647
|
+
const hash1602 = bytesToHex(reader.readBytes(20));
|
|
648
|
+
return c32address(version, hash1602);
|
|
649
|
+
}
|
|
650
|
+
function readLPString(reader, prefixBytes = 1) {
|
|
651
|
+
let length = 0;
|
|
652
|
+
for (let i = 0;i < prefixBytes; i++) {
|
|
653
|
+
length = length << 8 | reader.readUInt8();
|
|
654
|
+
}
|
|
655
|
+
return bytesToUtf8(reader.readBytes(length));
|
|
656
|
+
}
|
|
657
|
+
var MAX_CV_DEPTH = 64;
|
|
658
|
+
var MIN_LIST_ITEM_BYTES = 1;
|
|
659
|
+
var MIN_TUPLE_ENTRY_BYTES = 2;
|
|
660
|
+
function checkCount(reader, count, minBytes) {
|
|
661
|
+
if (count * minBytes > reader.remaining()) {
|
|
662
|
+
throw new SerializationError(`Clarity value declares ${count} elements but only ${reader.remaining()} bytes remain`);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
function readCV(reader, depth = 0) {
|
|
666
|
+
if (depth > MAX_CV_DEPTH) {
|
|
667
|
+
throw new SerializationError(`Clarity value nests deeper than ${MAX_CV_DEPTH} levels`);
|
|
668
|
+
}
|
|
669
|
+
const typeByte = reader.readUInt8();
|
|
670
|
+
const type = clarityTypeFromByte(typeByte);
|
|
671
|
+
switch (type) {
|
|
672
|
+
case "int":
|
|
673
|
+
return intCV(bytesToTwosBigInt(reader.readBytes(16)));
|
|
674
|
+
case "uint":
|
|
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);
|
|
715
|
+
}
|
|
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
|
+
}
|
|
726
|
+
default:
|
|
727
|
+
throw new SerializationError(`Cannot deserialize unknown clarity type: ${type}`);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
function deserializeCVBytes(input) {
|
|
731
|
+
const bytes = typeof input === "string" ? hexToBytes(without0x(input)) : input;
|
|
732
|
+
return readCV(new BytesReader(bytes));
|
|
733
|
+
}
|
|
734
|
+
function deserializeCV(input) {
|
|
735
|
+
return deserializeCVBytes(input);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// src/clarity/serialize.ts
|
|
739
|
+
var CLARITY_INT_SIZE = 128n;
|
|
740
|
+
var CLARITY_INT_BYTE_SIZE = 16;
|
|
741
|
+
function typeIdByte(type) {
|
|
742
|
+
return ClarityWireType[type];
|
|
743
|
+
}
|
|
744
|
+
function withTypeId(type, bytes) {
|
|
745
|
+
return concatBytes(new Uint8Array([typeIdByte(type)]), bytes);
|
|
746
|
+
}
|
|
747
|
+
function serializeAddress(c32Address) {
|
|
748
|
+
const [version, hash1602] = c32addressDecode(c32Address);
|
|
749
|
+
return concatBytes(new Uint8Array([version]), hexToBytes(hash1602));
|
|
750
|
+
}
|
|
751
|
+
function serializeLPString(str, prefixBytes = 1) {
|
|
752
|
+
const content = utf8ToBytes(str);
|
|
753
|
+
const lengthPrefix = hexToBytes(intToHex(content.byteLength, prefixBytes));
|
|
754
|
+
return concatBytes(lengthPrefix, content);
|
|
755
|
+
}
|
|
756
|
+
function serializeCVBytes(value) {
|
|
757
|
+
switch (value.type) {
|
|
758
|
+
case "true":
|
|
759
|
+
case "false":
|
|
760
|
+
return new Uint8Array([typeIdByte(value.type)]);
|
|
761
|
+
case "int": {
|
|
762
|
+
const bytes = bigIntToBytes(toTwos(BigInt(value.value), CLARITY_INT_SIZE), CLARITY_INT_BYTE_SIZE);
|
|
763
|
+
return withTypeId(value.type, bytes);
|
|
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");
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
function serializeCV(value) {
|
|
817
|
+
return bytesToHex(serializeCVBytes(value));
|
|
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));
|
|
828
|
+
}
|
|
829
|
+
if (v instanceof Uint8Array)
|
|
830
|
+
v = bytesToTwosBigInt(v);
|
|
831
|
+
const n = intToBigInt(v);
|
|
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");
|
|
852
|
+
}
|
|
853
|
+
return { type: "buffer", value: bytesToHex(buffer) };
|
|
854
|
+
}
|
|
855
|
+
function standardPrincipalCV(address) {
|
|
856
|
+
const [version, hash1602] = c32addressDecode(address);
|
|
857
|
+
const normalized = c32address(version, hash1602);
|
|
858
|
+
return { type: "address", value: normalized };
|
|
859
|
+
}
|
|
860
|
+
function contractPrincipalCV(address, contractName) {
|
|
861
|
+
const [version, hash1602] = c32addressDecode(address);
|
|
862
|
+
const normalized = c32address(version, hash1602);
|
|
863
|
+
if (utf8ToBytes(contractName).byteLength >= 128) {
|
|
864
|
+
throw new Error("Contract name must be less than 128 bytes");
|
|
865
|
+
}
|
|
866
|
+
return { type: "contract", value: `${normalized}.${contractName}` };
|
|
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
|
+
}
|
|
888
|
+
}
|
|
889
|
+
return { type: "tuple", value: data };
|
|
890
|
+
}
|
|
891
|
+
function stringAsciiCV(value) {
|
|
892
|
+
return { type: "ascii", value };
|
|
893
|
+
}
|
|
894
|
+
function stringUtf8CV(value) {
|
|
895
|
+
return { type: "utf8", value };
|
|
896
|
+
}
|
|
897
|
+
var Cl = {
|
|
898
|
+
int: intCV,
|
|
899
|
+
uint: uintCV,
|
|
900
|
+
bool: boolCV,
|
|
901
|
+
principal(address) {
|
|
902
|
+
const parsed = parsePrincipal(address);
|
|
903
|
+
if (!parsed)
|
|
904
|
+
throw new Error(`Invalid principal: ${address}`);
|
|
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));
|
|
941
|
+
}
|
|
942
|
+
function isDomain(value) {
|
|
943
|
+
if (value.type !== "tuple")
|
|
944
|
+
return false;
|
|
945
|
+
const { name, version, "chain-id": chainId } = value.value;
|
|
946
|
+
return name?.type === "ascii" && version?.type === "ascii" && chainId?.type === "uint";
|
|
947
|
+
}
|
|
948
|
+
function encodeStructuredData(opts) {
|
|
949
|
+
if (!isDomain(opts.domain)) {
|
|
950
|
+
throw new Error("domain must be a tuple { name: ascii, version: ascii, chain-id: uint }");
|
|
951
|
+
}
|
|
952
|
+
return concatBytes(SIP018_PREFIX, hashStructuredData(opts.domain), hashStructuredData(opts.message));
|
|
953
|
+
}
|
|
954
|
+
function structuredDataHash(opts) {
|
|
955
|
+
return import_sha24.sha256(encodeStructuredData(opts));
|
|
956
|
+
}
|
|
957
|
+
async function signStructuredData(account, opts) {
|
|
958
|
+
const vrs = await account.sign(structuredDataHash(opts));
|
|
959
|
+
if (vrs.length !== 65) {
|
|
960
|
+
throw new Error(`Expected 65-byte recoverable signature, got ${vrs.length}`);
|
|
961
|
+
}
|
|
962
|
+
return bytesToHex(concatBytes(vrs.slice(1), vrs.slice(0, 1)));
|
|
963
|
+
}
|
|
964
|
+
// src/clarity/prettyPrint.ts
|
|
965
|
+
function prettyPrint(val, encoding = "hex") {
|
|
966
|
+
switch (val.type) {
|
|
967
|
+
case "true":
|
|
968
|
+
return "true";
|
|
969
|
+
case "false":
|
|
970
|
+
return "false";
|
|
971
|
+
case "int":
|
|
972
|
+
return val.value.toString();
|
|
973
|
+
case "uint":
|
|
974
|
+
return `u${val.value.toString()}`;
|
|
975
|
+
case "buffer":
|
|
976
|
+
if (encoding === "tryAscii") {
|
|
977
|
+
const str = bytesToAscii(hexToBytes(val.value));
|
|
978
|
+
if (/^[ -~]*$/.test(str))
|
|
979
|
+
return JSON.stringify(str);
|
|
980
|
+
}
|
|
981
|
+
return `0x${val.value}`;
|
|
982
|
+
case "none":
|
|
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}"`;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
function cvToJSON(val) {
|
|
1004
|
+
switch (val.type) {
|
|
1005
|
+
case "true":
|
|
1006
|
+
return { type: "bool", value: true };
|
|
1007
|
+
case "false":
|
|
1008
|
+
return { type: "bool", value: false };
|
|
1009
|
+
case "int":
|
|
1010
|
+
return { type: "int", value: val.value.toString() };
|
|
1011
|
+
case "uint":
|
|
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
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
case "none":
|
|
1021
|
+
return { type: "(optional none)", value: null };
|
|
1022
|
+
case "some":
|
|
1023
|
+
return { type: "(optional)", value: cvToJSON(val.value) };
|
|
1024
|
+
case "ok":
|
|
1025
|
+
return { type: "(response)", value: cvToJSON(val.value), success: true };
|
|
1026
|
+
case "err":
|
|
1027
|
+
return { type: "(response)", value: cvToJSON(val.value), success: false };
|
|
1028
|
+
case "address":
|
|
1029
|
+
case "contract":
|
|
1030
|
+
return { type: "principal", value: val.value };
|
|
1031
|
+
case "list":
|
|
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 };
|
|
1039
|
+
}
|
|
1040
|
+
case "ascii":
|
|
1041
|
+
return {
|
|
1042
|
+
type: `(string-ascii ${asciiToBytes(val.value).length})`,
|
|
1043
|
+
value: val.value
|
|
1044
|
+
};
|
|
1045
|
+
case "utf8":
|
|
1046
|
+
return {
|
|
1047
|
+
type: `(string-utf8 ${utf8ToBytes(val.value).length})`,
|
|
1048
|
+
value: val.value
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
function cvToValue(val) {
|
|
1053
|
+
switch (val.type) {
|
|
1054
|
+
case "true":
|
|
1055
|
+
return true;
|
|
1056
|
+
case "false":
|
|
1057
|
+
return false;
|
|
1058
|
+
case "int":
|
|
1059
|
+
case "uint":
|
|
1060
|
+
return val.value;
|
|
1061
|
+
case "buffer":
|
|
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]);
|
|
1079
|
+
}
|
|
1080
|
+
return result;
|
|
1081
|
+
}
|
|
1082
|
+
case "ascii":
|
|
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";
|
|
1110
|
+
}
|
|
1111
|
+
function cvToPrincipal(val) {
|
|
1112
|
+
if (val.type !== "address" && val.type !== "contract") {
|
|
1113
|
+
throw new Error(`cvToPrincipal: expected principal or contract, got ${val.type}`);
|
|
1114
|
+
}
|
|
1115
|
+
return val.value;
|
|
1116
|
+
}
|
|
1117
|
+
// src/clarity/abi/guards.ts
|
|
1118
|
+
function isUint128(value) {
|
|
1119
|
+
return typeof value === "bigint" && value >= 0n && value <= MAX_U128;
|
|
1120
|
+
}
|
|
1121
|
+
function isInt128(value) {
|
|
1122
|
+
return typeof value === "bigint" && value >= MIN_I128 && value <= MAX_I128;
|
|
1123
|
+
}
|
|
1124
|
+
function isBool(value) {
|
|
1125
|
+
return typeof value === "boolean";
|
|
1126
|
+
}
|
|
1127
|
+
function isPrincipal(value) {
|
|
1128
|
+
return typeof value === "string" && parsePrincipal(value) !== null;
|
|
1129
|
+
}
|
|
1130
|
+
function isStandardPrincipal(value) {
|
|
1131
|
+
if (typeof value !== "string")
|
|
1132
|
+
return false;
|
|
1133
|
+
const parsed = parsePrincipal(value);
|
|
1134
|
+
return parsed !== null && parsed.contractName === undefined;
|
|
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/, "_$&");
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
// src/clarity/abi/converters.ts
|
|
1203
|
+
class ClarityConversionError extends Error {
|
|
1204
|
+
type;
|
|
1205
|
+
value;
|
|
1206
|
+
constructor(message, type, value) {
|
|
1207
|
+
super(message);
|
|
1208
|
+
this.type = type;
|
|
1209
|
+
this.value = value;
|
|
1210
|
+
this.name = "ClarityConversionError";
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
function jsToClarity(type, value) {
|
|
1214
|
+
if (type === "none")
|
|
1215
|
+
return null;
|
|
1216
|
+
if (type === "uint128") {
|
|
1217
|
+
if (!isUint128(value))
|
|
1218
|
+
throw new ClarityConversionError("Invalid uint128 value", type, value);
|
|
1219
|
+
return value;
|
|
1220
|
+
}
|
|
1221
|
+
if (type === "int128") {
|
|
1222
|
+
if (!isInt128(value))
|
|
1223
|
+
throw new ClarityConversionError("Invalid int128 value", type, value);
|
|
1224
|
+
return value;
|
|
1225
|
+
}
|
|
1226
|
+
if (type === "bool") {
|
|
1227
|
+
if (!isBool(value))
|
|
1228
|
+
throw new ClarityConversionError("Invalid bool value", type, value);
|
|
1229
|
+
return value;
|
|
1230
|
+
}
|
|
1231
|
+
if (type === "principal") {
|
|
1232
|
+
if (!isPrincipal(value))
|
|
1233
|
+
throw new ClarityConversionError("Invalid principal value", type, value);
|
|
1234
|
+
return value;
|
|
1235
|
+
}
|
|
1236
|
+
if (type === "trait_reference") {
|
|
1237
|
+
if (!isPrincipal(value))
|
|
1238
|
+
throw new ClarityConversionError("Invalid trait_reference value", type, value);
|
|
1239
|
+
return value;
|
|
1240
|
+
}
|
|
1241
|
+
if (isAbiStringAscii(type)) {
|
|
1242
|
+
if (!isString(value))
|
|
1243
|
+
throw new ClarityConversionError("Invalid string-ascii value", type, value);
|
|
1244
|
+
const str = value;
|
|
1245
|
+
for (let i = 0;i < str.length; i++) {
|
|
1246
|
+
if (str.charCodeAt(i) > 127) {
|
|
1247
|
+
throw new ClarityConversionError(`Non-ASCII character at position ${i}: '${str[i]}' (code ${str.charCodeAt(i)})`, type, value);
|
|
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;
|
|
1254
|
+
}
|
|
1255
|
+
if (isAbiStringUtf8(type)) {
|
|
1256
|
+
if (!isString(value))
|
|
1257
|
+
throw new ClarityConversionError("Invalid string-utf8 value", type, value);
|
|
1258
|
+
const str = value;
|
|
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;
|
|
1264
|
+
}
|
|
1265
|
+
if (isAbiBuffer(type)) {
|
|
1266
|
+
if (!isUint8Array(value))
|
|
1267
|
+
throw new ClarityConversionError("Invalid buffer value", type, value);
|
|
1268
|
+
const buff = value;
|
|
1269
|
+
if (buff.length > type.buff.length) {
|
|
1270
|
+
throw new ClarityConversionError(`Buffer length ${buff.length} exceeds max ${type.buff.length}`, type, value);
|
|
1271
|
+
}
|
|
1272
|
+
return value;
|
|
1273
|
+
}
|
|
1274
|
+
if (isAbiList(type)) {
|
|
1275
|
+
if (!Array.isArray(value))
|
|
1276
|
+
throw new ClarityConversionError("Expected array for list type", type, value);
|
|
1277
|
+
if (value.length > type.list.length) {
|
|
1278
|
+
throw new ClarityConversionError(`List length ${value.length} exceeds max ${type.list.length}`, type, value);
|
|
1279
|
+
}
|
|
1280
|
+
return value.map((item) => jsToClarity(type.list.type, item));
|
|
1281
|
+
}
|
|
1282
|
+
if (isAbiTuple(type)) {
|
|
1283
|
+
if (typeof value !== "object" || value === null)
|
|
1284
|
+
throw new ClarityConversionError("Expected object for tuple type", type, value);
|
|
1285
|
+
const result = {};
|
|
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);
|
|
1292
|
+
}
|
|
1293
|
+
const fieldValue = hasOriginal ? value[field.name] : value[camelKey];
|
|
1294
|
+
result[field.name] = jsToClarity(field.type, fieldValue);
|
|
1295
|
+
}
|
|
1296
|
+
return result;
|
|
1297
|
+
}
|
|
1298
|
+
if (isAbiOptional(type)) {
|
|
1299
|
+
if (value === null || value === undefined)
|
|
1300
|
+
return null;
|
|
1301
|
+
return jsToClarity(type.optional, value);
|
|
1302
|
+
}
|
|
1303
|
+
if (isAbiResponse(type)) {
|
|
1304
|
+
if (typeof value !== "object" || value === null)
|
|
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
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
if (hasErr && !hasOk) {
|
|
1314
|
+
return {
|
|
1315
|
+
err: jsToClarity(type.response.error, value.err)
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1318
|
+
throw new ClarityConversionError("Response must have exactly 'ok' or 'err' property", type, value);
|
|
1319
|
+
}
|
|
1320
|
+
throw new ClarityConversionError("Unknown Clarity type", type, value);
|
|
1321
|
+
}
|
|
1322
|
+
function prepareArgs(func, args) {
|
|
1323
|
+
return func.args.map((arg) => {
|
|
1324
|
+
if (!(arg.name in args)) {
|
|
1325
|
+
throw new ClarityConversionError(`Missing argument: ${arg.name}`, arg.type, undefined);
|
|
1326
|
+
}
|
|
1327
|
+
return jsToClarity(arg.type, args[arg.name]);
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
function validateArgs(func, args) {
|
|
1331
|
+
for (const arg of func.args) {
|
|
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
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
function validateArgsArray(func, args) {
|
|
1339
|
+
if (args.length !== func.args.length) {
|
|
1340
|
+
throw new ClarityConversionError(`Expected ${func.args.length} arguments, got ${args.length}`, func.args[0]?.type ?? "bool", args);
|
|
1341
|
+
}
|
|
1342
|
+
func.args.forEach((arg, i) => {
|
|
1343
|
+
jsToClarity(arg.type, args[i]);
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
// src/clarity/abi/standards.ts
|
|
1347
|
+
var SIP010_ABI = {
|
|
1348
|
+
functions: [
|
|
1349
|
+
{
|
|
1350
|
+
name: "transfer",
|
|
1351
|
+
access: "public",
|
|
1352
|
+
args: [
|
|
1353
|
+
{ name: "amount", type: "uint128" },
|
|
1354
|
+
{ name: "sender", type: "principal" },
|
|
1355
|
+
{ name: "recipient", type: "principal" },
|
|
1356
|
+
{ name: "memo", type: { optional: { buff: { length: 34 } } } }
|
|
1357
|
+
],
|
|
1358
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1359
|
+
},
|
|
1360
|
+
{
|
|
1361
|
+
name: "get-balance",
|
|
1362
|
+
access: "read-only",
|
|
1363
|
+
args: [{ name: "account", type: "principal" }],
|
|
1364
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
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
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
],
|
|
1412
|
+
fungible_tokens: [{ name: "token" }]
|
|
1413
|
+
};
|
|
1414
|
+
var SIP009_ABI = {
|
|
1415
|
+
functions: [
|
|
1416
|
+
{
|
|
1417
|
+
name: "transfer",
|
|
1418
|
+
access: "public",
|
|
1419
|
+
args: [
|
|
1420
|
+
{ name: "id", type: "uint128" },
|
|
1421
|
+
{ name: "sender", type: "principal" },
|
|
1422
|
+
{ name: "recipient", type: "principal" }
|
|
1423
|
+
],
|
|
1424
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1425
|
+
},
|
|
1426
|
+
{
|
|
1427
|
+
name: "get-owner",
|
|
1428
|
+
access: "read-only",
|
|
1429
|
+
args: [{ name: "id", type: "uint128" }],
|
|
1430
|
+
outputs: {
|
|
1431
|
+
response: { ok: { optional: "principal" }, error: "uint128" }
|
|
1432
|
+
}
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
name: "get-last-token-id",
|
|
1436
|
+
access: "read-only",
|
|
1437
|
+
args: [],
|
|
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
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
],
|
|
1452
|
+
non_fungible_tokens: [{ name: "nft", type: "uint128" }]
|
|
1453
|
+
};
|
|
1454
|
+
var SIP013_ABI = {
|
|
1455
|
+
functions: [
|
|
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
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
],
|
|
1571
|
+
fungible_tokens: [],
|
|
1572
|
+
non_fungible_tokens: []
|
|
1573
|
+
};
|
|
1574
|
+
var sip010Abi = SIP010_ABI;
|
|
1575
|
+
var sip009Abi = SIP009_ABI;
|
|
1576
|
+
var sip013Abi = SIP013_ABI;
|
|
1577
|
+
// src/clarity/abi/classify.ts
|
|
1578
|
+
var TRAIT_STANDARDS = ["sip-009", "sip-010", "sip-013"];
|
|
1579
|
+
var STANDARDS = [
|
|
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
|
+
])
|
|
1593
|
+
}
|
|
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
|
+
}
|
|
1601
|
+
function conformsTo(candidate, spec) {
|
|
1602
|
+
const fns = indexByName(candidate);
|
|
1603
|
+
for (const required of spec.abi.functions) {
|
|
1604
|
+
if (spec.optional.has(required.name))
|
|
1605
|
+
continue;
|
|
1606
|
+
const got = fns.get(required.name);
|
|
1607
|
+
if (!got)
|
|
1608
|
+
return false;
|
|
1609
|
+
if (got.access !== required.access)
|
|
1610
|
+
return false;
|
|
1611
|
+
if (got.args.length !== required.args.length)
|
|
1612
|
+
return false;
|
|
1613
|
+
}
|
|
1614
|
+
return true;
|
|
1615
|
+
}
|
|
1616
|
+
function classifyContract(abi) {
|
|
1617
|
+
if (!abi || !Array.isArray(abi.functions))
|
|
1618
|
+
return [];
|
|
1619
|
+
return STANDARDS.filter((s) => conformsTo(abi, s)).map((s) => s.id);
|
|
1620
|
+
}
|
|
1621
|
+
function parseDeclaredStandards(claritySource) {
|
|
1622
|
+
const out = new Set;
|
|
1623
|
+
const matches = claritySource.matchAll(/\(impl-trait\s+[^)]+\)/gi);
|
|
1624
|
+
for (const m of matches) {
|
|
1625
|
+
const ref = m[0].toLowerCase();
|
|
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");
|
|
1632
|
+
}
|
|
1633
|
+
return [...out];
|
|
1634
|
+
}
|
|
1635
|
+
// src/clarity/abi/normalize.ts
|
|
1636
|
+
function normalizeAccess(access) {
|
|
1637
|
+
if (access === "read_only")
|
|
1638
|
+
return "read-only";
|
|
1639
|
+
return access;
|
|
1640
|
+
}
|
|
1641
|
+
function normalizeType(type) {
|
|
1642
|
+
if (typeof type === "string") {
|
|
1643
|
+
switch (type) {
|
|
1644
|
+
case "uint128":
|
|
1645
|
+
case "int128":
|
|
1646
|
+
case "bool":
|
|
1647
|
+
case "principal":
|
|
1648
|
+
case "trait_reference":
|
|
1649
|
+
return type;
|
|
1650
|
+
default:
|
|
1651
|
+
return type;
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
if (typeof type !== "object" || type === null) {
|
|
1655
|
+
throw new Error(`Invalid ABI type: expected object, got ${typeof type}`);
|
|
1656
|
+
}
|
|
1657
|
+
const typeObj = type;
|
|
1658
|
+
if ("buffer" in typeObj) {
|
|
1659
|
+
const buffer = typeObj.buffer;
|
|
1660
|
+
return {
|
|
1661
|
+
buff: {
|
|
1662
|
+
length: buffer?.length ?? 32
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
1665
|
+
}
|
|
1666
|
+
if ("buff" in typeObj) {
|
|
1667
|
+
const buff = typeObj.buff;
|
|
1668
|
+
return {
|
|
1669
|
+
buff: {
|
|
1670
|
+
length: buff?.length ?? 32
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
if ("string-ascii" in typeObj) {
|
|
1675
|
+
const strAscii = typeObj["string-ascii"];
|
|
1676
|
+
return {
|
|
1677
|
+
"string-ascii": {
|
|
1678
|
+
length: strAscii?.length ?? 256
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
if ("string-utf8" in typeObj) {
|
|
1683
|
+
const strUtf8 = typeObj["string-utf8"];
|
|
1684
|
+
return {
|
|
1685
|
+
"string-utf8": {
|
|
1686
|
+
length: strUtf8?.length ?? 256
|
|
1687
|
+
}
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
if ("response" in typeObj) {
|
|
1691
|
+
const response = typeObj.response;
|
|
1692
|
+
return {
|
|
1693
|
+
response: {
|
|
1694
|
+
ok: normalizeType(response?.ok ?? "bool"),
|
|
1695
|
+
error: normalizeType(response?.error ?? "uint128")
|
|
1696
|
+
}
|
|
1697
|
+
};
|
|
1698
|
+
}
|
|
1699
|
+
if ("optional" in typeObj) {
|
|
1700
|
+
return {
|
|
1701
|
+
optional: normalizeType(typeObj.optional)
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
if ("list" in typeObj) {
|
|
1705
|
+
const list = typeObj.list;
|
|
1706
|
+
return {
|
|
1707
|
+
list: {
|
|
1708
|
+
type: normalizeType(list?.type ?? "uint128"),
|
|
1709
|
+
length: list?.length ?? 100
|
|
1710
|
+
}
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
if ("tuple" in typeObj) {
|
|
1714
|
+
const tuple = typeObj.tuple;
|
|
1715
|
+
return {
|
|
1716
|
+
tuple: tuple.map((field) => ({
|
|
1717
|
+
name: field.name,
|
|
1718
|
+
type: normalizeType(field.type)
|
|
1719
|
+
}))
|
|
1720
|
+
};
|
|
1721
|
+
}
|
|
1722
|
+
throw new Error(`Unknown ABI type structure: ${JSON.stringify(type)}`);
|
|
1723
|
+
}
|
|
1724
|
+
function normalizeFunction(func) {
|
|
1725
|
+
const access = normalizeAccess(func.access);
|
|
1726
|
+
const args = func.args ?? [];
|
|
1727
|
+
const outputs = func.outputs;
|
|
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
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
function normalizeMap(map) {
|
|
1739
|
+
return {
|
|
1740
|
+
name: map.name,
|
|
1741
|
+
key: normalizeType(map.key),
|
|
1742
|
+
value: normalizeType(map.value)
|
|
1743
|
+
};
|
|
1744
|
+
}
|
|
1745
|
+
function normalizeVariable(variable) {
|
|
1746
|
+
return {
|
|
1747
|
+
name: variable.name,
|
|
1748
|
+
type: normalizeType(variable.type),
|
|
1749
|
+
access: variable.access
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
function normalizeFungibleToken(token) {
|
|
1753
|
+
return { name: token.name };
|
|
1754
|
+
}
|
|
1755
|
+
function normalizeNonFungibleToken(token) {
|
|
1756
|
+
return { name: token.name, type: normalizeType(token.type) };
|
|
1757
|
+
}
|
|
1758
|
+
function normalizeTraitDefinition(trait) {
|
|
1759
|
+
const rawFunctions = Array.isArray(trait.functions) ? trait.functions : [];
|
|
1760
|
+
const functions = [];
|
|
1761
|
+
for (const func of rawFunctions) {
|
|
1762
|
+
if (typeof func !== "object" || func === null)
|
|
1763
|
+
continue;
|
|
1764
|
+
const normalized = normalizeFunction(func);
|
|
1765
|
+
if (normalized.access === "private")
|
|
1766
|
+
continue;
|
|
1767
|
+
functions.push(normalized);
|
|
1768
|
+
}
|
|
1769
|
+
return { name: trait.name, functions };
|
|
1770
|
+
}
|
|
1771
|
+
function normalizeAbi(abi) {
|
|
1772
|
+
if (typeof abi !== "object" || abi === null) {
|
|
1773
|
+
return { functions: [] };
|
|
1774
|
+
}
|
|
1775
|
+
const abiObj = abi;
|
|
1776
|
+
const functions = [];
|
|
1777
|
+
const maps = [];
|
|
1778
|
+
const variables = [];
|
|
1779
|
+
const fungibleTokens = [];
|
|
1780
|
+
const nonFungibleTokens = [];
|
|
1781
|
+
const implementedTraits = [];
|
|
1782
|
+
const definedTraits = [];
|
|
1783
|
+
if (Array.isArray(abiObj.functions)) {
|
|
1784
|
+
for (const func of abiObj.functions) {
|
|
1785
|
+
if (typeof func === "object" && func !== null) {
|
|
1786
|
+
functions.push(normalizeFunction(func));
|
|
1787
|
+
}
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
if (Array.isArray(abiObj.maps)) {
|
|
1791
|
+
for (const map of abiObj.maps) {
|
|
1792
|
+
if (typeof map === "object" && map !== null) {
|
|
1793
|
+
maps.push(normalizeMap(map));
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
if (Array.isArray(abiObj.variables)) {
|
|
1798
|
+
for (const variable of abiObj.variables) {
|
|
1799
|
+
if (typeof variable === "object" && variable !== null) {
|
|
1800
|
+
variables.push(normalizeVariable(variable));
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
if (Array.isArray(abiObj.fungible_tokens)) {
|
|
1805
|
+
for (const token of abiObj.fungible_tokens) {
|
|
1806
|
+
if (typeof token === "object" && token !== null) {
|
|
1807
|
+
fungibleTokens.push(normalizeFungibleToken(token));
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
if (Array.isArray(abiObj.non_fungible_tokens)) {
|
|
1812
|
+
for (const token of abiObj.non_fungible_tokens) {
|
|
1813
|
+
if (typeof token === "object" && token !== null) {
|
|
1814
|
+
nonFungibleTokens.push(normalizeNonFungibleToken(token));
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
if (Array.isArray(abiObj.implemented_traits)) {
|
|
1819
|
+
for (const trait of abiObj.implemented_traits) {
|
|
1820
|
+
if (typeof trait === "string")
|
|
1821
|
+
implementedTraits.push(trait);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
if (Array.isArray(abiObj.defined_traits)) {
|
|
1825
|
+
for (const trait of abiObj.defined_traits) {
|
|
1826
|
+
if (typeof trait === "object" && trait !== null) {
|
|
1827
|
+
definedTraits.push(normalizeTraitDefinition(trait));
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
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
|
+
}
|
|
1841
|
+
// src/clarity/bridge.ts
|
|
1842
|
+
var CV_TYPE_TAGS = new Set([
|
|
1843
|
+
"int",
|
|
1844
|
+
"uint",
|
|
1845
|
+
"true",
|
|
1846
|
+
"false",
|
|
1847
|
+
"address",
|
|
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;
|
|
1868
|
+
}
|
|
1869
|
+
var HEX_PAIRS_REGEX = /^(?:[0-9a-fA-F]{2})+$/;
|
|
1870
|
+
function coerceBuffer(value) {
|
|
1871
|
+
if (value instanceof Uint8Array)
|
|
1872
|
+
return bufferCV(value);
|
|
1873
|
+
if (typeof value === "object" && value !== null && "type" in value) {
|
|
1874
|
+
const tagged = value;
|
|
1875
|
+
if (tagged.type === "buffer" && isClarityValue(value))
|
|
1876
|
+
return value;
|
|
1877
|
+
if (typeof tagged.value === "string") {
|
|
1878
|
+
if (tagged.type === "ascii")
|
|
1879
|
+
return Cl.bufferFromAscii(tagged.value);
|
|
1880
|
+
if (tagged.type === "utf8")
|
|
1881
|
+
return Cl.bufferFromUtf8(tagged.value);
|
|
1882
|
+
if (tagged.type === "hex")
|
|
1883
|
+
return Cl.bufferFromHex(tagged.value);
|
|
1884
|
+
}
|
|
1885
|
+
throw new Error(`Unsupported buffer input: ${JSON.stringify(value)}`);
|
|
1886
|
+
}
|
|
1887
|
+
if (typeof value === "string") {
|
|
1888
|
+
const hex = value.startsWith("0x") ? value.slice(2) : value;
|
|
1889
|
+
if (HEX_PAIRS_REGEX.test(hex))
|
|
1890
|
+
return Cl.bufferFromHex(hex);
|
|
1891
|
+
return Cl.bufferFromUtf8(value);
|
|
1892
|
+
}
|
|
1893
|
+
throw new Error("buffer arg expects Uint8Array, hex string, { type, value }, or BufferCV");
|
|
1894
|
+
}
|
|
1895
|
+
function jsToClarityValue(abiType, value) {
|
|
1896
|
+
if (isAbiBuffer(abiType))
|
|
1897
|
+
return coerceBuffer(value);
|
|
1898
|
+
if (isClarityValue(value))
|
|
1899
|
+
return value;
|
|
1900
|
+
if (abiType === "uint128")
|
|
1901
|
+
return uintCV(value);
|
|
1902
|
+
if (abiType === "int128")
|
|
1903
|
+
return intCV(value);
|
|
1904
|
+
if (abiType === "bool")
|
|
1905
|
+
return boolCV(value);
|
|
1906
|
+
if (abiType === "principal" || abiType === "trait_reference")
|
|
1907
|
+
return Cl.principal(value);
|
|
1908
|
+
if (isAbiStringAscii(abiType))
|
|
1909
|
+
return stringAsciiCV(value);
|
|
1910
|
+
if (isAbiStringUtf8(abiType))
|
|
1911
|
+
return stringUtf8CV(value);
|
|
1912
|
+
if (isAbiList(abiType)) {
|
|
1913
|
+
const arr = value;
|
|
1914
|
+
return listCV(arr.map((item) => jsToClarityValue(abiType.list.type, item)));
|
|
1915
|
+
}
|
|
1916
|
+
if (isAbiTuple(abiType)) {
|
|
1917
|
+
const obj = value;
|
|
1918
|
+
const data = {};
|
|
1919
|
+
for (const field of abiType.tuple) {
|
|
1920
|
+
const camelKey = toCamelCase(field.name);
|
|
1921
|
+
const hasOriginal = field.name in obj;
|
|
1922
|
+
const hasCamel = camelKey in obj;
|
|
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}`);
|
|
1926
|
+
}
|
|
1927
|
+
data[field.name] = jsToClarityValue(field.type, fieldValue);
|
|
1928
|
+
}
|
|
1929
|
+
return tupleCV(data);
|
|
1930
|
+
}
|
|
1931
|
+
if (isAbiOptional(abiType)) {
|
|
1932
|
+
if (value === null || value === undefined)
|
|
1933
|
+
return noneCV();
|
|
1934
|
+
return someCV(jsToClarityValue(abiType.optional, value));
|
|
1935
|
+
}
|
|
1936
|
+
if (isAbiResponse(abiType)) {
|
|
1937
|
+
const obj = value;
|
|
1938
|
+
if ("ok" in obj && !("err" in obj))
|
|
1939
|
+
return responseOkCV(jsToClarityValue(abiType.response.ok, obj.ok));
|
|
1940
|
+
if ("err" in obj && !("ok" in obj))
|
|
1941
|
+
return responseErrorCV(jsToClarityValue(abiType.response.error, obj.err));
|
|
1942
|
+
throw new Error("Response must have exactly 'ok' or 'err' property");
|
|
1943
|
+
}
|
|
1944
|
+
throw new Error(`Unknown ABI type: ${JSON.stringify(abiType)}`);
|
|
1945
|
+
}
|
|
1946
|
+
function clarityValueToJS(abiType, cv) {
|
|
1947
|
+
return clarityValueToJSInner(abiType, cv);
|
|
1948
|
+
}
|
|
1949
|
+
function clarityValueToJSUntyped(abiType, cv) {
|
|
1950
|
+
return clarityValueToJSInner(abiType, cv);
|
|
1951
|
+
}
|
|
1952
|
+
function clarityValueToJSInner(abiType, cv) {
|
|
1953
|
+
if (abiType === "uint128" || abiType === "int128") {
|
|
1954
|
+
if (cv.type !== "int" && cv.type !== "uint")
|
|
1955
|
+
throw new Error(`Expected int/uint CV, got ${cv.type}`);
|
|
1956
|
+
return cv.value;
|
|
1957
|
+
}
|
|
1958
|
+
if (abiType === "bool") {
|
|
1959
|
+
if (cv.type === "true")
|
|
1960
|
+
return true;
|
|
1961
|
+
if (cv.type === "false")
|
|
1962
|
+
return false;
|
|
1963
|
+
throw new Error(`Expected bool CV, got ${cv.type}`);
|
|
1964
|
+
}
|
|
1965
|
+
if (abiType === "principal" || abiType === "trait_reference") {
|
|
1966
|
+
if (cv.type !== "address" && cv.type !== "contract")
|
|
1967
|
+
throw new Error(`Expected principal CV, got ${cv.type}`);
|
|
1968
|
+
return cv.value;
|
|
1969
|
+
}
|
|
1970
|
+
if (isAbiStringAscii(abiType) || isAbiStringUtf8(abiType)) {
|
|
1971
|
+
if (cv.type !== "ascii" && cv.type !== "utf8")
|
|
1972
|
+
throw new Error(`Expected string CV, got ${cv.type}`);
|
|
1973
|
+
return cv.value;
|
|
1974
|
+
}
|
|
1975
|
+
if (isAbiBuffer(abiType)) {
|
|
1976
|
+
if (cv.type !== "buffer")
|
|
1977
|
+
throw new Error(`Expected buffer CV, got ${cv.type}`);
|
|
1978
|
+
const hex = cv.value;
|
|
1979
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
1980
|
+
for (let i = 0;i < bytes.length; i++) {
|
|
1981
|
+
bytes[i] = Number.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
|
|
1982
|
+
}
|
|
1983
|
+
return bytes;
|
|
1984
|
+
}
|
|
1985
|
+
if (isAbiList(abiType)) {
|
|
1986
|
+
if (cv.type !== "list")
|
|
1987
|
+
throw new Error(`Expected list CV, got ${cv.type}`);
|
|
1988
|
+
return cv.value.map((item) => clarityValueToJSInner(abiType.list.type, item));
|
|
1989
|
+
}
|
|
1990
|
+
if (isAbiTuple(abiType)) {
|
|
1991
|
+
if (cv.type !== "tuple")
|
|
1992
|
+
throw new Error(`Expected tuple CV, got ${cv.type}`);
|
|
1993
|
+
const result = {};
|
|
1994
|
+
for (const field of abiType.tuple) {
|
|
1995
|
+
const fieldCV = cv.value[field.name];
|
|
1996
|
+
if (!fieldCV)
|
|
1997
|
+
throw new Error(`Missing tuple field in CV: ${field.name}`);
|
|
1998
|
+
const camelKey = toCamelCase(field.name);
|
|
1999
|
+
result[camelKey] = clarityValueToJSInner(field.type, fieldCV);
|
|
2000
|
+
}
|
|
2001
|
+
return result;
|
|
2002
|
+
}
|
|
2003
|
+
if (isAbiOptional(abiType)) {
|
|
2004
|
+
if (cv.type === "none")
|
|
2005
|
+
return null;
|
|
2006
|
+
if (cv.type === "some")
|
|
2007
|
+
return clarityValueToJSInner(abiType.optional, cv.value);
|
|
2008
|
+
throw new Error(`Expected optional CV, got ${cv.type}`);
|
|
2009
|
+
}
|
|
2010
|
+
if (isAbiResponse(abiType)) {
|
|
2011
|
+
if (cv.type === "ok")
|
|
2012
|
+
return { ok: clarityValueToJSInner(abiType.response.ok, cv.value) };
|
|
2013
|
+
if (cv.type === "err")
|
|
2014
|
+
return { err: clarityValueToJSInner(abiType.response.error, cv.value) };
|
|
2015
|
+
throw new Error(`Expected response CV, got ${cv.type}`);
|
|
2016
|
+
}
|
|
2017
|
+
throw new Error(`Unknown ABI type: ${JSON.stringify(abiType)}`);
|
|
2018
|
+
}
|
|
1
2019
|
// src/bitcoin/index.ts
|
|
2
2020
|
var exports_bitcoin = {};
|
|
3
2021
|
__export(exports_bitcoin, {
|
|
@@ -35,6 +2053,367 @@ __export(exports_bitcoin, {
|
|
|
35
2053
|
});
|
|
36
2054
|
module.exports = __toCommonJS(exports_bitcoin);
|
|
37
2055
|
|
|
2056
|
+
// src/bitcoin/serialize.ts
|
|
2057
|
+
function doubleSha256(bytes) {
|
|
2058
|
+
return import_sha22.sha256(import_sha22.sha256(bytes));
|
|
2059
|
+
}
|
|
2060
|
+
function reverseBytes(bytes) {
|
|
2061
|
+
const out = new Uint8Array(bytes.length);
|
|
2062
|
+
for (let i = 0;i < bytes.length; i++) {
|
|
2063
|
+
out[i] = bytes[bytes.length - 1 - i];
|
|
2064
|
+
}
|
|
2065
|
+
return out;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
class BtcReader {
|
|
2069
|
+
data;
|
|
2070
|
+
view;
|
|
2071
|
+
offset = 0;
|
|
2072
|
+
constructor(data) {
|
|
2073
|
+
this.data = data;
|
|
2074
|
+
this.view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
2075
|
+
}
|
|
2076
|
+
get length() {
|
|
2077
|
+
return this.data.length;
|
|
2078
|
+
}
|
|
2079
|
+
readUInt8() {
|
|
2080
|
+
const v = this.view.getUint8(this.offset);
|
|
2081
|
+
this.offset += 1;
|
|
2082
|
+
return v;
|
|
2083
|
+
}
|
|
2084
|
+
peekUInt8() {
|
|
2085
|
+
return this.view.getUint8(this.offset);
|
|
2086
|
+
}
|
|
2087
|
+
readUInt32LE() {
|
|
2088
|
+
const v = this.view.getUint32(this.offset, true);
|
|
2089
|
+
this.offset += 4;
|
|
2090
|
+
return v;
|
|
2091
|
+
}
|
|
2092
|
+
readUInt64LE() {
|
|
2093
|
+
const v = this.view.getBigUint64(this.offset, true);
|
|
2094
|
+
this.offset += 8;
|
|
2095
|
+
return v;
|
|
2096
|
+
}
|
|
2097
|
+
readBytes(n) {
|
|
2098
|
+
if (this.offset + n > this.data.length) {
|
|
2099
|
+
throw new Error(`Bitcoin tx underflow: need ${n} bytes at offset ${this.offset}, have ${this.data.length}`);
|
|
2100
|
+
}
|
|
2101
|
+
const slice = this.data.slice(this.offset, this.offset + n);
|
|
2102
|
+
this.offset += n;
|
|
2103
|
+
return slice;
|
|
2104
|
+
}
|
|
2105
|
+
readVarInt() {
|
|
2106
|
+
const first = this.readUInt8();
|
|
2107
|
+
if (first < 253)
|
|
2108
|
+
return first;
|
|
2109
|
+
if (first === 253) {
|
|
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();
|
|
2116
|
+
}
|
|
2117
|
+
const big = this.readUInt64LE();
|
|
2118
|
+
if (big > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
2119
|
+
throw new Error("Bitcoin varint exceeds safe integer range");
|
|
2120
|
+
}
|
|
2121
|
+
return Number(big);
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
function scanTx(rawTx) {
|
|
2125
|
+
const r = new BtcReader(rawTx);
|
|
2126
|
+
const version = r.readUInt32LE();
|
|
2127
|
+
let hasWitness = false;
|
|
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)}`);
|
|
2133
|
+
}
|
|
2134
|
+
hasWitness = true;
|
|
2135
|
+
}
|
|
2136
|
+
const bodyStart = r.offset;
|
|
2137
|
+
const inputCount = r.readVarInt();
|
|
2138
|
+
const inputs = [];
|
|
2139
|
+
for (let i = 0;i < inputCount; i++) {
|
|
2140
|
+
const prevTxid = r.readBytes(32);
|
|
2141
|
+
const vout = r.readUInt32LE();
|
|
2142
|
+
const scriptSig = r.readBytes(r.readVarInt());
|
|
2143
|
+
const sequence = r.readUInt32LE();
|
|
2144
|
+
inputs.push({ prevTxid, vout, scriptSig, sequence });
|
|
2145
|
+
}
|
|
2146
|
+
const outputCount = r.readVarInt();
|
|
2147
|
+
const outputs = [];
|
|
2148
|
+
for (let i = 0;i < outputCount; i++) {
|
|
2149
|
+
const value = r.readUInt64LE();
|
|
2150
|
+
const scriptPubKey = r.readBytes(r.readVarInt());
|
|
2151
|
+
outputs.push({ value, scriptPubKey });
|
|
2152
|
+
}
|
|
2153
|
+
const bodyEnd = r.offset;
|
|
2154
|
+
if (hasWitness) {
|
|
2155
|
+
for (let i = 0;i < inputCount; i++) {
|
|
2156
|
+
const itemCount = r.readVarInt();
|
|
2157
|
+
for (let j = 0;j < itemCount; j++) {
|
|
2158
|
+
r.readBytes(r.readVarInt());
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
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
|
+
return {
|
|
2169
|
+
version: s.version,
|
|
2170
|
+
hasWitness: s.hasWitness,
|
|
2171
|
+
inputs: s.inputs,
|
|
2172
|
+
outputs: s.outputs,
|
|
2173
|
+
locktime: s.locktime,
|
|
2174
|
+
txidInternal: doubleSha256(s.legacy)
|
|
2175
|
+
};
|
|
2176
|
+
}
|
|
2177
|
+
function stripWitness(rawTx) {
|
|
2178
|
+
return scanTx(rawTx).legacy;
|
|
2179
|
+
}
|
|
2180
|
+
function bitcoinTxid(rawTx, { display = false } = {}) {
|
|
2181
|
+
const txid = doubleSha256(scanTx(rawTx).legacy);
|
|
2182
|
+
return display ? reverseBytes(txid) : txid;
|
|
2183
|
+
}
|
|
2184
|
+
function parseBlockHeader(header) {
|
|
2185
|
+
if (header.length !== 80) {
|
|
2186
|
+
throw new Error(`Bitcoin block header must be 80 bytes, got ${header.length}`);
|
|
2187
|
+
}
|
|
2188
|
+
const r = new BtcReader(header);
|
|
2189
|
+
const version = r.readUInt32LE();
|
|
2190
|
+
const prevBlock = r.readBytes(32);
|
|
2191
|
+
const merkleRoot = r.readBytes(32);
|
|
2192
|
+
const timestamp = r.readUInt32LE();
|
|
2193
|
+
const bits = r.readUInt32LE();
|
|
2194
|
+
const nonce = r.readUInt32LE();
|
|
2195
|
+
return { version, prevBlock, merkleRoot, timestamp, bits, nonce };
|
|
2196
|
+
}
|
|
2197
|
+
function blockHash(header, { display = false } = {}) {
|
|
2198
|
+
const hash = doubleSha256(header);
|
|
2199
|
+
return display ? reverseBytes(hash) : hash;
|
|
2200
|
+
}
|
|
2201
|
+
// src/bitcoin/merkle.ts
|
|
2202
|
+
function hashPair(left, right) {
|
|
2203
|
+
return doubleSha256(concatBytes(left, right));
|
|
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;
|
|
2215
|
+
}
|
|
2216
|
+
function merkleRoot(txidsInternal) {
|
|
2217
|
+
if (txidsInternal.length === 0) {
|
|
2218
|
+
throw new Error("merkleRoot: empty tx list");
|
|
2219
|
+
}
|
|
2220
|
+
let level = txidsInternal.slice();
|
|
2221
|
+
while (level.length > 1) {
|
|
2222
|
+
level = nextLevel(level);
|
|
2223
|
+
}
|
|
2224
|
+
const root = level[0];
|
|
2225
|
+
if (root === undefined)
|
|
2226
|
+
throw new Error("merkleRoot: no root");
|
|
2227
|
+
return root;
|
|
2228
|
+
}
|
|
2229
|
+
function buildMerkleProof(txidsInternal, txIndex) {
|
|
2230
|
+
const txCount = txidsInternal.length;
|
|
2231
|
+
if (txCount === 0) {
|
|
2232
|
+
throw new Error("buildMerkleProof: empty tx list");
|
|
2233
|
+
}
|
|
2234
|
+
if (txIndex < 0 || txIndex >= txCount) {
|
|
2235
|
+
throw new Error(`buildMerkleProof: txIndex ${txIndex} out of range for ${txCount} txs`);
|
|
2236
|
+
}
|
|
2237
|
+
const siblings = [];
|
|
2238
|
+
let index = txIndex;
|
|
2239
|
+
let level = txidsInternal.slice();
|
|
2240
|
+
while (level.length > 1) {
|
|
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);
|
|
2249
|
+
}
|
|
2250
|
+
return { siblings, txIndex, txCount };
|
|
2251
|
+
}
|
|
2252
|
+
function rootFromProof(leafInternal, proof) {
|
|
2253
|
+
let hash = leafInternal;
|
|
2254
|
+
let index = proof.txIndex;
|
|
2255
|
+
for (const sibling of proof.siblings) {
|
|
2256
|
+
hash = index % 2 === 1 ? hashPair(sibling, hash) : hashPair(hash, sibling);
|
|
2257
|
+
index = Math.floor(index / 2);
|
|
2258
|
+
}
|
|
2259
|
+
return hash;
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
// src/bitcoin/proof.ts
|
|
2263
|
+
function normalizeTxid(txid) {
|
|
2264
|
+
return without0x(txid).toLowerCase();
|
|
2265
|
+
}
|
|
2266
|
+
function assembleBlockForTx(args) {
|
|
2267
|
+
const txIndex = args.txidsDisplay.indexOf(normalizeTxid(args.txid));
|
|
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
|
+
};
|
|
2277
|
+
}
|
|
2278
|
+
async function buildTxProof(source, params) {
|
|
2279
|
+
const { txid, vout } = params;
|
|
2280
|
+
const want = normalizeTxid(txid);
|
|
2281
|
+
const [rawTx, block] = await Promise.all([
|
|
2282
|
+
source.getRawTx(txid),
|
|
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}`);
|
|
2289
|
+
}
|
|
2290
|
+
const atIndex = block.txidsInternal[block.txIndex];
|
|
2291
|
+
if (!atIndex || bytesToHex(atIndex) !== bytesToHex(parsed.txidInternal)) {
|
|
2292
|
+
throw new Error(`source txIndex ${block.txIndex} does not point at tx ${want}`);
|
|
2293
|
+
}
|
|
2294
|
+
const merkle = buildMerkleProof(block.txidsInternal, block.txIndex);
|
|
2295
|
+
const headerRoot = parseBlockHeader(block.header).merkleRoot;
|
|
2296
|
+
const computed = rootFromProof(parsed.txidInternal, merkle);
|
|
2297
|
+
if (bytesToHex(computed) !== bytesToHex(headerRoot)) {
|
|
2298
|
+
throw new Error("constructed merkle proof does not reconcile with the block header merkle root");
|
|
2299
|
+
}
|
|
2300
|
+
return {
|
|
2301
|
+
rawTx,
|
|
2302
|
+
txidInternal: parsed.txidInternal,
|
|
2303
|
+
vout,
|
|
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");
|
|
2312
|
+
}
|
|
2313
|
+
async function firstSuccess(fn) {
|
|
2314
|
+
let lastError;
|
|
2315
|
+
for (const source of sources) {
|
|
2316
|
+
try {
|
|
2317
|
+
return await fn(source);
|
|
2318
|
+
} catch (error) {
|
|
2319
|
+
lastError = error;
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
throw lastError;
|
|
2323
|
+
}
|
|
2324
|
+
return {
|
|
2325
|
+
getRawTx: (txid) => firstSuccess((s) => s.getRawTx(txid)),
|
|
2326
|
+
getBlockForTx: (txid) => firstSuccess((s) => s.getBlockForTx(txid))
|
|
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;
|
|
2357
|
+
}
|
|
2358
|
+
return {
|
|
2359
|
+
async getRawTx(txid) {
|
|
2360
|
+
return hexToBytes(await rpc("getrawtransaction", [txid, false]));
|
|
2361
|
+
},
|
|
2362
|
+
async getBlockForTx(txid) {
|
|
2363
|
+
const tx = await rpc("getrawtransaction", [
|
|
2364
|
+
txid,
|
|
2365
|
+
true
|
|
2366
|
+
]);
|
|
2367
|
+
if (!tx.blockhash) {
|
|
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}`);
|
|
2392
|
+
}
|
|
2393
|
+
return res;
|
|
2394
|
+
}
|
|
2395
|
+
return {
|
|
2396
|
+
async getRawTx(txid) {
|
|
2397
|
+
return hexToBytes((await (await get(`/tx/${txid}/hex`)).text()).trim());
|
|
2398
|
+
},
|
|
2399
|
+
async getBlockForTx(txid) {
|
|
2400
|
+
const status = await (await get(`/tx/${txid}`)).json();
|
|
2401
|
+
if (!status.status.confirmed) {
|
|
2402
|
+
throw new Error(`tx ${txid} is unconfirmed`);
|
|
2403
|
+
}
|
|
2404
|
+
const blockHashHex = status.status.block_hash;
|
|
2405
|
+
const header = (await (await get(`/block/${blockHashHex}/header`)).text()).trim();
|
|
2406
|
+
const txids = await (await get(`/block/${blockHashHex}/txids`)).json();
|
|
2407
|
+
return assembleBlockForTx({
|
|
2408
|
+
txid,
|
|
2409
|
+
blockId: blockHashHex,
|
|
2410
|
+
headerHex: header,
|
|
2411
|
+
height: status.status.block_height,
|
|
2412
|
+
txidsDisplay: txids
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
};
|
|
2416
|
+
}
|
|
38
2417
|
// src/bitcoin/codec.ts
|
|
39
2418
|
function merkleDepth(txCount) {
|
|
40
2419
|
let depth = 0;
|
|
@@ -203,6 +2582,18 @@ var SPV_ADAPTER_ABI = {
|
|
|
203
2582
|
}
|
|
204
2583
|
]
|
|
205
2584
|
};
|
|
2585
|
+
// src/epochs.ts
|
|
2586
|
+
var EPOCH_4_ACTIVATION_BURN_HEIGHT_MAINNET = 960230;
|
|
2587
|
+
|
|
2588
|
+
// src/errors/response.ts
|
|
2589
|
+
class MalformedResponseError extends BaseError {
|
|
2590
|
+
name = "MalformedResponseError";
|
|
2591
|
+
}
|
|
2592
|
+
|
|
2593
|
+
class ReadContractError extends BaseError {
|
|
2594
|
+
name = "ReadContractError";
|
|
2595
|
+
}
|
|
2596
|
+
|
|
206
2597
|
// src/bitcoin/activation.ts
|
|
207
2598
|
async function getBurnBlockHeight(client) {
|
|
208
2599
|
const info = await client.request("/v2/info");
|
|
@@ -219,6 +2610,28 @@ async function isClarity6Active(client, gate = {}) {
|
|
|
219
2610
|
const current = await getBurnBlockHeight(client);
|
|
220
2611
|
return current >= activation;
|
|
221
2612
|
}
|
|
2613
|
+
// src/actions/public/readContract.ts
|
|
2614
|
+
async function readContract(client, params) {
|
|
2615
|
+
const [address, name] = parseContractId(params.contract);
|
|
2616
|
+
const sender = params.sender ?? address;
|
|
2617
|
+
const serializedArgs = (params.args ?? []).map((arg) => with0x(bytesToHex(serializeCVBytes(arg))));
|
|
2618
|
+
const path = `/v2/contracts/call-read/${encodeURIComponent(address)}/${encodeURIComponent(name)}/${encodeURIComponent(params.functionName)}`;
|
|
2619
|
+
const data = await client.request(params.tip ? `${path}?tip=${encodeURIComponent(params.tip)}` : path, {
|
|
2620
|
+
method: "POST",
|
|
2621
|
+
body: {
|
|
2622
|
+
sender,
|
|
2623
|
+
arguments: serializedArgs
|
|
2624
|
+
}
|
|
2625
|
+
});
|
|
2626
|
+
if (data.okay) {
|
|
2627
|
+
if (typeof data.result !== "string") {
|
|
2628
|
+
throw new MalformedResponseError(`readContract: /v2/contracts/call-read response is missing "result"`);
|
|
2629
|
+
}
|
|
2630
|
+
return deserializeCVBytes(data.result);
|
|
2631
|
+
}
|
|
2632
|
+
throw new ReadContractError(data.cause ?? "Read-only call failed");
|
|
2633
|
+
}
|
|
2634
|
+
|
|
222
2635
|
// src/bitcoin/verifier.ts
|
|
223
2636
|
function clarityToBool(cv) {
|
|
224
2637
|
const value = cv.type === "ok" ? cv.value : cv;
|
|
@@ -282,6 +2695,69 @@ function bitcoinVerifier(client, config) {
|
|
|
282
2695
|
}
|
|
283
2696
|
};
|
|
284
2697
|
}
|
|
2698
|
+
// src/bitcoin/address.ts
|
|
2699
|
+
var import_secp256k1 = require("@noble/curves/secp256k1.js");
|
|
2700
|
+
var import_base3 = require("@scure/base");
|
|
2701
|
+
var BITCOIN_NETWORK_PARAMS = {
|
|
2702
|
+
mainnet: { p2pkh: 0, p2sh: 5, hrp: "bc" },
|
|
2703
|
+
testnet: { p2pkh: 111, p2sh: 196, hrp: "tb" },
|
|
2704
|
+
regtest: { p2pkh: 111, p2sh: 196, hrp: "bcrt" }
|
|
2705
|
+
};
|
|
2706
|
+
var NETWORK_PARAMS = BITCOIN_NETWORK_PARAMS;
|
|
2707
|
+
function base58CheckEncode(version, payload) {
|
|
2708
|
+
const data = concatBytes(Uint8Array.of(version), payload);
|
|
2709
|
+
const checksum = doubleSha256(data).slice(0, 4);
|
|
2710
|
+
return import_base3.base58.encode(concatBytes(data, checksum));
|
|
2711
|
+
}
|
|
2712
|
+
function formatBitcoinAddress(parsed, network = "mainnet") {
|
|
2713
|
+
const params = NETWORK_PARAMS[network];
|
|
2714
|
+
const hash = parsed.hash;
|
|
2715
|
+
if (!hash)
|
|
2716
|
+
return;
|
|
2717
|
+
switch (parsed.type) {
|
|
2718
|
+
case "p2pkh":
|
|
2719
|
+
return base58CheckEncode(params.p2pkh, hash);
|
|
2720
|
+
case "p2sh":
|
|
2721
|
+
return base58CheckEncode(params.p2sh, hash);
|
|
2722
|
+
case "p2wpkh":
|
|
2723
|
+
case "p2wsh":
|
|
2724
|
+
return import_base3.bech32.encode(params.hrp, [0, ...import_base3.bech32.toWords(hash)]);
|
|
2725
|
+
case "p2tr":
|
|
2726
|
+
return import_base3.bech32m.encode(params.hrp, [1, ...import_base3.bech32m.toWords(hash)]);
|
|
2727
|
+
default:
|
|
2728
|
+
return;
|
|
2729
|
+
}
|
|
2730
|
+
}
|
|
2731
|
+
function toPubkeyBytes(publicKey) {
|
|
2732
|
+
return typeof publicKey === "string" ? hexToBytes(publicKey) : publicKey;
|
|
2733
|
+
}
|
|
2734
|
+
function taprootTweakPubkey(xonly) {
|
|
2735
|
+
if (xonly.length !== 32)
|
|
2736
|
+
throw new Error(`Expected 32-byte x-only pubkey, got ${xonly.length}`);
|
|
2737
|
+
const tweak = import_secp256k1.schnorr.utils.taggedHash("TapTweak", xonly);
|
|
2738
|
+
const t = BigInt(`0x${Array.from(tweak, (b) => b.toString(16).padStart(2, "0")).join("")}`);
|
|
2739
|
+
if (t >= import_secp256k1.secp256k1.Point.Fn.ORDER)
|
|
2740
|
+
throw new Error("Invalid tap tweak (exceeds curve order)");
|
|
2741
|
+
const internal = import_secp256k1.secp256k1.Point.fromBytes(concatBytes(Uint8Array.of(2), xonly));
|
|
2742
|
+
const output = internal.add(import_secp256k1.secp256k1.Point.BASE.multiply(t));
|
|
2743
|
+
return output.toBytes(true).slice(1);
|
|
2744
|
+
}
|
|
2745
|
+
function publicKeyToP2wpkhAddress(publicKey, network = "mainnet") {
|
|
2746
|
+
const pubkey = toPubkeyBytes(publicKey);
|
|
2747
|
+
if (pubkey.length !== 33)
|
|
2748
|
+
throw new Error(`Expected 33-byte compressed pubkey, got ${pubkey.length}`);
|
|
2749
|
+
const params = NETWORK_PARAMS[network];
|
|
2750
|
+
return import_base3.bech32.encode(params.hrp, [0, ...import_base3.bech32.toWords(hash160(pubkey))]);
|
|
2751
|
+
}
|
|
2752
|
+
function publicKeyToP2trAddress(publicKey, network = "mainnet") {
|
|
2753
|
+
const pubkey = toPubkeyBytes(publicKey);
|
|
2754
|
+
const xonly = pubkey.length === 33 ? pubkey.slice(1) : pubkey.length === 32 ? pubkey : undefined;
|
|
2755
|
+
if (!xonly)
|
|
2756
|
+
throw new Error(`Expected 33-byte compressed or 32-byte x-only pubkey, got ${pubkey.length}`);
|
|
2757
|
+
const params = NETWORK_PARAMS[network];
|
|
2758
|
+
const outputKey = taprootTweakPubkey(xonly);
|
|
2759
|
+
return import_base3.bech32m.encode(params.hrp, [1, ...import_base3.bech32m.toWords(outputKey)]);
|
|
2760
|
+
}
|
|
285
2761
|
// src/bitcoin/actions.ts
|
|
286
2762
|
async function verifyBitcoinPayment(client, params) {
|
|
287
2763
|
const {
|
|
@@ -323,5 +2799,5 @@ async function verifyBitcoinPayment(client, params) {
|
|
|
323
2799
|
return { verified, mined, output, proof };
|
|
324
2800
|
}
|
|
325
2801
|
|
|
326
|
-
//# debugId=
|
|
2802
|
+
//# debugId=DE7406CAE6FEF1BF64756E2164756E21
|
|
327
2803
|
//# sourceMappingURL=index.cjs.map
|