@layerzerolabs/protocol-stellar-v2 0.2.60 → 0.2.61
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/.turbo/turbo-build.log +64 -65
- package/.turbo/turbo-lint.log +68 -73
- package/.turbo/turbo-test.log +1953 -1882
- package/contracts/workers/dvn/src/auth.rs +67 -30
- package/contracts/workers/dvn/src/dvn.rs +31 -6
- package/contracts/workers/dvn/src/errors.rs +4 -1
- package/contracts/workers/dvn/src/events.rs +7 -1
- package/contracts/workers/dvn/src/interfaces/dvn.rs +34 -8
- package/contracts/workers/dvn/src/storage.rs +5 -1
- package/contracts/workers/dvn/src/tests/auth.rs +539 -90
- package/package.json +4 -4
- package/sdk/.turbo/turbo-test.log +303 -269
- package/sdk/dist/generated/dvn.d.ts +59 -11
- package/sdk/dist/generated/dvn.js +21 -10
- package/sdk/package.json +1 -1
- package/sdk/test/counter-uln.test.ts +34 -15
- package/sdk/test/upgrader.test.ts +21 -0
- package/sdk/test/utils.ts +101 -14
package/sdk/test/utils.ts
CHANGED
|
@@ -167,7 +167,6 @@ 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)
|
|
171
170
|
*/
|
|
172
171
|
export async function signDvnAuthEntries<T>(
|
|
173
172
|
dvnAddress: string,
|
|
@@ -234,11 +233,15 @@ export async function signDvnAuthEntries<T>(
|
|
|
234
233
|
adminSignature.toString('hex').slice(0, 32) + '...',
|
|
235
234
|
);
|
|
236
235
|
|
|
237
|
-
// 3.
|
|
238
|
-
//
|
|
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)
|
|
239
239
|
const expiration = BigInt(validUntilLedgerSeq) * 5n + BigInt(Math.floor(Date.now() / 1000));
|
|
240
|
-
const
|
|
241
|
-
const
|
|
240
|
+
const rootCall = getRootCall(rootInvocation);
|
|
241
|
+
const isSelfCall = rootCall.to === dvnAddr.toString();
|
|
242
|
+
const calls = isSelfCall ? [rootCall] : collectCallsFromInvocation(rootInvocation);
|
|
243
|
+
const callsXdr = serializeCallsToXdr(calls);
|
|
244
|
+
const callHash = computeCallHash(vid, expiration, callsXdr);
|
|
242
245
|
console.log('📝 Call hash for multisig:', Buffer.from(callHash).toString('hex'));
|
|
243
246
|
|
|
244
247
|
// 4. Sign the call hash with multisig signers
|
|
@@ -261,19 +264,16 @@ export async function signDvnAuthEntries<T>(
|
|
|
261
264
|
const sortedSignatures = signaturesWithAddresses.map((s) => s.sig);
|
|
262
265
|
|
|
263
266
|
// 6. Build TransactionAuthData as ScVal
|
|
264
|
-
// struct TransactionAuthData { vid, expiration, signatures
|
|
265
|
-
|
|
267
|
+
// struct TransactionAuthData { vid: u32, expiration: u64, signatures: Vec<BytesN<65>>, sender: Sender }
|
|
268
|
+
// enum Sender { None, Admin(BytesN<32>, BytesN<64>) }
|
|
266
269
|
const transactionAuthDataScVal = xdr.ScVal.scvMap([
|
|
267
270
|
new xdr.ScMapEntry({
|
|
268
271
|
key: xdr.ScVal.scvSymbol('expiration'),
|
|
269
272
|
val: xdr.ScVal.scvU64(new xdr.Uint64(expiration)),
|
|
270
273
|
}),
|
|
271
|
-
new xdr.ScMapEntry({
|
|
272
|
-
key: xdr.ScVal.scvSymbol('preimage'),
|
|
273
|
-
val: xdr.ScVal.scvBytes(preimageXdr),
|
|
274
|
-
}),
|
|
275
274
|
new xdr.ScMapEntry({
|
|
276
275
|
key: xdr.ScVal.scvSymbol('sender'),
|
|
276
|
+
// Sender::Admin(public_key, signature)
|
|
277
277
|
val: xdr.ScVal.scvVec([
|
|
278
278
|
xdr.ScVal.scvSymbol('Admin'),
|
|
279
279
|
xdr.ScVal.scvBytes(adminKeypair.rawPublicKey()),
|
|
@@ -325,11 +325,97 @@ export async function signDvnAuthEntries<T>(
|
|
|
325
325
|
console.log('✅ Final simulation complete');
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
+
/**
|
|
329
|
+
* Represents a contract call for multisig authorization.
|
|
330
|
+
*/
|
|
331
|
+
interface Call {
|
|
332
|
+
to: string; // Contract address
|
|
333
|
+
func: string; // Function name
|
|
334
|
+
args: xdr.ScVal[]; // Function arguments
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Extracts only the root call from an invocation (no recursion into sub-invocations).
|
|
339
|
+
*/
|
|
340
|
+
function getRootCall(invocation: xdr.SorobanAuthorizedInvocation): Call {
|
|
341
|
+
const fn = invocation.function();
|
|
342
|
+
if (
|
|
343
|
+
fn.switch() !== xdr.SorobanAuthorizedFunctionType.sorobanAuthorizedFunctionTypeContractFn()
|
|
344
|
+
) {
|
|
345
|
+
throw new Error('Root invocation is not a contract function');
|
|
346
|
+
}
|
|
347
|
+
const contractFn = fn.contractFn();
|
|
348
|
+
return {
|
|
349
|
+
to: Address.fromScAddress(contractFn.contractAddress()).toString(),
|
|
350
|
+
func: contractFn.functionName().toString(),
|
|
351
|
+
args: contractFn.args(),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Collects all contract calls from an invocation tree.
|
|
357
|
+
*/
|
|
358
|
+
function collectCallsFromInvocation(invocation: xdr.SorobanAuthorizedInvocation): Call[] {
|
|
359
|
+
const calls: Call[] = [];
|
|
360
|
+
collectCallsRecursive(invocation, calls);
|
|
361
|
+
return calls;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function collectCallsRecursive(invocation: xdr.SorobanAuthorizedInvocation, calls: Call[]): void {
|
|
365
|
+
const fn = invocation.function();
|
|
366
|
+
|
|
367
|
+
if (
|
|
368
|
+
fn.switch() === xdr.SorobanAuthorizedFunctionType.sorobanAuthorizedFunctionTypeContractFn()
|
|
369
|
+
) {
|
|
370
|
+
const contractFn = fn.contractFn();
|
|
371
|
+
const contractAddr = Address.fromScAddress(contractFn.contractAddress());
|
|
372
|
+
|
|
373
|
+
calls.push({
|
|
374
|
+
to: contractAddr.toString(),
|
|
375
|
+
func: contractFn.functionName().toString(),
|
|
376
|
+
args: contractFn.args(),
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Process sub-invocations
|
|
381
|
+
for (const sub of invocation.subInvocations()) {
|
|
382
|
+
collectCallsRecursive(sub, calls);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Serializes calls to XDR format matching Soroban's Vec<Call> serialization.
|
|
388
|
+
*
|
|
389
|
+
* Call struct: { args: Vec<Val>, func: Symbol, to: Address }
|
|
390
|
+
* Serialized as ScMap with keys in alphabetical order.
|
|
391
|
+
*/
|
|
392
|
+
function serializeCallsToXdr(calls: Call[]): Buffer {
|
|
393
|
+
const callScVals = calls.map((call) =>
|
|
394
|
+
xdr.ScVal.scvMap([
|
|
395
|
+
new xdr.ScMapEntry({
|
|
396
|
+
key: xdr.ScVal.scvSymbol('args'),
|
|
397
|
+
val: xdr.ScVal.scvVec(call.args),
|
|
398
|
+
}),
|
|
399
|
+
new xdr.ScMapEntry({
|
|
400
|
+
key: xdr.ScVal.scvSymbol('func'),
|
|
401
|
+
val: xdr.ScVal.scvSymbol(call.func),
|
|
402
|
+
}),
|
|
403
|
+
new xdr.ScMapEntry({
|
|
404
|
+
key: xdr.ScVal.scvSymbol('to'),
|
|
405
|
+
val: Address.fromString(call.to).toScVal(),
|
|
406
|
+
}),
|
|
407
|
+
]),
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
const vecScVal = xdr.ScVal.scvVec(callScVals);
|
|
411
|
+
return Buffer.from(vecScVal.toXDR());
|
|
412
|
+
}
|
|
413
|
+
|
|
328
414
|
/**
|
|
329
415
|
* Computes the call hash for multisig signing.
|
|
330
|
-
* hash = keccak256(vid.to_be_bytes(4) || expiration.to_be_bytes(8) ||
|
|
416
|
+
* hash = keccak256(vid.to_be_bytes(4) || expiration.to_be_bytes(8) || calls_xdr)
|
|
331
417
|
*/
|
|
332
|
-
function computeCallHash(vid: number, expiration: bigint,
|
|
418
|
+
function computeCallHash(vid: number, expiration: bigint, callsXdr: Buffer): Uint8Array {
|
|
333
419
|
// vid as 4-byte big-endian
|
|
334
420
|
const vidBytes = Buffer.alloc(4);
|
|
335
421
|
vidBytes.writeUInt32BE(vid, 0);
|
|
@@ -338,7 +424,8 @@ function computeCallHash(vid: number, expiration: bigint, invocationXdr: Buffer)
|
|
|
338
424
|
const expirationBytes = Buffer.alloc(8);
|
|
339
425
|
expirationBytes.writeBigUInt64BE(expiration, 0);
|
|
340
426
|
|
|
341
|
-
|
|
427
|
+
// Concatenate and hash
|
|
428
|
+
const data = Buffer.concat([vidBytes, expirationBytes, callsXdr]);
|
|
342
429
|
return keccak_256(data);
|
|
343
430
|
}
|
|
344
431
|
|