@mysten/sui 1.28.2 → 1.29.1

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 (117) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +5 -4
  3. package/dist/cjs/client/client.d.ts +2 -1
  4. package/dist/cjs/client/client.js +7 -0
  5. package/dist/cjs/client/client.js.map +2 -2
  6. package/dist/cjs/experimental/core.d.ts +1 -1
  7. package/dist/cjs/experimental/core.js +3 -2
  8. package/dist/cjs/experimental/core.js.map +2 -2
  9. package/dist/cjs/experimental/transports/graphql.d.ts +26 -0
  10. package/dist/cjs/experimental/transports/graphql.js +310 -0
  11. package/dist/cjs/experimental/transports/graphql.js.map +7 -0
  12. package/dist/cjs/experimental/transports/jsonRPC.d.ts +5 -3
  13. package/dist/cjs/experimental/transports/jsonRPC.js +53 -105
  14. package/dist/cjs/experimental/transports/jsonRPC.js.map +3 -3
  15. package/dist/cjs/experimental/transports/utils.d.ts +6 -0
  16. package/dist/cjs/experimental/transports/utils.js +102 -0
  17. package/dist/cjs/experimental/transports/utils.js.map +7 -0
  18. package/dist/cjs/experimental/types.d.ts +21 -6
  19. package/dist/cjs/experimental/types.js.map +1 -1
  20. package/dist/cjs/faucet/faucet.d.ts +1 -1
  21. package/dist/cjs/faucet/faucet.js.map +1 -1
  22. package/dist/cjs/graphql/client.d.ts +10 -3
  23. package/dist/cjs/graphql/client.js +12 -4
  24. package/dist/cjs/graphql/client.js.map +3 -3
  25. package/dist/cjs/graphql/generated/queries.d.ts +5653 -0
  26. package/dist/cjs/graphql/generated/queries.js +722 -0
  27. package/dist/cjs/graphql/generated/queries.js.map +7 -0
  28. package/dist/cjs/multisig/publickey.d.ts +3 -3
  29. package/dist/cjs/multisig/publickey.js.map +2 -2
  30. package/dist/cjs/transactions/Commands.d.ts +2 -2
  31. package/dist/cjs/transactions/Commands.js.map +2 -2
  32. package/dist/cjs/transactions/Transaction.d.ts +10 -2
  33. package/dist/cjs/transactions/Transaction.js +165 -21
  34. package/dist/cjs/transactions/Transaction.js.map +3 -3
  35. package/dist/cjs/transactions/TransactionData.d.ts +4 -2
  36. package/dist/cjs/transactions/TransactionData.js +72 -41
  37. package/dist/cjs/transactions/TransactionData.js.map +2 -2
  38. package/dist/cjs/transactions/intents/CoinWithBalance.js.map +1 -1
  39. package/dist/cjs/verify/verify.d.ts +5 -5
  40. package/dist/cjs/verify/verify.js.map +2 -2
  41. package/dist/cjs/version.d.ts +2 -2
  42. package/dist/cjs/version.js +2 -2
  43. package/dist/cjs/version.js.map +1 -1
  44. package/dist/cjs/zklogin/publickey.d.ts +9 -3
  45. package/dist/cjs/zklogin/publickey.js +8 -30
  46. package/dist/cjs/zklogin/publickey.js.map +2 -2
  47. package/dist/esm/client/client.d.ts +2 -1
  48. package/dist/esm/client/client.js +7 -0
  49. package/dist/esm/client/client.js.map +2 -2
  50. package/dist/esm/experimental/core.d.ts +1 -1
  51. package/dist/esm/experimental/core.js +3 -2
  52. package/dist/esm/experimental/core.js.map +2 -2
  53. package/dist/esm/experimental/transports/graphql.d.ts +26 -0
  54. package/dist/esm/experimental/transports/graphql.js +303 -0
  55. package/dist/esm/experimental/transports/graphql.js.map +7 -0
  56. package/dist/esm/experimental/transports/jsonRPC.d.ts +5 -3
  57. package/dist/esm/experimental/transports/jsonRPC.js +52 -104
  58. package/dist/esm/experimental/transports/jsonRPC.js.map +2 -2
  59. package/dist/esm/experimental/transports/utils.d.ts +6 -0
  60. package/dist/esm/experimental/transports/utils.js +82 -0
  61. package/dist/esm/experimental/transports/utils.js.map +7 -0
  62. package/dist/esm/experimental/types.d.ts +21 -6
  63. package/dist/esm/faucet/faucet.d.ts +1 -1
  64. package/dist/esm/faucet/faucet.js.map +1 -1
  65. package/dist/esm/graphql/client.d.ts +10 -3
  66. package/dist/esm/graphql/client.js +12 -4
  67. package/dist/esm/graphql/client.js.map +2 -2
  68. package/dist/esm/graphql/generated/queries.d.ts +5653 -0
  69. package/dist/esm/graphql/generated/queries.js +702 -0
  70. package/dist/esm/graphql/generated/queries.js.map +7 -0
  71. package/dist/esm/multisig/publickey.d.ts +3 -3
  72. package/dist/esm/multisig/publickey.js.map +2 -2
  73. package/dist/esm/transactions/Commands.d.ts +2 -2
  74. package/dist/esm/transactions/Commands.js.map +2 -2
  75. package/dist/esm/transactions/Transaction.d.ts +10 -2
  76. package/dist/esm/transactions/Transaction.js +165 -21
  77. package/dist/esm/transactions/Transaction.js.map +3 -3
  78. package/dist/esm/transactions/TransactionData.d.ts +4 -2
  79. package/dist/esm/transactions/TransactionData.js +72 -41
  80. package/dist/esm/transactions/TransactionData.js.map +2 -2
  81. package/dist/esm/transactions/intents/CoinWithBalance.js.map +1 -1
  82. package/dist/esm/verify/verify.d.ts +5 -5
  83. package/dist/esm/verify/verify.js.map +2 -2
  84. package/dist/esm/version.d.ts +2 -2
  85. package/dist/esm/version.js +2 -2
  86. package/dist/esm/version.js.map +1 -1
  87. package/dist/esm/zklogin/publickey.d.ts +9 -3
  88. package/dist/esm/zklogin/publickey.js +8 -30
  89. package/dist/esm/zklogin/publickey.js.map +2 -2
  90. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  91. package/dist/tsconfig.tsbuildinfo +1 -1
  92. package/package.json +5 -2
  93. package/src/client/client.ts +10 -0
  94. package/src/experimental/core.ts +5 -2
  95. package/src/experimental/transports/graphql.ts +421 -0
  96. package/src/experimental/transports/jsonRPC.ts +47 -132
  97. package/src/experimental/transports/utils.ts +117 -0
  98. package/src/experimental/types.ts +30 -7
  99. package/src/faucet/faucet.ts +1 -1
  100. package/src/graphql/client.ts +21 -3
  101. package/src/graphql/generated/queries.ts +6061 -0
  102. package/src/graphql/queries/getAllBalances.graphql +20 -0
  103. package/src/graphql/queries/getBalance.graphql +14 -0
  104. package/src/graphql/queries/getCoins.graphql +29 -0
  105. package/src/graphql/queries/getDynamicFields.graphql +36 -0
  106. package/src/graphql/queries/getReferenceGasPrice.graphql +8 -0
  107. package/src/graphql/queries/objects.graphql +89 -0
  108. package/src/graphql/queries/transactions.graphql +80 -0
  109. package/src/graphql/queries/verifyZkLoginSignature.graphql +16 -0
  110. package/src/multisig/publickey.ts +3 -3
  111. package/src/transactions/Commands.ts +3 -2
  112. package/src/transactions/Transaction.ts +215 -12
  113. package/src/transactions/TransactionData.ts +86 -46
  114. package/src/transactions/intents/CoinWithBalance.ts +1 -1
  115. package/src/verify/verify.ts +6 -6
  116. package/src/version.ts +2 -2
  117. package/src/zklogin/publickey.ts +23 -39
@@ -0,0 +1,20 @@
1
+ # Copyright (c) Mysten Labs, Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ query getAllBalances($owner: SuiAddress!, $limit: Int, $cursor: String) {
5
+ address(address: $owner) {
6
+ balances(first: $limit, after: $cursor) {
7
+ pageInfo {
8
+ hasNextPage
9
+ endCursor
10
+ }
11
+ nodes {
12
+ coinType {
13
+ repr
14
+ }
15
+ coinObjectCount
16
+ totalBalance
17
+ }
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,14 @@
1
+ # Copyright (c) Mysten Labs, Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ query getBalance($owner: SuiAddress!, $type: String = "0x2::sui::SUI") {
5
+ address(address: $owner) {
6
+ balance(type: $type) {
7
+ coinType {
8
+ repr
9
+ }
10
+ coinObjectCount
11
+ totalBalance
12
+ }
13
+ }
14
+ }
@@ -0,0 +1,29 @@
1
+ # Copyright (c) Mysten Labs, Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ query getCoins($owner: SuiAddress!, $first: Int, $cursor: String, $type: String = "0x2::sui::SUI") {
5
+ address(address: $owner) {
6
+ address
7
+ coins(first: $first, after: $cursor, type: $type) {
8
+ pageInfo {
9
+ hasNextPage
10
+ endCursor
11
+ }
12
+ nodes {
13
+ coinBalance
14
+ owner {
15
+ ...OBJECT_OWNER_FIELDS
16
+ }
17
+ contents {
18
+ bcs
19
+ type {
20
+ repr
21
+ }
22
+ }
23
+ address
24
+ version
25
+ digest
26
+ }
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,36 @@
1
+ # Copyright (c) Mysten Labs, Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ query getDynamicFields($parentId: SuiAddress!, $first: Int, $cursor: String) {
5
+ owner(address: $parentId) {
6
+ dynamicFields(first: $first, after: $cursor) {
7
+ pageInfo {
8
+ hasNextPage
9
+ endCursor
10
+ }
11
+ nodes {
12
+ name {
13
+ bcs
14
+ type {
15
+ repr
16
+ }
17
+ }
18
+ value {
19
+ __typename
20
+ ... on MoveValue {
21
+ type {
22
+ repr
23
+ }
24
+ }
25
+ ... on MoveObject {
26
+ contents {
27
+ type {
28
+ repr
29
+ }
30
+ }
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,8 @@
1
+ # Copyright (c) Mysten Labs, Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ query getReferenceGasPrice {
5
+ epoch {
6
+ referenceGasPrice
7
+ }
8
+ }
@@ -0,0 +1,89 @@
1
+ # Copyright (c) Mysten Labs, Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ query getOwnedObjects($owner: SuiAddress!, $limit: Int, $cursor: String, $filter: ObjectFilter) {
5
+ address(address: $owner) {
6
+ objects(first: $limit, after: $cursor, filter: $filter) {
7
+ pageInfo {
8
+ hasNextPage
9
+ endCursor
10
+ }
11
+ nodes {
12
+ ...MOVE_OBJECT_FIELDS
13
+ }
14
+ }
15
+ }
16
+ }
17
+
18
+ query multiGetObjects($objectIds: [SuiAddress!]!, $limit: Int, $cursor: String) {
19
+ objects(first: $limit, after: $cursor, filter: { objectIds: $objectIds }) {
20
+ pageInfo {
21
+ hasNextPage
22
+ endCursor
23
+ }
24
+ nodes {
25
+ ...OBJECT_FIELDS
26
+ }
27
+ }
28
+ }
29
+
30
+ fragment OBJECT_FIELDS on Object {
31
+ address
32
+ digest
33
+ version
34
+ asMoveObject {
35
+ contents {
36
+ bcs
37
+ type {
38
+ repr
39
+ }
40
+ }
41
+ }
42
+ owner {
43
+ ...OBJECT_OWNER_FIELDS
44
+ }
45
+ }
46
+
47
+ fragment MOVE_OBJECT_FIELDS on MoveObject {
48
+ address
49
+ digest
50
+ version
51
+ contents {
52
+ bcs
53
+ type {
54
+ repr
55
+ }
56
+ }
57
+ owner {
58
+ ...OBJECT_OWNER_FIELDS
59
+ }
60
+ }
61
+
62
+ fragment OBJECT_OWNER_FIELDS on ObjectOwner {
63
+ __typename
64
+ ... on AddressOwner {
65
+ owner {
66
+ asObject {
67
+ address
68
+ }
69
+ asAddress {
70
+ address
71
+ }
72
+ }
73
+ }
74
+ ... on Parent {
75
+ parent {
76
+ address
77
+ }
78
+ }
79
+ ... on Shared {
80
+ initialSharedVersion
81
+ }
82
+ ... on ConsensusV2 {
83
+ authenticator {
84
+ ... on Address {
85
+ address
86
+ }
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,80 @@
1
+ # Copyright (c) Mysten Labs, Inc.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+
4
+ query dryRunTransactionBlock($txBytes: String!) {
5
+ dryRunTransactionBlock(txBytes: $txBytes) {
6
+ error
7
+ transaction {
8
+ ...TRANSACTION_FIELDS
9
+ }
10
+ }
11
+ }
12
+
13
+ mutation executeTransactionBlock($txBytes: String!, $signatures: [String!]!) {
14
+ executeTransactionBlock(txBytes: $txBytes, signatures: $signatures) {
15
+ errors
16
+ effects {
17
+ transactionBlock {
18
+ ...TRANSACTION_FIELDS
19
+ }
20
+ }
21
+ }
22
+ }
23
+
24
+ query getTransactionBlock($digest: String!) {
25
+ transactionBlock(digest: $digest) {
26
+ ...TRANSACTION_FIELDS
27
+ }
28
+ }
29
+
30
+ fragment TRANSACTION_FIELDS on TransactionBlock {
31
+ digest
32
+ bcs
33
+ signatures
34
+ effects {
35
+ bcs
36
+ unchangedSharedObjects {
37
+ nodes {
38
+ __typename
39
+ ... on SharedObjectRead {
40
+ object {
41
+ asMoveObject {
42
+ address
43
+ contents {
44
+ type {
45
+ repr
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ objectChanges {
54
+ nodes {
55
+ address
56
+ inputState {
57
+ version
58
+ asMoveObject {
59
+ address
60
+ contents {
61
+ type {
62
+ repr
63
+ }
64
+ }
65
+ }
66
+ }
67
+ outputState {
68
+ asMoveObject {
69
+ address
70
+ contents {
71
+ type {
72
+ repr
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,16 @@
1
+ query verifyZkLoginSignature(
2
+ $bytes: Base64!
3
+ $signature: Base64!
4
+ $intentScope: ZkLoginIntentScope!
5
+ $author: SuiAddress!
6
+ ) {
7
+ verifyZkloginSignature(
8
+ bytes: $bytes
9
+ signature: $signature
10
+ intentScope: $intentScope
11
+ author: $author
12
+ ) {
13
+ success
14
+ errors
15
+ }
16
+ }
@@ -14,10 +14,10 @@ import {
14
14
  } from '../cryptography/signature-scheme.js';
15
15
  import type { SignatureFlag, SignatureScheme } from '../cryptography/signature-scheme.js';
16
16
  import { parseSerializedSignature } from '../cryptography/signature.js';
17
- import type { SuiGraphQLClient } from '../graphql/client.js';
18
17
  import { normalizeSuiAddress } from '../utils/sui-types.js';
19
18
  // eslint-disable-next-line import/no-cycle
20
19
  import { publicKeyFromRawBytes } from '../verify/index.js';
20
+ import type { ZkLoginCompatibleClient } from '../zklogin/publickey.js';
21
21
  import { toZkLoginPublicIdentifier } from '../zklogin/publickey.js';
22
22
  import { MultiSigSigner } from './signer.js';
23
23
 
@@ -76,7 +76,7 @@ export class MultiSigPublicKey extends PublicKey {
76
76
  * MultiSig public key as buffer or base-64 encoded string
77
77
  */
78
78
  value: string | Uint8Array | MultiSigPublicKeyStruct,
79
- options: { client?: SuiGraphQLClient } = {},
79
+ options: { client?: ZkLoginCompatibleClient } = {},
80
80
  ) {
81
81
  super();
82
82
 
@@ -315,7 +315,7 @@ export class MultiSigPublicKey extends PublicKey {
315
315
  */
316
316
  export function parsePartialSignatures(
317
317
  multisig: MultiSigStruct,
318
- options: { client?: SuiGraphQLClient } = {},
318
+ options: { client?: ZkLoginCompatibleClient } = {},
319
319
  ): ParsedPartialMultiSigSignature[] {
320
320
  const res: ParsedPartialMultiSigSignature[] = new Array(multisig.sigs.length);
321
321
  for (let i = 0; i < multisig.sigs.length; i++) {
@@ -8,11 +8,12 @@ import { parse } from 'valibot';
8
8
  import { normalizeSuiObjectId } from '../utils/sui-types.js';
9
9
  import { Argument } from './data/internal.js';
10
10
  import type { CallArg, Command } from './data/internal.js';
11
- import type { Transaction } from './Transaction.js';
11
+ import type { AsyncTransactionThunk, Transaction } from './Transaction.js';
12
12
 
13
13
  export type TransactionArgument =
14
14
  | InferInput<typeof Argument>
15
- | ((tx: Transaction) => InferInput<typeof Argument>);
15
+ | ((tx: Transaction) => InferInput<typeof Argument>)
16
+ | AsyncTransactionThunk;
16
17
  export type TransactionInput = CallArg;
17
18
 
18
19
  // Keep in sync with constants in
@@ -29,11 +29,20 @@ import { getIdFromCallArg } from './utils.js';
29
29
 
30
30
  export type TransactionObjectArgument =
31
31
  | Exclude<InferInput<typeof Argument>, { Input: unknown; type?: 'pure' }>
32
- | ((tx: Transaction) => Exclude<InferInput<typeof Argument>, { Input: unknown; type?: 'pure' }>);
32
+ | ((tx: Transaction) => Exclude<InferInput<typeof Argument>, { Input: unknown; type?: 'pure' }>)
33
+ | AsyncTransactionThunk<TransactionResultArgument>;
33
34
 
34
35
  export type TransactionResult = Extract<Argument, { Result: unknown }> &
35
36
  Extract<Argument, { NestedResult: unknown }>[];
36
37
 
38
+ export type TransactionResultArgument =
39
+ | Extract<Argument, { Result: unknown }>
40
+ | readonly Extract<Argument, { NestedResult: unknown }>[];
41
+
42
+ export type AsyncTransactionThunk<
43
+ T extends TransactionResultArgument | void = TransactionResultArgument | void,
44
+ > = (tx: Transaction) => Promise<T | void>;
45
+
37
46
  function createTransactionResult(index: number, length = Infinity): TransactionResult {
38
47
  const baseResult = { $kind: 'Result' as const, Result: index };
39
48
 
@@ -128,6 +137,9 @@ function getGlobalPluginRegistry() {
128
137
  }
129
138
  }
130
139
 
140
+ type InputSection = (CallArg | InputSection)[];
141
+ type CommandSection = (Command | CommandSection)[];
142
+
131
143
  /**
132
144
  * Transaction Builder
133
145
  */
@@ -135,6 +147,11 @@ export class Transaction {
135
147
  #serializationPlugins: TransactionPlugin[];
136
148
  #buildPlugins: TransactionPlugin[];
137
149
  #intentResolvers = new Map<string, TransactionPlugin>();
150
+ #inputSection: InputSection = [];
151
+ #commandSection: CommandSection = [];
152
+ #availableResults: Set<number> = new Set();
153
+ #pendingPromises = new Set<Promise<unknown>>();
154
+ #added = new Map<(...args: any[]) => unknown, unknown>();
138
155
 
139
156
  /**
140
157
  * Converts from a serialize transaction kind (built with `build({ onlyTransactionKind: true })`) to a `Transaction` class.
@@ -147,6 +164,9 @@ export class Transaction {
147
164
  typeof serialized === 'string' ? fromBase64(serialized) : serialized,
148
165
  );
149
166
 
167
+ tx.#inputSection = tx.#data.inputs;
168
+ tx.#commandSection = tx.#data.commands;
169
+
150
170
  return tx;
151
171
  }
152
172
 
@@ -169,6 +189,9 @@ export class Transaction {
169
189
  newTransaction.#data = TransactionDataBuilder.restore(JSON.parse(transaction));
170
190
  }
171
191
 
192
+ newTransaction.#inputSection = newTransaction.#data.inputs;
193
+ newTransaction.#commandSection = newTransaction.#data.commands;
194
+
172
195
  return newTransaction;
173
196
  }
174
197
 
@@ -281,7 +304,7 @@ export class Transaction {
281
304
  enumerable: false,
282
305
  value: createPure<Argument>((value): Argument => {
283
306
  if (isSerializedBcs(value)) {
284
- return this.#data.addInput('pure', {
307
+ return this.#addInput('pure', {
285
308
  $kind: 'Pure',
286
309
  Pure: {
287
310
  bytes: value.toBase64(),
@@ -290,7 +313,7 @@ export class Transaction {
290
313
  }
291
314
 
292
315
  // TODO: we can also do some deduplication here
293
- return this.#data.addInput(
316
+ return this.#addInput(
294
317
  'pure',
295
318
  is(NormalizedCallArg, value)
296
319
  ? parse(NormalizedCallArg, value)
@@ -324,7 +347,7 @@ export class Transaction {
324
347
  > = createObjectMethods(
325
348
  (value: TransactionObjectInput): { $kind: 'Input'; Input: number; type?: 'object' } => {
326
349
  if (typeof value === 'function') {
327
- return this.object(value(this));
350
+ return this.object(this.add(value as (tx: Transaction) => TransactionObjectArgument));
328
351
  }
329
352
 
330
353
  if (typeof value === 'object' && is(Argument, value)) {
@@ -347,7 +370,7 @@ export class Transaction {
347
370
 
348
371
  return inserted
349
372
  ? { $kind: 'Input', Input: this.#data.inputs.indexOf(inserted), type: 'object' }
350
- : this.#data.addInput(
373
+ : this.#addInput(
351
374
  'object',
352
375
  typeof value === 'string'
353
376
  ? {
@@ -383,15 +406,106 @@ export class Transaction {
383
406
  return this.object(Inputs.SharedObjectRef(...args));
384
407
  }
385
408
 
409
+ #fork() {
410
+ const fork = new Transaction();
411
+
412
+ fork.#data = this.#data;
413
+ fork.#serializationPlugins = this.#serializationPlugins;
414
+ fork.#buildPlugins = this.#buildPlugins;
415
+ fork.#intentResolvers = this.#intentResolvers;
416
+ fork.#pendingPromises = this.#pendingPromises;
417
+ fork.#availableResults = new Set(this.#availableResults);
418
+ fork.#added = this.#added;
419
+ this.#inputSection.push(fork.#inputSection);
420
+ this.#commandSection.push(fork.#commandSection);
421
+
422
+ return fork;
423
+ }
424
+
386
425
  /** Add a transaction to the transaction */
387
- add<T = TransactionResult>(command: Command | ((tx: Transaction) => T)): T {
426
+
427
+ add<T extends Command>(command: T): TransactionResult;
428
+ add<T extends void | TransactionResultArgument | TransactionArgument | Command>(
429
+ thunk: (tx: Transaction) => T,
430
+ ): T;
431
+ add<T extends TransactionResultArgument | void>(
432
+ asyncTransactionThunk: AsyncTransactionThunk<T>,
433
+ ): T;
434
+ add(command: Command | AsyncTransactionThunk | ((tx: Transaction) => unknown)): unknown {
388
435
  if (typeof command === 'function') {
389
- return command(this);
436
+ if (this.#added.has(command)) {
437
+ return this.#added.get(command);
438
+ }
439
+
440
+ const fork = this.#fork();
441
+ const result = command(fork);
442
+
443
+ if (!(result && typeof result === 'object' && 'then' in result)) {
444
+ this.#availableResults = fork.#availableResults;
445
+ this.#added.set(command, result);
446
+ return result;
447
+ }
448
+
449
+ const placeholder = this.#addCommand({
450
+ $kind: '$Intent',
451
+ $Intent: {
452
+ name: 'AsyncTransactionThunk',
453
+ inputs: {},
454
+ data: {
455
+ result: null as TransactionResult | null,
456
+ },
457
+ },
458
+ });
459
+
460
+ this.#pendingPromises.add(
461
+ Promise.resolve(result as Promise<TransactionResult>).then((result) => {
462
+ placeholder.$Intent.data.result = result;
463
+ }),
464
+ );
465
+ const txResult = createTransactionResult(this.#data.commands.length - 1);
466
+ this.#added.set(command, txResult);
467
+ return txResult;
468
+ } else {
469
+ this.#addCommand(command);
390
470
  }
391
471
 
392
- const index = this.#data.commands.push(command);
472
+ return createTransactionResult(this.#data.commands.length - 1);
473
+ }
474
+
475
+ #addCommand<T extends Command>(command: T) {
476
+ const resultIndex = this.#data.commands.length;
477
+ this.#commandSection.push(command);
478
+ this.#availableResults.add(resultIndex);
479
+ this.#data.commands.push(command);
480
+
481
+ this.#data.mapCommandArguments(resultIndex, (arg) => {
482
+ if (arg.$kind === 'Result' && !this.#availableResults.has(arg.Result)) {
483
+ throw new Error(
484
+ `Result { Result: ${arg.Result} } is not available to use the current transaction`,
485
+ );
486
+ }
393
487
 
394
- return createTransactionResult(index - 1) as T;
488
+ if (arg.$kind === 'NestedResult' && !this.#availableResults.has(arg.NestedResult[0])) {
489
+ throw new Error(
490
+ `Result { NestedResult: [${arg.NestedResult[0]}, ${arg.NestedResult[1]}] } is not available to use the current transaction`,
491
+ );
492
+ }
493
+
494
+ if (arg.$kind === 'Input' && arg.Input >= this.#data.inputs.length) {
495
+ throw new Error(
496
+ `Input { Input: ${arg.Input} } references an input that does not exist in the current transaction`,
497
+ );
498
+ }
499
+
500
+ return arg;
501
+ });
502
+
503
+ return command;
504
+ }
505
+
506
+ #addInput<T extends 'pure' | 'object'>(type: T, input: CallArg) {
507
+ this.#inputSection.push(input);
508
+ return this.#data.addInput(type, input);
395
509
  }
396
510
 
397
511
  #normalizeTransactionArgument(arg: TransactionArgument | SerializedBcs<any>) {
@@ -404,7 +518,13 @@ export class Transaction {
404
518
 
405
519
  #resolveArgument(arg: TransactionArgument): Argument {
406
520
  if (typeof arg === 'function') {
407
- return parse(Argument, arg(this));
521
+ const resolved = this.add(arg as never);
522
+
523
+ if (typeof resolved === 'function') {
524
+ return this.#resolveArgument(resolved);
525
+ }
526
+
527
+ return parse(Argument, resolved);
408
528
  }
409
529
 
410
530
  return parse(Argument, arg);
@@ -423,8 +543,8 @@ export class Transaction {
423
543
  : this.#normalizeTransactionArgument(amount),
424
544
  ),
425
545
  );
426
- const index = this.#data.commands.push(command);
427
- return createTransactionResult(index - 1, amounts.length) as Extract<
546
+ this.#addCommand(command);
547
+ return createTransactionResult(this.#data.commands.length - 1, amounts.length) as Extract<
428
548
  Argument,
429
549
  { Result: unknown }
430
550
  > & {
@@ -611,9 +731,92 @@ export class Transaction {
611
731
  };
612
732
 
613
733
  await createNext(0)();
734
+
735
+ this.#inputSection = this.#data.inputs;
736
+ this.#commandSection = this.#data.commands;
737
+ }
738
+
739
+ async #waitForPendingTasks() {
740
+ while (this.#pendingPromises.size > 0) {
741
+ const newPromise = Promise.all(this.#pendingPromises);
742
+ this.#pendingPromises.clear();
743
+ this.#pendingPromises.add(newPromise);
744
+ await newPromise;
745
+ this.#pendingPromises.delete(newPromise);
746
+ }
747
+ }
748
+
749
+ #sortCommandsAndInputs() {
750
+ const unorderedCommands = this.#data.commands;
751
+ const unorderedInputs = this.#data.inputs;
752
+
753
+ const orderedCommands = (this.#commandSection as Command[]).flat(Infinity);
754
+ const orderedInputs = (this.#inputSection as CallArg[]).flat(Infinity);
755
+
756
+ if (orderedCommands.length !== unorderedCommands.length) {
757
+ throw new Error('Unexpected number of commands found in transaction data');
758
+ }
759
+
760
+ if (orderedInputs.length !== unorderedInputs.length) {
761
+ throw new Error('Unexpected number of inputs found in transaction data');
762
+ }
763
+
764
+ const filteredCommands = orderedCommands.filter(
765
+ (cmd) => cmd.$Intent?.name !== 'AsyncTransactionThunk',
766
+ );
767
+
768
+ this.#data.commands = filteredCommands;
769
+ this.#data.inputs = orderedInputs;
770
+ this.#commandSection = filteredCommands;
771
+ this.#inputSection = orderedInputs;
772
+
773
+ function getOriginalIndex(index: number): number {
774
+ const command = unorderedCommands[index];
775
+ if (command.$Intent?.name === 'AsyncTransactionThunk') {
776
+ const result = command.$Intent.data.result as TransactionResult | null;
777
+
778
+ if (result == null) {
779
+ throw new Error('AsyncTransactionThunk has not been resolved');
780
+ }
781
+
782
+ return getOriginalIndex(result.Result);
783
+ }
784
+
785
+ const updated = filteredCommands.indexOf(command);
786
+
787
+ if (updated === -1) {
788
+ throw new Error('Unable to find original index for command');
789
+ }
790
+
791
+ return updated;
792
+ }
793
+
794
+ this.#data.mapArguments((arg) => {
795
+ if (arg.$kind === 'Input') {
796
+ const updated = orderedInputs.indexOf(unorderedInputs[arg.Input]);
797
+
798
+ if (updated === -1) {
799
+ throw new Error('Input has not been resolved');
800
+ }
801
+
802
+ return { ...arg, Input: updated };
803
+ } else if (arg.$kind === 'Result') {
804
+ const updated = getOriginalIndex(arg.Result);
805
+
806
+ return { ...arg, Result: updated };
807
+ } else if (arg.$kind === 'NestedResult') {
808
+ const updated = getOriginalIndex(arg.NestedResult[0]);
809
+
810
+ return { ...arg, NestedResult: [updated, arg.NestedResult[1]] };
811
+ }
812
+
813
+ return arg;
814
+ });
614
815
  }
615
816
 
616
817
  async prepareForSerialization(options: SerializeTransactionOptions) {
818
+ await this.#waitForPendingTasks();
819
+ this.#sortCommandsAndInputs();
617
820
  const intents = new Set<string>();
618
821
  for (const command of this.#data.commands) {
619
822
  if (command.$Intent) {