stxer 0.4.5 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +322 -16
- package/dist/ast.d.ts +32 -0
- package/dist/clarity-api.d.ts +1 -1
- package/dist/constants.d.ts +9 -0
- package/dist/index.d.ts +6 -1
- package/dist/simulation-api.d.ts +138 -0
- package/dist/simulation.d.ts +12 -4
- package/dist/stxer.cjs.development.js +693 -285
- package/dist/stxer.cjs.development.js.map +1 -1
- package/dist/stxer.cjs.production.min.js +1 -1
- package/dist/stxer.cjs.production.min.js.map +1 -1
- package/dist/stxer.esm.js +685 -286
- package/dist/stxer.esm.js.map +1 -1
- package/dist/tip.d.ts +16 -0
- package/dist/types.d.ts +327 -0
- package/package.json +11 -9
- package/src/ast.ts +120 -0
- package/src/{BatchProcessor.ts → batch-processor.ts} +1 -1
- package/src/clarity-api.ts +1 -1
- package/src/constants.ts +12 -0
- package/src/index.ts +15 -1
- package/src/simulation-api.ts +273 -0
- package/src/simulation.ts +169 -138
- package/src/tip.ts +42 -0
- package/src/types.ts +392 -0
- package/dist/sample/counter.d.ts +0 -1
- package/dist/sample/read.d.ts +0 -1
- package/src/sample/counter.ts +0 -42
- package/src/sample/read.ts +0 -139
- /package/dist/{BatchAPI.d.ts → batch-api.d.ts} +0 -0
- /package/dist/{BatchProcessor.d.ts → batch-processor.d.ts} +0 -0
- /package/src/{BatchAPI.ts → batch-api.ts} +0 -0
package/src/simulation.ts
CHANGED
|
@@ -7,24 +7,23 @@ import {
|
|
|
7
7
|
import type { Block } from '@stacks/stacks-blockchain-api-types';
|
|
8
8
|
import {
|
|
9
9
|
AddressHashMode,
|
|
10
|
-
bufferCV,
|
|
11
10
|
type ClarityValue,
|
|
12
11
|
ClarityVersion,
|
|
13
|
-
contractPrincipalCV,
|
|
14
|
-
deserializeTransaction,
|
|
15
12
|
type MultiSigSpendingCondition,
|
|
16
13
|
makeUnsignedContractCall,
|
|
17
14
|
makeUnsignedContractDeploy,
|
|
18
15
|
makeUnsignedSTXTokenTransfer,
|
|
19
16
|
PostConditionMode,
|
|
20
17
|
type StacksTransactionWire,
|
|
21
|
-
serializeCVBytes,
|
|
22
|
-
stringAsciiCV,
|
|
23
|
-
tupleCV,
|
|
24
|
-
uintCV,
|
|
25
18
|
} from '@stacks/transactions';
|
|
26
19
|
import { c32addressDecode } from 'c32check';
|
|
27
20
|
import { type AccountDataResponse, getNodeInfo, richFetch } from 'ts-clarity';
|
|
21
|
+
import { STXER_API_MAINNET, STXER_API_TESTNET } from './constants';
|
|
22
|
+
import {
|
|
23
|
+
createSimulationSession,
|
|
24
|
+
submitSimulationSteps,
|
|
25
|
+
} from './simulation-api';
|
|
26
|
+
import type { ReadStep, SimulationStepInput } from './types';
|
|
28
27
|
|
|
29
28
|
function setSender(tx: StacksTransactionWire, sender: string) {
|
|
30
29
|
const [addressVersion, signer] = c32addressDecode(sender);
|
|
@@ -51,107 +50,23 @@ function setSender(tx: StacksTransactionWire, sender: string) {
|
|
|
51
50
|
return tx;
|
|
52
51
|
}
|
|
53
52
|
|
|
54
|
-
function runTx(tx: StacksTransactionWire) {
|
|
55
|
-
// type 0: run transaction
|
|
56
|
-
return tupleCV({ type: uintCV(0), data: bufferCV(tx.serializeBytes()) });
|
|
57
|
-
}
|
|
58
|
-
|
|
59
53
|
export interface SimulationEval {
|
|
60
54
|
contract_id: string;
|
|
61
55
|
code: string;
|
|
62
56
|
}
|
|
63
57
|
|
|
64
|
-
export function runEval({ contract_id, code }: SimulationEval) {
|
|
65
|
-
const [contract_address, contract_name] = contract_id.split('.');
|
|
66
|
-
// type 1: eval arbitrary code inside a contract
|
|
67
|
-
return tupleCV({
|
|
68
|
-
type: uintCV(1),
|
|
69
|
-
data: bufferCV(
|
|
70
|
-
serializeCVBytes(
|
|
71
|
-
tupleCV({
|
|
72
|
-
contract: contractPrincipalCV(contract_address, contract_name),
|
|
73
|
-
code: stringAsciiCV(code),
|
|
74
|
-
}),
|
|
75
|
-
),
|
|
76
|
-
),
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export async function runSimulation(
|
|
81
|
-
apiEndpoint: string,
|
|
82
|
-
block_hash: string,
|
|
83
|
-
block_height: number,
|
|
84
|
-
txs: (StacksTransactionWire | SimulationEval)[],
|
|
85
|
-
) {
|
|
86
|
-
// Convert 'sim-v1' to Uint8Array
|
|
87
|
-
const header = new TextEncoder().encode('sim-v1');
|
|
88
|
-
// Create 8 bytes for block height
|
|
89
|
-
const heightBytes = new Uint8Array(8);
|
|
90
|
-
// Convert block height to bytes
|
|
91
|
-
const view = new DataView(heightBytes.buffer);
|
|
92
|
-
view.setBigUint64(0, BigInt(block_height), false); // false for big-endian
|
|
93
|
-
|
|
94
|
-
// Convert block hash to bytes
|
|
95
|
-
const hashHex = block_hash.startsWith('0x')
|
|
96
|
-
? block_hash.substring(2)
|
|
97
|
-
: block_hash;
|
|
98
|
-
// Replace non-null assertion with null check
|
|
99
|
-
const matches = hashHex.match(/.{1,2}/g);
|
|
100
|
-
if (!matches) {
|
|
101
|
-
throw new Error('Invalid block hash format');
|
|
102
|
-
}
|
|
103
|
-
const hashBytes = new Uint8Array(
|
|
104
|
-
matches.map((byte) => Number.parseInt(byte, 16)),
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
// Convert transactions to bytes
|
|
108
|
-
const txBytes = txs
|
|
109
|
-
.map((t) => ('contract_id' in t && 'code' in t ? runEval(t) : runTx(t)))
|
|
110
|
-
.map((t) => serializeCVBytes(t));
|
|
111
|
-
|
|
112
|
-
// Combine all byte arrays
|
|
113
|
-
const totalLength =
|
|
114
|
-
header.length +
|
|
115
|
-
heightBytes.length +
|
|
116
|
-
hashBytes.length +
|
|
117
|
-
txBytes.reduce((acc, curr) => acc + curr.length, 0);
|
|
118
|
-
const body = new Uint8Array(totalLength);
|
|
119
|
-
|
|
120
|
-
let offset = 0;
|
|
121
|
-
body.set(header, offset);
|
|
122
|
-
offset += header.length;
|
|
123
|
-
body.set(heightBytes, offset);
|
|
124
|
-
offset += heightBytes.length;
|
|
125
|
-
body.set(hashBytes, offset);
|
|
126
|
-
offset += hashBytes.length;
|
|
127
|
-
for (const tx of txBytes) {
|
|
128
|
-
body.set(tx, offset);
|
|
129
|
-
offset += tx.length;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const rs = await fetch(apiEndpoint, {
|
|
133
|
-
method: 'POST',
|
|
134
|
-
body,
|
|
135
|
-
}).then(async (rs) => {
|
|
136
|
-
const response = await rs.text();
|
|
137
|
-
if (!response.startsWith('{')) {
|
|
138
|
-
throw new Error(`failed to submit simulation: ${response}`);
|
|
139
|
-
}
|
|
140
|
-
return JSON.parse(response) as { id: string };
|
|
141
|
-
});
|
|
142
|
-
return rs.id;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
58
|
interface SimulationBuilderOptions {
|
|
146
59
|
apiEndpoint?: string;
|
|
147
60
|
stacksNodeAPI?: string;
|
|
148
61
|
network?: StacksNetworkName | string;
|
|
62
|
+
skipTracing?: boolean;
|
|
149
63
|
}
|
|
150
64
|
|
|
151
65
|
export class SimulationBuilder {
|
|
152
66
|
private apiEndpoint: string;
|
|
153
67
|
private stacksNodeAPI: string;
|
|
154
68
|
private network: StacksNetworkName | string;
|
|
69
|
+
private skipTracing: boolean;
|
|
155
70
|
|
|
156
71
|
private constructor(options: SimulationBuilderOptions = {}) {
|
|
157
72
|
this.network = options.network ?? 'mainnet';
|
|
@@ -159,10 +74,11 @@ export class SimulationBuilder {
|
|
|
159
74
|
|
|
160
75
|
this.apiEndpoint =
|
|
161
76
|
options.apiEndpoint ??
|
|
162
|
-
(isTestnet ?
|
|
77
|
+
(isTestnet ? STXER_API_TESTNET : STXER_API_MAINNET);
|
|
163
78
|
this.stacksNodeAPI =
|
|
164
79
|
options.stacksNodeAPI ??
|
|
165
80
|
(isTestnet ? 'https://api.testnet.hiro.so' : 'https://api.hiro.so');
|
|
81
|
+
this.skipTracing = options.skipTracing ?? false;
|
|
166
82
|
}
|
|
167
83
|
|
|
168
84
|
public static new(options?: SimulationBuilderOptions) {
|
|
@@ -174,7 +90,7 @@ export class SimulationBuilder {
|
|
|
174
90
|
private sender = '';
|
|
175
91
|
private steps: (
|
|
176
92
|
| {
|
|
177
|
-
// inline simulation
|
|
93
|
+
// inline simulation (V1 - not supported in V2, but kept for potential future support)
|
|
178
94
|
simulationId: string;
|
|
179
95
|
}
|
|
180
96
|
| {
|
|
@@ -201,22 +117,41 @@ export class SimulationBuilder {
|
|
|
201
117
|
fee: number;
|
|
202
118
|
}
|
|
203
119
|
| SimulationEval
|
|
120
|
+
| {
|
|
121
|
+
// SetContractCode - V2 native step type
|
|
122
|
+
type: 'SetContractCode';
|
|
123
|
+
contract_id: string;
|
|
124
|
+
source_code: string;
|
|
125
|
+
clarity_version: ClarityVersion;
|
|
126
|
+
}
|
|
127
|
+
| {
|
|
128
|
+
// Reads - V2 native batch reads step type
|
|
129
|
+
type: 'Reads';
|
|
130
|
+
reads: ReadStep[];
|
|
131
|
+
}
|
|
132
|
+
| {
|
|
133
|
+
// TenureExtend - V2 native step type
|
|
134
|
+
type: 'TenureExtend';
|
|
135
|
+
}
|
|
204
136
|
)[] = [];
|
|
205
137
|
|
|
206
138
|
public useBlockHeight(block: number) {
|
|
207
139
|
this.block = block;
|
|
208
140
|
return this;
|
|
209
141
|
}
|
|
142
|
+
|
|
210
143
|
public withSender(address: string) {
|
|
211
144
|
this.sender = address;
|
|
212
145
|
return this;
|
|
213
146
|
}
|
|
147
|
+
|
|
214
148
|
public inlineSimulation(simulationId: string) {
|
|
215
149
|
this.steps.push({
|
|
216
150
|
simulationId,
|
|
217
151
|
});
|
|
218
152
|
return this;
|
|
219
153
|
}
|
|
154
|
+
|
|
220
155
|
public addSTXTransfer(params: {
|
|
221
156
|
recipient: string;
|
|
222
157
|
amount: number;
|
|
@@ -235,6 +170,7 @@ export class SimulationBuilder {
|
|
|
235
170
|
});
|
|
236
171
|
return this;
|
|
237
172
|
}
|
|
173
|
+
|
|
238
174
|
public addContractCall(params: {
|
|
239
175
|
contract_id: string;
|
|
240
176
|
function_name: string;
|
|
@@ -254,6 +190,7 @@ export class SimulationBuilder {
|
|
|
254
190
|
});
|
|
255
191
|
return this;
|
|
256
192
|
}
|
|
193
|
+
|
|
257
194
|
public addContractDeploy(params: {
|
|
258
195
|
contract_name: string;
|
|
259
196
|
source_code: string;
|
|
@@ -274,6 +211,7 @@ export class SimulationBuilder {
|
|
|
274
211
|
});
|
|
275
212
|
return this;
|
|
276
213
|
}
|
|
214
|
+
|
|
277
215
|
public addEvalCode(inside_contract_id: string, code: string) {
|
|
278
216
|
this.steps.push({
|
|
279
217
|
contract_id: inside_contract_id,
|
|
@@ -281,6 +219,7 @@ export class SimulationBuilder {
|
|
|
281
219
|
});
|
|
282
220
|
return this;
|
|
283
221
|
}
|
|
222
|
+
|
|
284
223
|
public addMapRead(contract_id: string, map: string, key: string) {
|
|
285
224
|
this.steps.push({
|
|
286
225
|
contract_id,
|
|
@@ -288,6 +227,7 @@ export class SimulationBuilder {
|
|
|
288
227
|
});
|
|
289
228
|
return this;
|
|
290
229
|
}
|
|
230
|
+
|
|
291
231
|
public addVarRead(contract_id: string, variable: string) {
|
|
292
232
|
this.steps.push({
|
|
293
233
|
contract_id,
|
|
@@ -296,6 +236,35 @@ export class SimulationBuilder {
|
|
|
296
236
|
return this;
|
|
297
237
|
}
|
|
298
238
|
|
|
239
|
+
public addSetContractCode(params: {
|
|
240
|
+
contract_id: string;
|
|
241
|
+
source_code: string;
|
|
242
|
+
clarity_version?: ClarityVersion;
|
|
243
|
+
}) {
|
|
244
|
+
this.steps.push({
|
|
245
|
+
type: 'SetContractCode',
|
|
246
|
+
contract_id: params.contract_id,
|
|
247
|
+
source_code: params.source_code,
|
|
248
|
+
clarity_version: params.clarity_version ?? ClarityVersion.Clarity4,
|
|
249
|
+
});
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
public addReads(reads: ReadStep[]) {
|
|
254
|
+
this.steps.push({
|
|
255
|
+
type: 'Reads',
|
|
256
|
+
reads,
|
|
257
|
+
});
|
|
258
|
+
return this;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
public addTenureExtend() {
|
|
262
|
+
this.steps.push({
|
|
263
|
+
type: 'TenureExtend',
|
|
264
|
+
});
|
|
265
|
+
return this;
|
|
266
|
+
}
|
|
267
|
+
|
|
299
268
|
private async getBlockInfo() {
|
|
300
269
|
if (Number.isNaN(this.block)) {
|
|
301
270
|
const { stacks_tip_height } = await getNodeInfo({
|
|
@@ -322,7 +291,7 @@ export class SimulationBuilder {
|
|
|
322
291
|
};
|
|
323
292
|
}
|
|
324
293
|
|
|
325
|
-
public async run() {
|
|
294
|
+
public async run(): Promise<string> {
|
|
326
295
|
console.log(
|
|
327
296
|
`--------------------------------
|
|
328
297
|
This product can never exist without your support!
|
|
@@ -338,7 +307,8 @@ To get in touch: contact@stxer.xyz
|
|
|
338
307
|
console.log(
|
|
339
308
|
`Using block height ${block.block_height} hash 0x${block.block_hash} to run simulation.`,
|
|
340
309
|
);
|
|
341
|
-
|
|
310
|
+
|
|
311
|
+
const v2Steps: SimulationStepInput[] = [];
|
|
342
312
|
const nonce_by_address = new Map<string, number>();
|
|
343
313
|
const nextNonce = async (sender: string) => {
|
|
344
314
|
const nonce = nonce_by_address.get(sender);
|
|
@@ -355,6 +325,7 @@ To get in touch: contact@stxer.xyz
|
|
|
355
325
|
nonce_by_address.set(sender, nonce + 1);
|
|
356
326
|
return nonce;
|
|
357
327
|
};
|
|
328
|
+
|
|
358
329
|
let network = this.network === 'mainnet' ? STACKS_MAINNET : STACKS_TESTNET;
|
|
359
330
|
if (this.stacksNodeAPI) {
|
|
360
331
|
network = {
|
|
@@ -365,39 +336,21 @@ To get in touch: contact@stxer.xyz
|
|
|
365
336
|
},
|
|
366
337
|
};
|
|
367
338
|
}
|
|
339
|
+
|
|
368
340
|
for (const step of this.steps) {
|
|
369
341
|
if ('simulationId' in step) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
`failed to get simulation ${step.simulationId}: ${body}`,
|
|
379
|
-
);
|
|
380
|
-
}
|
|
381
|
-
return JSON.parse(body) as {
|
|
382
|
-
steps: ({ tx: string } | { code: string; contract: string })[];
|
|
383
|
-
};
|
|
384
|
-
});
|
|
385
|
-
for (const step of previousSimulation.steps) {
|
|
386
|
-
if ('tx' in step) {
|
|
387
|
-
txs.push(deserializeTransaction(step.tx));
|
|
388
|
-
} else if ('code' in step && 'contract' in step) {
|
|
389
|
-
txs.push({
|
|
390
|
-
contract_id: step.contract,
|
|
391
|
-
code: step.code,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
} else if ('sender' in step && 'function_name' in step) {
|
|
342
|
+
// Inline simulation - for V2 we would need to fetch the previous simulation
|
|
343
|
+
// and convert its steps to V2 format. This is complex and may not be
|
|
344
|
+
// commonly used, so for now we'll throw an error.
|
|
345
|
+
throw new Error(
|
|
346
|
+
'inlineSimulation is not yet supported in V2 API. Please run simulations from scratch.',
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
if ('sender' in step && 'function_name' in step) {
|
|
396
350
|
const nonce = await nextNonce(step.sender);
|
|
397
|
-
const [contractAddress, contractName] = step.contract_id.split('.');
|
|
398
351
|
const tx = await makeUnsignedContractCall({
|
|
399
|
-
contractAddress,
|
|
400
|
-
contractName,
|
|
352
|
+
contractAddress: step.contract_id.split('.')[0] as string,
|
|
353
|
+
contractName: step.contract_id.split('.')[1] as string,
|
|
401
354
|
functionName: step.function_name,
|
|
402
355
|
functionArgs: step.function_args ?? [],
|
|
403
356
|
nonce,
|
|
@@ -407,7 +360,7 @@ To get in touch: contact@stxer.xyz
|
|
|
407
360
|
fee: step.fee,
|
|
408
361
|
});
|
|
409
362
|
setSender(tx, step.sender);
|
|
410
|
-
|
|
363
|
+
v2Steps.push({ Transaction: bytesToHex(tx.serializeBytes()) });
|
|
411
364
|
} else if ('sender' in step && 'recipient' in step) {
|
|
412
365
|
const nonce = await nextNonce(step.sender);
|
|
413
366
|
const tx = await makeUnsignedSTXTokenTransfer({
|
|
@@ -419,7 +372,7 @@ To get in touch: contact@stxer.xyz
|
|
|
419
372
|
fee: step.fee,
|
|
420
373
|
});
|
|
421
374
|
setSender(tx, step.sender);
|
|
422
|
-
|
|
375
|
+
v2Steps.push({ Transaction: bytesToHex(tx.serializeBytes()) });
|
|
423
376
|
} else if ('deployer' in step) {
|
|
424
377
|
const nonce = await nextNonce(step.deployer);
|
|
425
378
|
const tx = await makeUnsignedContractDeploy({
|
|
@@ -430,26 +383,67 @@ To get in touch: contact@stxer.xyz
|
|
|
430
383
|
publicKey: '',
|
|
431
384
|
postConditionMode: PostConditionMode.Allow,
|
|
432
385
|
fee: step.fee,
|
|
433
|
-
clarityVersion: step.clarity_version
|
|
386
|
+
clarityVersion: step.clarity_version,
|
|
434
387
|
});
|
|
435
388
|
setSender(tx, step.deployer);
|
|
436
|
-
|
|
389
|
+
v2Steps.push({ Transaction: bytesToHex(tx.serializeBytes()) });
|
|
437
390
|
} else if ('code' in step) {
|
|
438
|
-
|
|
391
|
+
// Eval step - format: [sender, sponsor, contract_id, code]
|
|
392
|
+
// For eval without a sender, we use empty string for sponsor
|
|
393
|
+
const [contractAddress, contractName] = step.contract_id.split('.');
|
|
394
|
+
v2Steps.push({
|
|
395
|
+
Eval: [
|
|
396
|
+
this.sender || contractAddress,
|
|
397
|
+
'',
|
|
398
|
+
`${contractAddress}.${contractName}`,
|
|
399
|
+
step.code,
|
|
400
|
+
],
|
|
401
|
+
});
|
|
402
|
+
} else if (step.type === 'SetContractCode') {
|
|
403
|
+
// SetContractCode - format: [contract_id, code, clarity_version]
|
|
404
|
+
v2Steps.push({
|
|
405
|
+
SetContractCode: [
|
|
406
|
+
step.contract_id,
|
|
407
|
+
step.source_code,
|
|
408
|
+
clarityVersionToNumber(step.clarity_version),
|
|
409
|
+
],
|
|
410
|
+
});
|
|
411
|
+
} else if (step.type === 'Reads') {
|
|
412
|
+
// Reads - batch read operations
|
|
413
|
+
v2Steps.push({
|
|
414
|
+
Reads: step.reads,
|
|
415
|
+
});
|
|
416
|
+
} else if (step.type === 'TenureExtend') {
|
|
417
|
+
// TenureExtend - format: []
|
|
418
|
+
v2Steps.push({
|
|
419
|
+
TenureExtend: [],
|
|
420
|
+
});
|
|
439
421
|
} else {
|
|
440
422
|
console.log(`Invalid simulation step: ${step}`);
|
|
441
423
|
}
|
|
442
424
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
425
|
+
|
|
426
|
+
// Create V2 simulation session
|
|
427
|
+
const simulationId = await createSimulationSession(
|
|
428
|
+
{
|
|
429
|
+
block_height: block.block_height,
|
|
430
|
+
block_hash: block.block_hash,
|
|
431
|
+
skip_tracing: this.skipTracing,
|
|
432
|
+
},
|
|
433
|
+
{ stxerApi: this.apiEndpoint },
|
|
448
434
|
);
|
|
435
|
+
|
|
436
|
+
// Submit steps
|
|
437
|
+
await submitSimulationSteps(
|
|
438
|
+
simulationId,
|
|
439
|
+
{ steps: v2Steps },
|
|
440
|
+
{ stxerApi: this.apiEndpoint },
|
|
441
|
+
);
|
|
442
|
+
|
|
449
443
|
console.log(
|
|
450
|
-
`Simulation will be available at: https://stxer.xyz/simulations/${this.network}/${
|
|
444
|
+
`Simulation will be available at: https://stxer.xyz/simulations/${this.network}/${simulationId}`,
|
|
451
445
|
);
|
|
452
|
-
return
|
|
446
|
+
return simulationId;
|
|
453
447
|
}
|
|
454
448
|
|
|
455
449
|
public pipe(
|
|
@@ -458,3 +452,40 @@ To get in touch: contact@stxer.xyz
|
|
|
458
452
|
return transform(this);
|
|
459
453
|
}
|
|
460
454
|
}
|
|
455
|
+
|
|
456
|
+
// Helper function to convert Uint8Array to hex string
|
|
457
|
+
function bytesToHex(bytes: Uint8Array): string {
|
|
458
|
+
return Array.from(bytes)
|
|
459
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
460
|
+
.join('');
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Helper function to convert ClarityVersion to number
|
|
464
|
+
function clarityVersionToNumber(version: ClarityVersion): number {
|
|
465
|
+
switch (version) {
|
|
466
|
+
case ClarityVersion.Clarity1:
|
|
467
|
+
return 1;
|
|
468
|
+
case ClarityVersion.Clarity2:
|
|
469
|
+
return 2;
|
|
470
|
+
case ClarityVersion.Clarity3:
|
|
471
|
+
return 3;
|
|
472
|
+
case ClarityVersion.Clarity4:
|
|
473
|
+
return 4;
|
|
474
|
+
default:
|
|
475
|
+
return 4;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Re-export simulation types
|
|
480
|
+
export type {
|
|
481
|
+
CreateSimulationRequest,
|
|
482
|
+
ExecutionCost,
|
|
483
|
+
InstantSimulationRequest,
|
|
484
|
+
InstantSimulationResponse,
|
|
485
|
+
ReadResult,
|
|
486
|
+
ReadStep,
|
|
487
|
+
SimulationMetadata,
|
|
488
|
+
SimulationResult,
|
|
489
|
+
SimulationStepInput,
|
|
490
|
+
TransactionReceipt,
|
|
491
|
+
} from './types';
|
package/src/tip.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WARNING:
|
|
3
|
+
*
|
|
4
|
+
* this file will be used in cross-runtime environments (browser, cloudflare workers, XLinkSDK, etc.),
|
|
5
|
+
* so please be careful when adding `import`s to it.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { DEFAULT_STXER_API } from './constants';
|
|
9
|
+
import type { SidecarTip } from './types';
|
|
10
|
+
|
|
11
|
+
export interface TipOptions {
|
|
12
|
+
stxerApi?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Fetch the current tip information from the sidecar.
|
|
17
|
+
* @param options - Optional API endpoint configuration
|
|
18
|
+
* @returns The current chain tip information
|
|
19
|
+
*/
|
|
20
|
+
export async function getTip(options: TipOptions = {}): Promise<SidecarTip> {
|
|
21
|
+
const url = `${options.stxerApi ?? DEFAULT_STXER_API}/sidecar/tip`;
|
|
22
|
+
|
|
23
|
+
const response = await fetch(url, {
|
|
24
|
+
method: 'GET',
|
|
25
|
+
headers: {
|
|
26
|
+
Accept: 'application/json',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Failed to fetch tip: ${response.status} ${response.statusText}`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const text = await response.text();
|
|
37
|
+
if (!text.startsWith('{')) {
|
|
38
|
+
throw new Error(`Invalid response from tip endpoint: ${text}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return JSON.parse(text) as SidecarTip;
|
|
42
|
+
}
|