@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.
- package/LICENSE +23 -0
- package/README.md +108 -0
- package/dist/4UKUSHEU.js +30 -0
- package/dist/4UKUSHEU.js.map +1 -0
- package/dist/7DZ4SVEO.js +46 -0
- package/dist/7DZ4SVEO.js.map +1 -0
- package/dist/CYINPPER.js +293 -0
- package/dist/CYINPPER.js.map +1 -0
- package/dist/DNRE4ENZ.js +56 -0
- package/dist/DNRE4ENZ.js.map +1 -0
- package/dist/GAGBEOCZ.js +25 -0
- package/dist/GAGBEOCZ.js.map +1 -0
- package/dist/PMDPSIA2.js +149 -0
- package/dist/PMDPSIA2.js.map +1 -0
- package/dist/TYAJMKGY.js +183 -0
- package/dist/TYAJMKGY.js.map +1 -0
- package/dist/VRABOZPX.js +364 -0
- package/dist/VRABOZPX.js.map +1 -0
- package/dist/VUOMXK5T.js +6 -0
- package/dist/VUOMXK5T.js.map +1 -0
- package/dist/ZWKXKZVT.js +394 -0
- package/dist/ZWKXKZVT.js.map +1 -0
- package/dist/client.d.ts +17 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +4 -0
- package/dist/client.js.map +1 -0
- package/dist/deploy.d.ts +43 -0
- package/dist/deploy.d.ts.map +1 -0
- package/dist/deploy.js +4 -0
- package/dist/deploy.js.map +1 -0
- package/dist/env.d.ts +45 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +5 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/localnet-global-setup.d.ts +7 -0
- package/dist/localnet-global-setup.d.ts.map +1 -0
- package/dist/localnet-global-setup.js +6 -0
- package/dist/localnet-global-setup.js.map +1 -0
- package/dist/localnet.d.ts +37 -0
- package/dist/localnet.d.ts.map +1 -0
- package/dist/localnet.js +5 -0
- package/dist/localnet.js.map +1 -0
- package/dist/protocol-global-setup.d.ts +58 -0
- package/dist/protocol-global-setup.d.ts.map +1 -0
- package/dist/protocol-global-setup.js +7 -0
- package/dist/protocol-global-setup.js.map +1 -0
- package/dist/scan.d.ts +59 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +4 -0
- package/dist/scan.js.map +1 -0
- package/dist/secp256k1.d.ts +23 -0
- package/dist/secp256k1.d.ts.map +1 -0
- package/dist/secp256k1.js +4 -0
- package/dist/secp256k1.js.map +1 -0
- package/dist/utils.d.ts +54 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +5 -0
- package/dist/utils.js.map +1 -0
- package/package.json +50 -0
- package/src/client.ts +37 -0
- package/src/deploy.ts +316 -0
- package/src/env.ts +104 -0
- package/src/index.ts +40 -0
- package/src/localnet-global-setup.ts +30 -0
- package/src/localnet.ts +406 -0
- package/src/protocol-global-setup.ts +747 -0
- package/src/scan.ts +255 -0
- package/src/secp256k1.ts +59 -0
- 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
|
+
}
|