@solana/signers 2.0.0-experimental.699bde0 → 2.0.0-experimental.6bfb261

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 (51) hide show
  1. package/README.md +214 -12
  2. package/dist/index.browser.cjs +238 -28
  3. package/dist/index.browser.cjs.map +1 -1
  4. package/dist/index.browser.js +228 -30
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.native.js +228 -30
  7. package/dist/index.native.js.map +1 -1
  8. package/dist/index.node.cjs +238 -28
  9. package/dist/index.node.cjs.map +1 -1
  10. package/dist/index.node.js +228 -30
  11. package/dist/index.node.js.map +1 -1
  12. package/dist/types/account-signer-meta.d.ts +21 -0
  13. package/dist/types/account-signer-meta.d.ts.map +1 -0
  14. package/dist/types/add-signers.d.ts +9 -0
  15. package/dist/types/add-signers.d.ts.map +1 -0
  16. package/dist/types/deduplicate-signers.d.ts +5 -0
  17. package/dist/types/deduplicate-signers.d.ts.map +1 -0
  18. package/dist/types/fee-payer-signer.d.ts +10 -0
  19. package/dist/types/fee-payer-signer.d.ts.map +1 -0
  20. package/dist/types/index.d.ts +16 -10
  21. package/dist/types/index.d.ts.map +1 -0
  22. package/dist/types/keypair-signer.d.ts +4 -2
  23. package/dist/types/keypair-signer.d.ts.map +1 -0
  24. package/dist/types/message-modifying-signer.d.ts +4 -2
  25. package/dist/types/message-modifying-signer.d.ts.map +1 -0
  26. package/dist/types/message-partial-signer.d.ts +4 -3
  27. package/dist/types/message-partial-signer.d.ts.map +1 -0
  28. package/dist/types/message-signer.d.ts +2 -2
  29. package/dist/types/message-signer.d.ts.map +1 -0
  30. package/dist/types/noop-signer.d.ts +8 -0
  31. package/dist/types/noop-signer.d.ts.map +1 -0
  32. package/dist/types/sign-transaction.d.ts +33 -0
  33. package/dist/types/sign-transaction.d.ts.map +1 -0
  34. package/dist/types/signable-message.d.ts +1 -1
  35. package/dist/types/signable-message.d.ts.map +1 -0
  36. package/dist/types/transaction-modifying-signer.d.ts +3 -1
  37. package/dist/types/transaction-modifying-signer.d.ts.map +1 -0
  38. package/dist/types/transaction-partial-signer.d.ts +3 -2
  39. package/dist/types/transaction-partial-signer.d.ts.map +1 -0
  40. package/dist/types/transaction-sending-signer.d.ts +3 -1
  41. package/dist/types/transaction-sending-signer.d.ts.map +1 -0
  42. package/dist/types/transaction-signer.d.ts +3 -3
  43. package/dist/types/transaction-signer.d.ts.map +1 -0
  44. package/dist/types/transaction-with-single-sending-signer.d.ts +11 -0
  45. package/dist/types/transaction-with-single-sending-signer.d.ts.map +1 -0
  46. package/dist/types/types.d.ts +3 -0
  47. package/dist/types/types.d.ts.map +1 -0
  48. package/package.json +16 -37
  49. package/dist/index.development.js +0 -1216
  50. package/dist/index.development.js.map +0 -1
  51. package/dist/index.production.min.js +0 -33
package/README.md CHANGED
@@ -336,33 +336,235 @@ assertIsKeyPairSigner({ address: address('1234..5678') }); // ❌ Throws an erro
336
336
 
337
337
  ## Creating Noop signers
338
338
 
339
- ### Functions
340
-
341
- #### `createNoopSigner()`
342
-
343
- _Coming soon..._
344
-
345
- Creates a Noop (No-Operation) signer from a given address. It will return an implementation of both the `MessagePartialSigner` and `TransactionPartialSigner` interfaces that do not sign anything. Namely, signing a transaction or a message will return an empty `SignatureDictionary`.
339
+ For a given address, a Noop (No-Operation) signer can be created to offer an implementation of both the `MessagePartialSigner` and `TransactionPartialSigner` interfaces such that they do not sign anything. Namely, signing a transaction or a message with a `NoopSigner` will return an empty `SignatureDictionary`.
346
340
 
347
341
  This signer may be useful:
348
342
 
349
343
  - For testing purposes.
350
344
  - For indicating that a given account is a signer and taking the responsibility to provide the signature for that account ourselves. For instance, if we need to send the transaction to a server that will sign it and send it for us.
351
345
 
346
+ ### Types
347
+
348
+ #### `NoopSigner<TAddress>`
349
+
350
+ Defines a Noop (No-Operation) signer.
351
+
352
+ ```ts
353
+ const myNoopSigner: NoopSigner;
354
+ myNoopSigner satisfies MessagePartialSigner;
355
+ myNoopSigner satisfies TransactionPartialSigner;
356
+ ```
357
+
358
+ ### Functions
359
+
360
+ #### `createNoopSigner()`
361
+
362
+ Creates a Noop (No-Operation) signer from a given address.
363
+
352
364
  ```ts
353
365
  import { createNoopSigner } from '@solana/signers';
354
366
 
355
- const myAddress = address('1234..5678');
356
- const myNoopSigner = createNoopSigner(myAddress);
357
- // ^ MessagePartialSigner<'1234..5678'> & TransactionPartialSigner<'1234..5678'>
367
+ const myNoopSigner = createNoopSigner(address('1234..5678'));
368
+ const [myMessageSignatures] = await myNoopSigner.signMessages([myMessage]); // <- Empty signature dictionary.
369
+ const [myTransactionSignatures] = await myNoopSigner.signTransactions([myTransaction]); // <- Empty signature dictionary.
358
370
  ```
359
371
 
360
372
  ## Storing transaction signers inside instruction account metas
361
373
 
374
+ This package defines an alternative definition for account metas that allows us to store `TransactionSigners` inside them. This means each instruction can keep track of its own set of signers and, by extension, so can transactions.
375
+
376
+ It also provides helper functions that deduplicate and extract signers from instructions and transactions which makes it possible to sign an entire transaction automatically as we will see in the next section.
377
+
362
378
  ### Types
363
379
 
364
- _Coming soon..._
380
+ #### `IAccountSignerMeta`
381
+
382
+ Alternative `IAccountMeta` definition for signer accounts that allows us to store `TransactionSigners` inside it.
383
+
384
+ ```ts
385
+ const mySignerMeta: IAccountSignerMeta = {
386
+ address: myTransactionSigner.address,
387
+ role: AccountRole.READONLY_SIGNER,
388
+ signer: myTransactionSigner,
389
+ };
390
+ ```
391
+
392
+ #### `IInstructionWithSigners`
393
+
394
+ Composable type that allows `IAccountSignerMetas` to be used inside the instruction's `accounts` array.
395
+
396
+ ```ts
397
+ const myInstructionWithSigners: IInstruction & IInstructionWithSigners = {
398
+ programAddress: address('1234..5678'),
399
+ accounts: [
400
+ {
401
+ address: myTransactionSigner.address,
402
+ role: AccountRole.READONLY_SIGNER,
403
+ signer: myTransactionSigner,
404
+ },
405
+ ],
406
+ };
407
+ ```
408
+
409
+ #### `ITransactionWithSigners`
410
+
411
+ Composable type that allows `IAccountSignerMetas` to be used inside all of the transaction's account metas.
412
+
413
+ ```ts
414
+ const myTransactionWithSigners: BaseTransaction & ITransactionWithSigners = {
415
+ instructions: [
416
+ myInstructionA as IInstruction & IInstructionWithSigners,
417
+ myInstructionB as IInstruction & IInstructionWithSigners,
418
+ myInstructionC as IInstruction,
419
+ ],
420
+ version: 0,
421
+ };
422
+ ```
365
423
 
366
424
  ### Functions
367
425
 
368
- _Coming soon..._
426
+ #### `getSignersFromInstruction()`
427
+
428
+ Extracts and deduplicates all signers stored inside the account metas of an instruction.
429
+
430
+ ```ts
431
+ const mySignerA = { address: address('1111..1111'), signTransactions: async () => {} };
432
+ const mySignerB = { address: address('2222..2222'), signTransactions: async () => {} };
433
+ const myInstructionWithSigners: IInstructionWithSigners = {
434
+ programAddress: address('1234..5678'),
435
+ accounts: [
436
+ { address: mySignerA.address, role: AccountRole.READONLY_SIGNER, signer: mySignerA },
437
+ { address: mySignerB.address, role: AccountRole.WRITABLE_SIGNER, signer: mySignerB },
438
+ { address: mySignerA.address, role: AccountRole.WRITABLE_SIGNER, signer: mySignerA },
439
+ ],
440
+ };
441
+
442
+ const instructionSigners = getSignersFromInstruction(myInstructionWithSigners);
443
+ // ^ [mySignerA, mySignerB]
444
+ ```
445
+
446
+ #### `getSignersFromTransaction()`
447
+
448
+ Similarly to `getSignersFromInstruction`, this function extracts and deduplicates all signers stored inside the account metas of all the instructions inside a transaction.
449
+
450
+ ```ts
451
+ const transactionSigners = getSignersFromTransaction(myTransactionWithSigners);
452
+ ```
453
+
454
+ #### `addSignersToInstruction()`
455
+
456
+ Helper function that adds the provided signers to any of the applicable account metas. For an account meta to match a provided signer it:
457
+
458
+ - Must have a signer role (`AccountRole.READONLY_SIGNER` or `AccountRole.WRITABLE_SIGNER`).
459
+ - Must have the same address as the provided signer.
460
+ - Must not have an attached signer already.
461
+
462
+ ```ts
463
+ const myInstruction: IInstruction = {
464
+ accounts: [
465
+ { address: '1111' as Address, role: AccountRole.READONLY_SIGNER },
466
+ { address: '2222' as Address, role: AccountRole.WRITABLE_SIGNER },
467
+ ],
468
+ // ...
469
+ };
470
+
471
+ const signerA: TransactionSigner<'1111'>;
472
+ const signerB: TransactionSigner<'2222'>;
473
+ const myInstructionWithSigners = addSignersToInstruction([mySignerA, mySignerB], myInstruction);
474
+
475
+ // myInstructionWithSigners.accounts[0].signer === mySignerA
476
+ // myInstructionWithSigners.accounts[1].signer === mySignerB
477
+ ```
478
+
479
+ #### `addSignersToTransaction()`
480
+
481
+ Similarly to `addSignersToInstruction`, this function adds signer to all the applicable account metas of all the instructions inside a transaction.
482
+
483
+ ```ts
484
+ const myTransactionWithSigners = addSignersToTransaction(mySigners, myTransaction);
485
+ ```
486
+
487
+ ## Signing transactions with signers
488
+
489
+ As we've seen in the previous section, we can store and extract `TransactionSigners` from instructions and transactions. This allows us to provide helper methods that sign transactions using the signers stored inside them.
490
+
491
+ ### Functions
492
+
493
+ #### `partiallySignTransactionWithSigners()`
494
+
495
+ Extracts all signers inside the provided transaction and uses them to sign it. It first uses all `TransactionModifyingSigners` sequentially before using all `TransactionPartialSigners` in parallel.
496
+
497
+ If a composite signer implements both interfaces, it will be used as a modifying signer if no other signer implements that interface. Otherwise, it will be used as a partial signer.
498
+
499
+ ```ts
500
+ const mySignedTransaction = await partiallySignTransactionWithSigners(myTransaction);
501
+ ```
502
+
503
+ It also accepts an optional `AbortSignal` that will be propagated to all signers.
504
+
505
+ ```ts
506
+ const mySignedTransaction = await partiallySignTransactionWithSigners(myTransaction, {
507
+ abortSignal: myAbortController.signal,
508
+ });
509
+ ```
510
+
511
+ Finally, note that this function ignores `TransactionSendingSigners` as it does not send the transaction. See the `signAndSendTransactionWithSigners` function below for more details on how to use sending signers.
512
+
513
+ #### `signTransactionWithSigners()`
514
+
515
+ This function works the same as the `partiallySignTransactionWithSigners` function described above except that it also ensures the transaction is fully signed before returning it. An error will be thrown if that's not the case.
516
+
517
+ ```ts
518
+ const mySignedTransaction = await signTransactionWithSigners(myTransaction);
519
+
520
+ // With additional config.
521
+ const mySignedTransaction = await signTransactionWithSigners(myTransaction, {
522
+ abortSignal: myAbortController.signal,
523
+ });
524
+
525
+ // We now know the transaction is fully signed.
526
+ mySignedTransaction satisfies IFullySignedTransaction;
527
+ ```
528
+
529
+ #### `signAndSendTransactionWithSigners()`
530
+
531
+ Extracts all signers inside the provided transaction and uses them to sign it before sending it immediately to the blockchain. It returns the signature of the sent transaction (i.e. its identifier).
532
+
533
+ ```ts
534
+ const myTransactionSignature = await signAndSendTransactionWithSigners(myTransaction);
535
+
536
+ // With additional config.
537
+ const myTransactionSignature = await signAndSendTransactionWithSigners(myTransaction, {
538
+ abortSignal: myAbortController.signal,
539
+ });
540
+ ```
541
+
542
+ Similarly to the `partiallySignTransactionWithSigners` function, it first uses all `TransactionModifyingSigners` sequentially before using all `TransactionPartialSigners` in parallel. It then sends the transaction using the `TransactionSendingSigner` it identified.
543
+
544
+ Here as well, composite transaction signers are treated such that at least one sending signer is used if any. When a `TransactionSigner` implements more than one interface, use it as a:
545
+
546
+ - `TransactionSendingSigner`, if no other `TransactionSendingSigner` exists.
547
+ - `TransactionModifyingSigner`, if no other `TransactionModifyingSigner` exists.
548
+ - `TransactionPartialSigner`, otherwise.
549
+
550
+ The provided transaction must be of type `ITransactionWithSingleSendingSigner` meaning that it must contain exactly one `TransactionSendingSigner` inside its account metas. If more than one composite signers implement the `TransactionSendingSigner` interface, one of them will be selected as the sending signer.
551
+
552
+ Therefore, you may use the `assertIsTransactionWithSingleSendingSigner()` function to ensure the transaction is of the expected type.
553
+
554
+ ```ts
555
+ assertIsTransactionWithSingleSendingSigner(myTransaction);
556
+ const myTransactionSignature = await signAndSendTransactionWithSigners(myTransaction);
557
+ ```
558
+
559
+ Alternatively, you may use the `isTransactionWithSingleSendingSigner()` function to provide a fallback in case the transaction does not contain any sending signer.
560
+
561
+ ```ts
562
+ let transactionSignature: SignatureBytes;
563
+ if (isTransactionWithSingleSendingSigner(transaction)) {
564
+ transactionSignature = await signAndSendTransactionWithSigners(transaction);
565
+ } else {
566
+ const signedTransaction = await signTransactionWithSigners(transaction);
567
+ const encodedTransaction = getBase64EncodedWireTransaction(signedTransaction);
568
+ transactionSignature = await rpc.sendTransaction(encodedTransaction).send();
569
+ }
570
+ ```
@@ -1,28 +1,97 @@
1
1
  'use strict';
2
2
 
3
+ var errors = require('@solana/errors');
4
+ var instructions = require('@solana/instructions');
5
+ var transactions = require('@solana/transactions');
3
6
  var addresses = require('@solana/addresses');
4
7
  var keys = require('@solana/keys');
5
- var transactions = require('@solana/transactions');
6
8
 
7
- // src/keypair-signer.ts
9
+ // src/deduplicate-signers.ts
10
+ function deduplicateSigners(signers) {
11
+ const deduplicated = {};
12
+ signers.forEach((signer) => {
13
+ if (!deduplicated[signer.address]) {
14
+ deduplicated[signer.address] = signer;
15
+ } else if (deduplicated[signer.address] !== signer) {
16
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_ADDRESS_CANNOT_HAVE_MULTIPLE_SIGNERS, {
17
+ address: signer.address
18
+ });
19
+ }
20
+ });
21
+ return Object.values(deduplicated);
22
+ }
8
23
 
9
- // src/message-partial-signer.ts
24
+ // src/account-signer-meta.ts
25
+ function getSignersFromInstruction(instruction) {
26
+ return deduplicateSigners(
27
+ (instruction.accounts ?? []).flatMap((account) => "signer" in account ? account.signer : [])
28
+ );
29
+ }
30
+ function getSignersFromTransaction(transaction) {
31
+ return deduplicateSigners([
32
+ ...transaction.feePayerSigner ? [transaction.feePayerSigner] : [],
33
+ ...transaction.instructions.flatMap(getSignersFromInstruction)
34
+ ]);
35
+ }
36
+ function addSignersToInstruction(signers, instruction) {
37
+ if (!instruction.accounts || instruction.accounts.length === 0) {
38
+ return instruction;
39
+ }
40
+ const signerByAddress = new Map(deduplicateSigners(signers).map((signer) => [signer.address, signer]));
41
+ return Object.freeze({
42
+ ...instruction,
43
+ accounts: instruction.accounts.map((account) => {
44
+ const signer = signerByAddress.get(account.address);
45
+ if (!instructions.isSignerRole(account.role) || "signer" in account || !signer) {
46
+ return account;
47
+ }
48
+ return Object.freeze({ ...account, signer });
49
+ })
50
+ });
51
+ }
52
+ function addSignersToTransaction(signers, transaction) {
53
+ if (transaction.instructions.length === 0) {
54
+ return transaction;
55
+ }
56
+ return Object.freeze({
57
+ ...transaction,
58
+ instructions: transaction.instructions.map((instruction) => addSignersToInstruction(signers, instruction))
59
+ });
60
+ }
61
+ function setTransactionFeePayerSigner(feePayerSigner, transaction) {
62
+ if ("feePayer" in transaction && feePayerSigner.address === transaction.feePayer) {
63
+ if ("feePayerSigner" in transaction)
64
+ return transaction;
65
+ const out2 = { ...transaction, feePayerSigner };
66
+ Object.freeze(out2);
67
+ return out2;
68
+ }
69
+ const out = {
70
+ ...transactions.getUnsignedTransaction(transaction),
71
+ feePayer: feePayerSigner.address,
72
+ feePayerSigner
73
+ };
74
+ Object.freeze(out);
75
+ return out;
76
+ }
10
77
  function isMessagePartialSigner(value) {
11
78
  return "signMessages" in value && typeof value.signMessages === "function";
12
79
  }
13
80
  function assertIsMessagePartialSigner(value) {
14
81
  if (!isMessagePartialSigner(value)) {
15
- throw new Error("The provided value does not implement the MessagePartialSigner interface");
82
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_EXPECTED_MESSAGE_PARTIAL_SIGNER, {
83
+ address: value.address
84
+ });
16
85
  }
17
86
  }
18
-
19
- // src/transaction-partial-signer.ts
20
87
  function isTransactionPartialSigner(value) {
21
88
  return "signTransactions" in value && typeof value.signTransactions === "function";
22
89
  }
23
90
  function assertIsTransactionPartialSigner(value) {
24
91
  if (!isTransactionPartialSigner(value)) {
25
- throw new Error("The provided value does not implement the TransactionPartialSigner interface");
92
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_EXPECTED_TRANSACTION_PARTIAL_SIGNER, {
93
+ address: value.address
94
+ });
26
95
  }
27
96
  }
28
97
 
@@ -32,7 +101,9 @@ function isKeyPairSigner(value) {
32
101
  }
33
102
  function assertIsKeyPairSigner(value) {
34
103
  if (!isKeyPairSigner(value)) {
35
- throw new Error("The provided value does not implement the KeyPairSigner interface");
104
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_EXPECTED_KEY_PAIR_SIGNER, {
105
+ address: value.address
106
+ });
36
107
  }
37
108
  }
38
109
  async function createSignerFromKeyPair(keyPair) {
@@ -57,64 +128,193 @@ async function createSignerFromKeyPair(keyPair) {
57
128
  async function generateKeyPairSigner() {
58
129
  return createSignerFromKeyPair(await keys.generateKeyPair());
59
130
  }
131
+ async function createKeyPairSignerFromBytes(bytes, extractable) {
132
+ return createSignerFromKeyPair(await keys.createKeyPairFromBytes(bytes, extractable));
133
+ }
60
134
  function isMessageModifyingSigner(value) {
61
135
  return addresses.isAddress(value.address) && "modifyAndSignMessages" in value && typeof value.modifyAndSignMessages === "function";
62
136
  }
63
137
  function assertIsMessageModifyingSigner(value) {
64
138
  if (!isMessageModifyingSigner(value)) {
65
- throw new Error("The provided value does not implement the MessageModifyingSigner interface");
139
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_EXPECTED_MESSAGE_MODIFYING_SIGNER, {
140
+ address: value.address
141
+ });
66
142
  }
67
143
  }
68
-
69
- // src/message-signer.ts
70
144
  function isMessageSigner(value) {
71
145
  return isMessagePartialSigner(value) || isMessageModifyingSigner(value);
72
146
  }
73
147
  function assertIsMessageSigner(value) {
74
148
  if (!isMessageSigner(value)) {
75
- throw new Error("The provided value does not implement any of the MessageSigner interfaces");
149
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_EXPECTED_MESSAGE_SIGNER, {
150
+ address: value.address
151
+ });
76
152
  }
77
153
  }
78
- var o = globalThis.TextEncoder;
79
154
 
80
- // src/signable-message.ts
81
- function createSignableMessage(content, signatures = {}) {
82
- return Object.freeze({
83
- content: typeof content === "string" ? new o().encode(content) : content,
84
- signatures: Object.freeze({ ...signatures })
85
- });
155
+ // src/noop-signer.ts
156
+ function createNoopSigner(address) {
157
+ const out = {
158
+ address,
159
+ signMessages: async (messages) => messages.map(() => Object.freeze({})),
160
+ signTransactions: async (transactions) => transactions.map(() => Object.freeze({}))
161
+ };
162
+ return Object.freeze(out);
86
163
  }
87
-
88
- // src/transaction-modifying-signer.ts
89
164
  function isTransactionModifyingSigner(value) {
90
165
  return "modifyAndSignTransactions" in value && typeof value.modifyAndSignTransactions === "function";
91
166
  }
92
167
  function assertIsTransactionModifyingSigner(value) {
93
168
  if (!isTransactionModifyingSigner(value)) {
94
- throw new Error("The provided value does not implement the TransactionModifyingSigner interface");
169
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_EXPECTED_TRANSACTION_MODIFYING_SIGNER, {
170
+ address: value.address
171
+ });
95
172
  }
96
173
  }
97
-
98
- // src/transaction-sending-signer.ts
99
174
  function isTransactionSendingSigner(value) {
100
175
  return "signAndSendTransactions" in value && typeof value.signAndSendTransactions === "function";
101
176
  }
102
177
  function assertIsTransactionSendingSigner(value) {
103
178
  if (!isTransactionSendingSigner(value)) {
104
- throw new Error("The provided value does not implement the TransactionSendingSigner interface");
179
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_EXPECTED_TRANSACTION_SENDING_SIGNER, {
180
+ address: value.address
181
+ });
105
182
  }
106
183
  }
107
-
108
- // src/transaction-signer.ts
109
184
  function isTransactionSigner(value) {
110
185
  return isTransactionPartialSigner(value) || isTransactionModifyingSigner(value) || isTransactionSendingSigner(value);
111
186
  }
112
187
  function assertIsTransactionSigner(value) {
113
188
  if (!isTransactionSigner(value)) {
114
- throw new Error("The provided value does not implement any of the TransactionSigner interfaces");
189
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_EXPECTED_TRANSACTION_SIGNER, {
190
+ address: value.address
191
+ });
192
+ }
193
+ }
194
+
195
+ // src/sign-transaction.ts
196
+ async function partiallySignTransactionWithSigners(transaction, config = {}) {
197
+ const { partialSigners, modifyingSigners } = categorizeTransactionSigners(
198
+ deduplicateSigners(getSignersFromTransaction(transaction).filter(isTransactionSigner)),
199
+ { identifySendingSigner: false }
200
+ );
201
+ return signModifyingAndPartialTransactionSigners(transaction, modifyingSigners, partialSigners, config.abortSignal);
202
+ }
203
+ async function signTransactionWithSigners(transaction, config = {}) {
204
+ const signedTransaction = await partiallySignTransactionWithSigners(transaction, config);
205
+ transactions.assertTransactionIsFullySigned(signedTransaction);
206
+ return signedTransaction;
207
+ }
208
+ async function signAndSendTransactionWithSigners(transaction, config = {}) {
209
+ const abortSignal = config.abortSignal;
210
+ const { partialSigners, modifyingSigners, sendingSigner } = categorizeTransactionSigners(
211
+ deduplicateSigners(getSignersFromTransaction(transaction).filter(isTransactionSigner))
212
+ );
213
+ abortSignal?.throwIfAborted();
214
+ const signedTransaction = await signModifyingAndPartialTransactionSigners(
215
+ transaction,
216
+ modifyingSigners,
217
+ partialSigners,
218
+ abortSignal
219
+ );
220
+ if (!sendingSigner) {
221
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_TRANSACTION_SENDING_SIGNER_MISSING);
222
+ }
223
+ abortSignal?.throwIfAborted();
224
+ const [signature] = await sendingSigner.signAndSendTransactions([signedTransaction], { abortSignal });
225
+ abortSignal?.throwIfAborted();
226
+ return signature;
227
+ }
228
+ function categorizeTransactionSigners(signers, config = {}) {
229
+ const identifySendingSigner = config.identifySendingSigner ?? true;
230
+ const sendingSigner = identifySendingSigner ? identifyTransactionSendingSigner(signers) : null;
231
+ const otherSigners = signers.filter(
232
+ (signer) => signer !== sendingSigner && (isTransactionModifyingSigner(signer) || isTransactionPartialSigner(signer))
233
+ );
234
+ const modifyingSigners = identifyTransactionModifyingSigners(otherSigners);
235
+ const partialSigners = otherSigners.filter(isTransactionPartialSigner).filter((signer) => !modifyingSigners.includes(signer));
236
+ return Object.freeze({ modifyingSigners, partialSigners, sendingSigner });
237
+ }
238
+ function identifyTransactionSendingSigner(signers) {
239
+ const sendingSigners = signers.filter(isTransactionSendingSigner);
240
+ if (sendingSigners.length === 0)
241
+ return null;
242
+ const sendingOnlySigners = sendingSigners.filter(
243
+ (signer) => !isTransactionModifyingSigner(signer) && !isTransactionPartialSigner(signer)
244
+ );
245
+ if (sendingOnlySigners.length > 0) {
246
+ return sendingOnlySigners[0];
247
+ }
248
+ return sendingSigners[0];
249
+ }
250
+ function identifyTransactionModifyingSigners(signers) {
251
+ const modifyingSigners = signers.filter(isTransactionModifyingSigner);
252
+ if (modifyingSigners.length === 0)
253
+ return [];
254
+ const nonPartialSigners = modifyingSigners.filter((signer) => !isTransactionPartialSigner(signer));
255
+ if (nonPartialSigners.length > 0)
256
+ return nonPartialSigners;
257
+ return [modifyingSigners[0]];
258
+ }
259
+ async function signModifyingAndPartialTransactionSigners(transaction, modifyingSigners = [], partialSigners = [], abortSignal) {
260
+ const modifiedTransaction = await modifyingSigners.reduce(
261
+ async (transaction2, modifyingSigner) => {
262
+ abortSignal?.throwIfAborted();
263
+ const [tx] = await modifyingSigner.modifyAndSignTransactions([await transaction2], { abortSignal });
264
+ return Object.freeze(tx);
265
+ },
266
+ Promise.resolve(transaction)
267
+ );
268
+ abortSignal?.throwIfAborted();
269
+ const signatureDictionaries = await Promise.all(
270
+ partialSigners.map(async (partialSigner) => {
271
+ const [signatures] = await partialSigner.signTransactions([modifiedTransaction], { abortSignal });
272
+ return signatures;
273
+ })
274
+ );
275
+ const signedTransaction = {
276
+ ...modifiedTransaction,
277
+ signatures: Object.freeze(
278
+ signatureDictionaries.reduce((signatures, signatureDictionary) => {
279
+ return { ...signatures, ...signatureDictionary };
280
+ }, modifiedTransaction.signatures ?? {})
281
+ )
282
+ };
283
+ return Object.freeze(signedTransaction);
284
+ }
285
+ var o = globalThis.TextEncoder;
286
+
287
+ // src/signable-message.ts
288
+ function createSignableMessage(content, signatures = {}) {
289
+ return Object.freeze({
290
+ content: typeof content === "string" ? new o().encode(content) : content,
291
+ signatures: Object.freeze({ ...signatures })
292
+ });
293
+ }
294
+ function isTransactionWithSingleSendingSigner(transaction) {
295
+ try {
296
+ assertIsTransactionWithSingleSendingSigner(transaction);
297
+ return true;
298
+ } catch {
299
+ return false;
300
+ }
301
+ }
302
+ function assertIsTransactionWithSingleSendingSigner(transaction) {
303
+ const signers = getSignersFromTransaction(transaction);
304
+ const sendingSigners = signers.filter(isTransactionSendingSigner);
305
+ if (sendingSigners.length === 0) {
306
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_TRANSACTION_SENDING_SIGNER_MISSING);
307
+ }
308
+ const sendingOnlySigners = sendingSigners.filter(
309
+ (signer) => !isTransactionPartialSigner(signer) && !isTransactionModifyingSigner(signer)
310
+ );
311
+ if (sendingOnlySigners.length > 1) {
312
+ throw new errors.SolanaError(errors.SOLANA_ERROR__SIGNER_TRANSACTION_CANNOT_HAVE_MULTIPLE_SENDING_SIGNERS);
115
313
  }
116
314
  }
117
315
 
316
+ exports.addSignersToInstruction = addSignersToInstruction;
317
+ exports.addSignersToTransaction = addSignersToTransaction;
118
318
  exports.assertIsKeyPairSigner = assertIsKeyPairSigner;
119
319
  exports.assertIsMessageModifyingSigner = assertIsMessageModifyingSigner;
120
320
  exports.assertIsMessagePartialSigner = assertIsMessagePartialSigner;
@@ -123,9 +323,14 @@ exports.assertIsTransactionModifyingSigner = assertIsTransactionModifyingSigner;
123
323
  exports.assertIsTransactionPartialSigner = assertIsTransactionPartialSigner;
124
324
  exports.assertIsTransactionSendingSigner = assertIsTransactionSendingSigner;
125
325
  exports.assertIsTransactionSigner = assertIsTransactionSigner;
326
+ exports.assertIsTransactionWithSingleSendingSigner = assertIsTransactionWithSingleSendingSigner;
327
+ exports.createKeyPairSignerFromBytes = createKeyPairSignerFromBytes;
328
+ exports.createNoopSigner = createNoopSigner;
126
329
  exports.createSignableMessage = createSignableMessage;
127
330
  exports.createSignerFromKeyPair = createSignerFromKeyPair;
128
331
  exports.generateKeyPairSigner = generateKeyPairSigner;
332
+ exports.getSignersFromInstruction = getSignersFromInstruction;
333
+ exports.getSignersFromTransaction = getSignersFromTransaction;
129
334
  exports.isKeyPairSigner = isKeyPairSigner;
130
335
  exports.isMessageModifyingSigner = isMessageModifyingSigner;
131
336
  exports.isMessagePartialSigner = isMessagePartialSigner;
@@ -134,5 +339,10 @@ exports.isTransactionModifyingSigner = isTransactionModifyingSigner;
134
339
  exports.isTransactionPartialSigner = isTransactionPartialSigner;
135
340
  exports.isTransactionSendingSigner = isTransactionSendingSigner;
136
341
  exports.isTransactionSigner = isTransactionSigner;
342
+ exports.isTransactionWithSingleSendingSigner = isTransactionWithSingleSendingSigner;
343
+ exports.partiallySignTransactionWithSigners = partiallySignTransactionWithSigners;
344
+ exports.setTransactionFeePayerSigner = setTransactionFeePayerSigner;
345
+ exports.signAndSendTransactionWithSigners = signAndSendTransactionWithSigners;
346
+ exports.signTransactionWithSigners = signTransactionWithSigners;
137
347
  //# sourceMappingURL=out.js.map
138
348
  //# sourceMappingURL=index.browser.cjs.map