@layerzerolabs/test-utils-stellar 0.2.122

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.
Files changed (73) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +108 -0
  3. package/dist/4UKUSHEU.js +30 -0
  4. package/dist/4UKUSHEU.js.map +1 -0
  5. package/dist/7DZ4SVEO.js +46 -0
  6. package/dist/7DZ4SVEO.js.map +1 -0
  7. package/dist/CYINPPER.js +293 -0
  8. package/dist/CYINPPER.js.map +1 -0
  9. package/dist/DNRE4ENZ.js +56 -0
  10. package/dist/DNRE4ENZ.js.map +1 -0
  11. package/dist/GAGBEOCZ.js +25 -0
  12. package/dist/GAGBEOCZ.js.map +1 -0
  13. package/dist/PMDPSIA2.js +149 -0
  14. package/dist/PMDPSIA2.js.map +1 -0
  15. package/dist/TYAJMKGY.js +183 -0
  16. package/dist/TYAJMKGY.js.map +1 -0
  17. package/dist/VRABOZPX.js +364 -0
  18. package/dist/VRABOZPX.js.map +1 -0
  19. package/dist/VUOMXK5T.js +6 -0
  20. package/dist/VUOMXK5T.js.map +1 -0
  21. package/dist/ZWKXKZVT.js +394 -0
  22. package/dist/ZWKXKZVT.js.map +1 -0
  23. package/dist/client.d.ts +17 -0
  24. package/dist/client.d.ts.map +1 -0
  25. package/dist/client.js +4 -0
  26. package/dist/client.js.map +1 -0
  27. package/dist/deploy.d.ts +43 -0
  28. package/dist/deploy.d.ts.map +1 -0
  29. package/dist/deploy.js +4 -0
  30. package/dist/deploy.js.map +1 -0
  31. package/dist/env.d.ts +45 -0
  32. package/dist/env.d.ts.map +1 -0
  33. package/dist/env.js +5 -0
  34. package/dist/env.js.map +1 -0
  35. package/dist/index.d.ts +10 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +12 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/localnet-global-setup.d.ts +7 -0
  40. package/dist/localnet-global-setup.d.ts.map +1 -0
  41. package/dist/localnet-global-setup.js +6 -0
  42. package/dist/localnet-global-setup.js.map +1 -0
  43. package/dist/localnet.d.ts +37 -0
  44. package/dist/localnet.d.ts.map +1 -0
  45. package/dist/localnet.js +5 -0
  46. package/dist/localnet.js.map +1 -0
  47. package/dist/protocol-global-setup.d.ts +58 -0
  48. package/dist/protocol-global-setup.d.ts.map +1 -0
  49. package/dist/protocol-global-setup.js +7 -0
  50. package/dist/protocol-global-setup.js.map +1 -0
  51. package/dist/scan.d.ts +59 -0
  52. package/dist/scan.d.ts.map +1 -0
  53. package/dist/scan.js +4 -0
  54. package/dist/scan.js.map +1 -0
  55. package/dist/secp256k1.d.ts +23 -0
  56. package/dist/secp256k1.d.ts.map +1 -0
  57. package/dist/secp256k1.js +4 -0
  58. package/dist/secp256k1.js.map +1 -0
  59. package/dist/utils.d.ts +54 -0
  60. package/dist/utils.d.ts.map +1 -0
  61. package/dist/utils.js +5 -0
  62. package/dist/utils.js.map +1 -0
  63. package/package.json +50 -0
  64. package/src/client.ts +37 -0
  65. package/src/deploy.ts +316 -0
  66. package/src/env.ts +104 -0
  67. package/src/index.ts +40 -0
  68. package/src/localnet-global-setup.ts +30 -0
  69. package/src/localnet.ts +406 -0
  70. package/src/protocol-global-setup.ts +747 -0
  71. package/src/scan.ts +255 -0
  72. package/src/secp256k1.ts +59 -0
  73. package/src/utils.ts +642 -0
package/src/deploy.ts ADDED
@@ -0,0 +1,316 @@
1
+ import type { Keypair } from '@stellar/stellar-sdk';
2
+ import {
3
+ Asset,
4
+ BASE_FEE,
5
+ hash,
6
+ Operation,
7
+ rpc,
8
+ TransactionBuilder,
9
+ xdr,
10
+ } from '@stellar/stellar-sdk';
11
+ import { readFileSync } from 'fs';
12
+
13
+ import type { StellarTestEnv } from './env.js';
14
+
15
+ export interface DeployableContractClient<T extends { options: { contractId: string } }> {
16
+ deploy: (
17
+ argsOrOptions: unknown,
18
+ options?: unknown,
19
+ ) => Promise<{ signAndSend: () => Promise<{ result: T }> }>;
20
+ }
21
+
22
+ /**
23
+ * Query and display the TTL (Time To Live) of uploaded WASM code.
24
+ *
25
+ * @param env - Stellar test environment (RPC URL, etc.)
26
+ * @param wasmHash - The hex-encoded SHA-256 hash of the WASM code
27
+ * @param server - The Stellar RPC server instance
28
+ */
29
+ async function queryWasmTtl(
30
+ env: StellarTestEnv,
31
+ wasmHash: string,
32
+ server: rpc.Server,
33
+ ): Promise<void> {
34
+ try {
35
+ const latestLedger = await server.getLatestLedger();
36
+ const currentLedger = latestLedger.sequence;
37
+
38
+ // Create the LedgerKey for contract code using XDR encoding
39
+ const wasmHashBuffer = Buffer.from(wasmHash, 'hex');
40
+ // Ensure hash is exactly 32 bytes
41
+ const hashBytes =
42
+ wasmHashBuffer.length === 32 ? wasmHashBuffer : wasmHashBuffer.slice(0, 32);
43
+ // Create LedgerKeyContractCode with hash
44
+ const ledgerKeyContractCode = new xdr.LedgerKeyContractCode({
45
+ hash: hashBytes,
46
+ });
47
+ const ledgerKey = xdr.LedgerKey.contractCode(ledgerKeyContractCode);
48
+ const ledgerKeyXdr = ledgerKey.toXDR('base64');
49
+
50
+ // Query contract code entry using direct RPC call
51
+ const response = await fetch(env.RPC_URL, {
52
+ method: 'POST',
53
+ headers: { 'Content-Type': 'application/json' },
54
+ body: JSON.stringify({
55
+ jsonrpc: '2.0',
56
+ id: 1,
57
+ method: 'getLedgerEntries',
58
+ params: {
59
+ keys: [ledgerKeyXdr],
60
+ },
61
+ }),
62
+ });
63
+
64
+ const result = (await response.json()) as any;
65
+ if (result.error) {
66
+ console.warn(`Warning: Could not retrieve WASM TTL: ${result.error.message}`);
67
+ } else if (result.result?.entries?.[0]?.liveUntilLedgerSeq) {
68
+ const liveUntilLedgerSeq = result.result.entries[0].liveUntilLedgerSeq;
69
+ const ttlLedgers = liveUntilLedgerSeq - currentLedger;
70
+ const ttlDays = (ttlLedgers * 5) / (24 * 3600); // ~5 seconds per ledger
71
+ console.log(
72
+ `⏰ WASM TTL: live until ledger ${liveUntilLedgerSeq} (${ttlLedgers} ledgers remaining, ~${ttlDays.toFixed(2)} days)`,
73
+ );
74
+ }
75
+ } catch (error) {
76
+ // If querying TTL fails, it might be because the code isn't indexed yet
77
+ // This is non-fatal, so we just log a warning
78
+ console.warn(
79
+ `Warning: Could not retrieve WASM TTL: ${error instanceof Error ? error.message : String(error)}`,
80
+ );
81
+ }
82
+ }
83
+
84
+ export async function uploadWasm(
85
+ env: StellarTestEnv,
86
+ wasmBuffer: Buffer,
87
+ keypair: Keypair,
88
+ server: rpc.Server,
89
+ ): Promise<string> {
90
+ console.log(
91
+ `📦 WASM buffer size: ${wasmBuffer.length} bytes (${(wasmBuffer.length / 1024).toFixed(2)} KB)`,
92
+ );
93
+
94
+ const account = await server.getAccount(keypair.publicKey());
95
+
96
+ const uploadTx = new TransactionBuilder(account, {
97
+ fee: BASE_FEE,
98
+ networkPassphrase: env.NETWORK_PASSPHRASE,
99
+ })
100
+ .addOperation(Operation.uploadContractWasm({ wasm: wasmBuffer }))
101
+ .setTimeout(30)
102
+ .build();
103
+
104
+ const simulated = await server.simulateTransaction(uploadTx);
105
+ const preparedTx = rpc.assembleTransaction(uploadTx, simulated).build();
106
+
107
+ console.log(
108
+ `💰 Upload transaction fee: ${preparedTx.fee} stroops (${(Number(preparedTx.fee) / 10000000).toFixed(7)} XLM)`,
109
+ );
110
+
111
+ preparedTx.sign(keypair);
112
+
113
+ const sendResult = await server.sendTransaction(preparedTx);
114
+
115
+ if (sendResult.status !== 'PENDING') {
116
+ throw new Error(`Transaction failed: ${JSON.stringify(sendResult)}`);
117
+ }
118
+
119
+ // Wait for transaction to be confirmed
120
+ const txResult = await server.pollTransaction(sendResult.hash);
121
+
122
+ if (txResult.status !== 'SUCCESS') {
123
+ throw new Error(`Transaction not successful: ${JSON.stringify(txResult)}`);
124
+ }
125
+
126
+ // Compute the WASM hash (SHA-256 of the WASM bytes)
127
+ const wasmHash = hash(wasmBuffer).toString('hex');
128
+
129
+ // Query and display the WASM code TTL
130
+ await queryWasmTtl(env, wasmHash, server);
131
+
132
+ return wasmHash;
133
+ }
134
+
135
+ /**
136
+ * Generic contract deployment helper that works with any contract Client
137
+ *
138
+ * @param ClientClass - The contract Client class (e.g., EndpointClient, SMLClient)
139
+ * @param wasmFilePath - Path to the compiled WASM file
140
+ * @param constructorArgs - Arguments for the contract's constructor
141
+ * @param deployer - The keypair that will deploy the contract
142
+ * @param options - Optional deployment options (salt, fee, timeout, etc.)
143
+ * @returns The deployed contract's Client instance with the contractId
144
+ */
145
+ export async function deployContract<T extends { options: { contractId: string } }>(
146
+ env: StellarTestEnv,
147
+ ClientClass: DeployableContractClient<T>,
148
+ wasmFilePath: string,
149
+ constructorArgs: unknown,
150
+ deployer: Keypair,
151
+ options: {
152
+ salt?: Buffer;
153
+ wasmHash?: string;
154
+ rpcUrl?: string;
155
+ networkPassphrase?: string;
156
+ allowHttp?: boolean;
157
+ } = {},
158
+ ): Promise<T> {
159
+ const {
160
+ rpcUrl = env.RPC_URL,
161
+ networkPassphrase = env.NETWORK_PASSPHRASE,
162
+ allowHttp = true,
163
+ salt,
164
+ } = options;
165
+
166
+ const server = new rpc.Server(rpcUrl, {
167
+ allowHttp: allowHttp,
168
+ });
169
+
170
+ let wasmHash = options.wasmHash;
171
+ if (wasmHash) {
172
+ console.log('📦 Using pre-uploaded WASM hash:', wasmHash);
173
+ } else {
174
+ // Step 1: Read WASM file
175
+ console.log('📖 Reading WASM file from:', wasmFilePath);
176
+ const wasmBuffer = readFileSync(wasmFilePath);
177
+
178
+ // Step 2: Upload WASM and get hash
179
+ console.log('📤 Uploading WASM...');
180
+ wasmHash = await uploadWasm(env, wasmBuffer, deployer, server);
181
+ console.log('✅ WASM uploaded, hash:', wasmHash);
182
+ }
183
+
184
+ // Step 3: Deploy the contract
185
+ console.log('🚀 Deploying contract...');
186
+ const deployOptions = {
187
+ wasmHash,
188
+ publicKey: deployer.publicKey(),
189
+ signTransaction: async (tx: string) => {
190
+ const transaction = TransactionBuilder.fromXDR(tx, networkPassphrase);
191
+ transaction.sign(deployer);
192
+ return {
193
+ signedTxXdr: transaction.toXDR(),
194
+ signerAddress: deployer.publicKey(),
195
+ };
196
+ },
197
+ rpcUrl,
198
+ networkPassphrase,
199
+ allowHttp,
200
+ salt,
201
+ };
202
+ const deployTx =
203
+ constructorArgs == null
204
+ ? await ClientClass.deploy(deployOptions)
205
+ : await ClientClass.deploy(constructorArgs, deployOptions);
206
+
207
+ // Step 4: Sign and send
208
+ const sentTx = await deployTx.signAndSend();
209
+
210
+ // Step 5: Extract contract ID from result
211
+ const contractClient = sentTx.result;
212
+ const contractId = contractClient.options.contractId;
213
+ console.log('✅ Contract deployed at:', contractId);
214
+
215
+ return contractClient;
216
+ }
217
+
218
+ export async function deployNativeSac(env: StellarTestEnv): Promise<void> {
219
+ await deployAssetSac(env, Asset.native());
220
+ console.log('✅ Native SAC deployed');
221
+ }
222
+
223
+ export async function deployZroToken(env: StellarTestEnv): Promise<void> {
224
+ const server = new rpc.Server(env.RPC_URL, {
225
+ allowHttp: true,
226
+ });
227
+
228
+ // First, issue the ZRO token.
229
+ // We can't changeTrust of Issuer account, because the Issuer can't hold the asset.
230
+ const account = await server.getAccount(env.DEFAULT_DEPLOYER.publicKey());
231
+ const transaction = new TransactionBuilder(account, {
232
+ fee: BASE_FEE,
233
+ networkPassphrase: env.NETWORK_PASSPHRASE,
234
+ })
235
+ .addOperation(
236
+ Operation.changeTrust({
237
+ asset: env.ZRO_ASSET,
238
+ source: env.ZRO_DISTRIBUTOR.publicKey(),
239
+ }),
240
+ )
241
+ .addOperation(
242
+ Operation.payment({
243
+ asset: env.ZRO_ASSET,
244
+ amount: '10000',
245
+ destination: env.ZRO_DISTRIBUTOR.publicKey(),
246
+ }),
247
+ )
248
+ .setTimeout(10)
249
+ .build();
250
+ transaction.sign(env.DEFAULT_DEPLOYER, env.ZRO_DISTRIBUTOR);
251
+
252
+ const sendResult = await server.sendTransaction(transaction);
253
+ if (sendResult.status !== 'PENDING') {
254
+ throw new Error(`Failed to issue ZRO token: ${JSON.stringify(sendResult)}`);
255
+ }
256
+ const txResult = await server.pollTransaction(sendResult.hash);
257
+ if (txResult.status !== 'SUCCESS') {
258
+ throw new Error(`Failed to issue ZRO token: ${JSON.stringify(txResult)}`);
259
+ }
260
+ console.log('✅ ZRO asset issued');
261
+
262
+ // Deploy the Stellar Asset Contract (SAC)
263
+ await deployAssetSac(env, env.ZRO_ASSET);
264
+ console.log('✅ ZRO SAC deployed');
265
+ }
266
+
267
+ /**
268
+ * Deploy SAC for a custom asset using TypeScript
269
+ */
270
+ export async function deployAssetSac(env: StellarTestEnv, asset: Asset): Promise<string> {
271
+ console.log('Deploying SAC for asset:', asset.toString());
272
+
273
+ const server = new rpc.Server(env.RPC_URL, { allowHttp: true });
274
+ const account = await server.getAccount(env.DEFAULT_DEPLOYER.publicKey());
275
+
276
+ // Build transaction with createStellarAssetContract operation
277
+ const deployTx = new TransactionBuilder(account, {
278
+ fee: BASE_FEE,
279
+ networkPassphrase: env.NETWORK_PASSPHRASE,
280
+ })
281
+ .addOperation(
282
+ Operation.createStellarAssetContract({
283
+ asset: asset,
284
+ }),
285
+ )
286
+ .setTimeout(30)
287
+ .build();
288
+
289
+ // Simulate transaction first (required for contract operations)
290
+ const simulated = await server.simulateTransaction(deployTx);
291
+
292
+ // Check if simulation was successful
293
+ if (rpc.Api.isSimulationError(simulated)) {
294
+ // Soroban returns ExistingValue when the contract is already deployed.
295
+ // This is expected on container reuse (local dev reruns).
296
+ if (simulated.error?.includes('ExistingValue')) {
297
+ console.log(`SAC for ${asset.toString()} already deployed, skipping`);
298
+ return asset.contractId(env.NETWORK_PASSPHRASE);
299
+ }
300
+ throw new Error(`Transaction simulation failed: ${JSON.stringify(simulated)}`);
301
+ }
302
+
303
+ const preparedTx = rpc.assembleTransaction(deployTx, simulated).build();
304
+
305
+ // Sign and send
306
+ preparedTx.sign(env.DEFAULT_DEPLOYER);
307
+ const sendResult = await server.sendTransaction(preparedTx);
308
+ if (sendResult.status !== 'PENDING') {
309
+ throw new Error(`Failed to deploy SAC: ${JSON.stringify(sendResult)}`);
310
+ }
311
+ const txResult = await server.pollTransaction(sendResult.hash);
312
+ if (txResult.status !== 'SUCCESS') {
313
+ throw new Error(`SAC deployment not successful: ${JSON.stringify(txResult)}`);
314
+ }
315
+ return asset.contractId(env.NETWORK_PASSPHRASE);
316
+ }
package/src/env.ts ADDED
@@ -0,0 +1,104 @@
1
+ import { Asset, Keypair, Networks } from '@stellar/stellar-sdk';
2
+
3
+ import { Secp256k1KeyPair } from './secp256k1.js';
4
+
5
+ export interface CreateStellarTestEnvOptions {
6
+ /** Docker container name — must be unique when suites run concurrently. */
7
+ containerName: string;
8
+ /** Host port mapped to the localnet container's RPC port. */
9
+ hostPort: number;
10
+ /**
11
+ * Optional localnet image override. Defaults to the versioned LayerZero ECR snapshot.
12
+ * Useful for testing a locally built image without changing the shared default.
13
+ */
14
+ dockerImage?: string;
15
+ }
16
+
17
+ /**
18
+ * Shared Stellar E2E constants (RPC URL, keys, EIDs, token addresses).
19
+ * Constructed from containerName/hostPort so concurrent suites do not collide.
20
+ */
21
+ export interface StellarTestEnv {
22
+ CONTAINER_NAME: string;
23
+ HOST_PORT: number;
24
+ /** Optional localnet Docker image override. */
25
+ DOCKER_IMAGE?: string;
26
+ RPC_URL: string;
27
+ NETWORK_PASSPHRASE: typeof Networks.STANDALONE;
28
+ JUNK_WALLET: Keypair;
29
+ DEFAULT_DEPLOYER: Keypair;
30
+ ZRO_DISTRIBUTOR: Keypair;
31
+ EXECUTOR_ADMIN: Keypair;
32
+ CHAIN_B_DEPLOYER: Keypair;
33
+ DVN_SIGNER: Secp256k1KeyPair;
34
+ DVN_VID: number;
35
+ EID_A: number;
36
+ EID_B: number;
37
+ /** Legacy single EID (alias of EID_A). */
38
+ EID: number;
39
+ NATIVE_TOKEN_ADDRESS: string;
40
+ ZRO_ASSET: Asset;
41
+ ZRO_TOKEN_ADDRESS: string;
42
+ MSG_TYPE_VANILLA: number;
43
+ MSG_TYPE_COMPOSED: number;
44
+ MSG_TYPE_ABA: number;
45
+ MSG_TYPE_COMPOSED_ABA: number;
46
+ }
47
+
48
+ export function createStellarTestEnv(options: CreateStellarTestEnvOptions): StellarTestEnv {
49
+ const { containerName, hostPort, dockerImage } = options;
50
+ const networkPassphrase = Networks.STANDALONE;
51
+ const coreUrl = `http://localhost:${hostPort}`;
52
+
53
+ // Pre-funded in the ECR localnet image (BIP39: "test test...junk", path m/44'/148'/0')
54
+ const junkWallet = Keypair.fromSecret(
55
+ 'SCZ5VBFVGE4SLZV5WJO33LEEU36EEOEHWO27KYJIIUWGOKZB2OSNAQBI',
56
+ );
57
+ const defaultDeployer = Keypair.fromSecret(
58
+ 'SDLCA3JUES3G6R4FTI6XXDIWW7QCNMZNWPYQQIKQ26TEIZUFOLIVIUDK',
59
+ );
60
+ const zroDistributor = Keypair.fromSecret(
61
+ 'SB6QAFXFRR2MXYHW4RRZ23JDGKHDCYCT5YTQEGG3WNT5VKZADJQFVNWG',
62
+ );
63
+ // Deterministic so globalSetup and test files agree (separate processes).
64
+ const executorAdmin = Keypair.fromSecret(
65
+ 'SACWJCNRT2AYRPBWW7IBRNI765EMZSWPXXAAHYN57UFQNOXMGET7HM5K',
66
+ );
67
+ // Separate deployer for Chain B parallel deploy in protocol globalSetup.
68
+ const chainBDeployer = Keypair.fromSecret(
69
+ 'SDLIZSTG7W4C3FZYY52WIKF7FTWAXCWC5Z4OVVF3TDA3MBOR37LMIANJ',
70
+ );
71
+
72
+ // Private key is keccak256("dvn_test_signer") truncated to 32 bytes
73
+ const dvnSigner = new Secp256k1KeyPair(
74
+ '0x8d3f8d5d8f1c7e2a5b4c3d6e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a',
75
+ );
76
+
77
+ const eidA = 30401;
78
+ const zroAsset = new Asset('ZRO', defaultDeployer.publicKey());
79
+
80
+ return {
81
+ CONTAINER_NAME: containerName,
82
+ HOST_PORT: hostPort,
83
+ DOCKER_IMAGE: dockerImage,
84
+ RPC_URL: `${coreUrl}/soroban/rpc`,
85
+ NETWORK_PASSPHRASE: networkPassphrase,
86
+ JUNK_WALLET: junkWallet,
87
+ DEFAULT_DEPLOYER: defaultDeployer,
88
+ ZRO_DISTRIBUTOR: zroDistributor,
89
+ EXECUTOR_ADMIN: executorAdmin,
90
+ CHAIN_B_DEPLOYER: chainBDeployer,
91
+ DVN_SIGNER: dvnSigner,
92
+ DVN_VID: 1,
93
+ EID_A: eidA,
94
+ EID_B: 30402,
95
+ EID: eidA,
96
+ NATIVE_TOKEN_ADDRESS: Asset.native().contractId(networkPassphrase),
97
+ ZRO_ASSET: zroAsset,
98
+ ZRO_TOKEN_ADDRESS: zroAsset.contractId(networkPassphrase),
99
+ MSG_TYPE_VANILLA: 1,
100
+ MSG_TYPE_COMPOSED: 2,
101
+ MSG_TYPE_ABA: 3,
102
+ MSG_TYPE_COMPOSED_ABA: 4,
103
+ };
104
+ }
package/src/index.ts ADDED
@@ -0,0 +1,40 @@
1
+ export { createClient } from './client.js';
2
+ export {
3
+ deployAssetSac,
4
+ deployContract,
5
+ deployNativeSac,
6
+ deployZroToken,
7
+ uploadWasm,
8
+ } from './deploy.js';
9
+ export {
10
+ createStellarTestEnv,
11
+ type CreateStellarTestEnvOptions,
12
+ type StellarTestEnv,
13
+ } from './env.js';
14
+ export { fundAccount, startStellarLocalnet, stopStellarLocalnet } from './localnet.js';
15
+ export { createLocalnetOnlyGlobalSetup } from './localnet-global-setup.js';
16
+ export {
17
+ type ChainAddresses,
18
+ createProtocolStackGlobalSetup,
19
+ type ProtocolContractModule,
20
+ type ProtocolGlobalSetupContext,
21
+ type ProtocolStackGlobalSetupOptions,
22
+ type ProtocolStackModules,
23
+ } from './protocol-global-setup.js';
24
+ export {
25
+ type EventFilter,
26
+ type PacketSentEvent,
27
+ type ParsedContractEvent,
28
+ scanEvents,
29
+ scanPacketSentEvents,
30
+ waitAndScanEvents,
31
+ } from './scan.js';
32
+ export { Secp256k1KeyPair } from './secp256k1.js';
33
+ export {
34
+ assertTransactionSucceeded,
35
+ getNativeBalance,
36
+ getTokenAuthorized,
37
+ getTokenBalance,
38
+ signAndSendWithExecutorAuth,
39
+ signDvnAuthEntries,
40
+ } from './utils.js';
@@ -0,0 +1,30 @@
1
+ import type { StellarTestEnv } from './env.js';
2
+ import { startStellarLocalnet, stopStellarLocalnet } from './localnet.js';
3
+
4
+ /**
5
+ * Vitest globalSetup that only starts/stops Stellar localnet.
6
+ * Use when the suite deploys its own contracts (e.g. protocol SDK upgrader tests).
7
+ */
8
+ export function createLocalnetOnlyGlobalSetup(
9
+ env: StellarTestEnv,
10
+ ): (_ctx?: unknown) => Promise<() => Promise<void>> {
11
+ return async function globalSetup(_ctx?: unknown): Promise<() => Promise<void>> {
12
+ console.log('\n========================================');
13
+ console.log('🌐 GLOBAL SETUP: Starting Stellar Localnet');
14
+ console.log('========================================\n');
15
+
16
+ await startStellarLocalnet({ env });
17
+
18
+ console.log('\n========================================');
19
+ console.log('✅ GLOBAL SETUP COMPLETE (localnet only)');
20
+ console.log('========================================\n');
21
+
22
+ return async () => {
23
+ console.log('\n========================================');
24
+ console.log('🛑 GLOBAL TEARDOWN: Stopping Stellar Localnet');
25
+ console.log('========================================\n');
26
+
27
+ await stopStellarLocalnet({ env });
28
+ };
29
+ };
30
+ }