@layerzerolabs/lz-v2-stellar-sdk 0.2.61 → 0.2.63

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 (37) hide show
  1. package/.turbo/turbo-test.log +422 -318
  2. package/dist/generated/bml.d.ts +2 -0
  3. package/dist/generated/counter.d.ts +2 -0
  4. package/dist/generated/dvn.d.ts +2 -0
  5. package/dist/generated/dvn_fee_lib.d.ts +2 -0
  6. package/dist/generated/endpoint.d.ts +2 -0
  7. package/dist/generated/executor.d.ts +2 -0
  8. package/dist/generated/executor_fee_lib.d.ts +2 -0
  9. package/dist/generated/executor_helper.d.ts +2 -0
  10. package/dist/generated/layerzero_view.d.ts +2 -0
  11. package/dist/generated/oft.d.ts +2 -0
  12. package/dist/generated/price_feed.d.ts +2 -0
  13. package/dist/generated/sac_manager.d.ts +2 -0
  14. package/dist/generated/sml.d.ts +2 -0
  15. package/dist/generated/treasury.d.ts +2 -0
  16. package/dist/generated/uln302.d.ts +2 -0
  17. package/dist/generated/upgrader.d.ts +2 -0
  18. package/package.json +5 -7
  19. package/src/generated/bml.ts +10 -0
  20. package/src/generated/counter.ts +10 -0
  21. package/src/generated/dvn.ts +10 -0
  22. package/src/generated/dvn_fee_lib.ts +10 -0
  23. package/src/generated/endpoint.ts +10 -0
  24. package/src/generated/executor.ts +10 -0
  25. package/src/generated/executor_fee_lib.ts +10 -0
  26. package/src/generated/executor_helper.ts +10 -0
  27. package/src/generated/layerzero_view.ts +10 -0
  28. package/src/generated/oft.ts +10 -0
  29. package/src/generated/price_feed.ts +10 -0
  30. package/src/generated/sac_manager.ts +10 -0
  31. package/src/generated/sml.ts +10 -0
  32. package/src/generated/treasury.ts +10 -0
  33. package/src/generated/uln302.ts +10 -0
  34. package/src/generated/upgrader.ts +10 -0
  35. package/test/suites/constants.ts +8 -4
  36. package/test/suites/deploy.ts +8 -2
  37. package/test/suites/localnet.ts +146 -71
@@ -1,118 +1,193 @@
1
- import axios from 'axios';
2
- import { $, sleep } from 'zx';
1
+ import { execSync } from 'child_process';
2
+
3
+ import { BASE_FEE, Operation, rpc, TransactionBuilder } from '@stellar/stellar-sdk';
3
4
 
4
5
  import {
5
6
  CHAIN_B_DEPLOYER,
6
7
  DEFAULT_DEPLOYER,
7
8
  EXECUTOR_ADMIN,
8
- FRIENDBOT_URL,
9
+ JUNK_WALLET,
10
+ NETWORK_PASSPHRASE,
9
11
  RPC_URL,
10
12
  ZRO_DISTRIBUTOR,
11
13
  } from './constants';
12
14
  import { deployNativeSac, deployZroToken } from './deploy';
13
15
 
14
- const CONTAINER_NAME = 'stellar-localnet';
15
- const QUICKSTART_IMAGE = 'stellar/quickstart:testing';
16
+ const CONTAINER_NAME = 'stellar-protocol-sdk';
17
+ const ECR_IMAGE = '438003944538.dkr.ecr.us-east-1.amazonaws.com/layerzerolabs/stellar:2026-03-02';
18
+ const CONTAINER_PORT = 8000;
19
+ const HOST_PORT = 8086;
16
20
 
17
21
  // Timeout configuration (in milliseconds)
18
- const STARTUP_TIMEOUT_MS = 300_000; // 5 minutes total timeout for localnet startup
19
- const REQUEST_TIMEOUT_MS = 10_000; // 10 seconds per request
20
- const RETRY_INTERVAL_MS = 2_000; // 2 seconds between retries
22
+ const STARTUP_TIMEOUT_MS = 120_000; // 2 minutes
23
+ const REQUEST_TIMEOUT_MS = 5_000;
24
+ const RETRY_INTERVAL_MS = 2_000;
21
25
 
22
26
  export async function startStellarLocalnet(): Promise<void> {
23
27
  console.log('🚀 Starting Stellar localnet...');
24
28
 
25
- // Remove any existing container first (ignore errors if not running)
26
- await $`docker rm -f ${CONTAINER_NAME}`.nothrow();
27
-
28
- // Pull image only if not available locally
29
- const imageExists = await $`docker image inspect ${QUICKSTART_IMAGE}`.nothrow().quiet();
30
- if (imageExists.exitCode !== 0) {
31
- console.log(`📥 Pulling ${QUICKSTART_IMAGE}...`);
32
- await $`docker pull ${QUICKSTART_IMAGE}`;
29
+ // Remove any existing container and start fresh from the ECR snapshot
30
+ try {
31
+ execSync(`docker rm -f ${CONTAINER_NAME}`, { stdio: 'ignore' });
32
+ } catch {
33
+ // Container didn't exist ignore
33
34
  }
34
35
 
35
- // Start the stellar/quickstart container directly (no Stellar CLI needed)
36
- await $`docker run -d --name ${CONTAINER_NAME} -p 8086:8000 ${QUICKSTART_IMAGE} --local`;
37
-
38
- const startTime = Date.now();
36
+ execSync(
37
+ `docker run -d --name ${CONTAINER_NAME} -p ${HOST_PORT}:${CONTAINER_PORT} ${ECR_IMAGE}`,
38
+ { stdio: 'inherit' },
39
+ );
39
40
 
40
- // Wait for RPC to be healthy first (friendbot depends on it)
41
41
  console.log('⏳ Waiting for Stellar RPC to be healthy...');
42
- await waitForRpcHealth(startTime);
42
+ await waitForRpcHealth();
43
43
  console.log('✅ Stellar RPC is healthy');
44
44
 
45
- // Wait for friendbot to be ready and fund accounts
46
- console.log('⏳ Waiting for friendbot to be ready...');
47
- await waitForFriendbotAndFundAccounts(startTime);
48
-
45
+ await fundTestAccounts();
49
46
  await deployNativeSac();
50
47
  await deployZroToken();
51
48
  }
52
49
 
53
- async function waitForRpcHealth(startTime: number): Promise<void> {
54
- while (Date.now() - startTime < STARTUP_TIMEOUT_MS) {
50
+ // Serialization queue for fundAccount — the junk wallet can only have one pending tx at a time.
51
+ // Chaining onto this promise ensures concurrent calls are sequenced correctly.
52
+ let fundAccountQueue: Promise<void> = Promise.resolve();
53
+
54
+ /**
55
+ * Fund a single account from the junk wallet (for ad-hoc test accounts).
56
+ * Calls are serialized to avoid sequence number conflicts on the junk wallet.
57
+ */
58
+ export function fundAccount(publicKey: string): Promise<void> {
59
+ const result = fundAccountQueue.then(() => fundAccountInternal(publicKey));
60
+ fundAccountQueue = result.catch(() => {}); // keep queue alive if this call fails
61
+ return result;
62
+ }
63
+
64
+ async function fundAccountInternal(publicKey: string): Promise<void> {
65
+ const MAX_RETRIES = 5;
66
+ let lastError: unknown;
67
+
68
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
55
69
  try {
56
- const response = await axios.post(
57
- RPC_URL,
58
- { jsonrpc: '2.0', id: 1, method: 'getHealth' },
59
- {
60
- timeout: REQUEST_TIMEOUT_MS,
61
- headers: { 'Content-Type': 'application/json' },
62
- },
63
- );
64
- if (response.data?.result?.status === 'healthy') {
65
- return;
70
+ const server = new rpc.Server(RPC_URL, { allowHttp: true });
71
+ // Re-fetch account on every attempt to get the latest sequence number
72
+ const junkAccount = await server.getAccount(JUNK_WALLET.publicKey());
73
+
74
+ const tx = new TransactionBuilder(junkAccount, {
75
+ fee: BASE_FEE,
76
+ networkPassphrase: NETWORK_PASSPHRASE,
77
+ })
78
+ .addOperation(
79
+ Operation.createAccount({
80
+ destination: publicKey,
81
+ startingBalance: '100',
82
+ }),
83
+ )
84
+ .setTimeout(30)
85
+ .build();
86
+
87
+ tx.sign(JUNK_WALLET);
88
+
89
+ const sendResult = await server.sendTransaction(tx);
90
+ if (sendResult.status !== 'PENDING') {
91
+ throw new Error(
92
+ `Failed to fund account ${publicKey}: ${JSON.stringify(sendResult)}`,
93
+ );
94
+ }
95
+
96
+ const txResult = await server.pollTransaction(sendResult.hash);
97
+ if (txResult.status !== 'SUCCESS') {
98
+ throw new Error(
99
+ `Account funding failed for ${publicKey}: ${JSON.stringify(txResult)}`,
100
+ );
101
+ }
102
+
103
+ return; // success
104
+ } catch (err) {
105
+ lastError = err;
106
+ if (attempt < MAX_RETRIES) {
107
+ await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL_MS));
66
108
  }
67
- } catch {
68
- // RPC not ready yet
69
109
  }
70
- await sleep(RETRY_INTERVAL_MS);
71
110
  }
111
+
72
112
  throw new Error(
73
- `Stellar RPC failed to become healthy within ${STARTUP_TIMEOUT_MS / 1000} seconds`,
113
+ `Failed to fund account ${publicKey} after ${MAX_RETRIES} attempts: ${lastError instanceof Error ? lastError.message : String(lastError)}`,
74
114
  );
75
115
  }
76
116
 
77
- async function waitForFriendbotAndFundAccounts(startTime: number): Promise<void> {
117
+ async function waitForRpcHealth(): Promise<void> {
118
+ const startTime = Date.now();
78
119
  while (Date.now() - startTime < STARTUP_TIMEOUT_MS) {
79
120
  try {
80
- // Fund DEFAULT_DEPLOYER first (doubles as friendbot readiness check)
81
- await fundAccount(DEFAULT_DEPLOYER.publicKey());
82
- console.log(' Friendbot ready, DEFAULT_DEPLOYER funded');
83
-
84
- // Fund remaining accounts in parallel
85
- await Promise.all([
86
- fundAccount(ZRO_DISTRIBUTOR.publicKey()),
87
- fundAccount(EXECUTOR_ADMIN.publicKey()),
88
- fundAccount(CHAIN_B_DEPLOYER.publicKey()),
89
- ]);
90
- console.log('✅ All accounts funded');
91
- return;
121
+ const response = await fetch(RPC_URL, {
122
+ method: 'POST',
123
+ headers: { 'Content-Type': 'application/json' },
124
+ body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'getHealth' }),
125
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
126
+ });
127
+ const data = (await response.json()) as { result?: { status?: string } };
128
+ if (data.result?.status === 'healthy') return;
92
129
  } catch {
93
- const elapsed = Math.round((Date.now() - startTime) / 1000);
94
- console.log(`⏳ [${elapsed}s] Waiting for friendbot...`);
95
- await sleep(RETRY_INTERVAL_MS);
130
+ // Not ready yet
96
131
  }
132
+ await new Promise((resolve) => setTimeout(resolve, RETRY_INTERVAL_MS));
97
133
  }
98
- throw new Error(`Friendbot not ready within ${STARTUP_TIMEOUT_MS / 1000} seconds`);
134
+ throw new Error(
135
+ `Stellar RPC failed to become healthy within ${STARTUP_TIMEOUT_MS / 1000} seconds`,
136
+ );
99
137
  }
100
138
 
101
- export async function fundAccount(publicKey: string): Promise<void> {
102
- const response = await axios.get(FRIENDBOT_URL, {
103
- params: {
104
- addr: publicKey,
105
- },
106
- timeout: REQUEST_TIMEOUT_MS,
107
- });
108
-
109
- // Check for error responses (friendbot returns 400 if already funded, which is OK)
110
- if (response.status >= 500) {
111
- throw new Error(`Friendbot returned error: ${response.status}`);
139
+ async function fundTestAccounts(): Promise<void> {
140
+ console.log('💰 Funding test accounts from junk wallet...');
141
+ const server = new rpc.Server(RPC_URL, { allowHttp: true });
142
+ const junkAccount = await server.getAccount(JUNK_WALLET.publicKey());
143
+
144
+ const tx = new TransactionBuilder(junkAccount, {
145
+ fee: BASE_FEE,
146
+ networkPassphrase: NETWORK_PASSPHRASE,
147
+ })
148
+ .addOperation(
149
+ Operation.createAccount({
150
+ destination: DEFAULT_DEPLOYER.publicKey(),
151
+ startingBalance: '2000',
152
+ }),
153
+ )
154
+ .addOperation(
155
+ Operation.createAccount({
156
+ destination: ZRO_DISTRIBUTOR.publicKey(),
157
+ startingBalance: '2000',
158
+ }),
159
+ )
160
+ .addOperation(
161
+ Operation.createAccount({
162
+ destination: EXECUTOR_ADMIN.publicKey(),
163
+ startingBalance: '2000',
164
+ }),
165
+ )
166
+ .addOperation(
167
+ Operation.createAccount({
168
+ destination: CHAIN_B_DEPLOYER.publicKey(),
169
+ startingBalance: '2000',
170
+ }),
171
+ )
172
+ .setTimeout(30)
173
+ .build();
174
+
175
+ tx.sign(JUNK_WALLET);
176
+
177
+ const sendResult = await server.sendTransaction(tx);
178
+ if (sendResult.status !== 'PENDING') {
179
+ throw new Error(`Failed to fund test accounts: ${JSON.stringify(sendResult)}`);
112
180
  }
181
+
182
+ const txResult = await server.pollTransaction(sendResult.hash);
183
+ if (txResult.status !== 'SUCCESS') {
184
+ throw new Error(`Account funding transaction failed: ${JSON.stringify(txResult)}`);
185
+ }
186
+
187
+ console.log('✅ All test accounts funded');
113
188
  }
114
189
 
115
190
  export async function stopStellarLocalnet(): Promise<void> {
116
- await $`docker rm -f ${CONTAINER_NAME}`;
191
+ execSync(`docker rm -f ${CONTAINER_NAME}`, { stdio: 'ignore' });
117
192
  console.log('✅ Stellar localnet stopped');
118
193
  }