@layerzerolabs/protocol-stellar-v2 0.2.53 → 0.2.55

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/sdk/test/utils.ts CHANGED
@@ -167,6 +167,7 @@ import { Secp256k1KeyPair } from './secp256k1';
167
167
  * - expiration: u64 - Ledger timestamp for when auth expires
168
168
  * - signatures: Vec<BytesN<65>> - Secp256k1 signatures from multisig signers
169
169
  * - sender: Sender - Either None or Admin(public_key, ed25519_signature)
170
+ * - preimage: Bytes - XDR-encoded HashIdPreimage::SorobanAuthorization (invocation is sliced from byte 48)
170
171
  */
171
172
  export async function signDvnAuthEntries<T>(
172
173
  dvnAddress: string,
@@ -233,13 +234,11 @@ export async function signDvnAuthEntries<T>(
233
234
  adminSignature.toString('hex').slice(0, 32) + '...',
234
235
  );
235
236
 
236
- // 3. Extract calls from the auth entry and compute the multisig hash
237
- // The expiration is the ledger timestamp when the auth expires
238
- // We use validUntilLedgerSeq * 5 as a rough approximation (5 seconds per ledger)
237
+ // 3. Compute the multisig hash from raw invocation XDR
238
+ // hash = keccak256(vid || expiration || invocation_xdr)
239
239
  const expiration = BigInt(validUntilLedgerSeq) * 5n + BigInt(Math.floor(Date.now() / 1000));
240
- const calls = collectCallsFromInvocation(rootInvocation);
241
- const callsXdr = serializeCallsToXdr(calls);
242
- const callHash = computeCallHash(vid, expiration, callsXdr);
240
+ const invocationXdr = Buffer.from(rootInvocation.toXDR());
241
+ const callHash = computeCallHash(vid, expiration, invocationXdr);
243
242
  console.log('📝 Call hash for multisig:', Buffer.from(callHash).toString('hex'));
244
243
 
245
244
  // 4. Sign the call hash with multisig signers
@@ -262,16 +261,19 @@ export async function signDvnAuthEntries<T>(
262
261
  const sortedSignatures = signaturesWithAddresses.map((s) => s.sig);
263
262
 
264
263
  // 6. Build TransactionAuthData as ScVal
265
- // struct TransactionAuthData { vid: u32, expiration: u64, signatures: Vec<BytesN<65>>, sender: Sender }
266
- // enum Sender { None, Admin(BytesN<32>, BytesN<64>) }
264
+ // struct TransactionAuthData { vid, expiration, signatures, sender, preimage }
265
+ const preimageXdr = Buffer.from(preimage.toXDR());
267
266
  const transactionAuthDataScVal = xdr.ScVal.scvMap([
268
267
  new xdr.ScMapEntry({
269
268
  key: xdr.ScVal.scvSymbol('expiration'),
270
269
  val: xdr.ScVal.scvU64(new xdr.Uint64(expiration)),
271
270
  }),
271
+ new xdr.ScMapEntry({
272
+ key: xdr.ScVal.scvSymbol('preimage'),
273
+ val: xdr.ScVal.scvBytes(preimageXdr),
274
+ }),
272
275
  new xdr.ScMapEntry({
273
276
  key: xdr.ScVal.scvSymbol('sender'),
274
- // Sender::Admin(public_key, signature)
275
277
  val: xdr.ScVal.scvVec([
276
278
  xdr.ScVal.scvSymbol('Admin'),
277
279
  xdr.ScVal.scvBytes(adminKeypair.rawPublicKey()),
@@ -323,79 +325,11 @@ export async function signDvnAuthEntries<T>(
323
325
  console.log('✅ Final simulation complete');
324
326
  }
325
327
 
326
- /**
327
- * Represents a contract call for multisig authorization.
328
- */
329
- interface Call {
330
- to: string; // Contract address
331
- func: string; // Function name
332
- args: xdr.ScVal[]; // Function arguments
333
- }
334
-
335
- /**
336
- * Collects all contract calls from an invocation tree.
337
- */
338
- function collectCallsFromInvocation(invocation: xdr.SorobanAuthorizedInvocation): Call[] {
339
- const calls: Call[] = [];
340
- collectCallsRecursive(invocation, calls);
341
- return calls;
342
- }
343
-
344
- function collectCallsRecursive(invocation: xdr.SorobanAuthorizedInvocation, calls: Call[]): void {
345
- const fn = invocation.function();
346
-
347
- if (
348
- fn.switch() === xdr.SorobanAuthorizedFunctionType.sorobanAuthorizedFunctionTypeContractFn()
349
- ) {
350
- const contractFn = fn.contractFn();
351
- const contractAddr = Address.fromScAddress(contractFn.contractAddress());
352
-
353
- calls.push({
354
- to: contractAddr.toString(),
355
- func: contractFn.functionName().toString(),
356
- args: contractFn.args(),
357
- });
358
- }
359
-
360
- // Process sub-invocations
361
- for (const sub of invocation.subInvocations()) {
362
- collectCallsRecursive(sub, calls);
363
- }
364
- }
365
-
366
- /**
367
- * Serializes calls to XDR format matching Soroban's Vec<Call> serialization.
368
- *
369
- * Call struct: { args: Vec<Val>, func: Symbol, to: Address }
370
- * Serialized as ScMap with keys in alphabetical order.
371
- */
372
- function serializeCallsToXdr(calls: Call[]): Buffer {
373
- const callScVals = calls.map((call) =>
374
- xdr.ScVal.scvMap([
375
- new xdr.ScMapEntry({
376
- key: xdr.ScVal.scvSymbol('args'),
377
- val: xdr.ScVal.scvVec(call.args),
378
- }),
379
- new xdr.ScMapEntry({
380
- key: xdr.ScVal.scvSymbol('func'),
381
- val: xdr.ScVal.scvSymbol(call.func),
382
- }),
383
- new xdr.ScMapEntry({
384
- key: xdr.ScVal.scvSymbol('to'),
385
- val: Address.fromString(call.to).toScVal(),
386
- }),
387
- ]),
388
- );
389
-
390
- const vecScVal = xdr.ScVal.scvVec(callScVals);
391
- return Buffer.from(vecScVal.toXDR());
392
- }
393
-
394
328
  /**
395
329
  * Computes the call hash for multisig signing.
396
- * hash = keccak256(vid.to_be_bytes(4) || expiration.to_be_bytes(8) || calls_xdr)
330
+ * hash = keccak256(vid.to_be_bytes(4) || expiration.to_be_bytes(8) || invocation_xdr)
397
331
  */
398
- function computeCallHash(vid: number, expiration: bigint, callsXdr: Buffer): Uint8Array {
332
+ function computeCallHash(vid: number, expiration: bigint, invocationXdr: Buffer): Uint8Array {
399
333
  // vid as 4-byte big-endian
400
334
  const vidBytes = Buffer.alloc(4);
401
335
  vidBytes.writeUInt32BE(vid, 0);
@@ -404,8 +338,7 @@ function computeCallHash(vid: number, expiration: bigint, callsXdr: Buffer): Uin
404
338
  const expirationBytes = Buffer.alloc(8);
405
339
  expirationBytes.writeBigUInt64BE(expiration, 0);
406
340
 
407
- // Concatenate and hash
408
- const data = Buffer.concat([vidBytes, expirationBytes, callsXdr]);
341
+ const data = Buffer.concat([vidBytes, expirationBytes, invocationXdr]);
409
342
  return keccak_256(data);
410
343
  }
411
344