@mysten/sui 2.16.3 → 2.18.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.
Files changed (138) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/bcs/bcs.d.mts +6 -6
  3. package/dist/bcs/index.d.mts +20 -20
  4. package/dist/graphql/generated/queries.d.mts.map +1 -1
  5. package/dist/graphql/generated/queries.mjs.map +1 -1
  6. package/dist/graphql/generated/tada-env.d.mts +82 -1
  7. package/dist/grpc/client.d.mts +2 -0
  8. package/dist/grpc/client.d.mts.map +1 -1
  9. package/dist/grpc/client.mjs +2 -0
  10. package/dist/grpc/client.mjs.map +1 -1
  11. package/dist/grpc/proto/google/protobuf/struct.mjs +1 -1
  12. package/dist/grpc/proto/google/protobuf/struct.mjs.map +1 -1
  13. package/dist/grpc/proto/google/rpc/status.mjs +1 -1
  14. package/dist/grpc/proto/google/rpc/status.mjs.map +1 -1
  15. package/dist/grpc/proto/sui/forking/v1alpha/forking_service.client.d.mts +66 -0
  16. package/dist/grpc/proto/sui/forking/v1alpha/forking_service.client.d.mts.map +1 -0
  17. package/dist/grpc/proto/sui/forking/v1alpha/forking_service.client.mjs +48 -0
  18. package/dist/grpc/proto/sui/forking/v1alpha/forking_service.client.mjs.map +1 -0
  19. package/dist/grpc/proto/sui/forking/v1alpha/forking_service.d.mts +135 -0
  20. package/dist/grpc/proto/sui/forking/v1alpha/forking_service.d.mts.map +1 -0
  21. package/dist/grpc/proto/sui/forking/v1alpha/forking_service.mjs +144 -0
  22. package/dist/grpc/proto/sui/forking/v1alpha/forking_service.mjs.map +1 -0
  23. package/dist/grpc/proto/sui/rpc/v2/checkpoint.mjs +1 -1
  24. package/dist/grpc/proto/sui/rpc/v2/checkpoint.mjs.map +1 -1
  25. package/dist/grpc/proto/sui/rpc/v2/checkpoint_contents.mjs +3 -3
  26. package/dist/grpc/proto/sui/rpc/v2/checkpoint_contents.mjs.map +1 -1
  27. package/dist/grpc/proto/sui/rpc/v2/checkpoint_summary.mjs +3 -3
  28. package/dist/grpc/proto/sui/rpc/v2/checkpoint_summary.mjs.map +1 -1
  29. package/dist/grpc/proto/sui/rpc/v2/effects.d.mts +71 -3
  30. package/dist/grpc/proto/sui/rpc/v2/effects.d.mts.map +1 -1
  31. package/dist/grpc/proto/sui/rpc/v2/effects.mjs +71 -5
  32. package/dist/grpc/proto/sui/rpc/v2/effects.mjs.map +1 -1
  33. package/dist/grpc/proto/sui/rpc/v2/event.mjs +1 -1
  34. package/dist/grpc/proto/sui/rpc/v2/event.mjs.map +1 -1
  35. package/dist/grpc/proto/sui/rpc/v2/executed_transaction.mjs +2 -2
  36. package/dist/grpc/proto/sui/rpc/v2/executed_transaction.mjs.map +1 -1
  37. package/dist/grpc/proto/sui/rpc/v2/ledger_service.client.d.mts +4 -4
  38. package/dist/grpc/proto/sui/rpc/v2/ledger_service.mjs +3 -3
  39. package/dist/grpc/proto/sui/rpc/v2/ledger_service.mjs.map +1 -1
  40. package/dist/grpc/proto/sui/rpc/v2/move_package.d.mts.map +1 -1
  41. package/dist/grpc/proto/sui/rpc/v2/move_package.mjs +13 -13
  42. package/dist/grpc/proto/sui/rpc/v2/move_package.mjs.map +1 -1
  43. package/dist/grpc/proto/sui/rpc/v2/move_package_service.client.d.mts +4 -4
  44. package/dist/grpc/proto/sui/rpc/v2/move_package_service.mjs +1 -1
  45. package/dist/grpc/proto/sui/rpc/v2/move_package_service.mjs.map +1 -1
  46. package/dist/grpc/proto/sui/rpc/v2/name_service.client.d.mts +4 -4
  47. package/dist/grpc/proto/sui/rpc/v2/object.d.mts.map +1 -1
  48. package/dist/grpc/proto/sui/rpc/v2/object.mjs +1 -1
  49. package/dist/grpc/proto/sui/rpc/v2/object.mjs.map +1 -1
  50. package/dist/grpc/proto/sui/rpc/v2/signature.mjs +3 -3
  51. package/dist/grpc/proto/sui/rpc/v2/signature.mjs.map +1 -1
  52. package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.client.d.mts +4 -4
  53. package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.d.mts.map +1 -1
  54. package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.mjs +1 -1
  55. package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.mjs.map +1 -1
  56. package/dist/grpc/proto/sui/rpc/v2/state_service.client.d.mts +4 -4
  57. package/dist/grpc/proto/sui/rpc/v2/state_service.d.mts.map +1 -1
  58. package/dist/grpc/proto/sui/rpc/v2/state_service.mjs +3 -3
  59. package/dist/grpc/proto/sui/rpc/v2/state_service.mjs.map +1 -1
  60. package/dist/grpc/proto/sui/rpc/v2/subscription_service.client.d.mts +4 -4
  61. package/dist/grpc/proto/sui/rpc/v2/system_state.mjs +2 -2
  62. package/dist/grpc/proto/sui/rpc/v2/system_state.mjs.map +1 -1
  63. package/dist/grpc/proto/sui/rpc/v2/transaction.d.mts.map +1 -1
  64. package/dist/grpc/proto/sui/rpc/v2/transaction.mjs +16 -16
  65. package/dist/grpc/proto/sui/rpc/v2/transaction.mjs.map +1 -1
  66. package/dist/grpc/proto/sui/rpc/v2/transaction_execution_service.mjs +4 -4
  67. package/dist/grpc/proto/sui/rpc/v2/transaction_execution_service.mjs.map +1 -1
  68. package/dist/grpc/proto/types.d.mts +3 -2
  69. package/dist/grpc/proto/types.mjs +11 -1
  70. package/dist/grpc/proto/types.mjs.map +1 -1
  71. package/dist/jsonRpc/types/params.d.mts +5 -5
  72. package/dist/transactions/Transaction.d.mts +25 -11
  73. package/dist/transactions/Transaction.d.mts.map +1 -1
  74. package/dist/transactions/Transaction.mjs +8 -3
  75. package/dist/transactions/Transaction.mjs.map +1 -1
  76. package/dist/transactions/index.d.mts +2 -2
  77. package/dist/version.mjs +1 -1
  78. package/dist/version.mjs.map +1 -1
  79. package/dist/zklogin/jwt-utils.d.mts.map +1 -1
  80. package/dist/zklogin/jwt-utils.mjs.map +1 -1
  81. package/dist/zklogin/utils.d.mts.map +1 -1
  82. package/dist/zklogin/utils.mjs +9 -0
  83. package/dist/zklogin/utils.mjs.map +1 -1
  84. package/docs/bcs.md +11 -6
  85. package/docs/clients/core.md +10 -9
  86. package/docs/clients/grpc.md +1 -1
  87. package/docs/index.md +176 -22
  88. package/docs/llms-index.md +6 -9
  89. package/docs/migrations/0.38.md +2 -2
  90. package/docs/migrations/sui-1.0.md +2 -2
  91. package/docs/migrations/sui-2.0/json-rpc-migration.md +76 -33
  92. package/docs/plugins.md +29 -5
  93. package/docs/transactions/basics.md +279 -0
  94. package/docs/transactions/coins-and-balances.md +293 -0
  95. package/docs/transactions/offline.md +192 -0
  96. package/docs/transactions/reference.md +380 -0
  97. package/docs/transactions/signing-and-execution.md +401 -0
  98. package/package.json +27 -27
  99. package/src/graphql/generated/queries.ts +46 -1
  100. package/src/graphql/generated/schema.graphql +49 -3
  101. package/src/graphql/generated/tada-env.ts +97 -1
  102. package/src/grpc/client.ts +3 -0
  103. package/src/grpc/proto/google/protobuf/struct.ts +1 -1
  104. package/src/grpc/proto/google/rpc/error_details.ts +4 -4
  105. package/src/grpc/proto/google/rpc/status.ts +1 -1
  106. package/src/grpc/proto/sui/forking/v1alpha/forking_service.client.ts +125 -0
  107. package/src/grpc/proto/sui/forking/v1alpha/forking_service.ts +230 -0
  108. package/src/grpc/proto/sui/rpc/v2/checkpoint.ts +1 -1
  109. package/src/grpc/proto/sui/rpc/v2/checkpoint_contents.ts +3 -3
  110. package/src/grpc/proto/sui/rpc/v2/checkpoint_summary.ts +3 -3
  111. package/src/grpc/proto/sui/rpc/v2/effects.ts +112 -6
  112. package/src/grpc/proto/sui/rpc/v2/event.ts +1 -1
  113. package/src/grpc/proto/sui/rpc/v2/executed_transaction.ts +2 -2
  114. package/src/grpc/proto/sui/rpc/v2/ledger_service.ts +3 -3
  115. package/src/grpc/proto/sui/rpc/v2/move_package.ts +19 -13
  116. package/src/grpc/proto/sui/rpc/v2/move_package_service.ts +1 -1
  117. package/src/grpc/proto/sui/rpc/v2/object.ts +7 -1
  118. package/src/grpc/proto/sui/rpc/v2/signature.ts +3 -3
  119. package/src/grpc/proto/sui/rpc/v2/signature_verification_service.ts +7 -1
  120. package/src/grpc/proto/sui/rpc/v2/state_service.ts +9 -3
  121. package/src/grpc/proto/sui/rpc/v2/system_state.ts +2 -2
  122. package/src/grpc/proto/sui/rpc/v2/transaction.ts +22 -16
  123. package/src/grpc/proto/sui/rpc/v2/transaction_execution_service.ts +4 -4
  124. package/src/grpc/proto/types.ts +1 -0
  125. package/src/jsonRpc/types/params.ts +5 -5
  126. package/src/transactions/Transaction.ts +36 -5
  127. package/src/transactions/index.ts +1 -0
  128. package/src/version.ts +1 -1
  129. package/src/zklogin/jwt-utils.ts +3 -0
  130. package/src/zklogin/utils.ts +17 -0
  131. package/docs/faucet.md +0 -26
  132. package/docs/hello-sui.md +0 -115
  133. package/docs/install.md +0 -61
  134. package/docs/transaction-building/basics.md +0 -299
  135. package/docs/transaction-building/gas.md +0 -61
  136. package/docs/transaction-building/intents.md +0 -62
  137. package/docs/transaction-building/offline.md +0 -73
  138. package/docs/transaction-building/sponsored-transactions.md +0 -22
@@ -0,0 +1,293 @@
1
+ # Coins and Balances
2
+
3
+ > Work with coin objects and address balances in transactions
4
+
5
+ Sui has two systems for holding fungible token balances: coin objects and address balances.
6
+
7
+ **Coin objects** are individual onchain objects, each with its own ID, version, and balance. You own
8
+ specific coin objects and need to split, merge, and track them.
9
+
10
+ **Address balances** are an accumulator per address per coin type. There are no objects to manage
11
+ because deposits automatically merge into a single balance, and you withdraw from it as needed.
12
+
13
+ Both systems coexist. An address's total balance for a given coin type is the sum of its coin object
14
+ balances and its address balance.
15
+
16
+ Address balances have no object versions. When a transaction has no versioned object inputs (for
17
+ example, a balance transfer built entirely from address balance withdrawals), it won't be
18
+ invalidated by other transactions from the same address executing concurrently.
19
+
20
+ ## `tx.coin` and `tx.balance`
21
+
22
+ `tx.coin()` and `tx.balance()` are the recommended ways to get tokens in a transaction. They
23
+ automatically draw from both coin objects and address balances.
24
+
25
+ ### Getting a `Coin`
26
+
27
+ `tx.coin()` produces a `Coin<T>`. Use it for transfers and most operations:
28
+
29
+ ```tsx
30
+
31
+ const tx = new Transaction();
32
+
33
+ // SUI (balance is in MIST — 1 SUI = 1,000,000,000 MIST)
34
+ tx.transferObjects([tx.coin({ balance: 1_000_000_000n })], '0xRecipientAddress');
35
+
36
+ // Another coin type
37
+ tx.transferObjects(
38
+ [tx.coin({ balance: 1_000_000n, type: '0xPackageId::module::CoinType' })],
39
+ '0xRecipientAddress',
40
+ );
41
+ ```
42
+
43
+ ### Getting a `Balance`
44
+
45
+ `tx.balance()` produces a `Balance<T>`. Use it for Move functions that expect a balance directly, or
46
+ for gasless transactions:
47
+
48
+ ```tsx
49
+ const tx = new Transaction();
50
+
51
+ tx.moveCall({
52
+ target: '0xPackage::module::deposit',
53
+ arguments: [tx.object('0xPoolId'), tx.balance({ balance: 1_000_000_000n })],
54
+ });
55
+ ```
56
+
57
+ ### Sending to address balances
58
+
59
+ To deposit tokens into a recipient's address balance (instead of creating a coin object), use
60
+ `tx.balance()` with `balance::send_funds`:
61
+
62
+ ```tsx
63
+ const tx = new Transaction();
64
+
65
+ tx.moveCall({
66
+ target: '0x2::balance::send_funds',
67
+ typeArguments: ['0x2::sui::SUI'],
68
+ arguments: [tx.balance({ balance: 1_000_000_000n }), tx.pure.address('0xRecipientAddress')],
69
+ });
70
+ ```
71
+
72
+ > **Note:** Transactions built entirely from `tx.balance()` and gasless-eligible Move calls like `send_funds`
73
+ > and `redeem_funds` might qualify as [gasless transactions](#gasless-transactions).
74
+
75
+ ### Options
76
+
77
+ | Option | Type | Default | Description |
78
+ | ------------ | ------------------ | ---------- | ------------------------------------------------------------------------ |
79
+ | `balance` | `bigint \| number` | _required_ | Amount in base units (MIST for SUI) |
80
+ | `type` | `string` | SUI | Coin type. Defaults to `0x2::sui::SUI` |
81
+ | `useGasCoin` | `boolean` | `true` | For SUI, split from the gas coin. Set `false` for sponsored transactions |
82
+
83
+ For SUI, `tx.coin()` splits from the gas coin by default. For sponsored transactions where the gas
84
+ coin belongs to the sponsor, set `useGasCoin: false`:
85
+
86
+ ```tsx
87
+ tx.transferObjects([tx.coin({ balance: 100n, useGasCoin: false })], recipient);
88
+ ```
89
+
90
+ ### `coinWithBalance`
91
+
92
+ `coinWithBalance()` is a standalone alias for `tx.coin()`:
93
+
94
+ ```tsx
95
+
96
+ const tx = new Transaction();
97
+ tx.transferObjects([coinWithBalance({ balance: 1_000_000_000 })], recipient);
98
+ ```
99
+
100
+ ## How resolution works
101
+
102
+ When you call `tx.coin()` or `tx.balance()`, the SDK adds a placeholder intent to the transaction.
103
+ At build time, the resolver replaces it with concrete commands based on the sender's funds:
104
+
105
+ - **`tx.balance()` with sufficient address balance:** Uses a direct `FundsWithdrawal` through
106
+ `balance::redeem_funds`. No coin objects are used, so the transaction has no versioned object
107
+ inputs from this intent, keeping it eligible for parallel execution.
108
+
109
+ - **Otherwise, coins are needed:** Fetches the sender's coin objects and address balance in
110
+ parallel. Merges available coins (topping up from address balance if needed), then splits the
111
+ exact amounts. For `tx.balance()` intents, the split results are converted to `Balance<T>` through
112
+ `coin::into_balance`, and any remainder is returned to the sender's address balance through
113
+ `coin::send_funds`.
114
+
115
+ The resolver prefers address balances when possible to avoid introducing versioned object
116
+ dependencies.
117
+
118
+ Zero-balance requests resolve to `balance::zero` or `coin::zero` with no network lookups.
119
+
120
+ ## Checking balances
121
+
122
+ Use `getBalance` to see both coin objects and address balance:
123
+
124
+ ```tsx
125
+ const { balance } = await grpcClient.getBalance({
126
+ owner: '0xMyAddress',
127
+ });
128
+
129
+ console.log(balance.balance); // total balance as string (coin objects + address balance)
130
+ console.log(balance.coinBalance); // balance from coin objects only
131
+ console.log(balance.addressBalance); // balance from address balance only
132
+ console.log(balance.coinType); // e.g. "0x2::sui::SUI"
133
+ ```
134
+
135
+ All balance values are returned as strings. Use `BigInt(balance.balance)` for arithmetic.
136
+
137
+ ## Manual coin operations
138
+
139
+ For fine-grained control, you can split and merge coins manually.
140
+
141
+ ### Splitting coins
142
+
143
+ `splitCoins` creates new coins from an existing coin:
144
+
145
+ ```tsx
146
+ const tx = new Transaction();
147
+
148
+ // Split specific amounts from a coin you own
149
+ const [coin1, coin2] = tx.splitCoins('0xMyCoinId', [1_000_000, 2_000_000]);
150
+
151
+ tx.transferObjects([coin1], '0xAlice');
152
+ tx.transferObjects([coin2], '0xBob');
153
+ ```
154
+
155
+ Split the gas coin for SUI:
156
+
157
+ ```tsx
158
+ const [coin] = tx.splitCoins(tx.gas, [1_000_000_000]);
159
+ tx.transferObjects([coin], '0xRecipientAddress');
160
+ ```
161
+
162
+ ### Merging coins
163
+
164
+ `mergeCoins` combines multiple coins into one:
165
+
166
+ ```tsx
167
+ const tx = new Transaction();
168
+
169
+ tx.mergeCoins('0xCoin1', ['0xCoin2', '0xCoin3']);
170
+ ```
171
+
172
+ ## Working with address balances directly
173
+
174
+ ### Withdrawing from address balance
175
+
176
+ Create a withdrawal input and redeem it to get a `Coin<T>`:
177
+
178
+ ```tsx
179
+ const tx = new Transaction();
180
+
181
+ const [coin] = tx.moveCall({
182
+ target: '0x2::coin::redeem_funds',
183
+ typeArguments: ['0x2::sui::SUI'],
184
+ arguments: [tx.withdrawal({ amount: 1_000_000_000 })],
185
+ });
186
+
187
+ tx.transferObjects([coin], '0xRecipientAddress');
188
+ ```
189
+
190
+ Or get a `Balance<T>` directly:
191
+
192
+ ```tsx
193
+ const [balance] = tx.moveCall({
194
+ target: '0x2::balance::redeem_funds',
195
+ typeArguments: ['0x2::sui::SUI'],
196
+ arguments: [tx.withdrawal({ amount: 1_000_000_000 })],
197
+ });
198
+ ```
199
+
200
+ For non-SUI coin types, pass the `type` parameter:
201
+
202
+ ```tsx
203
+ const [coin] = tx.moveCall({
204
+ target: '0x2::coin::redeem_funds',
205
+ typeArguments: ['0xPackageId::module::USDC'],
206
+ arguments: [tx.withdrawal({ amount: 1_000_000, type: '0xPackageId::module::USDC' })],
207
+ });
208
+ ```
209
+
210
+ ### Depositing into address balances
211
+
212
+ Use `coin::send_funds` to deposit a coin into a recipient's address balance:
213
+
214
+ ```tsx
215
+ const tx = new Transaction();
216
+
217
+ tx.moveCall({
218
+ target: '0x2::coin::send_funds',
219
+ typeArguments: ['0x2::sui::SUI'],
220
+ arguments: [tx.object('0xMyCoinObjectId'), tx.pure.address('0xRecipientAddress')],
221
+ });
222
+ ```
223
+
224
+ ## Listing coin objects
225
+
226
+ Use `listCoins` to see specific coin objects:
227
+
228
+ ```tsx
229
+ const { objects, hasNextPage, cursor } = await grpcClient.listCoins({
230
+ owner: '0xMyAddress',
231
+ });
232
+
233
+ for (const coin of objects) {
234
+ console.log(coin.objectId, coin.balance);
235
+ }
236
+ ```
237
+
238
+ ## Gasless transactions
239
+
240
+ Gasless transactions enable peer-to-peer payments of qualified stablecoins to execute without paying
241
+ gas fees in SUI. The sender does not need to hold SUI in their wallet. Gasless transactions are an
242
+ extension of
243
+ [address balances](https://docs.sui.io/onchain-finance/asset-custody/address-balances/using-address-balances),
244
+ built around `0x2::balance::send_funds` with `gasPrice = 0` and `gasBudget = 0` on the transaction.
245
+ See the
246
+ [Sui gasless stablecoin transfers guide](https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers)
247
+ for full details, including the current
248
+ [allowlist of eligible stablecoins](https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers#eligible-stablecoins).
249
+
250
+ Gasless transactions are limited to transactions that send funds as balances for specific
251
+ allowlisted stablecoins. Using `0x2::balance::send_funds` with `tx.balance()` is the recommended way
252
+ to build gasless transactions with the TypeScript SDK.
253
+
254
+ ### SDK support (gRPC and GraphQL)
255
+
256
+ When using the gRPC or GraphQL transports, transactions that qualify are automatically detected, and
257
+ the gas price is set when the transaction is built.
258
+
259
+ ```tsx
260
+
261
+ const client = new SuiGrpcClient({ url: 'https://grpc.mainnet.sui.io:443' });
262
+
263
+ // Mainnet USDC. For the full set of allowlisted gasless stablecoins, see:
264
+ // https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers#eligible-stablecoins
265
+ const USDC = '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC';
266
+
267
+ const tx = new Transaction();
268
+ tx.setSender(keypair.toSuiAddress());
269
+
270
+ tx.moveCall({
271
+ target: '0x2::balance::send_funds',
272
+ typeArguments: [USDC],
273
+ arguments: [tx.balance({ type: USDC, balance: 1_000_000 }), tx.pure.address(recipient)],
274
+ });
275
+
276
+ const result = await client.signAndExecuteTransaction({
277
+ transaction: tx,
278
+ signer: keypair,
279
+ });
280
+ ```
281
+
282
+ The JSON-RPC transport does not automatically detect gasless eligibility. You can opt in by setting
283
+ the gas price to zero with `tx.setGasPrice(0)`, but only after confirming the coin type is on the
284
+ [allowlist](https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers#eligible-stablecoins)
285
+ and the PTB shape is eligible. Otherwise the transaction fails at validation.
286
+
287
+ > **Warning:** If your wallet builds transactions with gRPC but executes through a different transport (for
288
+ > example, dapp-kit wallets that still execute over JSON-RPC), pass the gRPC client to `build` so
289
+ > the gas price still gets set correctly:
290
+ >
291
+ > ```tsx
292
+ > const bytes = await tx.build({ client: grpcClient });
293
+ > ```
@@ -0,0 +1,192 @@
1
+ # Building Offline
2
+
3
+ > Build transactions without a network connection
4
+
5
+ Normally the SDK resolves object versions, estimates gas, and fills in other details by querying the
6
+ network. For offline building of backend services, air-gapped signing, or pre-built transactions,
7
+ you must provide this information yourself. See also the Sui documentation on
8
+ [offline signing](https://docs.sui.io/guides/developer/transactions/transaction-auth/offline-signing)
9
+ for the protocol-level details.
10
+
11
+ ## Transactions without owned object inputs
12
+
13
+ When your transaction only uses shared objects, party objects, and/or address balance withdrawals,
14
+ there are no owned object versions to look up. Use `tx.withdrawal()` directly instead of `tx.coin()`
15
+ or `coinWithBalance` because they require a client to resolve coin objects at build time.
16
+
17
+ ```typescript
18
+
19
+ const tx = new Transaction();
20
+
21
+ // Use tx.withdrawal() + coin::redeem_funds to withdraw from address balance.
22
+ // No coin object lookups needed — fully offline.
23
+ const [coin] = tx.moveCall({
24
+ target: '0x2::coin::redeem_funds',
25
+ typeArguments: ['0x2::sui::SUI'],
26
+ arguments: [tx.withdrawal({ amount: 1_000_000_000 })],
27
+ });
28
+ tx.transferObjects([coin], '0xRecipientAddress');
29
+
30
+ // Shared/party objects only need objectId + initialSharedVersion (both stable)
31
+ tx.moveCall({
32
+ target: '0xPackage::module::function',
33
+ arguments: [
34
+ tx.sharedObjectRef({
35
+ objectId: '0xSharedObjectId',
36
+ initialSharedVersion: '1',
37
+ mutable: true,
38
+ }),
39
+ ],
40
+ });
41
+
42
+ // Required configuration for all offline builds
43
+ tx.setSender('0xSenderAddress');
44
+ tx.setGasPrice(1000); // query getReferenceGasPrice() beforehand, or use a known value
45
+ tx.setGasBudget(50_000_000);
46
+ tx.setGasPayment([]); // empty array = pay gas from address balance
47
+
48
+ // Expiration is required when there are no owned objects for gas or inputs
49
+ tx.setExpiration({
50
+ ValidDuring: {
51
+ minEpoch: 100, // current epoch
52
+ maxEpoch: 101, // current epoch + 1
53
+ minTimestamp: null,
54
+ maxTimestamp: null,
55
+ chain: 'mainnet', // or 'testnet', 'devnet'
56
+ nonce: 0,
57
+ },
58
+ });
59
+
60
+ // Build without a client
61
+ const bytes = await tx.build();
62
+ ```
63
+
64
+ This enables fully stateless construction. You only need the sender address, reference gas price,
65
+ epoch, and chain identifier.
66
+
67
+ ## Party objects
68
+
69
+ Party objects are address-owned but consensus-versioned, with per-address permissions. They are
70
+ referenced the same way as shared objects:
71
+
72
+ ```typescript
73
+ tx.sharedObjectRef({
74
+ objectId: '0xPartyObjectId',
75
+ initialSharedVersion: '1',
76
+ mutable: true,
77
+ });
78
+ ```
79
+
80
+ Key properties for offline building:
81
+
82
+ - **No version lookup needed**: `initialSharedVersion` is stable and set once when the object
83
+ becomes a party object
84
+ - **Enable pipelining**: Submit multiple transactions on the same party object without waiting for
85
+ each one to finalize
86
+ - **Cannot be used for gas**: Use address balance for gas payment (`setGasPayment([])`)
87
+
88
+ ## Transactions with owned object inputs
89
+
90
+ When your transaction uses owned or immutable objects, you must provide the exact version and digest
91
+ for each one:
92
+
93
+ ```typescript
94
+
95
+ const tx = new Transaction();
96
+
97
+ // Owned objects need exact version and digest
98
+ tx.transferObjects(
99
+ [
100
+ tx.objectRef({
101
+ objectId: '0xOwnedObjectId',
102
+ version: '42',
103
+ digest: 'abc123...',
104
+ }),
105
+ ],
106
+ '0xRecipientAddress',
107
+ );
108
+
109
+ // Receiving objects also need exact version and digest
110
+ tx.moveCall({
111
+ target: '0xPackage::module::receive',
112
+ arguments: [
113
+ tx.objectRef({
114
+ objectId: '0xParentId',
115
+ version: '10',
116
+ digest: 'def456...',
117
+ }),
118
+ tx.receivingRef({
119
+ objectId: '0xReceivingId',
120
+ version: '5',
121
+ digest: 'ghi789...',
122
+ }),
123
+ ],
124
+ });
125
+
126
+ // Gas payment with specific coin objects
127
+ tx.setGasPayment([{ objectId: '0xGasCoinId', version: '3', digest: 'jkl012...' }]);
128
+
129
+ tx.setSender('0xSenderAddress');
130
+ tx.setGasPrice(1000);
131
+ tx.setGasBudget(50_000_000);
132
+
133
+ const bytes = await tx.build();
134
+ ```
135
+
136
+ ## Required configuration for all offline builds
137
+
138
+ Every offline-built transaction must have the following:
139
+
140
+ | Method | Description |
141
+ | ----------------- | --------------------------------------------------------------- |
142
+ | `setSender()` | The address executing the transaction |
143
+ | `setGasPrice()` | Reference gas price (query `getReferenceGasPrice()` beforehand) |
144
+ | `setGasBudget()` | Maximum gas to spend (in MIST) |
145
+ | `setGasPayment()` | Coin object references, or `[]` for address balance |
146
+
147
+ ### Expiration
148
+
149
+ Set an expiration when your transaction uses no owned objects for gas or inputs. This applies when
150
+ you use address balances for gas (`setGasPayment([])`) with only shared and party object inputs:
151
+
152
+ ```typescript
153
+ tx.setExpiration({
154
+ ValidDuring: {
155
+ minEpoch: 100, // current epoch
156
+ maxEpoch: 101, // typically current epoch + 1
157
+ minTimestamp: null,
158
+ maxTimestamp: null,
159
+ chain: 'mainnet',
160
+ nonce: 0, // increment for multiple transactions in the same epoch
161
+ },
162
+ });
163
+ ```
164
+
165
+ You can also use epoch-based expiration:
166
+
167
+ ```typescript
168
+ tx.setExpiration({ Epoch: 100 });
169
+ ```
170
+
171
+ > **Note:** When building with a client, the SDK sets expiration automatically. You only need the manual
172
+ > configuration above for fully offline builds.
173
+
174
+ ## Serialization
175
+
176
+ ### Building to bytes
177
+
178
+ ```typescript
179
+ // Build to BCS bytes (Uint8Array) — fully offline, all data must be provided
180
+ const bytes = await tx.build();
181
+
182
+ // Build with a client — only makes network requests when there is unresolved data to look up
183
+ const bytes = await tx.build({ client: grpcClient });
184
+ ```
185
+
186
+ ### Converting bytes back to a Transaction
187
+
188
+ ```typescript
189
+ const tx = Transaction.from(bytes);
190
+ ```
191
+
192
+ This works with BCS byte arrays, base64-encoded strings, and JSON strings (from `toJSON()`).