@secondlayer/stacks 0.2.2 → 1.0.0-alpha.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/dist/shared/stacks-02actsrx.cjs.map +2 -2
- package/dist/shared/{stacks-xp9n3r0t.js → stacks-09wa7ewe.js} +108 -108
- package/dist/shared/stacks-09wa7ewe.js.map +15 -0
- package/dist/shared/{stacks-ky14tdf6.cjs → stacks-0nfexv24.cjs} +20 -8
- package/dist/shared/stacks-0nfexv24.cjs.map +14 -0
- package/dist/shared/{stacks-an5k8n4t.cjs → stacks-14pgpkrr.cjs} +82 -73
- package/dist/shared/stacks-14pgpkrr.cjs.map +23 -0
- package/dist/shared/{stacks-v6ja2eh7.cjs → stacks-17sdtaxg.cjs} +106 -102
- package/dist/shared/stacks-17sdtaxg.cjs.map +15 -0
- package/dist/shared/{stacks-96gaxfcf.js → stacks-1s5w4ncf.js} +44 -32
- package/dist/shared/stacks-1s5w4ncf.js.map +17 -0
- package/dist/shared/stacks-24h5k94q.cjs.map +3 -3
- package/dist/shared/{stacks-evnzth1q.cjs → stacks-4vzmhw3q.cjs} +3 -3
- package/dist/shared/stacks-4vzmhw3q.cjs.map +10 -0
- package/dist/shared/{stacks-k9p8m3wf.js → stacks-4x2bcc2k.js} +87 -78
- package/dist/shared/stacks-4x2bcc2k.js.map +23 -0
- package/dist/shared/stacks-5tprhns9.cjs.map +3 -3
- package/dist/shared/stacks-709tra19.js.map +2 -2
- package/dist/shared/{stacks-q79dx28x.js → stacks-70p84bgg.js} +3 -3
- package/dist/shared/stacks-70p84bgg.js.map +10 -0
- package/dist/shared/{stacks-k2p5tv6x.js → stacks-913a2rx7.js} +3 -3
- package/dist/shared/stacks-913a2rx7.js.map +10 -0
- package/dist/shared/{stacks-jrnmh4kc.js → stacks-96d6m1zy.js} +15 -6
- package/dist/shared/stacks-96d6m1zy.js.map +11 -0
- package/dist/shared/stacks-9g0jhab3.cjs.map +2 -2
- package/dist/shared/stacks-dr5en54r.cjs.map +2 -2
- package/dist/shared/stacks-fcaefc5b.cjs.map +2 -2
- package/dist/shared/stacks-gck1sq7h.cjs.map +2 -2
- package/dist/shared/stacks-je937aas.js.map +2 -2
- package/dist/shared/{stacks-k58k970n.js → stacks-kg1npstf.js} +5 -3
- package/dist/shared/stacks-kg1npstf.js.map +10 -0
- package/dist/shared/{stacks-qvg7c24g.cjs → stacks-n98w7g57.cjs} +5 -3
- package/dist/shared/stacks-n98w7g57.cjs.map +10 -0
- package/dist/shared/{stacks-6m1z4j07.js → stacks-nqae5amn.cjs} +74 -160
- package/dist/shared/stacks-nqae5amn.cjs.map +10 -0
- package/dist/shared/stacks-qcae5852.js.map +2 -2
- package/dist/shared/stacks-qt8ehebn.js.map +3 -3
- package/dist/shared/stacks-ra02bpny.cjs.map +3 -3
- package/dist/shared/stacks-rwfgts3s.js.map +2 -2
- package/dist/shared/stacks-s10yb9gz.js.map +2 -2
- package/dist/shared/{stacks-etf219gs.cjs → stacks-s30kkvm8.js} +101 -118
- package/dist/shared/stacks-s30kkvm8.js.map +10 -0
- package/dist/shared/stacks-s7z5q8be.js.map +3 -3
- package/dist/shared/stacks-v9jqcpd4.js.map +2 -2
- package/dist/shared/stacks-vdfag81a.cjs.map +2 -2
- package/dist/shared/{stacks-rg1g0fja.js → stacks-wjem3xw9.js} +21 -9
- package/dist/shared/stacks-wjem3xw9.js.map +14 -0
- package/dist/shared/{stacks-k08tgzyp.cjs → stacks-wyxj879g.cjs} +3 -3
- package/dist/shared/stacks-wyxj879g.cjs.map +13 -0
- package/dist/shared/stacks-y3dh7hv1.js.map +3 -3
- package/dist/shared/{stacks-2ar4prfz.cjs → stacks-y5262j0z.cjs} +14 -5
- package/dist/shared/stacks-y5262j0z.cjs.map +11 -0
- package/dist/shared/stacks-ya3x01yd.cjs.map +2 -2
- package/dist/shared/{stacks-p93g814f.js → stacks-zf7rbpzp.js} +4 -4
- package/dist/shared/stacks-zf7rbpzp.js.map +13 -0
- package/dist/shared/{stacks-61rvzkz1.cjs → stacks-znrb59ce.cjs} +41 -29
- package/dist/shared/stacks-znrb59ce.cjs.map +17 -0
- package/dist/src/accounts/index.cjs +2 -2
- package/dist/src/accounts/index.cjs.map +5 -5
- package/dist/src/accounts/index.js +2 -6
- package/dist/src/accounts/index.js.map +5 -5
- package/dist/src/actions/index.d.cts +29 -29
- package/dist/src/actions/index.d.ts +29 -29
- package/dist/src/actions/index.js +7 -7
- package/dist/src/bns/index.cjs +55 -43
- package/dist/src/bns/index.cjs.map +9 -9
- package/dist/src/bns/index.d.cts +29 -29
- package/dist/src/bns/index.d.ts +29 -29
- package/dist/src/bns/index.js +62 -50
- package/dist/src/bns/index.js.map +9 -9
- package/dist/src/clarity/index.js +4 -4
- package/dist/src/connect/index.cjs +114 -112
- package/dist/src/connect/index.cjs.map +13 -13
- package/dist/src/connect/index.js +114 -112
- package/dist/src/connect/index.js.map +13 -13
- package/dist/src/connect/walletconnect/index.cjs +3 -3
- package/dist/src/connect/walletconnect/index.cjs.map +10 -10
- package/dist/src/connect/walletconnect/index.js +3 -3
- package/dist/src/connect/walletconnect/index.js.map +10 -10
- package/dist/src/index.cjs +108 -2
- package/dist/src/index.cjs.map +19 -15
- package/dist/src/index.d.cts +291 -112
- package/dist/src/index.d.ts +291 -112
- package/dist/src/index.js +122 -9
- package/dist/src/index.js.map +19 -15
- package/dist/src/pox/index.cjs.map +6 -6
- package/dist/src/pox/index.d.cts +29 -29
- package/dist/src/pox/index.d.ts +29 -29
- package/dist/src/pox/index.js +5 -5
- package/dist/src/pox/index.js.map +6 -6
- package/dist/src/stackingdao/index.cjs +31 -6
- package/dist/src/stackingdao/index.cjs.map +6 -6
- package/dist/src/stackingdao/index.d.cts +29 -29
- package/dist/src/stackingdao/index.d.ts +29 -29
- package/dist/src/stackingdao/index.js +37 -12
- package/dist/src/stackingdao/index.js.map +6 -6
- package/dist/src/subscriptions/index.d.cts +29 -29
- package/dist/src/subscriptions/index.d.ts +29 -29
- package/dist/src/tools/btc/index.cjs +130 -0
- package/dist/src/tools/btc/index.cjs.map +10 -0
- package/dist/src/tools/btc/index.d.cts +8 -0
- package/dist/src/tools/btc/index.d.ts +8 -0
- package/dist/src/tools/btc/index.js +89 -0
- package/dist/src/tools/btc/index.js.map +10 -0
- package/dist/src/tools/index.cjs +2470 -0
- package/dist/src/tools/index.cjs.map +61 -0
- package/dist/src/tools/index.d.cts +144 -0
- package/dist/src/tools/index.d.ts +144 -0
- package/dist/src/tools/index.js +2435 -0
- package/dist/src/tools/index.js.map +61 -0
- package/dist/src/transactions/index.js +3 -3
- package/dist/src/triggers/index.cjs +66 -0
- package/dist/src/triggers/index.cjs.map +10 -0
- package/dist/src/triggers/index.d.cts +120 -0
- package/dist/src/triggers/index.d.ts +120 -0
- package/dist/src/triggers/index.js +25 -0
- package/dist/src/triggers/index.js.map +10 -0
- package/dist/src/tx/index.cjs +65 -0
- package/dist/src/tx/index.cjs.map +10 -0
- package/dist/src/tx/index.d.cts +42 -0
- package/dist/src/tx/index.d.ts +42 -0
- package/dist/src/tx/index.js +22 -0
- package/dist/src/tx/index.js.map +10 -0
- package/dist/src/ui/index.cjs +431 -0
- package/dist/src/ui/index.cjs.map +27 -0
- package/dist/src/ui/index.d.cts +107 -0
- package/dist/src/ui/index.d.ts +107 -0
- package/dist/src/ui/index.js +391 -0
- package/dist/src/ui/index.js.map +27 -0
- package/dist/src/ui/schemas.cjs +134 -0
- package/dist/src/ui/schemas.cjs.map +18 -0
- package/dist/src/ui/schemas.d.cts +83 -0
- package/dist/src/ui/schemas.d.ts +83 -0
- package/dist/src/ui/schemas.js +91 -0
- package/dist/src/ui/schemas.js.map +18 -0
- package/dist/src/utils/index.cjs +3 -3
- package/dist/src/utils/index.cjs.map +4 -4
- package/dist/src/utils/index.js +4 -4
- package/dist/src/utils/index.js.map +4 -4
- package/package.json +156 -105
- package/dist/shared/stacks-2ar4prfz.cjs.map +0 -11
- package/dist/shared/stacks-61rvzkz1.cjs.map +0 -17
- package/dist/shared/stacks-6m1z4j07.js.map +0 -10
- package/dist/shared/stacks-96gaxfcf.js.map +0 -17
- package/dist/shared/stacks-an5k8n4t.cjs.map +0 -23
- package/dist/shared/stacks-etf219gs.cjs.map +0 -10
- package/dist/shared/stacks-evnzth1q.cjs.map +0 -10
- package/dist/shared/stacks-jrnmh4kc.js.map +0 -11
- package/dist/shared/stacks-k08tgzyp.cjs.map +0 -13
- package/dist/shared/stacks-k2p5tv6x.js.map +0 -10
- package/dist/shared/stacks-k58k970n.js.map +0 -10
- package/dist/shared/stacks-k9p8m3wf.js.map +0 -23
- package/dist/shared/stacks-ky14tdf6.cjs.map +0 -13
- package/dist/shared/stacks-p93g814f.js.map +0 -13
- package/dist/shared/stacks-q79dx28x.js.map +0 -10
- package/dist/shared/stacks-qvg7c24g.cjs.map +0 -10
- package/dist/shared/stacks-rg1g0fja.js.map +0 -13
- package/dist/shared/stacks-v6ja2eh7.cjs.map +0 -15
- package/dist/shared/stacks-xp9n3r0t.js.map +0 -15
|
@@ -0,0 +1,2435 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/tools/index.ts
|
|
5
|
+
import { tool } from "ai";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
|
|
8
|
+
// src/utils/c32.ts
|
|
9
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
10
|
+
|
|
11
|
+
// src/utils/encoding.ts
|
|
12
|
+
var hexes = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
13
|
+
function bytesToHex(bytes) {
|
|
14
|
+
let hex = "";
|
|
15
|
+
for (const b of bytes) {
|
|
16
|
+
hex += hexes[b];
|
|
17
|
+
}
|
|
18
|
+
return hex;
|
|
19
|
+
}
|
|
20
|
+
function hexToBytes(hex) {
|
|
21
|
+
hex = without0x(hex);
|
|
22
|
+
if (hex.length % 2)
|
|
23
|
+
hex = `0${hex}`;
|
|
24
|
+
const array = new Uint8Array(hex.length / 2);
|
|
25
|
+
for (let i = 0;i < array.length; i++) {
|
|
26
|
+
const j = i * 2;
|
|
27
|
+
const byte = Number.parseInt(hex.slice(j, j + 2), 16);
|
|
28
|
+
if (Number.isNaN(byte) || byte < 0)
|
|
29
|
+
throw new Error("Invalid byte sequence");
|
|
30
|
+
array[i] = byte;
|
|
31
|
+
}
|
|
32
|
+
return array;
|
|
33
|
+
}
|
|
34
|
+
function with0x(value) {
|
|
35
|
+
return /^0x/i.test(value) ? value : `0x${value}`;
|
|
36
|
+
}
|
|
37
|
+
function without0x(value) {
|
|
38
|
+
return /^0x/i.test(value) ? value.slice(2) : value;
|
|
39
|
+
}
|
|
40
|
+
function utf8ToBytes(str) {
|
|
41
|
+
return new TextEncoder().encode(str);
|
|
42
|
+
}
|
|
43
|
+
function bytesToUtf8(bytes) {
|
|
44
|
+
return new TextDecoder().decode(bytes);
|
|
45
|
+
}
|
|
46
|
+
function asciiToBytes(str) {
|
|
47
|
+
const bytes = new Uint8Array(str.length);
|
|
48
|
+
for (let i = 0;i < str.length; i++) {
|
|
49
|
+
bytes[i] = str.charCodeAt(i) & 255;
|
|
50
|
+
}
|
|
51
|
+
return bytes;
|
|
52
|
+
}
|
|
53
|
+
function bytesToAscii(bytes) {
|
|
54
|
+
return String.fromCharCode(...bytes);
|
|
55
|
+
}
|
|
56
|
+
function concatBytes(...arrays) {
|
|
57
|
+
if (arrays.length === 1)
|
|
58
|
+
return arrays[0];
|
|
59
|
+
const length = arrays.reduce((a, arr) => a + arr.length, 0);
|
|
60
|
+
const result = new Uint8Array(length);
|
|
61
|
+
let pad = 0;
|
|
62
|
+
for (const arr of arrays) {
|
|
63
|
+
result.set(arr, pad);
|
|
64
|
+
pad += arr.length;
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
function intToBigInt(value) {
|
|
69
|
+
if (typeof value === "bigint")
|
|
70
|
+
return value;
|
|
71
|
+
if (typeof value === "string")
|
|
72
|
+
return BigInt(value);
|
|
73
|
+
if (typeof value === "number") {
|
|
74
|
+
if (!Number.isInteger(value))
|
|
75
|
+
throw new RangeError("Values of type 'number' must be an integer.");
|
|
76
|
+
if (value > Number.MAX_SAFE_INTEGER)
|
|
77
|
+
throw new RangeError(`Values of type 'number' must be <= ${Number.MAX_SAFE_INTEGER}. Use BigInt instead.`);
|
|
78
|
+
return BigInt(value);
|
|
79
|
+
}
|
|
80
|
+
if (value instanceof Uint8Array)
|
|
81
|
+
return BigInt(`0x${bytesToHex(value)}`);
|
|
82
|
+
throw new TypeError("Must be a number, bigint, string, or Uint8Array.");
|
|
83
|
+
}
|
|
84
|
+
function intToBytes(value, byteLength) {
|
|
85
|
+
return bigIntToBytes(intToBigInt(value), byteLength);
|
|
86
|
+
}
|
|
87
|
+
function bigIntToBytes(value, length = 16) {
|
|
88
|
+
const hex = value.toString(16).padStart(length * 2, "0");
|
|
89
|
+
return hexToBytes(hex);
|
|
90
|
+
}
|
|
91
|
+
function intToHex(integer, byteLength = 8) {
|
|
92
|
+
const value = typeof integer === "bigint" ? integer : intToBigInt(integer);
|
|
93
|
+
return value.toString(16).padStart(byteLength * 2, "0");
|
|
94
|
+
}
|
|
95
|
+
function toTwos(value, width) {
|
|
96
|
+
const limit = BigInt(1) << width - BigInt(1);
|
|
97
|
+
if (value < -limit || value > limit - BigInt(1)) {
|
|
98
|
+
throw new Error(`Unable to represent integer in width: ${width}`);
|
|
99
|
+
}
|
|
100
|
+
if (value >= BigInt(0))
|
|
101
|
+
return value;
|
|
102
|
+
return value + (BigInt(1) << width);
|
|
103
|
+
}
|
|
104
|
+
function fromTwos(value, width) {
|
|
105
|
+
if (value & BigInt(1) << width - BigInt(1)) {
|
|
106
|
+
return value - (BigInt(1) << width);
|
|
107
|
+
}
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
function bytesToTwosBigInt(bytes) {
|
|
111
|
+
if (bytes.length === 0)
|
|
112
|
+
return 0n;
|
|
113
|
+
const hex = bytesToHex(bytes);
|
|
114
|
+
if (hex.length === 0)
|
|
115
|
+
return 0n;
|
|
116
|
+
return fromTwos(BigInt(`0x${hex}`), BigInt(bytes.byteLength * 8));
|
|
117
|
+
}
|
|
118
|
+
function writeUInt32BE(value) {
|
|
119
|
+
const buf = new Uint8Array(4);
|
|
120
|
+
buf[0] = value >>> 24 & 255;
|
|
121
|
+
buf[1] = value >>> 16 & 255;
|
|
122
|
+
buf[2] = value >>> 8 & 255;
|
|
123
|
+
buf[3] = value & 255;
|
|
124
|
+
return buf;
|
|
125
|
+
}
|
|
126
|
+
function writeUInt16BE(value) {
|
|
127
|
+
const buf = new Uint8Array(2);
|
|
128
|
+
buf[0] = value >>> 8 & 255;
|
|
129
|
+
buf[1] = value & 255;
|
|
130
|
+
return buf;
|
|
131
|
+
}
|
|
132
|
+
function writeUInt8(value) {
|
|
133
|
+
return new Uint8Array([value & 255]);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/utils/c32.ts
|
|
137
|
+
var C32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
138
|
+
var HEX = "0123456789abcdef";
|
|
139
|
+
function c32normalize(input) {
|
|
140
|
+
return input.toUpperCase().replace(/O/g, "0").replace(/L|I/g, "1");
|
|
141
|
+
}
|
|
142
|
+
function c32encode(inputHex) {
|
|
143
|
+
if (inputHex.length % 2 !== 0)
|
|
144
|
+
inputHex = `0${inputHex}`;
|
|
145
|
+
inputHex = inputHex.toLowerCase();
|
|
146
|
+
const res = [];
|
|
147
|
+
let carry = 0;
|
|
148
|
+
for (let i = inputHex.length - 1;i >= 0; i--) {
|
|
149
|
+
if (carry < 4) {
|
|
150
|
+
const currentCode = HEX.indexOf(inputHex[i]) >> carry;
|
|
151
|
+
const nextCode = i !== 0 ? HEX.indexOf(inputHex[i - 1]) : 0;
|
|
152
|
+
const nextBits = 1 + carry;
|
|
153
|
+
const nextLowBits = nextCode % (1 << nextBits) << 5 - nextBits;
|
|
154
|
+
res.unshift(C32[currentCode + nextLowBits]);
|
|
155
|
+
carry = nextBits;
|
|
156
|
+
} else {
|
|
157
|
+
carry = 0;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
let leadingZeros = 0;
|
|
161
|
+
while (leadingZeros < res.length && res[leadingZeros] === "0")
|
|
162
|
+
leadingZeros++;
|
|
163
|
+
const stripped = res.slice(leadingZeros);
|
|
164
|
+
const bytes = hexToBytes(inputHex);
|
|
165
|
+
let zeroBytesCount = 0;
|
|
166
|
+
while (zeroBytesCount < bytes.length && bytes[zeroBytesCount] === 0)
|
|
167
|
+
zeroBytesCount++;
|
|
168
|
+
const prefix = Array(zeroBytesCount).fill(C32[0]);
|
|
169
|
+
return [...prefix, ...stripped].join("");
|
|
170
|
+
}
|
|
171
|
+
function c32decode(c32input) {
|
|
172
|
+
c32input = c32normalize(c32input);
|
|
173
|
+
if (!c32input.match(`^[${C32}]*$`))
|
|
174
|
+
throw new Error("Not a c32-encoded string");
|
|
175
|
+
const zeroPrefix = c32input.match(`^${C32[0]}*`);
|
|
176
|
+
const numLeadingZeroBytes = zeroPrefix ? zeroPrefix[0].length : 0;
|
|
177
|
+
const res = [];
|
|
178
|
+
let carry = 0;
|
|
179
|
+
let carryBits = 0;
|
|
180
|
+
for (let i = c32input.length - 1;i >= 0; i--) {
|
|
181
|
+
if (carryBits === 4) {
|
|
182
|
+
res.unshift(HEX[carry]);
|
|
183
|
+
carryBits = 0;
|
|
184
|
+
carry = 0;
|
|
185
|
+
}
|
|
186
|
+
const currentValue = (C32.indexOf(c32input[i]) << carryBits) + carry;
|
|
187
|
+
res.unshift(HEX[currentValue % 16]);
|
|
188
|
+
carryBits += 1;
|
|
189
|
+
carry = currentValue >> 4;
|
|
190
|
+
if (carry > 1 << carryBits)
|
|
191
|
+
throw new Error("Panic error in c32 decoding");
|
|
192
|
+
}
|
|
193
|
+
res.unshift(HEX[carry]);
|
|
194
|
+
if (res.length % 2 === 1)
|
|
195
|
+
res.unshift("0");
|
|
196
|
+
let hexLeadingZeros = 0;
|
|
197
|
+
while (hexLeadingZeros < res.length && res[hexLeadingZeros] === "0")
|
|
198
|
+
hexLeadingZeros++;
|
|
199
|
+
let hexStr = res.slice(hexLeadingZeros - hexLeadingZeros % 2).join("");
|
|
200
|
+
for (let i = 0;i < numLeadingZeroBytes; i++)
|
|
201
|
+
hexStr = `00${hexStr}`;
|
|
202
|
+
return hexStr;
|
|
203
|
+
}
|
|
204
|
+
function c32checksum(dataHex) {
|
|
205
|
+
return bytesToHex(sha256(sha256(hexToBytes(dataHex))).slice(0, 4));
|
|
206
|
+
}
|
|
207
|
+
function c32checkEncode(version, data) {
|
|
208
|
+
if (version < 0 || version >= 32)
|
|
209
|
+
throw new Error("Invalid version (must be between 0 and 31)");
|
|
210
|
+
if (!data.match(/^[0-9a-fA-F]*$/))
|
|
211
|
+
throw new Error("Invalid data (not a hex string)");
|
|
212
|
+
data = data.toLowerCase();
|
|
213
|
+
if (data.length % 2 !== 0)
|
|
214
|
+
data = `0${data}`;
|
|
215
|
+
let versionHex = version.toString(16);
|
|
216
|
+
if (versionHex.length === 1)
|
|
217
|
+
versionHex = `0${versionHex}`;
|
|
218
|
+
const checksumHex = c32checksum(`${versionHex}${data}`);
|
|
219
|
+
return `${C32[version]}${c32encode(`${data}${checksumHex}`)}`;
|
|
220
|
+
}
|
|
221
|
+
function c32checkDecode(c32data) {
|
|
222
|
+
c32data = c32normalize(c32data);
|
|
223
|
+
const dataHex = c32decode(c32data.slice(1));
|
|
224
|
+
const version = C32.indexOf(c32data[0]);
|
|
225
|
+
const checksum = dataHex.slice(-8);
|
|
226
|
+
let versionHex = version.toString(16);
|
|
227
|
+
if (versionHex.length === 1)
|
|
228
|
+
versionHex = `0${versionHex}`;
|
|
229
|
+
if (c32checksum(`${versionHex}${dataHex.substring(0, dataHex.length - 8)}`) !== checksum) {
|
|
230
|
+
throw new Error("Invalid c32check string: checksum mismatch");
|
|
231
|
+
}
|
|
232
|
+
return [version, dataHex.substring(0, dataHex.length - 8)];
|
|
233
|
+
}
|
|
234
|
+
function c32address(version, hash160hex) {
|
|
235
|
+
if (!hash160hex.match(/^[0-9a-fA-F]{40}$/)) {
|
|
236
|
+
throw new Error("Invalid argument: not a hash160 hex string");
|
|
237
|
+
}
|
|
238
|
+
return `S${c32checkEncode(version, hash160hex)}`;
|
|
239
|
+
}
|
|
240
|
+
function c32addressDecode(c32addr) {
|
|
241
|
+
if (c32addr.length <= 5)
|
|
242
|
+
throw new Error("Invalid c32 address: invalid length");
|
|
243
|
+
if (c32addr[0] !== "S")
|
|
244
|
+
throw new Error('Invalid c32 address: must start with "S"');
|
|
245
|
+
return c32checkDecode(c32addr.slice(1));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/clarity/types.ts
|
|
249
|
+
var ClarityWireType = {
|
|
250
|
+
int: 0,
|
|
251
|
+
uint: 1,
|
|
252
|
+
buffer: 2,
|
|
253
|
+
true: 3,
|
|
254
|
+
false: 4,
|
|
255
|
+
address: 5,
|
|
256
|
+
contract: 6,
|
|
257
|
+
ok: 7,
|
|
258
|
+
err: 8,
|
|
259
|
+
none: 9,
|
|
260
|
+
some: 10,
|
|
261
|
+
list: 11,
|
|
262
|
+
tuple: 12,
|
|
263
|
+
ascii: 13,
|
|
264
|
+
utf8: 14
|
|
265
|
+
};
|
|
266
|
+
var wireTypeToClarity = Object.fromEntries(Object.entries(ClarityWireType).map(([k, v]) => [v, k]));
|
|
267
|
+
function clarityTypeFromByte(byte) {
|
|
268
|
+
const type = wireTypeToClarity[byte];
|
|
269
|
+
if (!type)
|
|
270
|
+
throw new Error(`Unknown clarity wire type: ${byte}`);
|
|
271
|
+
return type;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/clarity/serialize.ts
|
|
275
|
+
var CLARITY_INT_SIZE = 128n;
|
|
276
|
+
var CLARITY_INT_BYTE_SIZE = 16;
|
|
277
|
+
function typeIdByte(type) {
|
|
278
|
+
return ClarityWireType[type];
|
|
279
|
+
}
|
|
280
|
+
function withTypeId(type, bytes) {
|
|
281
|
+
return concatBytes(new Uint8Array([typeIdByte(type)]), bytes);
|
|
282
|
+
}
|
|
283
|
+
function serializeAddress(c32Address) {
|
|
284
|
+
const [version, hash160] = c32addressDecode(c32Address);
|
|
285
|
+
return concatBytes(new Uint8Array([version]), hexToBytes(hash160));
|
|
286
|
+
}
|
|
287
|
+
function serializeLPString(str, prefixBytes = 1) {
|
|
288
|
+
const content = utf8ToBytes(str);
|
|
289
|
+
const lengthPrefix = hexToBytes(intToHex(content.byteLength, prefixBytes));
|
|
290
|
+
return concatBytes(lengthPrefix, content);
|
|
291
|
+
}
|
|
292
|
+
function serializeCVBytes(value) {
|
|
293
|
+
switch (value.type) {
|
|
294
|
+
case "true":
|
|
295
|
+
case "false":
|
|
296
|
+
return new Uint8Array([typeIdByte(value.type)]);
|
|
297
|
+
case "int": {
|
|
298
|
+
const bytes = bigIntToBytes(toTwos(BigInt(value.value), CLARITY_INT_SIZE), CLARITY_INT_BYTE_SIZE);
|
|
299
|
+
return withTypeId(value.type, bytes);
|
|
300
|
+
}
|
|
301
|
+
case "uint": {
|
|
302
|
+
const bytes = bigIntToBytes(BigInt(value.value), CLARITY_INT_BYTE_SIZE);
|
|
303
|
+
return withTypeId(value.type, bytes);
|
|
304
|
+
}
|
|
305
|
+
case "buffer": {
|
|
306
|
+
const bufBytes = hexToBytes(value.value);
|
|
307
|
+
return withTypeId(value.type, concatBytes(writeUInt32BE(bufBytes.length), bufBytes));
|
|
308
|
+
}
|
|
309
|
+
case "none":
|
|
310
|
+
return new Uint8Array([typeIdByte(value.type)]);
|
|
311
|
+
case "some":
|
|
312
|
+
return withTypeId(value.type, serializeCVBytes(value.value));
|
|
313
|
+
case "ok":
|
|
314
|
+
case "err":
|
|
315
|
+
return withTypeId(value.type, serializeCVBytes(value.value));
|
|
316
|
+
case "address":
|
|
317
|
+
return withTypeId(value.type, serializeAddress(value.value));
|
|
318
|
+
case "contract": {
|
|
319
|
+
const [addr, name] = value.value.split(".");
|
|
320
|
+
if (!addr || !name)
|
|
321
|
+
throw new Error(`Invalid contract principal: ${value.value}`);
|
|
322
|
+
return withTypeId(value.type, concatBytes(serializeAddress(addr), serializeLPString(name)));
|
|
323
|
+
}
|
|
324
|
+
case "list": {
|
|
325
|
+
const parts = [writeUInt32BE(value.value.length)];
|
|
326
|
+
for (const item of value.value) {
|
|
327
|
+
parts.push(serializeCVBytes(item));
|
|
328
|
+
}
|
|
329
|
+
return withTypeId(value.type, concatBytes(...parts));
|
|
330
|
+
}
|
|
331
|
+
case "tuple": {
|
|
332
|
+
const keys = Object.keys(value.value).sort((a, b) => a.localeCompare(b));
|
|
333
|
+
const parts = [writeUInt32BE(keys.length)];
|
|
334
|
+
for (const key of keys) {
|
|
335
|
+
parts.push(serializeLPString(key));
|
|
336
|
+
parts.push(serializeCVBytes(value.value[key]));
|
|
337
|
+
}
|
|
338
|
+
return withTypeId(value.type, concatBytes(...parts));
|
|
339
|
+
}
|
|
340
|
+
case "ascii": {
|
|
341
|
+
const strBytes = asciiToBytes(value.value);
|
|
342
|
+
return withTypeId(value.type, concatBytes(writeUInt32BE(strBytes.length), strBytes));
|
|
343
|
+
}
|
|
344
|
+
case "utf8": {
|
|
345
|
+
const strBytes = utf8ToBytes(value.value);
|
|
346
|
+
return withTypeId(value.type, concatBytes(writeUInt32BE(strBytes.length), strBytes));
|
|
347
|
+
}
|
|
348
|
+
default:
|
|
349
|
+
throw new Error(`Cannot serialize unknown clarity type`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// src/transactions/types.ts
|
|
354
|
+
var AuthType = {
|
|
355
|
+
Standard: 4,
|
|
356
|
+
Sponsored: 5
|
|
357
|
+
};
|
|
358
|
+
var PayloadType = {
|
|
359
|
+
TokenTransfer: 0,
|
|
360
|
+
SmartContract: 1,
|
|
361
|
+
ContractCall: 2,
|
|
362
|
+
PoisonMicroblock: 3,
|
|
363
|
+
Coinbase: 4,
|
|
364
|
+
CoinbaseToAltRecipient: 5,
|
|
365
|
+
VersionedSmartContract: 6,
|
|
366
|
+
TenureChange: 7,
|
|
367
|
+
NakamotoCoinbase: 8
|
|
368
|
+
};
|
|
369
|
+
var AnchorMode = {
|
|
370
|
+
OnChainOnly: 1,
|
|
371
|
+
OffChainOnly: 2,
|
|
372
|
+
Any: 3
|
|
373
|
+
};
|
|
374
|
+
var PostConditionModeWire = {
|
|
375
|
+
Allow: 1,
|
|
376
|
+
Deny: 2
|
|
377
|
+
};
|
|
378
|
+
var AddressHashMode = {
|
|
379
|
+
P2PKH: 0,
|
|
380
|
+
P2SH: 1,
|
|
381
|
+
P2WPKH: 2,
|
|
382
|
+
P2WSH: 3,
|
|
383
|
+
P2SH_NonSequential: 5,
|
|
384
|
+
P2WSH_P2SH_NonSequential: 7
|
|
385
|
+
};
|
|
386
|
+
var PubKeyEncoding = {
|
|
387
|
+
Compressed: 0,
|
|
388
|
+
Uncompressed: 1
|
|
389
|
+
};
|
|
390
|
+
var FungibleConditionCode = {
|
|
391
|
+
Equal: 1,
|
|
392
|
+
Greater: 2,
|
|
393
|
+
GreaterEqual: 3,
|
|
394
|
+
Less: 4,
|
|
395
|
+
LessEqual: 5
|
|
396
|
+
};
|
|
397
|
+
var NonFungibleConditionCode = {
|
|
398
|
+
Sends: 16,
|
|
399
|
+
DoesNotSend: 17
|
|
400
|
+
};
|
|
401
|
+
var PostConditionPrincipalId = {
|
|
402
|
+
Origin: 1,
|
|
403
|
+
Standard: 2,
|
|
404
|
+
Contract: 3
|
|
405
|
+
};
|
|
406
|
+
var AssetType = {
|
|
407
|
+
STX: 0,
|
|
408
|
+
Fungible: 1,
|
|
409
|
+
NonFungible: 2
|
|
410
|
+
};
|
|
411
|
+
var RECOVERABLE_ECDSA_SIG_LENGTH_BYTES = 65;
|
|
412
|
+
var MEMO_MAX_LENGTH_BYTES = 34;
|
|
413
|
+
|
|
414
|
+
// src/transactions/wire/serialize.ts
|
|
415
|
+
function serializeAddress2(c32Address) {
|
|
416
|
+
const [version, hash160] = c32addressDecode(c32Address);
|
|
417
|
+
return concatBytes(new Uint8Array([version]), hexToBytes(hash160));
|
|
418
|
+
}
|
|
419
|
+
function serializeLPString2(str, prefixBytes = 1) {
|
|
420
|
+
const content = utf8ToBytes(str);
|
|
421
|
+
const prefix = hexToBytes(intToHex(content.byteLength, prefixBytes));
|
|
422
|
+
return concatBytes(prefix, content);
|
|
423
|
+
}
|
|
424
|
+
function serializeLPStringLong(str) {
|
|
425
|
+
return serializeLPString2(str, 4);
|
|
426
|
+
}
|
|
427
|
+
function serializeMemo(memo) {
|
|
428
|
+
const content = asciiToBytes(memo);
|
|
429
|
+
const padded = new Uint8Array(MEMO_MAX_LENGTH_BYTES);
|
|
430
|
+
padded.set(content.slice(0, MEMO_MAX_LENGTH_BYTES));
|
|
431
|
+
return padded;
|
|
432
|
+
}
|
|
433
|
+
function serializeSpendingCondition(condition) {
|
|
434
|
+
const parts = [
|
|
435
|
+
writeUInt8(condition.hashMode),
|
|
436
|
+
hexToBytes(condition.signer),
|
|
437
|
+
intToBytes(condition.nonce, 8),
|
|
438
|
+
intToBytes(condition.fee, 8)
|
|
439
|
+
];
|
|
440
|
+
if ("signature" in condition) {
|
|
441
|
+
const sc = condition;
|
|
442
|
+
parts.push(writeUInt8(sc.keyEncoding));
|
|
443
|
+
parts.push(hexToBytes(sc.signature));
|
|
444
|
+
} else {
|
|
445
|
+
const mc = condition;
|
|
446
|
+
parts.push(writeUInt32BE(mc.fields.length));
|
|
447
|
+
for (const field of mc.fields) {
|
|
448
|
+
parts.push(serializeAuthField(field));
|
|
449
|
+
}
|
|
450
|
+
parts.push(writeUInt16BE(mc.signaturesRequired));
|
|
451
|
+
}
|
|
452
|
+
return concatBytes(...parts);
|
|
453
|
+
}
|
|
454
|
+
function serializeAuthField(field) {
|
|
455
|
+
if (field.type === "publicKey") {
|
|
456
|
+
const typeId = field.pubKeyEncoding === 0 ? 0 : 1;
|
|
457
|
+
return concatBytes(writeUInt8(typeId), hexToBytes(field.data));
|
|
458
|
+
} else {
|
|
459
|
+
const typeId = field.pubKeyEncoding === 0 ? 2 : 3;
|
|
460
|
+
return concatBytes(writeUInt8(typeId), hexToBytes(field.data));
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function serializeAuthorization(auth) {
|
|
464
|
+
const parts = [writeUInt8(auth.authType)];
|
|
465
|
+
parts.push(serializeSpendingCondition(auth.spendingCondition));
|
|
466
|
+
if (auth.authType === AuthType.Sponsored) {
|
|
467
|
+
parts.push(serializeSpendingCondition(auth.sponsorSpendingCondition));
|
|
468
|
+
}
|
|
469
|
+
return concatBytes(...parts);
|
|
470
|
+
}
|
|
471
|
+
function serializePrincipal(principal) {
|
|
472
|
+
switch (principal.type) {
|
|
473
|
+
case "origin":
|
|
474
|
+
return writeUInt8(PostConditionPrincipalId.Origin);
|
|
475
|
+
case "standard":
|
|
476
|
+
return concatBytes(writeUInt8(PostConditionPrincipalId.Standard), serializeAddress2(principal.address));
|
|
477
|
+
case "contract":
|
|
478
|
+
return concatBytes(writeUInt8(PostConditionPrincipalId.Contract), serializeAddress2(principal.address), serializeLPString2(principal.contractName));
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
function serializeAssetInfo(asset) {
|
|
482
|
+
return concatBytes(serializeAddress2(asset.address), serializeLPString2(asset.contractName), serializeLPString2(asset.assetName));
|
|
483
|
+
}
|
|
484
|
+
function serializePostCondition(pc) {
|
|
485
|
+
const parts = [];
|
|
486
|
+
switch (pc.type) {
|
|
487
|
+
case "stx":
|
|
488
|
+
parts.push(writeUInt8(AssetType.STX));
|
|
489
|
+
parts.push(serializePrincipal(pc.principal));
|
|
490
|
+
parts.push(writeUInt8(pc.conditionCode));
|
|
491
|
+
parts.push(intToBytes(pc.amount, 8));
|
|
492
|
+
break;
|
|
493
|
+
case "ft":
|
|
494
|
+
parts.push(writeUInt8(AssetType.Fungible));
|
|
495
|
+
parts.push(serializePrincipal(pc.principal));
|
|
496
|
+
parts.push(serializeAssetInfo(pc.asset));
|
|
497
|
+
parts.push(writeUInt8(pc.conditionCode));
|
|
498
|
+
parts.push(intToBytes(pc.amount, 8));
|
|
499
|
+
break;
|
|
500
|
+
case "nft":
|
|
501
|
+
parts.push(writeUInt8(AssetType.NonFungible));
|
|
502
|
+
parts.push(serializePrincipal(pc.principal));
|
|
503
|
+
parts.push(serializeAssetInfo(pc.asset));
|
|
504
|
+
parts.push(serializeCVBytes(pc.assetId));
|
|
505
|
+
parts.push(writeUInt8(pc.conditionCode));
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
return concatBytes(...parts);
|
|
509
|
+
}
|
|
510
|
+
function serializePostConditions(pcs) {
|
|
511
|
+
const parts = [writeUInt32BE(pcs.length)];
|
|
512
|
+
for (const pc of pcs) {
|
|
513
|
+
parts.push(serializePostCondition(pc));
|
|
514
|
+
}
|
|
515
|
+
return concatBytes(...parts);
|
|
516
|
+
}
|
|
517
|
+
function serializePayload(payload) {
|
|
518
|
+
const parts = [writeUInt8(payload.payloadType)];
|
|
519
|
+
switch (payload.payloadType) {
|
|
520
|
+
case PayloadType.TokenTransfer:
|
|
521
|
+
parts.push(serializeCVBytes(payload.recipient));
|
|
522
|
+
parts.push(intToBytes(payload.amount, 8));
|
|
523
|
+
parts.push(serializeMemo(payload.memo));
|
|
524
|
+
break;
|
|
525
|
+
case PayloadType.ContractCall:
|
|
526
|
+
parts.push(serializeAddress2(payload.contractAddress));
|
|
527
|
+
parts.push(serializeLPString2(payload.contractName));
|
|
528
|
+
parts.push(serializeLPString2(payload.functionName));
|
|
529
|
+
parts.push(writeUInt32BE(payload.functionArgs.length));
|
|
530
|
+
for (const arg of payload.functionArgs) {
|
|
531
|
+
parts.push(serializeCVBytes(arg));
|
|
532
|
+
}
|
|
533
|
+
break;
|
|
534
|
+
case PayloadType.SmartContract:
|
|
535
|
+
parts.push(serializeLPString2(payload.contractName));
|
|
536
|
+
parts.push(serializeLPStringLong(payload.codeBody));
|
|
537
|
+
break;
|
|
538
|
+
case PayloadType.VersionedSmartContract:
|
|
539
|
+
parts.push(writeUInt8(payload.clarityVersion ?? 2));
|
|
540
|
+
parts.push(serializeLPString2(payload.contractName));
|
|
541
|
+
parts.push(serializeLPStringLong(payload.codeBody));
|
|
542
|
+
break;
|
|
543
|
+
case PayloadType.Coinbase:
|
|
544
|
+
parts.push(hexToBytes(payload.coinbaseBuffer));
|
|
545
|
+
break;
|
|
546
|
+
case PayloadType.CoinbaseToAltRecipient: {
|
|
547
|
+
const cbAlt = payload;
|
|
548
|
+
parts.push(hexToBytes(cbAlt.coinbaseBuffer));
|
|
549
|
+
parts.push(serializeCVBytes(cbAlt.recipient));
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
case PayloadType.PoisonMicroblock: {
|
|
553
|
+
const pm = payload;
|
|
554
|
+
parts.push(hexToBytes(pm.header1));
|
|
555
|
+
parts.push(hexToBytes(pm.header2));
|
|
556
|
+
break;
|
|
557
|
+
}
|
|
558
|
+
case PayloadType.TenureChange: {
|
|
559
|
+
const tc = payload;
|
|
560
|
+
parts.push(hexToBytes(tc.tenureConsensusHash));
|
|
561
|
+
parts.push(hexToBytes(tc.prevTenureConsensusHash));
|
|
562
|
+
parts.push(hexToBytes(tc.burnViewConsensusHash));
|
|
563
|
+
parts.push(hexToBytes(tc.previousTenureEnd));
|
|
564
|
+
parts.push(writeUInt32BE(tc.previousTenureBlocks));
|
|
565
|
+
parts.push(writeUInt8(tc.cause));
|
|
566
|
+
parts.push(hexToBytes(tc.pubkeyHash));
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
case PayloadType.NakamotoCoinbase: {
|
|
570
|
+
const nc = payload;
|
|
571
|
+
parts.push(hexToBytes(nc.coinbaseBuffer));
|
|
572
|
+
if (nc.recipient) {
|
|
573
|
+
parts.push(serializeCVBytes({ type: "some", value: nc.recipient }));
|
|
574
|
+
} else {
|
|
575
|
+
parts.push(serializeCVBytes({ type: "none" }));
|
|
576
|
+
}
|
|
577
|
+
parts.push(hexToBytes(nc.vrfProof));
|
|
578
|
+
break;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return concatBytes(...parts);
|
|
582
|
+
}
|
|
583
|
+
function serializeTransaction(tx) {
|
|
584
|
+
return concatBytes(writeUInt8(tx.version), writeUInt32BE(tx.chainId), serializeAuthorization(tx.auth), writeUInt8(tx.anchorMode), writeUInt8(tx.postConditionMode), serializePostConditions(tx.postConditions), serializePayload(tx.payload));
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// src/actions/public/estimateFee.ts
|
|
588
|
+
async function estimateFee(client, params) {
|
|
589
|
+
const payloadHex = bytesToHex(serializePayload(params.transaction.payload));
|
|
590
|
+
const txHex = bytesToHex(serializeTransaction(params.transaction));
|
|
591
|
+
const data = await client.request("/v2/fees/transaction", {
|
|
592
|
+
method: "POST",
|
|
593
|
+
body: {
|
|
594
|
+
estimated_len: Math.ceil(txHex.length / 2),
|
|
595
|
+
transaction_payload: "0x" + payloadHex
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
return (data.estimations ?? []).map((e) => ({
|
|
599
|
+
feeRate: e.fee_rate,
|
|
600
|
+
fee: e.fee
|
|
601
|
+
}));
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/actions/public/getAccountInfo.ts
|
|
605
|
+
async function getAccountInfo(client, params) {
|
|
606
|
+
const data = await client.request(`/v2/accounts/${params.address}?proof=1`, {
|
|
607
|
+
method: "GET"
|
|
608
|
+
});
|
|
609
|
+
return {
|
|
610
|
+
balance: BigInt(data.balance),
|
|
611
|
+
nonce: BigInt(data.nonce),
|
|
612
|
+
balanceProof: data.balance_proof ?? "",
|
|
613
|
+
nonceProof: data.nonce_proof ?? ""
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// src/actions/public/getBalance.ts
|
|
618
|
+
async function getBalance(client, params) {
|
|
619
|
+
const data = await client.request(`/v2/accounts/${params.address}`, {
|
|
620
|
+
method: "GET"
|
|
621
|
+
});
|
|
622
|
+
return BigInt(data.balance);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// src/actions/public/getBlock.ts
|
|
626
|
+
async function getBlock(client, params) {
|
|
627
|
+
if (params?.hash) {
|
|
628
|
+
return client.request(`/extended/v2/blocks/${params.hash}`, {
|
|
629
|
+
method: "GET"
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
if (params?.height !== undefined) {
|
|
633
|
+
return client.request(`/extended/v2/blocks/${params.height}`, {
|
|
634
|
+
method: "GET"
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
return client.request("/extended/v2/blocks?limit=1", { method: "GET" });
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// src/actions/public/getBlockHeight.ts
|
|
641
|
+
async function getBlockHeight(client) {
|
|
642
|
+
const data = await client.request("/v2/info", { method: "GET" });
|
|
643
|
+
return data.stacks_tip_height;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// src/utils/bytes-reader.ts
|
|
647
|
+
class BytesReader {
|
|
648
|
+
data;
|
|
649
|
+
offset = 0;
|
|
650
|
+
constructor(data) {
|
|
651
|
+
this.data = data;
|
|
652
|
+
}
|
|
653
|
+
readUInt8() {
|
|
654
|
+
return this.data[this.offset++];
|
|
655
|
+
}
|
|
656
|
+
readUInt16BE() {
|
|
657
|
+
const val = (this.data[this.offset] << 8 | this.data[this.offset + 1]) >>> 0;
|
|
658
|
+
this.offset += 2;
|
|
659
|
+
return val;
|
|
660
|
+
}
|
|
661
|
+
readUInt32BE() {
|
|
662
|
+
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;
|
|
663
|
+
this.offset += 4;
|
|
664
|
+
return val;
|
|
665
|
+
}
|
|
666
|
+
readBytes(length) {
|
|
667
|
+
if (this.offset + length > this.data.length) {
|
|
668
|
+
throw new Error(`Buffer underflow: need ${length} bytes at offset ${this.offset}, have ${this.data.length}`);
|
|
669
|
+
}
|
|
670
|
+
const slice = this.data.slice(this.offset, this.offset + length);
|
|
671
|
+
this.offset += length;
|
|
672
|
+
return slice;
|
|
673
|
+
}
|
|
674
|
+
readBigUInt64BE() {
|
|
675
|
+
const hex = bytesToHex(this.readBytes(8));
|
|
676
|
+
return hex.length > 0 ? BigInt(`0x${hex}`) : 0n;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// src/utils/address.ts
|
|
681
|
+
function parseContractId(contractId) {
|
|
682
|
+
const [address, name] = contractId.split(".");
|
|
683
|
+
if (!address || !name)
|
|
684
|
+
throw new Error(`Invalid contract identifier: ${contractId}`);
|
|
685
|
+
return [address, name];
|
|
686
|
+
}
|
|
687
|
+
function isClarityName(name) {
|
|
688
|
+
const regex = /^[a-zA-Z]([a-zA-Z0-9]|[-_!?+<>=/*])*$|^[-+=/*]$|^[<>]=?$/;
|
|
689
|
+
return regex.test(name) && name.length < 128;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// src/clarity/values.ts
|
|
693
|
+
var MAX_U128 = BigInt("0xffffffffffffffffffffffffffffffff");
|
|
694
|
+
var MIN_I128 = BigInt("-170141183460469231731687303715884105728");
|
|
695
|
+
var MAX_I128 = BigInt("0x7fffffffffffffffffffffffffffffff");
|
|
696
|
+
function intCV(value) {
|
|
697
|
+
if (typeof value === "string" && value.toLowerCase().startsWith("0x")) {
|
|
698
|
+
value = bytesToTwosBigInt(hexToBytes(value));
|
|
699
|
+
}
|
|
700
|
+
if (value instanceof Uint8Array)
|
|
701
|
+
value = bytesToTwosBigInt(value);
|
|
702
|
+
const n = intToBigInt(value);
|
|
703
|
+
if (n > MAX_I128)
|
|
704
|
+
throw new RangeError(`Int exceeds max i128: ${MAX_I128}`);
|
|
705
|
+
if (n < MIN_I128)
|
|
706
|
+
throw new RangeError(`Int below min i128: ${MIN_I128}`);
|
|
707
|
+
return { type: "int", value: n };
|
|
708
|
+
}
|
|
709
|
+
function uintCV(value) {
|
|
710
|
+
const n = intToBigInt(value);
|
|
711
|
+
if (n < 0n)
|
|
712
|
+
throw new RangeError("Cannot construct unsigned int from negative value");
|
|
713
|
+
if (n > MAX_U128)
|
|
714
|
+
throw new RangeError(`UInt exceeds max u128: ${MAX_U128}`);
|
|
715
|
+
return { type: "uint", value: n };
|
|
716
|
+
}
|
|
717
|
+
var trueCV = () => ({ type: "true" });
|
|
718
|
+
var falseCV = () => ({ type: "false" });
|
|
719
|
+
var boolCV = (v) => v ? trueCV() : falseCV();
|
|
720
|
+
function bufferCV(buffer) {
|
|
721
|
+
if (buffer.byteLength > 1048576) {
|
|
722
|
+
throw new Error("Buffer exceeds max size of 1MB");
|
|
723
|
+
}
|
|
724
|
+
return { type: "buffer", value: bytesToHex(buffer) };
|
|
725
|
+
}
|
|
726
|
+
function standardPrincipalCV(address) {
|
|
727
|
+
const [version, hash160] = c32addressDecode(address);
|
|
728
|
+
const normalized = c32address(version, hash160);
|
|
729
|
+
return { type: "address", value: normalized };
|
|
730
|
+
}
|
|
731
|
+
function contractPrincipalCV(address, contractName) {
|
|
732
|
+
const [version, hash160] = c32addressDecode(address);
|
|
733
|
+
const normalized = c32address(version, hash160);
|
|
734
|
+
if (utf8ToBytes(contractName).byteLength >= 128) {
|
|
735
|
+
throw new Error("Contract name must be less than 128 bytes");
|
|
736
|
+
}
|
|
737
|
+
return { type: "contract", value: `${normalized}.${contractName}` };
|
|
738
|
+
}
|
|
739
|
+
function noneCV() {
|
|
740
|
+
return { type: "none" };
|
|
741
|
+
}
|
|
742
|
+
function someCV(value) {
|
|
743
|
+
return { type: "some", value };
|
|
744
|
+
}
|
|
745
|
+
function responseOkCV(value) {
|
|
746
|
+
return { type: "ok", value };
|
|
747
|
+
}
|
|
748
|
+
function responseErrorCV(value) {
|
|
749
|
+
return { type: "err", value };
|
|
750
|
+
}
|
|
751
|
+
function listCV(values) {
|
|
752
|
+
return { type: "list", value: values };
|
|
753
|
+
}
|
|
754
|
+
function tupleCV(data) {
|
|
755
|
+
for (const key in data) {
|
|
756
|
+
if (!isClarityName(key)) {
|
|
757
|
+
throw new Error(`"${key}" is not a valid Clarity name`);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
return { type: "tuple", value: data };
|
|
761
|
+
}
|
|
762
|
+
function stringAsciiCV(value) {
|
|
763
|
+
return { type: "ascii", value };
|
|
764
|
+
}
|
|
765
|
+
function stringUtf8CV(value) {
|
|
766
|
+
return { type: "utf8", value };
|
|
767
|
+
}
|
|
768
|
+
var Cl = {
|
|
769
|
+
int: intCV,
|
|
770
|
+
uint: uintCV,
|
|
771
|
+
bool: boolCV,
|
|
772
|
+
principal(address) {
|
|
773
|
+
const [addr, name] = address.split(".");
|
|
774
|
+
if (!addr)
|
|
775
|
+
throw new Error("Invalid principal address");
|
|
776
|
+
return name ? contractPrincipalCV(addr, name) : standardPrincipalCV(addr);
|
|
777
|
+
},
|
|
778
|
+
address(address) {
|
|
779
|
+
return Cl.principal(address);
|
|
780
|
+
},
|
|
781
|
+
contractPrincipal: contractPrincipalCV,
|
|
782
|
+
standardPrincipal: standardPrincipalCV,
|
|
783
|
+
buffer: bufferCV,
|
|
784
|
+
bufferFromHex: (hex) => bufferCV(hexToBytes(hex)),
|
|
785
|
+
bufferFromAscii: (ascii) => bufferCV(asciiToBytes(ascii)),
|
|
786
|
+
bufferFromUtf8: (utf8) => bufferCV(utf8ToBytes(utf8)),
|
|
787
|
+
none: noneCV,
|
|
788
|
+
some: someCV,
|
|
789
|
+
ok: responseOkCV,
|
|
790
|
+
error: responseErrorCV,
|
|
791
|
+
list: listCV,
|
|
792
|
+
tuple: tupleCV,
|
|
793
|
+
stringAscii: stringAsciiCV,
|
|
794
|
+
stringUtf8: stringUtf8CV,
|
|
795
|
+
serialize(value) {
|
|
796
|
+
return bytesToHex(serializeCVBytes(value));
|
|
797
|
+
},
|
|
798
|
+
deserialize: deserializeCVBytes
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
// src/clarity/deserialize.ts
|
|
802
|
+
function readAddress(reader) {
|
|
803
|
+
const version = reader.readUInt8();
|
|
804
|
+
const hash160 = bytesToHex(reader.readBytes(20));
|
|
805
|
+
return c32address(version, hash160);
|
|
806
|
+
}
|
|
807
|
+
function readLPString(reader, prefixBytes = 1) {
|
|
808
|
+
let length = 0;
|
|
809
|
+
for (let i = 0;i < prefixBytes; i++) {
|
|
810
|
+
length = length << 8 | reader.readUInt8();
|
|
811
|
+
}
|
|
812
|
+
return bytesToUtf8(reader.readBytes(length));
|
|
813
|
+
}
|
|
814
|
+
function readCV(reader) {
|
|
815
|
+
const typeByte = reader.readUInt8();
|
|
816
|
+
const type = clarityTypeFromByte(typeByte);
|
|
817
|
+
switch (type) {
|
|
818
|
+
case "int":
|
|
819
|
+
return intCV(bytesToTwosBigInt(reader.readBytes(16)));
|
|
820
|
+
case "uint":
|
|
821
|
+
return uintCV(reader.readBytes(16));
|
|
822
|
+
case "true":
|
|
823
|
+
return trueCV();
|
|
824
|
+
case "false":
|
|
825
|
+
return falseCV();
|
|
826
|
+
case "buffer": {
|
|
827
|
+
const len = reader.readUInt32BE();
|
|
828
|
+
return bufferCV(reader.readBytes(len));
|
|
829
|
+
}
|
|
830
|
+
case "none":
|
|
831
|
+
return noneCV();
|
|
832
|
+
case "some":
|
|
833
|
+
return someCV(readCV(reader));
|
|
834
|
+
case "ok":
|
|
835
|
+
return responseOkCV(readCV(reader));
|
|
836
|
+
case "err":
|
|
837
|
+
return responseErrorCV(readCV(reader));
|
|
838
|
+
case "address":
|
|
839
|
+
return standardPrincipalCV(readAddress(reader));
|
|
840
|
+
case "contract": {
|
|
841
|
+
const addr = readAddress(reader);
|
|
842
|
+
const name = readLPString(reader);
|
|
843
|
+
return contractPrincipalCV(addr, name);
|
|
844
|
+
}
|
|
845
|
+
case "list": {
|
|
846
|
+
const len = reader.readUInt32BE();
|
|
847
|
+
const items = [];
|
|
848
|
+
for (let i = 0;i < len; i++) {
|
|
849
|
+
items.push(readCV(reader));
|
|
850
|
+
}
|
|
851
|
+
return listCV(items);
|
|
852
|
+
}
|
|
853
|
+
case "tuple": {
|
|
854
|
+
const len = reader.readUInt32BE();
|
|
855
|
+
const data = {};
|
|
856
|
+
for (let i = 0;i < len; i++) {
|
|
857
|
+
const key = readLPString(reader);
|
|
858
|
+
data[key] = readCV(reader);
|
|
859
|
+
}
|
|
860
|
+
return tupleCV(data);
|
|
861
|
+
}
|
|
862
|
+
case "ascii": {
|
|
863
|
+
const len = reader.readUInt32BE();
|
|
864
|
+
return stringAsciiCV(bytesToAscii(reader.readBytes(len)));
|
|
865
|
+
}
|
|
866
|
+
case "utf8": {
|
|
867
|
+
const len = reader.readUInt32BE();
|
|
868
|
+
return stringUtf8CV(bytesToUtf8(reader.readBytes(len)));
|
|
869
|
+
}
|
|
870
|
+
default:
|
|
871
|
+
throw new Error(`Cannot deserialize unknown clarity type: ${type}`);
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
function deserializeCVBytes(input) {
|
|
875
|
+
const bytes = typeof input === "string" ? hexToBytes(without0x(input)) : input;
|
|
876
|
+
return readCV(new BytesReader(bytes));
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// src/actions/public/readContract.ts
|
|
880
|
+
async function readContract(client, params) {
|
|
881
|
+
const [address, name] = parseContractId(params.contract);
|
|
882
|
+
const sender = params.sender ?? address;
|
|
883
|
+
const serializedArgs = (params.args ?? []).map((arg) => with0x(bytesToHex(serializeCVBytes(arg))));
|
|
884
|
+
const data = await client.request(`/v2/contracts/call-read/${address}/${name}/${params.functionName}`, {
|
|
885
|
+
method: "POST",
|
|
886
|
+
body: {
|
|
887
|
+
sender,
|
|
888
|
+
arguments: serializedArgs
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
if (data.okay) {
|
|
892
|
+
return deserializeCVBytes(data.result);
|
|
893
|
+
}
|
|
894
|
+
throw new Error(data.cause ?? "Read-only call failed");
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// src/clarity/abi/utils.ts
|
|
898
|
+
function toCamelCase(str) {
|
|
899
|
+
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()).replace(/-([A-Z])/g, (_, letter) => letter).replace(/-(\d)/g, (_, digit) => digit).replace(/-/g, "").replace(/^\d/, "_$&");
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
// src/utils/constants.ts
|
|
903
|
+
var MAX_U1282 = (1n << 128n) - 1n;
|
|
904
|
+
var MAX_I1282 = (1n << 127n) - 1n;
|
|
905
|
+
var MIN_I1282 = -(1n << 127n);
|
|
906
|
+
|
|
907
|
+
// src/clarity/abi/guards.ts
|
|
908
|
+
function isAbiList(type) {
|
|
909
|
+
return typeof type === "object" && type !== null && "list" in type;
|
|
910
|
+
}
|
|
911
|
+
function isAbiTuple(type) {
|
|
912
|
+
return typeof type === "object" && type !== null && "tuple" in type;
|
|
913
|
+
}
|
|
914
|
+
function isAbiOptional(type) {
|
|
915
|
+
return typeof type === "object" && type !== null && "optional" in type;
|
|
916
|
+
}
|
|
917
|
+
function isAbiResponse(type) {
|
|
918
|
+
return typeof type === "object" && type !== null && "response" in type;
|
|
919
|
+
}
|
|
920
|
+
function isAbiBuffer(type) {
|
|
921
|
+
return typeof type === "object" && type !== null && "buff" in type;
|
|
922
|
+
}
|
|
923
|
+
function isAbiStringAscii(type) {
|
|
924
|
+
return typeof type === "object" && type !== null && "string-ascii" in type;
|
|
925
|
+
}
|
|
926
|
+
function isAbiStringUtf8(type) {
|
|
927
|
+
return typeof type === "object" && type !== null && "string-utf8" in type;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// src/clarity/bridge.ts
|
|
931
|
+
function jsToClarityValue(abiType, value) {
|
|
932
|
+
if (abiType === "uint128")
|
|
933
|
+
return uintCV(value);
|
|
934
|
+
if (abiType === "int128")
|
|
935
|
+
return intCV(value);
|
|
936
|
+
if (abiType === "bool")
|
|
937
|
+
return boolCV(value);
|
|
938
|
+
if (abiType === "principal" || abiType === "trait_reference")
|
|
939
|
+
return Cl.principal(value);
|
|
940
|
+
if (isAbiStringAscii(abiType))
|
|
941
|
+
return stringAsciiCV(value);
|
|
942
|
+
if (isAbiStringUtf8(abiType))
|
|
943
|
+
return stringUtf8CV(value);
|
|
944
|
+
if (isAbiBuffer(abiType))
|
|
945
|
+
return bufferCV(value);
|
|
946
|
+
if (isAbiList(abiType)) {
|
|
947
|
+
const arr = value;
|
|
948
|
+
return listCV(arr.map((item) => jsToClarityValue(abiType.list.type, item)));
|
|
949
|
+
}
|
|
950
|
+
if (isAbiTuple(abiType)) {
|
|
951
|
+
const obj = value;
|
|
952
|
+
const data = {};
|
|
953
|
+
for (const field of abiType.tuple) {
|
|
954
|
+
const camelKey = toCamelCase(field.name);
|
|
955
|
+
const hasOriginal = field.name in obj;
|
|
956
|
+
const hasCamel = camelKey in obj;
|
|
957
|
+
const fieldValue = hasOriginal ? obj[field.name] : hasCamel ? obj[camelKey] : undefined;
|
|
958
|
+
if (fieldValue === undefined && !isAbiOptional(field.type)) {
|
|
959
|
+
throw new Error(`Missing tuple field: ${field.name}`);
|
|
960
|
+
}
|
|
961
|
+
data[field.name] = jsToClarityValue(field.type, fieldValue);
|
|
962
|
+
}
|
|
963
|
+
return tupleCV(data);
|
|
964
|
+
}
|
|
965
|
+
if (isAbiOptional(abiType)) {
|
|
966
|
+
if (value === null || value === undefined)
|
|
967
|
+
return noneCV();
|
|
968
|
+
return someCV(jsToClarityValue(abiType.optional, value));
|
|
969
|
+
}
|
|
970
|
+
if (isAbiResponse(abiType)) {
|
|
971
|
+
const obj = value;
|
|
972
|
+
if ("ok" in obj && !("err" in obj))
|
|
973
|
+
return responseOkCV(jsToClarityValue(abiType.response.ok, obj.ok));
|
|
974
|
+
if ("err" in obj && !("ok" in obj))
|
|
975
|
+
return responseErrorCV(jsToClarityValue(abiType.response.error, obj.err));
|
|
976
|
+
throw new Error("Response must have exactly 'ok' or 'err' property");
|
|
977
|
+
}
|
|
978
|
+
throw new Error(`Unknown ABI type: ${JSON.stringify(abiType)}`);
|
|
979
|
+
}
|
|
980
|
+
function clarityValueToJSUntyped(abiType, cv) {
|
|
981
|
+
return clarityValueToJSInner(abiType, cv);
|
|
982
|
+
}
|
|
983
|
+
function clarityValueToJSInner(abiType, cv) {
|
|
984
|
+
if (abiType === "uint128" || abiType === "int128") {
|
|
985
|
+
if (cv.type !== "int" && cv.type !== "uint")
|
|
986
|
+
throw new Error(`Expected int/uint CV, got ${cv.type}`);
|
|
987
|
+
return cv.value;
|
|
988
|
+
}
|
|
989
|
+
if (abiType === "bool") {
|
|
990
|
+
if (cv.type === "true")
|
|
991
|
+
return true;
|
|
992
|
+
if (cv.type === "false")
|
|
993
|
+
return false;
|
|
994
|
+
throw new Error(`Expected bool CV, got ${cv.type}`);
|
|
995
|
+
}
|
|
996
|
+
if (abiType === "principal" || abiType === "trait_reference") {
|
|
997
|
+
if (cv.type !== "address" && cv.type !== "contract")
|
|
998
|
+
throw new Error(`Expected principal CV, got ${cv.type}`);
|
|
999
|
+
return cv.value;
|
|
1000
|
+
}
|
|
1001
|
+
if (isAbiStringAscii(abiType) || isAbiStringUtf8(abiType)) {
|
|
1002
|
+
if (cv.type !== "ascii" && cv.type !== "utf8")
|
|
1003
|
+
throw new Error(`Expected string CV, got ${cv.type}`);
|
|
1004
|
+
return cv.value;
|
|
1005
|
+
}
|
|
1006
|
+
if (isAbiBuffer(abiType)) {
|
|
1007
|
+
if (cv.type !== "buffer")
|
|
1008
|
+
throw new Error(`Expected buffer CV, got ${cv.type}`);
|
|
1009
|
+
const hex = cv.value;
|
|
1010
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
1011
|
+
for (let i = 0;i < bytes.length; i++) {
|
|
1012
|
+
bytes[i] = Number.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
|
|
1013
|
+
}
|
|
1014
|
+
return bytes;
|
|
1015
|
+
}
|
|
1016
|
+
if (isAbiList(abiType)) {
|
|
1017
|
+
if (cv.type !== "list")
|
|
1018
|
+
throw new Error(`Expected list CV, got ${cv.type}`);
|
|
1019
|
+
return cv.value.map((item) => clarityValueToJSInner(abiType.list.type, item));
|
|
1020
|
+
}
|
|
1021
|
+
if (isAbiTuple(abiType)) {
|
|
1022
|
+
if (cv.type !== "tuple")
|
|
1023
|
+
throw new Error(`Expected tuple CV, got ${cv.type}`);
|
|
1024
|
+
const result = {};
|
|
1025
|
+
for (const field of abiType.tuple) {
|
|
1026
|
+
const fieldCV = cv.value[field.name];
|
|
1027
|
+
if (!fieldCV)
|
|
1028
|
+
throw new Error(`Missing tuple field in CV: ${field.name}`);
|
|
1029
|
+
const camelKey = toCamelCase(field.name);
|
|
1030
|
+
result[camelKey] = clarityValueToJSInner(field.type, fieldCV);
|
|
1031
|
+
}
|
|
1032
|
+
return result;
|
|
1033
|
+
}
|
|
1034
|
+
if (isAbiOptional(abiType)) {
|
|
1035
|
+
if (cv.type === "none")
|
|
1036
|
+
return null;
|
|
1037
|
+
if (cv.type === "some")
|
|
1038
|
+
return clarityValueToJSInner(abiType.optional, cv.value);
|
|
1039
|
+
throw new Error(`Expected optional CV, got ${cv.type}`);
|
|
1040
|
+
}
|
|
1041
|
+
if (isAbiResponse(abiType)) {
|
|
1042
|
+
if (cv.type === "ok")
|
|
1043
|
+
return { ok: clarityValueToJSInner(abiType.response.ok, cv.value) };
|
|
1044
|
+
if (cv.type === "err")
|
|
1045
|
+
return { err: clarityValueToJSInner(abiType.response.error, cv.value) };
|
|
1046
|
+
throw new Error(`Expected response CV, got ${cv.type}`);
|
|
1047
|
+
}
|
|
1048
|
+
throw new Error(`Unknown ABI type: ${JSON.stringify(abiType)}`);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// src/actions/public/getMapEntry.ts
|
|
1052
|
+
async function getMapEntry(client, params) {
|
|
1053
|
+
const [address, name] = parseContractId(params.contract);
|
|
1054
|
+
const serializedKey = with0x(bytesToHex(serializeCVBytes(params.key)));
|
|
1055
|
+
const data = await client.request(`/v2/map_entry/${address}/${name}/${params.mapName}`, {
|
|
1056
|
+
method: "POST",
|
|
1057
|
+
body: serializedKey
|
|
1058
|
+
});
|
|
1059
|
+
return deserializeCVBytes(data.data);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// src/transactions/authorization.ts
|
|
1063
|
+
import { hmac } from "@noble/hashes/hmac.js";
|
|
1064
|
+
import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
|
|
1065
|
+
import { etc, getPublicKey as nobleGetPublicKey, sign } from "@noble/secp256k1";
|
|
1066
|
+
|
|
1067
|
+
// src/utils/hash.ts
|
|
1068
|
+
import { ripemd160 } from "@noble/hashes/legacy.js";
|
|
1069
|
+
import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
|
|
1070
|
+
import { sha512_256 } from "@noble/hashes/sha2.js";
|
|
1071
|
+
function hash160(input) {
|
|
1072
|
+
return ripemd160(sha2562(input));
|
|
1073
|
+
}
|
|
1074
|
+
function txidFromBytes(data) {
|
|
1075
|
+
return bytesToHex(sha512_256(data));
|
|
1076
|
+
}
|
|
1077
|
+
function hashP2PKH(input) {
|
|
1078
|
+
return bytesToHex(hash160(input));
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// src/transactions/authorization.ts
|
|
1082
|
+
etc.hmacSha256Sync = (key, ...msgs) => {
|
|
1083
|
+
const h = hmac.create(sha2563, key);
|
|
1084
|
+
msgs.forEach((msg) => h.update(msg));
|
|
1085
|
+
return h.digest();
|
|
1086
|
+
};
|
|
1087
|
+
var EMPTY_SIG = bytesToHex(new Uint8Array(RECOVERABLE_ECDSA_SIG_LENGTH_BYTES));
|
|
1088
|
+
function createSingleSigSpendingCondition(publicKey, nonce, fee) {
|
|
1089
|
+
const pubKeyBytes = hexToBytes(publicKey);
|
|
1090
|
+
const signer = hashP2PKH(pubKeyBytes);
|
|
1091
|
+
const isCompressed = pubKeyBytes.length === 33;
|
|
1092
|
+
return {
|
|
1093
|
+
hashMode: AddressHashMode.P2PKH,
|
|
1094
|
+
signer,
|
|
1095
|
+
nonce,
|
|
1096
|
+
fee,
|
|
1097
|
+
keyEncoding: isCompressed ? PubKeyEncoding.Compressed : PubKeyEncoding.Uncompressed,
|
|
1098
|
+
signature: EMPTY_SIG
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
function createStandardAuth(spendingCondition) {
|
|
1102
|
+
return { authType: AuthType.Standard, spendingCondition };
|
|
1103
|
+
}
|
|
1104
|
+
function createSponsoredAuth(spendingCondition, sponsorSpendingCondition) {
|
|
1105
|
+
return {
|
|
1106
|
+
authType: AuthType.Sponsored,
|
|
1107
|
+
spendingCondition,
|
|
1108
|
+
sponsorSpendingCondition: sponsorSpendingCondition ?? createSingleSigSpendingCondition("0".repeat(66), 0n, 0n)
|
|
1109
|
+
};
|
|
1110
|
+
}
|
|
1111
|
+
function clearCondition(condition) {
|
|
1112
|
+
if ("signature" in condition) {
|
|
1113
|
+
return {
|
|
1114
|
+
...condition,
|
|
1115
|
+
nonce: 0n,
|
|
1116
|
+
fee: 0n,
|
|
1117
|
+
signature: EMPTY_SIG
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
return {
|
|
1121
|
+
...condition,
|
|
1122
|
+
nonce: 0n,
|
|
1123
|
+
fee: 0n,
|
|
1124
|
+
fields: []
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
function intoInitialSighashAuth(auth) {
|
|
1128
|
+
if (auth.authType === AuthType.Standard) {
|
|
1129
|
+
return createStandardAuth(clearCondition(auth.spendingCondition));
|
|
1130
|
+
}
|
|
1131
|
+
return createSponsoredAuth(clearCondition(auth.spendingCondition), clearCondition(createSingleSigSpendingCondition("0".repeat(66), 0n, 0n)));
|
|
1132
|
+
}
|
|
1133
|
+
function sigHashPreSign(curSigHash, authType, fee, nonce) {
|
|
1134
|
+
const data = concatBytes(hexToBytes(curSigHash), new Uint8Array([authType]), intToBytes(fee, 8), intToBytes(nonce, 8));
|
|
1135
|
+
return txidFromBytes(data);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
// src/transactions/multisig.ts
|
|
1139
|
+
import {
|
|
1140
|
+
getPublicKey as nobleGetPublicKey2,
|
|
1141
|
+
sign as nobleSign
|
|
1142
|
+
} from "@noble/secp256k1";
|
|
1143
|
+
var OP_CHECKMULTISIG = 174;
|
|
1144
|
+
function makeRedeemScript(publicKeys, signaturesRequired) {
|
|
1145
|
+
const parts = [];
|
|
1146
|
+
parts.push(new Uint8Array([80 + signaturesRequired]));
|
|
1147
|
+
for (const pk of publicKeys) {
|
|
1148
|
+
const pkBytes = hexToBytes(pk);
|
|
1149
|
+
parts.push(new Uint8Array([pkBytes.length]));
|
|
1150
|
+
parts.push(pkBytes);
|
|
1151
|
+
}
|
|
1152
|
+
parts.push(new Uint8Array([80 + publicKeys.length]));
|
|
1153
|
+
parts.push(new Uint8Array([OP_CHECKMULTISIG]));
|
|
1154
|
+
return concatBytes(...parts);
|
|
1155
|
+
}
|
|
1156
|
+
function createMultiSigSpendingCondition(publicKeys, signaturesRequired, nonce, fee, hashMode = AddressHashMode.P2SH) {
|
|
1157
|
+
const redeemScript = makeRedeemScript(publicKeys, signaturesRequired);
|
|
1158
|
+
const signer = bytesToHex(hash160(redeemScript));
|
|
1159
|
+
return {
|
|
1160
|
+
hashMode,
|
|
1161
|
+
signer,
|
|
1162
|
+
nonce,
|
|
1163
|
+
fee,
|
|
1164
|
+
fields: [],
|
|
1165
|
+
signaturesRequired
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// src/transactions/build.ts
|
|
1170
|
+
function resolvePcMode(mode) {
|
|
1171
|
+
return mode === "allow" ? PostConditionModeWire.Allow : PostConditionModeWire.Deny;
|
|
1172
|
+
}
|
|
1173
|
+
function convertPostConditions(pcs) {
|
|
1174
|
+
if (!pcs || pcs.length === 0)
|
|
1175
|
+
return [];
|
|
1176
|
+
return pcs.map(convertPostCondition);
|
|
1177
|
+
}
|
|
1178
|
+
function resolvePrincipal(address) {
|
|
1179
|
+
if (address === "origin")
|
|
1180
|
+
return { type: "origin" };
|
|
1181
|
+
const [addr, name] = address.split(".");
|
|
1182
|
+
if (name) {
|
|
1183
|
+
return { type: "contract", address: addr, contractName: name };
|
|
1184
|
+
}
|
|
1185
|
+
return { type: "standard", address: addr };
|
|
1186
|
+
}
|
|
1187
|
+
var FUNGIBLE_CODE_MAP = {
|
|
1188
|
+
eq: FungibleConditionCode.Equal,
|
|
1189
|
+
gt: FungibleConditionCode.Greater,
|
|
1190
|
+
gte: FungibleConditionCode.GreaterEqual,
|
|
1191
|
+
lt: FungibleConditionCode.Less,
|
|
1192
|
+
lte: FungibleConditionCode.LessEqual
|
|
1193
|
+
};
|
|
1194
|
+
function convertPostCondition(pc) {
|
|
1195
|
+
switch (pc.type) {
|
|
1196
|
+
case "stx-postcondition":
|
|
1197
|
+
return {
|
|
1198
|
+
type: "stx",
|
|
1199
|
+
principal: resolvePrincipal(pc.address),
|
|
1200
|
+
conditionCode: FUNGIBLE_CODE_MAP[pc.condition],
|
|
1201
|
+
amount: intToBigInt(pc.amount)
|
|
1202
|
+
};
|
|
1203
|
+
case "ft-postcondition": {
|
|
1204
|
+
const [contractId, tokenName] = pc.asset.split("::");
|
|
1205
|
+
const [addr, name] = parseContractId(contractId);
|
|
1206
|
+
return {
|
|
1207
|
+
type: "ft",
|
|
1208
|
+
principal: resolvePrincipal(pc.address),
|
|
1209
|
+
asset: { address: addr, contractName: name, assetName: tokenName },
|
|
1210
|
+
conditionCode: FUNGIBLE_CODE_MAP[pc.condition],
|
|
1211
|
+
amount: intToBigInt(pc.amount)
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
case "nft-postcondition": {
|
|
1215
|
+
const [contractId, tokenName] = pc.asset.split("::");
|
|
1216
|
+
const [addr, name] = parseContractId(contractId);
|
|
1217
|
+
return {
|
|
1218
|
+
type: "nft",
|
|
1219
|
+
principal: resolvePrincipal(pc.address),
|
|
1220
|
+
asset: { address: addr, contractName: name, assetName: tokenName },
|
|
1221
|
+
conditionCode: pc.condition === "sent" ? NonFungibleConditionCode.Sends : NonFungibleConditionCode.DoesNotSend,
|
|
1222
|
+
assetId: pc.assetId
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
function resolveSpendingCondition(opts, nonce, fee) {
|
|
1228
|
+
if (opts.publicKeys) {
|
|
1229
|
+
return createMultiSigSpendingCondition(opts.publicKeys, opts.signaturesRequired, nonce, fee, opts.hashMode);
|
|
1230
|
+
}
|
|
1231
|
+
return createSingleSigSpendingCondition(opts.publicKey, nonce, fee);
|
|
1232
|
+
}
|
|
1233
|
+
function resolveAuth(spendingCondition, sponsored) {
|
|
1234
|
+
return sponsored ? createSponsoredAuth(spendingCondition) : createStandardAuth(spendingCondition);
|
|
1235
|
+
}
|
|
1236
|
+
function resolveVersionAndChainId(chain) {
|
|
1237
|
+
if (!chain)
|
|
1238
|
+
return { version: 0, chainId: 1 };
|
|
1239
|
+
return { version: chain.transactionVersion, chainId: chain.id };
|
|
1240
|
+
}
|
|
1241
|
+
function buildContractCall(options) {
|
|
1242
|
+
const { version, chainId } = resolveVersionAndChainId(options.chain);
|
|
1243
|
+
const fee = intToBigInt(options.fee);
|
|
1244
|
+
const nonce = intToBigInt(options.nonce);
|
|
1245
|
+
const spendingCondition = resolveSpendingCondition(options, nonce, fee);
|
|
1246
|
+
const tx = {
|
|
1247
|
+
version,
|
|
1248
|
+
chainId,
|
|
1249
|
+
auth: resolveAuth(spendingCondition, options.sponsored),
|
|
1250
|
+
anchorMode: AnchorMode.Any,
|
|
1251
|
+
postConditionMode: resolvePcMode(options.postConditionMode),
|
|
1252
|
+
postConditions: convertPostConditions(options.postConditions),
|
|
1253
|
+
payload: {
|
|
1254
|
+
payloadType: PayloadType.ContractCall,
|
|
1255
|
+
contractAddress: options.contractAddress,
|
|
1256
|
+
contractName: options.contractName,
|
|
1257
|
+
functionName: options.functionName,
|
|
1258
|
+
functionArgs: options.functionArgs
|
|
1259
|
+
}
|
|
1260
|
+
};
|
|
1261
|
+
if (options.publicKeys) {
|
|
1262
|
+
tx._multisig = { publicKeys: options.publicKeys };
|
|
1263
|
+
}
|
|
1264
|
+
return tx;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// src/transactions/signer.ts
|
|
1268
|
+
function txid(tx) {
|
|
1269
|
+
return txidFromBytes(serializeTransaction(tx));
|
|
1270
|
+
}
|
|
1271
|
+
function signBegin(tx) {
|
|
1272
|
+
const cleared = {
|
|
1273
|
+
...tx,
|
|
1274
|
+
auth: intoInitialSighashAuth(tx.auth)
|
|
1275
|
+
};
|
|
1276
|
+
return txid(cleared);
|
|
1277
|
+
}
|
|
1278
|
+
async function signTransactionWithAccount(tx, account) {
|
|
1279
|
+
const sigHash = signBegin(tx);
|
|
1280
|
+
const condition = tx.auth.spendingCondition;
|
|
1281
|
+
const sigHashPre = sigHashPreSign(sigHash, AuthType.Standard, condition.fee, condition.nonce);
|
|
1282
|
+
const sigBytes = await account.sign(hexToBytes(sigHashPre));
|
|
1283
|
+
const nextSig = bytesToHex(sigBytes);
|
|
1284
|
+
return {
|
|
1285
|
+
...tx,
|
|
1286
|
+
auth: {
|
|
1287
|
+
...tx.auth,
|
|
1288
|
+
spendingCondition: {
|
|
1289
|
+
...condition,
|
|
1290
|
+
signature: nextSig
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
};
|
|
1294
|
+
}
|
|
1295
|
+
function getTransactionId(tx) {
|
|
1296
|
+
return txid(tx);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// src/actions/public/getNonce.ts
|
|
1300
|
+
async function getNonce(client, params) {
|
|
1301
|
+
const data = await client.request(`/v2/accounts/${params.address}`, {
|
|
1302
|
+
method: "GET"
|
|
1303
|
+
});
|
|
1304
|
+
return BigInt(data.nonce);
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
// src/errors/base.ts
|
|
1308
|
+
class BaseError extends Error {
|
|
1309
|
+
name = "StacksError";
|
|
1310
|
+
shortMessage;
|
|
1311
|
+
details;
|
|
1312
|
+
constructor(shortMessage, options) {
|
|
1313
|
+
const message = [
|
|
1314
|
+
shortMessage,
|
|
1315
|
+
options?.details ? `
|
|
1316
|
+
${options.details}` : ""
|
|
1317
|
+
].join("");
|
|
1318
|
+
super(message, { cause: options?.cause });
|
|
1319
|
+
this.shortMessage = shortMessage;
|
|
1320
|
+
this.details = options?.details;
|
|
1321
|
+
}
|
|
1322
|
+
toJSON() {
|
|
1323
|
+
return {
|
|
1324
|
+
name: this.name,
|
|
1325
|
+
message: this.message,
|
|
1326
|
+
shortMessage: this.shortMessage,
|
|
1327
|
+
details: this.details,
|
|
1328
|
+
cause: this.cause instanceof Error ? this.cause.message : undefined
|
|
1329
|
+
};
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// src/errors/transaction.ts
|
|
1334
|
+
class BroadcastError extends BaseError {
|
|
1335
|
+
name = "BroadcastError";
|
|
1336
|
+
txid;
|
|
1337
|
+
reason;
|
|
1338
|
+
constructor(message, options) {
|
|
1339
|
+
super(message, options);
|
|
1340
|
+
this.txid = options?.txid;
|
|
1341
|
+
this.reason = options?.reason;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// src/actions/wallet/sendTransaction.ts
|
|
1346
|
+
async function sendTransaction(client, params) {
|
|
1347
|
+
const hex = bytesToHex(serializeTransaction(params.transaction));
|
|
1348
|
+
const body = { tx: hex };
|
|
1349
|
+
if (params.attachment) {
|
|
1350
|
+
body.attachment = typeof params.attachment === "string" ? params.attachment : bytesToHex(params.attachment);
|
|
1351
|
+
}
|
|
1352
|
+
const data = await client.request("/v2/transactions", {
|
|
1353
|
+
method: "POST",
|
|
1354
|
+
body
|
|
1355
|
+
});
|
|
1356
|
+
if (data.error) {
|
|
1357
|
+
throw new BroadcastError(data.reason ?? data.error, {
|
|
1358
|
+
reason: data.reason
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
const txid2 = typeof data === "string" ? data.replace(/"/g, "") : data.txid ?? getTransactionId(params.transaction);
|
|
1362
|
+
return { txid: txid2 };
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
// src/actions/wallet/utils.ts
|
|
1366
|
+
function isProviderAccount(account) {
|
|
1367
|
+
return account.type === "provider";
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// src/actions/wallet/callContract.ts
|
|
1371
|
+
async function callContract(client, params) {
|
|
1372
|
+
const account = client.account;
|
|
1373
|
+
if (!account)
|
|
1374
|
+
throw new Error("Account required");
|
|
1375
|
+
if (isProviderAccount(account)) {
|
|
1376
|
+
const result2 = await account.provider.request("stx_callContract", {
|
|
1377
|
+
contract: params.contract,
|
|
1378
|
+
functionName: params.functionName,
|
|
1379
|
+
functionArgs: params.functionArgs ?? []
|
|
1380
|
+
});
|
|
1381
|
+
return result2.txid;
|
|
1382
|
+
}
|
|
1383
|
+
const [contractAddress, contractName] = parseContractId(params.contract);
|
|
1384
|
+
const nonce = params.nonce ?? await getNonce(client, { address: account.address });
|
|
1385
|
+
const unsigned = buildContractCall({
|
|
1386
|
+
contractAddress,
|
|
1387
|
+
contractName,
|
|
1388
|
+
functionName: params.functionName,
|
|
1389
|
+
functionArgs: params.functionArgs ?? [],
|
|
1390
|
+
fee: params.fee ?? 0n,
|
|
1391
|
+
nonce,
|
|
1392
|
+
publicKey: account.publicKey,
|
|
1393
|
+
chain: client.chain,
|
|
1394
|
+
postConditionMode: params.postConditionMode,
|
|
1395
|
+
postConditions: params.postConditions
|
|
1396
|
+
});
|
|
1397
|
+
if (params.fee === undefined) {
|
|
1398
|
+
const estimates = await estimateFee(client, { transaction: unsigned });
|
|
1399
|
+
const mid = estimates[1] ?? estimates[0];
|
|
1400
|
+
if (mid) {
|
|
1401
|
+
unsigned.auth.spendingCondition.fee = BigInt(mid.fee);
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
const signed = await signTransactionWithAccount(unsigned, account);
|
|
1405
|
+
const result = await sendTransaction(client, { transaction: signed });
|
|
1406
|
+
return result.txid;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
// src/actions/getContract.ts
|
|
1410
|
+
function getContract(params) {
|
|
1411
|
+
const { client, address, name: contractName, abi } = params;
|
|
1412
|
+
const contractId = `${address}.${contractName}`;
|
|
1413
|
+
const fnByName = new Map;
|
|
1414
|
+
for (const fn of abi.functions) {
|
|
1415
|
+
fnByName.set(fn.name, fn);
|
|
1416
|
+
}
|
|
1417
|
+
const mapByName = new Map;
|
|
1418
|
+
if (abi.maps) {
|
|
1419
|
+
for (const m of abi.maps) {
|
|
1420
|
+
mapByName.set(m.name, m);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
const camelToKebab = new Map;
|
|
1424
|
+
for (const fn of abi.functions) {
|
|
1425
|
+
camelToKebab.set(toCamelCase(fn.name), fn.name);
|
|
1426
|
+
}
|
|
1427
|
+
if (abi.maps) {
|
|
1428
|
+
for (const m of abi.maps) {
|
|
1429
|
+
camelToKebab.set(toCamelCase(m.name), m.name);
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
const read = new Proxy({}, {
|
|
1433
|
+
get(_target, prop) {
|
|
1434
|
+
const fnName = camelToKebab.get(prop) ?? prop;
|
|
1435
|
+
const fn = fnByName.get(fnName);
|
|
1436
|
+
if (!fn || fn.access !== "read-only")
|
|
1437
|
+
return;
|
|
1438
|
+
return async (args) => {
|
|
1439
|
+
const clarityArgs = buildFunctionArgs(fn, args);
|
|
1440
|
+
const result = await readContract(client, {
|
|
1441
|
+
contract: contractId,
|
|
1442
|
+
functionName: fn.name,
|
|
1443
|
+
args: clarityArgs
|
|
1444
|
+
});
|
|
1445
|
+
const jsValue = clarityValueToJSUntyped(fn.outputs, result);
|
|
1446
|
+
if (isResponseOutput(fn.outputs)) {
|
|
1447
|
+
const resp = jsValue;
|
|
1448
|
+
if ("ok" in resp)
|
|
1449
|
+
return resp.ok;
|
|
1450
|
+
throw new ContractResponseError(`${contractId}::${fn.name} returned (err ${formatErrValue(resp.err)})`, resp.err);
|
|
1451
|
+
}
|
|
1452
|
+
return jsValue;
|
|
1453
|
+
};
|
|
1454
|
+
}
|
|
1455
|
+
});
|
|
1456
|
+
const call = new Proxy({}, {
|
|
1457
|
+
get(_target, prop) {
|
|
1458
|
+
const fnName = camelToKebab.get(prop) ?? prop;
|
|
1459
|
+
const fn = fnByName.get(fnName);
|
|
1460
|
+
if (!fn || fn.access !== "public")
|
|
1461
|
+
return;
|
|
1462
|
+
return async (args, options) => {
|
|
1463
|
+
const clarityArgs = buildFunctionArgs(fn, args);
|
|
1464
|
+
return callContract(client, {
|
|
1465
|
+
contract: contractId,
|
|
1466
|
+
functionName: fn.name,
|
|
1467
|
+
functionArgs: clarityArgs,
|
|
1468
|
+
...options
|
|
1469
|
+
});
|
|
1470
|
+
};
|
|
1471
|
+
}
|
|
1472
|
+
});
|
|
1473
|
+
const maps = new Proxy({}, {
|
|
1474
|
+
get(_target, prop) {
|
|
1475
|
+
const mapName = camelToKebab.get(prop) ?? prop;
|
|
1476
|
+
const map = mapByName.get(mapName);
|
|
1477
|
+
if (!map)
|
|
1478
|
+
return;
|
|
1479
|
+
return async (key) => {
|
|
1480
|
+
const clarityKey = jsToClarityValue(map.key, key);
|
|
1481
|
+
const result = await getMapEntry(client, {
|
|
1482
|
+
contract: contractId,
|
|
1483
|
+
mapName: map.name,
|
|
1484
|
+
key: clarityKey
|
|
1485
|
+
});
|
|
1486
|
+
if (result.type === "none")
|
|
1487
|
+
return null;
|
|
1488
|
+
if (result.type === "some") {
|
|
1489
|
+
return clarityValueToJSUntyped(map.value, result.value);
|
|
1490
|
+
}
|
|
1491
|
+
return clarityValueToJSUntyped(map.value, result);
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
});
|
|
1495
|
+
return { read, call, maps };
|
|
1496
|
+
}
|
|
1497
|
+
function buildFunctionArgs(fn, args) {
|
|
1498
|
+
return fn.args.map((arg) => {
|
|
1499
|
+
const camelKey = toCamelCase(arg.name);
|
|
1500
|
+
const hasOriginal = arg.name in args;
|
|
1501
|
+
const hasCamel = camelKey in args;
|
|
1502
|
+
const value = hasOriginal ? args[arg.name] : hasCamel ? args[camelKey] : undefined;
|
|
1503
|
+
if (value === undefined)
|
|
1504
|
+
throw new Error(`Missing argument: ${arg.name}`);
|
|
1505
|
+
return jsToClarityValue(arg.type, value);
|
|
1506
|
+
});
|
|
1507
|
+
}
|
|
1508
|
+
function isResponseOutput(type) {
|
|
1509
|
+
return typeof type === "object" && type !== null && "response" in type;
|
|
1510
|
+
}
|
|
1511
|
+
function formatErrValue(value) {
|
|
1512
|
+
if (typeof value === "bigint")
|
|
1513
|
+
return value.toString();
|
|
1514
|
+
if (typeof value === "string")
|
|
1515
|
+
return `"${value}"`;
|
|
1516
|
+
return String(value);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
class ContractResponseError extends Error {
|
|
1520
|
+
errorValue;
|
|
1521
|
+
name = "ContractResponseError";
|
|
1522
|
+
constructor(message, errorValue) {
|
|
1523
|
+
super(message);
|
|
1524
|
+
this.errorValue = errorValue;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
// src/bns/abi.ts
|
|
1528
|
+
var BNS_ABI = {
|
|
1529
|
+
functions: [
|
|
1530
|
+
{
|
|
1531
|
+
name: "get-owner-name",
|
|
1532
|
+
access: "read-only",
|
|
1533
|
+
args: [
|
|
1534
|
+
{ name: "name", type: { buff: { length: 48 } } },
|
|
1535
|
+
{ name: "namespace", type: { buff: { length: 20 } } }
|
|
1536
|
+
],
|
|
1537
|
+
outputs: {
|
|
1538
|
+
response: {
|
|
1539
|
+
ok: { optional: "principal" },
|
|
1540
|
+
error: "uint128"
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
name: "get-id-from-bns",
|
|
1546
|
+
access: "read-only",
|
|
1547
|
+
args: [
|
|
1548
|
+
{ name: "name", type: { buff: { length: 48 } } },
|
|
1549
|
+
{ name: "namespace", type: { buff: { length: 20 } } }
|
|
1550
|
+
],
|
|
1551
|
+
outputs: { optional: "uint128" }
|
|
1552
|
+
},
|
|
1553
|
+
{
|
|
1554
|
+
name: "get-bns-from-id",
|
|
1555
|
+
access: "read-only",
|
|
1556
|
+
args: [{ name: "id", type: "uint128" }],
|
|
1557
|
+
outputs: {
|
|
1558
|
+
optional: {
|
|
1559
|
+
tuple: [
|
|
1560
|
+
{ name: "name", type: { buff: { length: 48 } } },
|
|
1561
|
+
{ name: "namespace", type: { buff: { length: 20 } } }
|
|
1562
|
+
]
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
name: "get-owner",
|
|
1568
|
+
access: "read-only",
|
|
1569
|
+
args: [{ name: "id", type: "uint128" }],
|
|
1570
|
+
outputs: {
|
|
1571
|
+
response: {
|
|
1572
|
+
ok: { optional: "principal" },
|
|
1573
|
+
error: "none"
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
},
|
|
1577
|
+
{
|
|
1578
|
+
name: "get-primary",
|
|
1579
|
+
access: "read-only",
|
|
1580
|
+
args: [{ name: "owner", type: "principal" }],
|
|
1581
|
+
outputs: {
|
|
1582
|
+
response: {
|
|
1583
|
+
ok: {
|
|
1584
|
+
optional: {
|
|
1585
|
+
tuple: [
|
|
1586
|
+
{ name: "name", type: { buff: { length: 48 } } },
|
|
1587
|
+
{ name: "namespace", type: { buff: { length: 20 } } }
|
|
1588
|
+
]
|
|
1589
|
+
}
|
|
1590
|
+
},
|
|
1591
|
+
error: "none"
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
},
|
|
1595
|
+
{
|
|
1596
|
+
name: "can-resolve-name",
|
|
1597
|
+
access: "read-only",
|
|
1598
|
+
args: [
|
|
1599
|
+
{ name: "namespace", type: { buff: { length: 20 } } },
|
|
1600
|
+
{ name: "name", type: { buff: { length: 48 } } }
|
|
1601
|
+
],
|
|
1602
|
+
outputs: {
|
|
1603
|
+
response: {
|
|
1604
|
+
ok: {
|
|
1605
|
+
tuple: [
|
|
1606
|
+
{ name: "renewal", type: "uint128" },
|
|
1607
|
+
{ name: "owner", type: "principal" }
|
|
1608
|
+
]
|
|
1609
|
+
},
|
|
1610
|
+
error: "uint128"
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
},
|
|
1614
|
+
{
|
|
1615
|
+
name: "get-renewal-height",
|
|
1616
|
+
access: "read-only",
|
|
1617
|
+
args: [{ name: "id", type: "uint128" }],
|
|
1618
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1619
|
+
},
|
|
1620
|
+
{
|
|
1621
|
+
name: "get-name-price",
|
|
1622
|
+
access: "read-only",
|
|
1623
|
+
args: [
|
|
1624
|
+
{ name: "namespace", type: { buff: { length: 20 } } },
|
|
1625
|
+
{ name: "name", type: { buff: { length: 48 } } }
|
|
1626
|
+
],
|
|
1627
|
+
outputs: {
|
|
1628
|
+
response: {
|
|
1629
|
+
ok: { response: { ok: "uint128", error: "uint128" } },
|
|
1630
|
+
error: "uint128"
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
},
|
|
1634
|
+
{
|
|
1635
|
+
name: "get-bns-info",
|
|
1636
|
+
access: "read-only",
|
|
1637
|
+
args: [
|
|
1638
|
+
{ name: "name", type: { buff: { length: 48 } } },
|
|
1639
|
+
{ name: "namespace", type: { buff: { length: 20 } } }
|
|
1640
|
+
],
|
|
1641
|
+
outputs: {
|
|
1642
|
+
optional: {
|
|
1643
|
+
tuple: [
|
|
1644
|
+
{
|
|
1645
|
+
name: "hashed-salted-fqn-preorder",
|
|
1646
|
+
type: { optional: { buff: { length: 20 } } }
|
|
1647
|
+
},
|
|
1648
|
+
{ name: "imported-at", type: { optional: "uint128" } },
|
|
1649
|
+
{ name: "owner", type: "principal" },
|
|
1650
|
+
{ name: "preordered-by", type: { optional: "principal" } },
|
|
1651
|
+
{ name: "registered-at", type: { optional: "uint128" } },
|
|
1652
|
+
{ name: "renewal-height", type: "uint128" },
|
|
1653
|
+
{ name: "stx-burn", type: "uint128" }
|
|
1654
|
+
]
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
},
|
|
1658
|
+
{
|
|
1659
|
+
name: "name-preorder",
|
|
1660
|
+
access: "public",
|
|
1661
|
+
args: [
|
|
1662
|
+
{ name: "hashed-salted-fqn", type: { buff: { length: 20 } } },
|
|
1663
|
+
{ name: "stx-to-burn", type: "uint128" }
|
|
1664
|
+
],
|
|
1665
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1666
|
+
},
|
|
1667
|
+
{
|
|
1668
|
+
name: "name-register",
|
|
1669
|
+
access: "public",
|
|
1670
|
+
args: [
|
|
1671
|
+
{ name: "namespace", type: { buff: { length: 20 } } },
|
|
1672
|
+
{ name: "name", type: { buff: { length: 48 } } },
|
|
1673
|
+
{ name: "salt", type: { buff: { length: 20 } } }
|
|
1674
|
+
],
|
|
1675
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1676
|
+
},
|
|
1677
|
+
{
|
|
1678
|
+
name: "name-claim-fast",
|
|
1679
|
+
access: "public",
|
|
1680
|
+
args: [
|
|
1681
|
+
{ name: "name", type: { buff: { length: 48 } } },
|
|
1682
|
+
{ name: "namespace", type: { buff: { length: 20 } } },
|
|
1683
|
+
{ name: "send-to", type: "principal" }
|
|
1684
|
+
],
|
|
1685
|
+
outputs: { response: { ok: "uint128", error: "uint128" } }
|
|
1686
|
+
},
|
|
1687
|
+
{
|
|
1688
|
+
name: "name-renewal",
|
|
1689
|
+
access: "public",
|
|
1690
|
+
args: [
|
|
1691
|
+
{ name: "namespace", type: { buff: { length: 20 } } },
|
|
1692
|
+
{ name: "name", type: { buff: { length: 48 } } }
|
|
1693
|
+
],
|
|
1694
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1695
|
+
},
|
|
1696
|
+
{
|
|
1697
|
+
name: "transfer",
|
|
1698
|
+
access: "public",
|
|
1699
|
+
args: [
|
|
1700
|
+
{ name: "id", type: "uint128" },
|
|
1701
|
+
{ name: "owner", type: "principal" },
|
|
1702
|
+
{ name: "recipient", type: "principal" }
|
|
1703
|
+
],
|
|
1704
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1705
|
+
},
|
|
1706
|
+
{
|
|
1707
|
+
name: "set-primary-name",
|
|
1708
|
+
access: "public",
|
|
1709
|
+
args: [{ name: "primary-name-id", type: "uint128" }],
|
|
1710
|
+
outputs: { response: { ok: "bool", error: "uint128" } }
|
|
1711
|
+
}
|
|
1712
|
+
],
|
|
1713
|
+
non_fungible_tokens: [{ name: "BNS-V2", type: "uint128" }]
|
|
1714
|
+
};
|
|
1715
|
+
|
|
1716
|
+
// src/bns/constants.ts
|
|
1717
|
+
var BNS_CONTRACTS = {
|
|
1718
|
+
mainnet: {
|
|
1719
|
+
address: "SP2QEZ06AGJ3RKJPBV14SY1V5BBFNAW33D96YPGZF",
|
|
1720
|
+
name: "BNS-V2"
|
|
1721
|
+
},
|
|
1722
|
+
testnet: {
|
|
1723
|
+
address: "ST2QEZ06AGJ3RKJPBV14SY1V5BBFNAW33D9SZJQ0M",
|
|
1724
|
+
name: "BNS-V2"
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1727
|
+
var DEFAULT_NAMESPACE = "btc";
|
|
1728
|
+
|
|
1729
|
+
// src/bns/utils.ts
|
|
1730
|
+
function parseFQN(fqn) {
|
|
1731
|
+
const parts = fqn.split(".");
|
|
1732
|
+
if (parts.length === 1) {
|
|
1733
|
+
return {
|
|
1734
|
+
name: parts[0],
|
|
1735
|
+
namespace: DEFAULT_NAMESPACE
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
if (parts.length === 2) {
|
|
1739
|
+
return {
|
|
1740
|
+
name: parts[0],
|
|
1741
|
+
namespace: parts[1]
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
throw new Error(`Invalid fully qualified name: ${fqn}. Expected format: "name.namespace" or "name"`);
|
|
1745
|
+
}
|
|
1746
|
+
function formatFQN(name, namespace) {
|
|
1747
|
+
return `${name}.${namespace}`;
|
|
1748
|
+
}
|
|
1749
|
+
function validateName(name) {
|
|
1750
|
+
if (name.length < 1 || name.length > 48)
|
|
1751
|
+
return false;
|
|
1752
|
+
const regex = /^[a-z0-9]([a-z0-9_-]*[a-z0-9])?$/;
|
|
1753
|
+
return regex.test(name);
|
|
1754
|
+
}
|
|
1755
|
+
function validateNamespace(namespace) {
|
|
1756
|
+
if (namespace.length < 1 || namespace.length > 20)
|
|
1757
|
+
return false;
|
|
1758
|
+
const regex = /^[a-z0-9]+$/;
|
|
1759
|
+
return regex.test(namespace);
|
|
1760
|
+
}
|
|
1761
|
+
function validateFQN(fqn) {
|
|
1762
|
+
try {
|
|
1763
|
+
const { name, namespace } = parseFQN(fqn);
|
|
1764
|
+
return validateName(name) && validateNamespace(namespace);
|
|
1765
|
+
} catch {
|
|
1766
|
+
return false;
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
// src/bns/actions.ts
|
|
1771
|
+
function getBnsContract(client) {
|
|
1772
|
+
if (!client.chain) {
|
|
1773
|
+
throw new Error("Client must have a chain configured");
|
|
1774
|
+
}
|
|
1775
|
+
const network = client.chain.network;
|
|
1776
|
+
const contract = network === "mainnet" ? BNS_CONTRACTS.mainnet : BNS_CONTRACTS.testnet;
|
|
1777
|
+
return getContract({
|
|
1778
|
+
client,
|
|
1779
|
+
address: contract.address,
|
|
1780
|
+
name: contract.name,
|
|
1781
|
+
abi: BNS_ABI
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
function stringToBytes(str) {
|
|
1785
|
+
return new TextEncoder().encode(str);
|
|
1786
|
+
}
|
|
1787
|
+
async function resolveName(client, nameOrFQN) {
|
|
1788
|
+
if (!validateFQN(nameOrFQN)) {
|
|
1789
|
+
throw new Error(`Invalid name format: ${nameOrFQN}`);
|
|
1790
|
+
}
|
|
1791
|
+
const { name, namespace } = parseFQN(nameOrFQN);
|
|
1792
|
+
const bns = getBnsContract(client);
|
|
1793
|
+
try {
|
|
1794
|
+
return await bns.read.getOwnerName({
|
|
1795
|
+
name: stringToBytes(name),
|
|
1796
|
+
namespace: stringToBytes(namespace)
|
|
1797
|
+
});
|
|
1798
|
+
} catch (e) {
|
|
1799
|
+
if (e instanceof ContractResponseError)
|
|
1800
|
+
return null;
|
|
1801
|
+
throw e;
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
async function getPrimaryName(client, address) {
|
|
1805
|
+
const bns = getBnsContract(client);
|
|
1806
|
+
try {
|
|
1807
|
+
const result = await bns.read.getPrimary({
|
|
1808
|
+
owner: address
|
|
1809
|
+
});
|
|
1810
|
+
if (result === null)
|
|
1811
|
+
return null;
|
|
1812
|
+
const name = new TextDecoder().decode(result.name);
|
|
1813
|
+
const namespace = new TextDecoder().decode(result.namespace);
|
|
1814
|
+
return formatFQN(name, namespace);
|
|
1815
|
+
} catch (e) {
|
|
1816
|
+
if (e instanceof ContractResponseError)
|
|
1817
|
+
return null;
|
|
1818
|
+
throw e;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
// src/chains/definitions.ts
|
|
1823
|
+
var mainnet = {
|
|
1824
|
+
id: 1,
|
|
1825
|
+
name: "Stacks Mainnet",
|
|
1826
|
+
network: "mainnet",
|
|
1827
|
+
transactionVersion: 0,
|
|
1828
|
+
peerNetworkId: 385875968,
|
|
1829
|
+
addressVersion: { singleSig: 22, multiSig: 20 },
|
|
1830
|
+
magicBytes: "X2",
|
|
1831
|
+
bootAddress: "SP000000000000000000002Q6VF78",
|
|
1832
|
+
nativeCurrency: { name: "Stacks", symbol: "STX", decimals: 6 },
|
|
1833
|
+
rpcUrls: {
|
|
1834
|
+
default: {
|
|
1835
|
+
http: ["https://api.mainnet.hiro.so"],
|
|
1836
|
+
ws: ["wss://api.mainnet.hiro.so/extended/v1/ws"]
|
|
1837
|
+
}
|
|
1838
|
+
},
|
|
1839
|
+
blockExplorers: {
|
|
1840
|
+
default: { name: "Hiro Explorer", url: "https://explorer.hiro.so" }
|
|
1841
|
+
}
|
|
1842
|
+
};
|
|
1843
|
+
var testnet = {
|
|
1844
|
+
id: 2147483648,
|
|
1845
|
+
name: "Stacks Testnet",
|
|
1846
|
+
network: "testnet",
|
|
1847
|
+
transactionVersion: 128,
|
|
1848
|
+
peerNetworkId: 4278190080,
|
|
1849
|
+
addressVersion: { singleSig: 26, multiSig: 21 },
|
|
1850
|
+
magicBytes: "T2",
|
|
1851
|
+
bootAddress: "ST000000000000000000002AMW42H",
|
|
1852
|
+
nativeCurrency: { name: "Stacks", symbol: "STX", decimals: 6 },
|
|
1853
|
+
rpcUrls: {
|
|
1854
|
+
default: {
|
|
1855
|
+
http: ["https://api.testnet.hiro.so"],
|
|
1856
|
+
ws: ["wss://api.testnet.hiro.so/extended/v1/ws"]
|
|
1857
|
+
}
|
|
1858
|
+
},
|
|
1859
|
+
blockExplorers: {
|
|
1860
|
+
default: {
|
|
1861
|
+
name: "Hiro Explorer",
|
|
1862
|
+
url: "https://explorer.hiro.so/?chain=testnet"
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
};
|
|
1866
|
+
var devnet = {
|
|
1867
|
+
id: 2147483648,
|
|
1868
|
+
name: "Stacks Devnet",
|
|
1869
|
+
network: "testnet",
|
|
1870
|
+
transactionVersion: 128,
|
|
1871
|
+
peerNetworkId: 4278190080,
|
|
1872
|
+
addressVersion: { singleSig: 26, multiSig: 21 },
|
|
1873
|
+
magicBytes: "id",
|
|
1874
|
+
bootAddress: "ST000000000000000000002AMW42H",
|
|
1875
|
+
nativeCurrency: { name: "Stacks", symbol: "STX", decimals: 6 },
|
|
1876
|
+
rpcUrls: {
|
|
1877
|
+
default: {
|
|
1878
|
+
http: ["http://localhost:3999"],
|
|
1879
|
+
ws: ["ws://localhost:3999/extended/v1/ws"]
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
};
|
|
1883
|
+
var mocknet = {
|
|
1884
|
+
...devnet,
|
|
1885
|
+
name: "Stacks Mocknet",
|
|
1886
|
+
addressVersion: { ...devnet.addressVersion }
|
|
1887
|
+
};
|
|
1888
|
+
|
|
1889
|
+
// src/clients/createClient.ts
|
|
1890
|
+
var BASE_KEYS = new Set([
|
|
1891
|
+
"chain",
|
|
1892
|
+
"account",
|
|
1893
|
+
"transport",
|
|
1894
|
+
"request",
|
|
1895
|
+
"extend"
|
|
1896
|
+
]);
|
|
1897
|
+
function bindExtend(base) {
|
|
1898
|
+
return (fn) => {
|
|
1899
|
+
const extensions = fn(base);
|
|
1900
|
+
const next = { ...base };
|
|
1901
|
+
for (const [key, value] of Object.entries(extensions)) {
|
|
1902
|
+
if (BASE_KEYS.has(key))
|
|
1903
|
+
continue;
|
|
1904
|
+
next[key] = value;
|
|
1905
|
+
}
|
|
1906
|
+
next.extend = bindExtend(next);
|
|
1907
|
+
return next;
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
function createClient(config) {
|
|
1911
|
+
const transport = config.transport({ chain: config.chain });
|
|
1912
|
+
const client = {
|
|
1913
|
+
chain: config.chain,
|
|
1914
|
+
account: config.account,
|
|
1915
|
+
transport,
|
|
1916
|
+
request: transport.request,
|
|
1917
|
+
extend: null
|
|
1918
|
+
};
|
|
1919
|
+
client.extend = bindExtend(client);
|
|
1920
|
+
return client;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
// src/actions/public/getContractAbi.ts
|
|
1924
|
+
async function getContractAbi(client, params) {
|
|
1925
|
+
const [address, name] = parseContractId(params.contract);
|
|
1926
|
+
return client.request(`/v2/contracts/interface/${address}/${name}`, {
|
|
1927
|
+
method: "GET"
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
// src/actions/public/multicall.ts
|
|
1932
|
+
async function multicall(client, params) {
|
|
1933
|
+
const { calls, allowFailure = true } = params;
|
|
1934
|
+
if (allowFailure) {
|
|
1935
|
+
const settled = await Promise.allSettled(calls.map((call) => readContract(client, call)));
|
|
1936
|
+
return settled.map((r) => r.status === "fulfilled" ? { status: "success", result: r.value } : {
|
|
1937
|
+
status: "failure",
|
|
1938
|
+
error: r.reason instanceof Error ? r.reason : new Error(String(r.reason))
|
|
1939
|
+
});
|
|
1940
|
+
}
|
|
1941
|
+
const results = await Promise.all(calls.map((call) => readContract(client, call)));
|
|
1942
|
+
return results;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
// src/errors/simulation.ts
|
|
1946
|
+
class SimulationError extends BaseError {
|
|
1947
|
+
name = "SimulationError";
|
|
1948
|
+
writesDetected;
|
|
1949
|
+
constructor(message, options) {
|
|
1950
|
+
super(message, { details: options.details });
|
|
1951
|
+
this.writesDetected = options.writesDetected;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
// src/actions/public/simulateCall.ts
|
|
1956
|
+
async function simulateCall(client, params) {
|
|
1957
|
+
const [address, name] = parseContractId(params.contract);
|
|
1958
|
+
const sender = params.sender ?? address;
|
|
1959
|
+
const serializedArgs = (params.args ?? []).map((arg) => with0x(bytesToHex(serializeCVBytes(arg))));
|
|
1960
|
+
let path = `/v2/contracts/call-read/${address}/${name}/${params.functionName}`;
|
|
1961
|
+
if (params.tip) {
|
|
1962
|
+
path += `?tip=${params.tip}`;
|
|
1963
|
+
}
|
|
1964
|
+
const data = await client.request(path, {
|
|
1965
|
+
method: "POST",
|
|
1966
|
+
body: {
|
|
1967
|
+
sender,
|
|
1968
|
+
arguments: serializedArgs
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1971
|
+
if (data.okay) {
|
|
1972
|
+
return { success: true, result: deserializeCVBytes(data.result) };
|
|
1973
|
+
}
|
|
1974
|
+
const cause = data.cause ?? "Simulation failed";
|
|
1975
|
+
const writesDetected = cause.includes("NotReadOnly") || cause.includes("CostBalanceExceeded");
|
|
1976
|
+
return {
|
|
1977
|
+
success: false,
|
|
1978
|
+
error: new SimulationError(writesDetected ? "Function mutates state and cannot be simulated" : "Simulation failed", { writesDetected, details: cause })
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
// src/actions/public/simulateTransaction.ts
|
|
1983
|
+
function isMultiSig(hashMode) {
|
|
1984
|
+
return hashMode === AddressHashMode.P2SH || hashMode === AddressHashMode.P2WSH || hashMode === AddressHashMode.P2SH_NonSequential || hashMode === AddressHashMode.P2WSH_P2SH_NonSequential;
|
|
1985
|
+
}
|
|
1986
|
+
function extractSender(tx, client) {
|
|
1987
|
+
const { hashMode, signer } = tx.auth.spendingCondition;
|
|
1988
|
+
const chain = client.chain;
|
|
1989
|
+
const version = isMultiSig(hashMode) ? chain?.addressVersion.multiSig ?? 20 : chain?.addressVersion.singleSig ?? 22;
|
|
1990
|
+
return c32address(version, signer);
|
|
1991
|
+
}
|
|
1992
|
+
async function simulateTransaction(client, params) {
|
|
1993
|
+
const { transaction, tip } = params;
|
|
1994
|
+
const { payload } = transaction;
|
|
1995
|
+
if (payload.payloadType === PayloadType.ContractCall) {
|
|
1996
|
+
const sender = params.sender ?? extractSender(transaction, client);
|
|
1997
|
+
const contract = `${payload.contractAddress}.${payload.contractName}`;
|
|
1998
|
+
const [execution, fees2] = await Promise.all([
|
|
1999
|
+
simulateCall(client, {
|
|
2000
|
+
contract,
|
|
2001
|
+
functionName: payload.functionName,
|
|
2002
|
+
args: payload.functionArgs,
|
|
2003
|
+
sender,
|
|
2004
|
+
tip
|
|
2005
|
+
}),
|
|
2006
|
+
estimateFee(client, { transaction })
|
|
2007
|
+
]);
|
|
2008
|
+
return { type: "contract-call", execution, fees: fees2 };
|
|
2009
|
+
}
|
|
2010
|
+
const fees = await estimateFee(client, { transaction });
|
|
2011
|
+
if (payload.payloadType === PayloadType.SmartContract || payload.payloadType === PayloadType.VersionedSmartContract) {
|
|
2012
|
+
return { type: "contract-deploy", fees };
|
|
2013
|
+
}
|
|
2014
|
+
return { type: "token-transfer", fees };
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
// src/errors/websocket.ts
|
|
2018
|
+
class WebSocketError extends BaseError {
|
|
2019
|
+
name = "WebSocketError";
|
|
2020
|
+
constructor(message, options) {
|
|
2021
|
+
super(message, options);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
|
|
2025
|
+
// src/subscriptions/actions.ts
|
|
2026
|
+
function getWsTransport(client) {
|
|
2027
|
+
if (client.transport.type !== "webSocket") {
|
|
2028
|
+
throw new WebSocketError("Watch actions require a webSocket transport. Use `webSocket()` when creating your client.");
|
|
2029
|
+
}
|
|
2030
|
+
return client.transport;
|
|
2031
|
+
}
|
|
2032
|
+
async function watchBlocks(client, params) {
|
|
2033
|
+
const transport = getWsTransport(client);
|
|
2034
|
+
return transport.subscribe({ event: "block" }, params.onBlock);
|
|
2035
|
+
}
|
|
2036
|
+
async function watchMempool(client, params) {
|
|
2037
|
+
const transport = getWsTransport(client);
|
|
2038
|
+
return transport.subscribe({ event: "mempool" }, params.onTransaction);
|
|
2039
|
+
}
|
|
2040
|
+
async function watchTransaction(client, params) {
|
|
2041
|
+
const transport = getWsTransport(client);
|
|
2042
|
+
return transport.subscribe({ event: "tx_update", tx_id: params.txId }, params.onUpdate);
|
|
2043
|
+
}
|
|
2044
|
+
async function watchAddress(client, params) {
|
|
2045
|
+
const transport = getWsTransport(client);
|
|
2046
|
+
return transport.subscribe({ event: "address_tx_update", address: params.address }, params.onTransaction);
|
|
2047
|
+
}
|
|
2048
|
+
async function watchAddressBalance(client, params) {
|
|
2049
|
+
const transport = getWsTransport(client);
|
|
2050
|
+
return transport.subscribe({ event: "address_balance_update", address: params.address }, params.onBalance);
|
|
2051
|
+
}
|
|
2052
|
+
async function watchNftEvent(client, params) {
|
|
2053
|
+
const transport = getWsTransport(client);
|
|
2054
|
+
let event;
|
|
2055
|
+
if (params.assetIdentifier && params.value) {
|
|
2056
|
+
event = "nft_event";
|
|
2057
|
+
} else if (params.assetIdentifier) {
|
|
2058
|
+
event = "nft_collection_event";
|
|
2059
|
+
} else {
|
|
2060
|
+
event = "nft_event";
|
|
2061
|
+
}
|
|
2062
|
+
return transport.subscribe({
|
|
2063
|
+
event,
|
|
2064
|
+
asset_identifier: params.assetIdentifier,
|
|
2065
|
+
value: params.value
|
|
2066
|
+
}, params.onEvent);
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
// src/clients/decorators/public.ts
|
|
2070
|
+
function publicActions(client) {
|
|
2071
|
+
return {
|
|
2072
|
+
getNonce: (params) => getNonce(client, params),
|
|
2073
|
+
getBalance: (params) => getBalance(client, params),
|
|
2074
|
+
getAccountInfo: (params) => getAccountInfo(client, params),
|
|
2075
|
+
getBlock: (params) => getBlock(client, params),
|
|
2076
|
+
getBlockHeight: () => getBlockHeight(client),
|
|
2077
|
+
readContract: (params) => readContract(client, params),
|
|
2078
|
+
getContractAbi: (params) => getContractAbi(client, params),
|
|
2079
|
+
getMapEntry: (params) => getMapEntry(client, params),
|
|
2080
|
+
estimateFee: (params) => estimateFee(client, params),
|
|
2081
|
+
multicall: (params) => multicall(client, params),
|
|
2082
|
+
simulateCall: (params) => simulateCall(client, params),
|
|
2083
|
+
simulateTransaction: (params) => simulateTransaction(client, params),
|
|
2084
|
+
watchBlocks: (params) => watchBlocks(client, params),
|
|
2085
|
+
watchMempool: (params) => watchMempool(client, params),
|
|
2086
|
+
watchTransaction: (params) => watchTransaction(client, params),
|
|
2087
|
+
watchAddress: (params) => watchAddress(client, params),
|
|
2088
|
+
watchAddressBalance: (params) => watchAddressBalance(client, params),
|
|
2089
|
+
watchNftEvent: (params) => watchNftEvent(client, params)
|
|
2090
|
+
};
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
// src/clients/createPublicClient.ts
|
|
2094
|
+
function createPublicClient(config) {
|
|
2095
|
+
return createClient(config).extend(publicActions);
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
// src/transports/createTransport.ts
|
|
2099
|
+
function createTransport(type, config) {
|
|
2100
|
+
return {
|
|
2101
|
+
type,
|
|
2102
|
+
request: config.request,
|
|
2103
|
+
config
|
|
2104
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
async function fetchWithRetry(url, options, retryCount, retryDelay, timeout) {
|
|
2107
|
+
let lastError;
|
|
2108
|
+
for (let attempt = 0;attempt <= retryCount; attempt++) {
|
|
2109
|
+
try {
|
|
2110
|
+
const controller = new AbortController;
|
|
2111
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
2112
|
+
const response = await fetch(url, {
|
|
2113
|
+
...options,
|
|
2114
|
+
signal: controller.signal
|
|
2115
|
+
});
|
|
2116
|
+
clearTimeout(timeoutId);
|
|
2117
|
+
if (response.ok || response.status < 500) {
|
|
2118
|
+
return response;
|
|
2119
|
+
}
|
|
2120
|
+
lastError = new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
2121
|
+
} catch (error) {
|
|
2122
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
2123
|
+
}
|
|
2124
|
+
if (attempt < retryCount) {
|
|
2125
|
+
await new Promise((r) => setTimeout(r, retryDelay * (attempt + 1)));
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
throw lastError ?? new Error("Request failed");
|
|
2129
|
+
}
|
|
2130
|
+
function buildRequestFn(baseUrl, config) {
|
|
2131
|
+
const {
|
|
2132
|
+
timeout = 30000,
|
|
2133
|
+
retryCount = 3,
|
|
2134
|
+
retryDelay = 150,
|
|
2135
|
+
fetchOptions = {},
|
|
2136
|
+
apiKey
|
|
2137
|
+
} = config;
|
|
2138
|
+
return async (path, options) => {
|
|
2139
|
+
const url = `${baseUrl.replace(/\/$/, "")}${path}`;
|
|
2140
|
+
const headers = {
|
|
2141
|
+
"Content-Type": "application/json",
|
|
2142
|
+
...fetchOptions.headers,
|
|
2143
|
+
...options?.headers
|
|
2144
|
+
};
|
|
2145
|
+
if (apiKey) {
|
|
2146
|
+
headers["x-api-key"] = apiKey;
|
|
2147
|
+
}
|
|
2148
|
+
const init = {
|
|
2149
|
+
...fetchOptions,
|
|
2150
|
+
method: options?.method ?? "GET",
|
|
2151
|
+
headers
|
|
2152
|
+
};
|
|
2153
|
+
if (options?.body !== undefined) {
|
|
2154
|
+
init.body = JSON.stringify(options.body);
|
|
2155
|
+
}
|
|
2156
|
+
const response = await fetchWithRetry(url, init, retryCount, retryDelay, timeout);
|
|
2157
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
2158
|
+
if (contentType.includes("application/json")) {
|
|
2159
|
+
return response.json();
|
|
2160
|
+
}
|
|
2161
|
+
return response.text();
|
|
2162
|
+
};
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
// src/transports/http.ts
|
|
2166
|
+
function http(url, config) {
|
|
2167
|
+
return (params) => {
|
|
2168
|
+
const resolvedUrl = url ?? params?.chain?.rpcUrls.default.http[0] ?? "http://localhost:3999";
|
|
2169
|
+
const mergedConfig = {
|
|
2170
|
+
...config,
|
|
2171
|
+
url: resolvedUrl
|
|
2172
|
+
};
|
|
2173
|
+
return createTransport("http", {
|
|
2174
|
+
...mergedConfig,
|
|
2175
|
+
request: buildRequestFn(resolvedUrl, mergedConfig)
|
|
2176
|
+
});
|
|
2177
|
+
};
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
// src/tools/client.ts
|
|
2181
|
+
var _defaultClient = null;
|
|
2182
|
+
function getDefaultPublicClient() {
|
|
2183
|
+
if (_defaultClient)
|
|
2184
|
+
return _defaultClient;
|
|
2185
|
+
const chain = process.env.STACKS_CHAIN === "testnet" ? testnet : mainnet;
|
|
2186
|
+
_defaultClient = createPublicClient({
|
|
2187
|
+
chain,
|
|
2188
|
+
transport: http(process.env.STACKS_RPC_URL)
|
|
2189
|
+
});
|
|
2190
|
+
return _defaultClient;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
// src/tools/index.ts
|
|
2194
|
+
var PRINCIPAL = z.string().describe("Stacks principal (SP…/SM… mainnet, ST… testnet)");
|
|
2195
|
+
async function stxBalance(client, principal) {
|
|
2196
|
+
const balance = await getBalance(client, { address: principal });
|
|
2197
|
+
return { microStx: balance.toString() };
|
|
2198
|
+
}
|
|
2199
|
+
async function accountInfo(client, principal) {
|
|
2200
|
+
const info = await getAccountInfo(client, { address: principal });
|
|
2201
|
+
return {
|
|
2202
|
+
balance: info.balance.toString(),
|
|
2203
|
+
nonce: info.nonce.toString()
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
async function block(client, args) {
|
|
2207
|
+
return getBlock(client, args);
|
|
2208
|
+
}
|
|
2209
|
+
async function blockHeight(client) {
|
|
2210
|
+
return { height: await getBlockHeight(client) };
|
|
2211
|
+
}
|
|
2212
|
+
async function contractRead(client, args) {
|
|
2213
|
+
const result = await readContract(client, args);
|
|
2214
|
+
return { result: JSON.stringify(result) };
|
|
2215
|
+
}
|
|
2216
|
+
async function fee(client, serializedTxHex) {
|
|
2217
|
+
const raw = serializedTxHex.startsWith("0x") ? serializedTxHex.slice(2) : serializedTxHex;
|
|
2218
|
+
const txBytes = new Uint8Array(Buffer.from(raw, "hex"));
|
|
2219
|
+
const { deserializeTransaction } = await import("@stacks/transactions");
|
|
2220
|
+
const transaction = deserializeTransaction(txBytes);
|
|
2221
|
+
const fees = await estimateFee(client, {
|
|
2222
|
+
transaction
|
|
2223
|
+
});
|
|
2224
|
+
return {
|
|
2225
|
+
low: fees[0]?.fee ?? 0,
|
|
2226
|
+
medium: fees[1]?.fee ?? 0,
|
|
2227
|
+
high: fees[2]?.fee ?? 0
|
|
2228
|
+
};
|
|
2229
|
+
}
|
|
2230
|
+
async function bnsResolveImpl(client, name) {
|
|
2231
|
+
return { owner: await resolveName(client, name) };
|
|
2232
|
+
}
|
|
2233
|
+
async function bnsReverseImpl(client, principal) {
|
|
2234
|
+
return { name: await getPrimaryName(client, principal) };
|
|
2235
|
+
}
|
|
2236
|
+
function hiroBase(client) {
|
|
2237
|
+
const url = client.chain?.rpcUrls.default.http[0] ?? process.env.STACKS_RPC_URL ?? "https://api.hiro.so";
|
|
2238
|
+
return url.replace(/\/$/, "");
|
|
2239
|
+
}
|
|
2240
|
+
async function hiroGet(client, path) {
|
|
2241
|
+
const res = await fetch(`${hiroBase(client)}${path}`, {
|
|
2242
|
+
headers: { Accept: "application/json" }
|
|
2243
|
+
});
|
|
2244
|
+
if (!res.ok) {
|
|
2245
|
+
throw new Error(`Hiro API ${path} → ${res.status} ${res.statusText}`);
|
|
2246
|
+
}
|
|
2247
|
+
return res.json();
|
|
2248
|
+
}
|
|
2249
|
+
async function transactionByTxId(client, txId) {
|
|
2250
|
+
const normalized = txId.startsWith("0x") ? txId : `0x${txId}`;
|
|
2251
|
+
return hiroGet(client, `/extended/v1/tx/${normalized}`);
|
|
2252
|
+
}
|
|
2253
|
+
async function accountHistory(client, principal, limit) {
|
|
2254
|
+
return hiroGet(client, `/extended/v2/addresses/${principal}/transactions?limit=${Math.min(limit, 50)}`);
|
|
2255
|
+
}
|
|
2256
|
+
async function mempoolStats(client) {
|
|
2257
|
+
return hiroGet(client, "/extended/v1/tx/mempool/stats");
|
|
2258
|
+
}
|
|
2259
|
+
async function nftHoldings(client, principal, limit) {
|
|
2260
|
+
return hiroGet(client, `/extended/v1/tokens/nft/holdings?principal=${encodeURIComponent(principal)}&limit=${Math.min(limit, 50)}`);
|
|
2261
|
+
}
|
|
2262
|
+
function createStacksTools(client) {
|
|
2263
|
+
return {
|
|
2264
|
+
getStxBalance: tool({
|
|
2265
|
+
description: "Get the STX balance (in micro-STX) for a Stacks principal.",
|
|
2266
|
+
inputSchema: z.object({ principal: PRINCIPAL }),
|
|
2267
|
+
execute: ({ principal }) => stxBalance(client, principal)
|
|
2268
|
+
}),
|
|
2269
|
+
getAccountInfo: tool({
|
|
2270
|
+
description: "Get account info (balance, locked, nonce) for a Stacks principal.",
|
|
2271
|
+
inputSchema: z.object({ principal: PRINCIPAL }),
|
|
2272
|
+
execute: ({ principal }) => accountInfo(client, principal)
|
|
2273
|
+
}),
|
|
2274
|
+
getBlock: tool({
|
|
2275
|
+
description: "Fetch a Stacks block by height or hash. Omit both for the latest block.",
|
|
2276
|
+
inputSchema: z.object({
|
|
2277
|
+
height: z.number().int().nonnegative().optional(),
|
|
2278
|
+
hash: z.string().optional()
|
|
2279
|
+
}),
|
|
2280
|
+
execute: (args) => block(client, args)
|
|
2281
|
+
}),
|
|
2282
|
+
getBlockHeight: tool({
|
|
2283
|
+
description: "Get the current Stacks chain tip height.",
|
|
2284
|
+
inputSchema: z.object({}),
|
|
2285
|
+
execute: () => blockHeight(client)
|
|
2286
|
+
}),
|
|
2287
|
+
readContract: tool({
|
|
2288
|
+
description: "Call a read-only Clarity function. Returns the decoded value as JSON.",
|
|
2289
|
+
inputSchema: z.object({
|
|
2290
|
+
contract: z.string().describe("Fully-qualified contract id: '{address}.{name}'"),
|
|
2291
|
+
functionName: z.string(),
|
|
2292
|
+
sender: PRINCIPAL.optional()
|
|
2293
|
+
}),
|
|
2294
|
+
execute: (args) => contractRead(client, args)
|
|
2295
|
+
}),
|
|
2296
|
+
estimateFee: tool({
|
|
2297
|
+
description: "Estimate fee range (low / medium / high) for a serialized Stacks transaction.",
|
|
2298
|
+
inputSchema: z.object({
|
|
2299
|
+
serializedTxHex: z.string().describe("Hex-encoded serialized transaction")
|
|
2300
|
+
}),
|
|
2301
|
+
execute: ({ serializedTxHex }) => fee(client, serializedTxHex)
|
|
2302
|
+
}),
|
|
2303
|
+
bnsResolve: tool({
|
|
2304
|
+
description: "Resolve a BNS name (e.g. 'satoshi.btc') to its owning Stacks principal.",
|
|
2305
|
+
inputSchema: z.object({
|
|
2306
|
+
name: z.string().describe("BNS name in 'name.namespace' form")
|
|
2307
|
+
}),
|
|
2308
|
+
execute: ({ name }) => bnsResolveImpl(client, name)
|
|
2309
|
+
}),
|
|
2310
|
+
bnsReverse: tool({
|
|
2311
|
+
description: "Reverse-lookup the primary BNS name for a Stacks principal, if set.",
|
|
2312
|
+
inputSchema: z.object({ principal: PRINCIPAL }),
|
|
2313
|
+
execute: ({ principal }) => bnsReverseImpl(client, principal)
|
|
2314
|
+
}),
|
|
2315
|
+
getTransaction: tool({
|
|
2316
|
+
description: "Fetch a confirmed Stacks transaction by txId (Hiro extended API).",
|
|
2317
|
+
inputSchema: z.object({
|
|
2318
|
+
txId: z.string().describe("Transaction id, with or without 0x prefix")
|
|
2319
|
+
}),
|
|
2320
|
+
execute: ({ txId }) => transactionByTxId(client, txId)
|
|
2321
|
+
}),
|
|
2322
|
+
getAccountHistory: tool({
|
|
2323
|
+
description: "Paginated transaction history for a Stacks principal (Hiro extended API).",
|
|
2324
|
+
inputSchema: z.object({
|
|
2325
|
+
principal: PRINCIPAL,
|
|
2326
|
+
limit: z.number().int().min(1).max(50).default(20)
|
|
2327
|
+
}),
|
|
2328
|
+
execute: ({ principal, limit }) => accountHistory(client, principal, limit)
|
|
2329
|
+
}),
|
|
2330
|
+
getMempoolStats: tool({
|
|
2331
|
+
description: "Current mempool statistics: pending count, fee distribution, age buckets (Hiro extended API).",
|
|
2332
|
+
inputSchema: z.object({}),
|
|
2333
|
+
execute: () => mempoolStats(client)
|
|
2334
|
+
}),
|
|
2335
|
+
getNftHoldings: tool({
|
|
2336
|
+
description: "NFT holdings for a Stacks principal across all collections (Hiro extended API).",
|
|
2337
|
+
inputSchema: z.object({
|
|
2338
|
+
principal: PRINCIPAL,
|
|
2339
|
+
limit: z.number().int().min(1).max(50).default(20)
|
|
2340
|
+
}),
|
|
2341
|
+
execute: ({ principal, limit }) => nftHoldings(client, principal, limit)
|
|
2342
|
+
})
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2345
|
+
var getStxBalance = tool({
|
|
2346
|
+
description: "Get the STX balance (in micro-STX) for a Stacks principal. Uses default client.",
|
|
2347
|
+
inputSchema: z.object({ principal: PRINCIPAL }),
|
|
2348
|
+
execute: ({ principal }) => stxBalance(getDefaultPublicClient(), principal)
|
|
2349
|
+
});
|
|
2350
|
+
var getAccountInfo2 = tool({
|
|
2351
|
+
description: "Get account info (balance, locked, nonce) for a Stacks principal.",
|
|
2352
|
+
inputSchema: z.object({ principal: PRINCIPAL }),
|
|
2353
|
+
execute: ({ principal }) => accountInfo(getDefaultPublicClient(), principal)
|
|
2354
|
+
});
|
|
2355
|
+
var getBlock2 = tool({
|
|
2356
|
+
description: "Fetch a Stacks block by height or hash. Omit both for the latest block.",
|
|
2357
|
+
inputSchema: z.object({
|
|
2358
|
+
height: z.number().int().nonnegative().optional(),
|
|
2359
|
+
hash: z.string().optional()
|
|
2360
|
+
}),
|
|
2361
|
+
execute: (args) => block(getDefaultPublicClient(), args)
|
|
2362
|
+
});
|
|
2363
|
+
var getBlockHeight2 = tool({
|
|
2364
|
+
description: "Get the current Stacks chain tip height.",
|
|
2365
|
+
inputSchema: z.object({}),
|
|
2366
|
+
execute: () => blockHeight(getDefaultPublicClient())
|
|
2367
|
+
});
|
|
2368
|
+
var readContract2 = tool({
|
|
2369
|
+
description: "Call a read-only Clarity function. Returns the decoded value as JSON.",
|
|
2370
|
+
inputSchema: z.object({
|
|
2371
|
+
contract: z.string(),
|
|
2372
|
+
functionName: z.string(),
|
|
2373
|
+
sender: PRINCIPAL.optional()
|
|
2374
|
+
}),
|
|
2375
|
+
execute: (args) => contractRead(getDefaultPublicClient(), args)
|
|
2376
|
+
});
|
|
2377
|
+
var estimateFee2 = tool({
|
|
2378
|
+
description: "Estimate fee range (low / medium / high) for a serialized Stacks transaction.",
|
|
2379
|
+
inputSchema: z.object({ serializedTxHex: z.string() }),
|
|
2380
|
+
execute: ({ serializedTxHex }) => fee(getDefaultPublicClient(), serializedTxHex)
|
|
2381
|
+
});
|
|
2382
|
+
var bnsResolve = tool({
|
|
2383
|
+
description: "Resolve a BNS name (e.g. 'satoshi.btc') to its owning Stacks principal.",
|
|
2384
|
+
inputSchema: z.object({ name: z.string() }),
|
|
2385
|
+
execute: ({ name }) => bnsResolveImpl(getDefaultPublicClient(), name)
|
|
2386
|
+
});
|
|
2387
|
+
var bnsReverse = tool({
|
|
2388
|
+
description: "Reverse-lookup the primary BNS name for a Stacks principal, if set.",
|
|
2389
|
+
inputSchema: z.object({ principal: PRINCIPAL }),
|
|
2390
|
+
execute: ({ principal }) => bnsReverseImpl(getDefaultPublicClient(), principal)
|
|
2391
|
+
});
|
|
2392
|
+
var getTransaction = tool({
|
|
2393
|
+
description: "Fetch a confirmed Stacks transaction by txId (Hiro extended API).",
|
|
2394
|
+
inputSchema: z.object({ txId: z.string() }),
|
|
2395
|
+
execute: ({ txId }) => transactionByTxId(getDefaultPublicClient(), txId)
|
|
2396
|
+
});
|
|
2397
|
+
var getAccountHistory = tool({
|
|
2398
|
+
description: "Paginated transaction history for a Stacks principal (Hiro extended API).",
|
|
2399
|
+
inputSchema: z.object({
|
|
2400
|
+
principal: PRINCIPAL,
|
|
2401
|
+
limit: z.number().int().min(1).max(50).default(20)
|
|
2402
|
+
}),
|
|
2403
|
+
execute: ({ principal, limit }) => accountHistory(getDefaultPublicClient(), principal, limit)
|
|
2404
|
+
});
|
|
2405
|
+
var getMempoolStats = tool({
|
|
2406
|
+
description: "Current mempool statistics: pending count, fee distribution, age buckets (Hiro extended API).",
|
|
2407
|
+
inputSchema: z.object({}),
|
|
2408
|
+
execute: () => mempoolStats(getDefaultPublicClient())
|
|
2409
|
+
});
|
|
2410
|
+
var getNftHoldings = tool({
|
|
2411
|
+
description: "NFT holdings for a Stacks principal across all collections (Hiro extended API).",
|
|
2412
|
+
inputSchema: z.object({
|
|
2413
|
+
principal: PRINCIPAL,
|
|
2414
|
+
limit: z.number().int().min(1).max(50).default(20)
|
|
2415
|
+
}),
|
|
2416
|
+
execute: ({ principal, limit }) => nftHoldings(getDefaultPublicClient(), principal, limit)
|
|
2417
|
+
});
|
|
2418
|
+
export {
|
|
2419
|
+
readContract2 as readContract,
|
|
2420
|
+
getTransaction,
|
|
2421
|
+
getStxBalance,
|
|
2422
|
+
getNftHoldings,
|
|
2423
|
+
getMempoolStats,
|
|
2424
|
+
getBlockHeight2 as getBlockHeight,
|
|
2425
|
+
getBlock2 as getBlock,
|
|
2426
|
+
getAccountInfo2 as getAccountInfo,
|
|
2427
|
+
getAccountHistory,
|
|
2428
|
+
estimateFee2 as estimateFee,
|
|
2429
|
+
createStacksTools,
|
|
2430
|
+
bnsReverse,
|
|
2431
|
+
bnsResolve
|
|
2432
|
+
};
|
|
2433
|
+
|
|
2434
|
+
//# debugId=233963F854D70C5B64756E2164756E21
|
|
2435
|
+
//# sourceMappingURL=index.js.map
|