@hashgraph/hedera-wallet-connect 2.0.4-canary.147c309.0 → 2.0.4-canary.3597314.0
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/README.md +3 -1
- package/dist/lib/dapp/DAppSigner.js +4 -47
- package/dist/lib/shared/utils.d.ts +1 -33
- package/dist/lib/shared/utils.js +1 -91
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ await dAppConnector.openModal()
|
|
|
121
121
|
2. Add Hedera dependencies to your project:
|
|
122
122
|
|
|
123
123
|
```sh
|
|
124
|
-
npm install @hashgraph/hedera-wallet-connect
|
|
124
|
+
npm install @hashgraph/hedera-wallet-connect @hashgraph/sdk @walletconnect/universal-provider
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
3. Update `createAppKit` with adapters and a universal provider for Hedera. Note the
|
|
@@ -226,10 +226,12 @@ refer to how to send transactions to wallets using the `hedera:(mainnet|testnet)
|
|
|
226
226
|
While minimal, the main breaking changes are:
|
|
227
227
|
|
|
228
228
|
- remove WalletConnect v1 modals
|
|
229
|
+
|
|
229
230
|
- these are very old, though in the spirit of semver, we kept the dependency until this
|
|
230
231
|
library's v2 release
|
|
231
232
|
|
|
232
233
|
- remove setting node id's within this library for transactions
|
|
234
|
+
|
|
233
235
|
- initially, a transaction created by the Hedera Javascript SDK needed to have one or more
|
|
234
236
|
consensus node ids set to be able to serialize into bytes, sent over a network, and
|
|
235
237
|
deserialized by the SDK
|
|
@@ -146,15 +146,7 @@ export class DAppSigner {
|
|
|
146
146
|
* @returns transaction - `Transaction` object with signature
|
|
147
147
|
*/
|
|
148
148
|
async signTransaction(transaction) {
|
|
149
|
-
|
|
150
|
-
// Ensure transaction is frozen with node account IDs before signing
|
|
151
|
-
// This is required so the transaction can be executed later by any client
|
|
152
|
-
if (!transaction.isFrozen()) {
|
|
153
|
-
transaction.freezeWith(this._getHederaClient());
|
|
154
|
-
}
|
|
155
|
-
// Extract the first node account ID from the frozen transaction to preserve it in the transaction body
|
|
156
|
-
const nodeAccountId = (_b = (_a = transaction.nodeAccountIds) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : null;
|
|
157
|
-
const transactionBody = transactionToTransactionBody(transaction, nodeAccountId);
|
|
149
|
+
const transactionBody = transactionToTransactionBody(transaction);
|
|
158
150
|
if (!transactionBody)
|
|
159
151
|
throw new Error('Failed to serialize transaction body');
|
|
160
152
|
const transactionBodyBase64 = transactionBodyToBase64String(transactionBody);
|
|
@@ -166,44 +158,9 @@ export class DAppSigner {
|
|
|
166
158
|
},
|
|
167
159
|
});
|
|
168
160
|
const sigMap = base64StringToSignatureMap(signatureMap);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const originalTransactionList = proto.TransactionList.decode(originalTransactionBytes);
|
|
173
|
-
// Add the signature to all transactions in the list
|
|
174
|
-
// Each transaction in the list corresponds to a different node
|
|
175
|
-
const signedTransactionList = originalTransactionList.transactionList.map((tx) => {
|
|
176
|
-
// Check if the transaction has signedTransactionBytes (frozen transactions)
|
|
177
|
-
if (tx.signedTransactionBytes) {
|
|
178
|
-
// Decode the SignedTransaction to access the bodyBytes and existing sigMap
|
|
179
|
-
const signedTx = proto.SignedTransaction.decode(tx.signedTransactionBytes);
|
|
180
|
-
const existingSigMap = signedTx.sigMap || proto.SignatureMap.create({});
|
|
181
|
-
// Merge the new signatures with existing signatures
|
|
182
|
-
const mergedSigPairs = [...(existingSigMap.sigPair || []), ...(sigMap.sigPair || [])];
|
|
183
|
-
// Create updated SignedTransaction with merged signatures
|
|
184
|
-
const updatedSignedTx = proto.SignedTransaction.encode({
|
|
185
|
-
bodyBytes: signedTx.bodyBytes,
|
|
186
|
-
sigMap: proto.SignatureMap.create({
|
|
187
|
-
sigPair: mergedSigPairs,
|
|
188
|
-
}),
|
|
189
|
-
}).finish();
|
|
190
|
-
return {
|
|
191
|
-
signedTransactionBytes: updatedSignedTx,
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
else {
|
|
195
|
-
// Transaction has bodyBytes and sigMap at the top level (not frozen)
|
|
196
|
-
const existingSigMap = tx.sigMap || proto.SignatureMap.create({});
|
|
197
|
-
// Merge the new signatures with existing signatures
|
|
198
|
-
const mergedSigPairs = [...(existingSigMap.sigPair || []), ...(sigMap.sigPair || [])];
|
|
199
|
-
return Object.assign(Object.assign({}, tx), { sigMap: Object.assign(Object.assign({}, existingSigMap), { sigPair: mergedSigPairs }) });
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
// Encode the signed transaction list back to bytes
|
|
203
|
-
const signedBytes = proto.TransactionList.encode({
|
|
204
|
-
transactionList: signedTransactionList,
|
|
205
|
-
}).finish();
|
|
206
|
-
return Transaction.fromBytes(signedBytes);
|
|
161
|
+
const bodyBytes = base64StringToUint8Array(transactionBodyBase64);
|
|
162
|
+
const bytes = proto.Transaction.encode({ bodyBytes, sigMap }).finish();
|
|
163
|
+
return Transaction.fromBytes(bytes);
|
|
207
164
|
}
|
|
208
165
|
async _tryExecuteTransactionRequest(request) {
|
|
209
166
|
try {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AccountId, PublicKey,
|
|
1
|
+
import { AccountId, PublicKey, Transaction, LedgerId, Query, SignerSignature } from '@hashgraph/sdk';
|
|
2
2
|
import { ProposalTypes, SessionTypes } from '@walletconnect/types';
|
|
3
3
|
import { proto } from '@hashgraph/proto';
|
|
4
4
|
/**
|
|
@@ -273,35 +273,3 @@ export declare const accountAndLedgerFromSession: (session: SessionTypes.Struct)
|
|
|
273
273
|
network: LedgerId;
|
|
274
274
|
account: AccountId;
|
|
275
275
|
}[];
|
|
276
|
-
/**
|
|
277
|
-
* Adds an additional signature to an already-signed transaction.
|
|
278
|
-
*
|
|
279
|
-
* This function is critical for multi-signature workflows where a transaction
|
|
280
|
-
* has already been signed by one party (e.g., via WalletConnect) and needs
|
|
281
|
-
* an additional signature from another party (e.g., backend co-signer).
|
|
282
|
-
*
|
|
283
|
-
* IMPORTANT: The standard SDK `.sign()` method does NOT work on reconstructed
|
|
284
|
-
* transactions because it clears the `_transactions` array (Transaction.js:825),
|
|
285
|
-
* which deletes existing signatures. This function uses proto-level manipulation
|
|
286
|
-
* to preserve all existing signatures while adding new ones.
|
|
287
|
-
*
|
|
288
|
-
* This implementation mirrors the signature merging pattern used in
|
|
289
|
-
* `DAppSigner.signTransaction()` (DAppSigner.ts:248-273).
|
|
290
|
-
*
|
|
291
|
-
* @param transaction - Transaction that already has one or more signatures
|
|
292
|
-
* @param privateKey - Private key to create additional signature
|
|
293
|
-
* @returns New transaction instance with all signatures (existing + new)
|
|
294
|
-
*
|
|
295
|
-
* @example
|
|
296
|
-
* ```typescript
|
|
297
|
-
* // Wallet signs first
|
|
298
|
-
* const walletSigned = await signer.signTransaction(transaction)
|
|
299
|
-
*
|
|
300
|
-
* // Backend adds signature
|
|
301
|
-
* const fullySigned = await addSignatureToTransaction(walletSigned, backendPrivateKey)
|
|
302
|
-
*
|
|
303
|
-
* // Now has both signatures
|
|
304
|
-
* await fullySigned.execute(client)
|
|
305
|
-
* ```
|
|
306
|
-
*/
|
|
307
|
-
export declare function addSignatureToTransaction<T extends Transaction>(transaction: T, privateKey: PublicKey | PrivateKey): Promise<T>;
|
package/dist/lib/shared/utils.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*
|
|
19
19
|
*/
|
|
20
20
|
import { Buffer } from 'buffer';
|
|
21
|
-
import { AccountId,
|
|
21
|
+
import { AccountId, Transaction, LedgerId, Query, } from '@hashgraph/sdk';
|
|
22
22
|
import { proto } from '@hashgraph/proto';
|
|
23
23
|
/**
|
|
24
24
|
* Converts `Transaction` to a Base64-string.
|
|
@@ -418,93 +418,3 @@ export const accountAndLedgerFromSession = (session) => {
|
|
|
418
418
|
};
|
|
419
419
|
});
|
|
420
420
|
};
|
|
421
|
-
/**
|
|
422
|
-
* Adds an additional signature to an already-signed transaction.
|
|
423
|
-
*
|
|
424
|
-
* This function is critical for multi-signature workflows where a transaction
|
|
425
|
-
* has already been signed by one party (e.g., via WalletConnect) and needs
|
|
426
|
-
* an additional signature from another party (e.g., backend co-signer).
|
|
427
|
-
*
|
|
428
|
-
* IMPORTANT: The standard SDK `.sign()` method does NOT work on reconstructed
|
|
429
|
-
* transactions because it clears the `_transactions` array (Transaction.js:825),
|
|
430
|
-
* which deletes existing signatures. This function uses proto-level manipulation
|
|
431
|
-
* to preserve all existing signatures while adding new ones.
|
|
432
|
-
*
|
|
433
|
-
* This implementation mirrors the signature merging pattern used in
|
|
434
|
-
* `DAppSigner.signTransaction()` (DAppSigner.ts:248-273).
|
|
435
|
-
*
|
|
436
|
-
* @param transaction - Transaction that already has one or more signatures
|
|
437
|
-
* @param privateKey - Private key to create additional signature
|
|
438
|
-
* @returns New transaction instance with all signatures (existing + new)
|
|
439
|
-
*
|
|
440
|
-
* @example
|
|
441
|
-
* ```typescript
|
|
442
|
-
* // Wallet signs first
|
|
443
|
-
* const walletSigned = await signer.signTransaction(transaction)
|
|
444
|
-
*
|
|
445
|
-
* // Backend adds signature
|
|
446
|
-
* const fullySigned = await addSignatureToTransaction(walletSigned, backendPrivateKey)
|
|
447
|
-
*
|
|
448
|
-
* // Now has both signatures
|
|
449
|
-
* await fullySigned.execute(client)
|
|
450
|
-
* ```
|
|
451
|
-
*/
|
|
452
|
-
export async function addSignatureToTransaction(transaction, privateKey) {
|
|
453
|
-
// Step 1: Get original transaction bytes (preserves ALL existing signatures)
|
|
454
|
-
const originalBytes = transaction.toBytes();
|
|
455
|
-
const originalList = proto.TransactionList.decode(originalBytes);
|
|
456
|
-
// Step 2: Extract transaction body bytes to sign
|
|
457
|
-
const firstTransaction = originalList.transactionList[0];
|
|
458
|
-
let bodyBytes;
|
|
459
|
-
if (firstTransaction.signedTransactionBytes) {
|
|
460
|
-
const signedTx = proto.SignedTransaction.decode(firstTransaction.signedTransactionBytes);
|
|
461
|
-
bodyBytes = signedTx.bodyBytes;
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
bodyBytes = firstTransaction.bodyBytes;
|
|
465
|
-
}
|
|
466
|
-
// Step 3: Create signature with the provided private key
|
|
467
|
-
const publicKey = privateKey instanceof PublicKey ? privateKey : privateKey.publicKey;
|
|
468
|
-
const signature = privateKey instanceof PublicKey
|
|
469
|
-
? (() => {
|
|
470
|
-
throw new Error('Cannot sign with PublicKey, PrivateKey required');
|
|
471
|
-
})()
|
|
472
|
-
: await privateKey.sign(bodyBytes);
|
|
473
|
-
// Step 4: Add new signature to ALL transactions in the list
|
|
474
|
-
// Each transaction in the list corresponds to a different node
|
|
475
|
-
const signedTransactionList = originalList.transactionList.map((tx) => {
|
|
476
|
-
// Create the new signature pair using SDK's internal method
|
|
477
|
-
const newSigPair = publicKey._toProtobufSignature(signature);
|
|
478
|
-
// Check if the transaction has signedTransactionBytes (frozen transactions)
|
|
479
|
-
if (tx.signedTransactionBytes) {
|
|
480
|
-
// Decode the SignedTransaction to access the bodyBytes and existing sigMap
|
|
481
|
-
const signedTx = proto.SignedTransaction.decode(tx.signedTransactionBytes);
|
|
482
|
-
const existingSigMap = signedTx.sigMap || proto.SignatureMap.create({});
|
|
483
|
-
// Merge existing signatures with new signature
|
|
484
|
-
const mergedSigPairs = [...(existingSigMap.sigPair || []), newSigPair];
|
|
485
|
-
// Create updated SignedTransaction with merged signatures
|
|
486
|
-
const updatedSignedTx = proto.SignedTransaction.encode({
|
|
487
|
-
bodyBytes: signedTx.bodyBytes,
|
|
488
|
-
sigMap: proto.SignatureMap.create({
|
|
489
|
-
sigPair: mergedSigPairs,
|
|
490
|
-
}),
|
|
491
|
-
}).finish();
|
|
492
|
-
return {
|
|
493
|
-
signedTransactionBytes: updatedSignedTx,
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
|
-
else {
|
|
497
|
-
// Transaction has bodyBytes and sigMap at the top level (not frozen)
|
|
498
|
-
const existingSigMap = tx.sigMap || proto.SignatureMap.create({});
|
|
499
|
-
// Merge existing signatures with new signature
|
|
500
|
-
const mergedSigPairs = [...(existingSigMap.sigPair || []), newSigPair];
|
|
501
|
-
return Object.assign(Object.assign({}, tx), { sigMap: Object.assign(Object.assign({}, existingSigMap), { sigPair: mergedSigPairs }) });
|
|
502
|
-
}
|
|
503
|
-
});
|
|
504
|
-
// Step 5: Encode the signed transaction list back to bytes
|
|
505
|
-
const signedBytes = proto.TransactionList.encode({
|
|
506
|
-
transactionList: signedTransactionList,
|
|
507
|
-
}).finish();
|
|
508
|
-
// Step 6: Return reconstructed transaction with all signatures
|
|
509
|
-
return Transaction.fromBytes(signedBytes);
|
|
510
|
-
}
|
package/package.json
CHANGED