@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.
- package/CHANGELOG.md +36 -0
- package/dist/bcs/bcs.d.mts +6 -6
- package/dist/bcs/index.d.mts +20 -20
- package/dist/graphql/generated/queries.d.mts.map +1 -1
- package/dist/graphql/generated/queries.mjs.map +1 -1
- package/dist/graphql/generated/tada-env.d.mts +82 -1
- package/dist/grpc/client.d.mts +2 -0
- package/dist/grpc/client.d.mts.map +1 -1
- package/dist/grpc/client.mjs +2 -0
- package/dist/grpc/client.mjs.map +1 -1
- package/dist/grpc/proto/google/protobuf/struct.mjs +1 -1
- package/dist/grpc/proto/google/protobuf/struct.mjs.map +1 -1
- package/dist/grpc/proto/google/rpc/status.mjs +1 -1
- package/dist/grpc/proto/google/rpc/status.mjs.map +1 -1
- package/dist/grpc/proto/sui/forking/v1alpha/forking_service.client.d.mts +66 -0
- package/dist/grpc/proto/sui/forking/v1alpha/forking_service.client.d.mts.map +1 -0
- package/dist/grpc/proto/sui/forking/v1alpha/forking_service.client.mjs +48 -0
- package/dist/grpc/proto/sui/forking/v1alpha/forking_service.client.mjs.map +1 -0
- package/dist/grpc/proto/sui/forking/v1alpha/forking_service.d.mts +135 -0
- package/dist/grpc/proto/sui/forking/v1alpha/forking_service.d.mts.map +1 -0
- package/dist/grpc/proto/sui/forking/v1alpha/forking_service.mjs +144 -0
- package/dist/grpc/proto/sui/forking/v1alpha/forking_service.mjs.map +1 -0
- package/dist/grpc/proto/sui/rpc/v2/checkpoint.mjs +1 -1
- package/dist/grpc/proto/sui/rpc/v2/checkpoint.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/checkpoint_contents.mjs +3 -3
- package/dist/grpc/proto/sui/rpc/v2/checkpoint_contents.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/checkpoint_summary.mjs +3 -3
- package/dist/grpc/proto/sui/rpc/v2/checkpoint_summary.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/effects.d.mts +71 -3
- package/dist/grpc/proto/sui/rpc/v2/effects.d.mts.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/effects.mjs +71 -5
- package/dist/grpc/proto/sui/rpc/v2/effects.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/event.mjs +1 -1
- package/dist/grpc/proto/sui/rpc/v2/event.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/executed_transaction.mjs +2 -2
- package/dist/grpc/proto/sui/rpc/v2/executed_transaction.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/ledger_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/ledger_service.mjs +3 -3
- package/dist/grpc/proto/sui/rpc/v2/ledger_service.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/move_package.d.mts.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/move_package.mjs +13 -13
- package/dist/grpc/proto/sui/rpc/v2/move_package.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/move_package_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/move_package_service.mjs +1 -1
- package/dist/grpc/proto/sui/rpc/v2/move_package_service.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/name_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/object.d.mts.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/object.mjs +1 -1
- package/dist/grpc/proto/sui/rpc/v2/object.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/signature.mjs +3 -3
- package/dist/grpc/proto/sui/rpc/v2/signature.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.d.mts.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.mjs +1 -1
- package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/state_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/state_service.d.mts.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/state_service.mjs +3 -3
- package/dist/grpc/proto/sui/rpc/v2/state_service.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/subscription_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/system_state.mjs +2 -2
- package/dist/grpc/proto/sui/rpc/v2/system_state.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/transaction.d.mts.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/transaction.mjs +16 -16
- package/dist/grpc/proto/sui/rpc/v2/transaction.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/transaction_execution_service.mjs +4 -4
- package/dist/grpc/proto/sui/rpc/v2/transaction_execution_service.mjs.map +1 -1
- package/dist/grpc/proto/types.d.mts +3 -2
- package/dist/grpc/proto/types.mjs +11 -1
- package/dist/grpc/proto/types.mjs.map +1 -1
- package/dist/jsonRpc/types/params.d.mts +5 -5
- package/dist/transactions/Transaction.d.mts +25 -11
- package/dist/transactions/Transaction.d.mts.map +1 -1
- package/dist/transactions/Transaction.mjs +8 -3
- package/dist/transactions/Transaction.mjs.map +1 -1
- package/dist/transactions/index.d.mts +2 -2
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/dist/zklogin/jwt-utils.d.mts.map +1 -1
- package/dist/zklogin/jwt-utils.mjs.map +1 -1
- package/dist/zklogin/utils.d.mts.map +1 -1
- package/dist/zklogin/utils.mjs +9 -0
- package/dist/zklogin/utils.mjs.map +1 -1
- package/docs/bcs.md +11 -6
- package/docs/clients/core.md +10 -9
- package/docs/clients/grpc.md +1 -1
- package/docs/index.md +176 -22
- package/docs/llms-index.md +6 -9
- package/docs/migrations/0.38.md +2 -2
- package/docs/migrations/sui-1.0.md +2 -2
- package/docs/migrations/sui-2.0/json-rpc-migration.md +76 -33
- package/docs/plugins.md +29 -5
- package/docs/transactions/basics.md +279 -0
- package/docs/transactions/coins-and-balances.md +293 -0
- package/docs/transactions/offline.md +192 -0
- package/docs/transactions/reference.md +380 -0
- package/docs/transactions/signing-and-execution.md +401 -0
- package/package.json +27 -27
- package/src/graphql/generated/queries.ts +46 -1
- package/src/graphql/generated/schema.graphql +49 -3
- package/src/graphql/generated/tada-env.ts +97 -1
- package/src/grpc/client.ts +3 -0
- package/src/grpc/proto/google/protobuf/struct.ts +1 -1
- package/src/grpc/proto/google/rpc/error_details.ts +4 -4
- package/src/grpc/proto/google/rpc/status.ts +1 -1
- package/src/grpc/proto/sui/forking/v1alpha/forking_service.client.ts +125 -0
- package/src/grpc/proto/sui/forking/v1alpha/forking_service.ts +230 -0
- package/src/grpc/proto/sui/rpc/v2/checkpoint.ts +1 -1
- package/src/grpc/proto/sui/rpc/v2/checkpoint_contents.ts +3 -3
- package/src/grpc/proto/sui/rpc/v2/checkpoint_summary.ts +3 -3
- package/src/grpc/proto/sui/rpc/v2/effects.ts +112 -6
- package/src/grpc/proto/sui/rpc/v2/event.ts +1 -1
- package/src/grpc/proto/sui/rpc/v2/executed_transaction.ts +2 -2
- package/src/grpc/proto/sui/rpc/v2/ledger_service.ts +3 -3
- package/src/grpc/proto/sui/rpc/v2/move_package.ts +19 -13
- package/src/grpc/proto/sui/rpc/v2/move_package_service.ts +1 -1
- package/src/grpc/proto/sui/rpc/v2/object.ts +7 -1
- package/src/grpc/proto/sui/rpc/v2/signature.ts +3 -3
- package/src/grpc/proto/sui/rpc/v2/signature_verification_service.ts +7 -1
- package/src/grpc/proto/sui/rpc/v2/state_service.ts +9 -3
- package/src/grpc/proto/sui/rpc/v2/system_state.ts +2 -2
- package/src/grpc/proto/sui/rpc/v2/transaction.ts +22 -16
- package/src/grpc/proto/sui/rpc/v2/transaction_execution_service.ts +4 -4
- package/src/grpc/proto/types.ts +1 -0
- package/src/jsonRpc/types/params.ts +5 -5
- package/src/transactions/Transaction.ts +36 -5
- package/src/transactions/index.ts +1 -0
- package/src/version.ts +1 -1
- package/src/zklogin/jwt-utils.ts +3 -0
- package/src/zklogin/utils.ts +17 -0
- package/docs/faucet.md +0 -26
- package/docs/hello-sui.md +0 -115
- package/docs/install.md +0 -61
- package/docs/transaction-building/basics.md +0 -299
- package/docs/transaction-building/gas.md +0 -61
- package/docs/transaction-building/intents.md +0 -62
- package/docs/transaction-building/offline.md +0 -73
- package/docs/transaction-building/sponsored-transactions.md +0 -22
|
@@ -92,22 +92,26 @@ These JSON-RPC methods have direct replacements in the core API:
|
|
|
92
92
|
|
|
93
93
|
These JSON-RPC methods can be replaced by calling gRPC service clients directly:
|
|
94
94
|
|
|
95
|
-
| JSON-RPC Method | gRPC Service Replacement
|
|
96
|
-
| ----------------------------------- |
|
|
97
|
-
| `getCheckpoint` | `ledgerService.getCheckpoint`
|
|
98
|
-
| `
|
|
99
|
-
| `
|
|
100
|
-
| `
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
|
|
95
|
+
| JSON-RPC Method | gRPC Service Replacement |
|
|
96
|
+
| ----------------------------------- | ---------------------------------------------------------------- |
|
|
97
|
+
| `getCheckpoint` | `ledgerService.getCheckpoint` |
|
|
98
|
+
| `getLatestCheckpointSequenceNumber` | `ledgerService.getServiceInfo` (read `checkpointHeight`) |
|
|
99
|
+
| `getCurrentEpoch` | `ledgerService.getEpoch` (omit `epoch` for the current) |
|
|
100
|
+
| `getLatestSuiSystemState` | `ledgerService.getEpoch` with `system_state` in the read mask |
|
|
101
|
+
| `getCommitteeInfo` | `ledgerService.getEpoch` with `committee` in the read mask |
|
|
102
|
+
| `getProtocolConfig` | `ledgerService.getEpoch` with `protocol_config` in the read mask |
|
|
103
|
+
| `getCoinMetadata` | `stateService.getCoinInfo` (response includes `metadata`) |
|
|
104
|
+
| `getTotalSupply` | `stateService.getCoinInfo` (response includes `treasury`) |
|
|
105
|
+
| `getNormalizedMoveModule` | `movePackageService.getPackage` (response includes all modules) |
|
|
106
|
+
| `getNormalizedMoveModulesByPackage` | `movePackageService.getPackage` |
|
|
107
|
+
| `getNormalizedMoveStruct` | `movePackageService.getDatatype` |
|
|
108
|
+
| `resolveNameServiceAddress` | `nameService.lookupName` |
|
|
109
|
+
| `resolveNameServiceNames` | `nameService.reverseLookupName` |
|
|
110
|
+
|
|
111
|
+
> **Warning:** `getCheckpoints` and `getEpochs` (paginated listings) have no gRPC equivalent — use the
|
|
112
|
+
> `checkpoints` / `epochs` GraphQL queries instead. `getValidatorsApy` also has no replacement:
|
|
113
|
+
> there is no canonical definition of validator APY, so it must be computed client-side from
|
|
114
|
+
> validator exchange rates (see [Validator APY](#validator-apy) below).
|
|
111
115
|
|
|
112
116
|
### Example: using gRPC service clients
|
|
113
117
|
|
|
@@ -118,13 +122,32 @@ const client = new SuiGrpcClient({
|
|
|
118
122
|
network: 'mainnet',
|
|
119
123
|
});
|
|
120
124
|
|
|
121
|
-
// Get checkpoint
|
|
125
|
+
// Get the latest checkpoint sequence number (replaces getLatestCheckpointSequenceNumber)
|
|
126
|
+
const { response: info } = await client.ledgerService.getServiceInfo({});
|
|
127
|
+
const latestCheckpoint = info.checkpointHeight;
|
|
128
|
+
|
|
129
|
+
// Get a specific checkpoint by sequence number. `checkpointId` is required (a oneof);
|
|
130
|
+
// the read mask defaults to `sequence_number,digest`, so request more fields as needed.
|
|
122
131
|
const { response } = await client.ledgerService.getCheckpoint({
|
|
123
|
-
sequenceNumber:
|
|
132
|
+
checkpointId: { oneofKind: 'sequenceNumber', sequenceNumber: latestCheckpoint },
|
|
124
133
|
});
|
|
125
134
|
|
|
126
|
-
// Get current epoch
|
|
127
|
-
|
|
135
|
+
// Get the current epoch (omit `epoch` for the current one). The system state,
|
|
136
|
+
// committee, and protocol config are NOT returned by default — you must request
|
|
137
|
+
// them via the read mask (the default mask is just `epoch`).
|
|
138
|
+
const { response: epoch } = await client.ledgerService.getEpoch({
|
|
139
|
+
readMask: { paths: ['epoch', 'system_state', 'committee', 'protocol_config'] },
|
|
140
|
+
});
|
|
141
|
+
const systemState = epoch.epoch?.systemState;
|
|
142
|
+
const committee = epoch.epoch?.committee;
|
|
143
|
+
const protocolConfig = epoch.epoch?.protocolConfig;
|
|
144
|
+
|
|
145
|
+
// Get coin metadata and total supply in one call
|
|
146
|
+
const { response: coinInfo } = await client.stateService.getCoinInfo({
|
|
147
|
+
coinType: '0x2::sui::SUI',
|
|
148
|
+
});
|
|
149
|
+
const metadata = coinInfo.metadata;
|
|
150
|
+
const totalSupply = coinInfo.treasury?.totalSupply;
|
|
128
151
|
|
|
129
152
|
// Get Move package information (includes all modules)
|
|
130
153
|
const { response: pkg } = await client.movePackageService.getPackage({
|
|
@@ -148,19 +171,21 @@ const { response: address } = await client.nameService.lookupName({
|
|
|
148
171
|
|
|
149
172
|
Some JSON-RPC methods don't have gRPC equivalents and require using `SuiGraphQLClient` instead:
|
|
150
173
|
|
|
151
|
-
| JSON-RPC Method | GraphQL Alternative
|
|
152
|
-
| --------------------------- |
|
|
153
|
-
| `queryTransactionBlocks` | `transactions` query
|
|
154
|
-
| `multiGetTransactionBlocks` | `multiGetTransactionEffects` query
|
|
155
|
-
| `queryEvents` | `events` query
|
|
156
|
-
| `
|
|
157
|
-
| `
|
|
158
|
-
| `
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
174
|
+
| JSON-RPC Method | GraphQL Alternative |
|
|
175
|
+
| --------------------------- | --------------------------------------------------------- |
|
|
176
|
+
| `queryTransactionBlocks` | `transactions` query |
|
|
177
|
+
| `multiGetTransactionBlocks` | `multiGetTransactionEffects` query |
|
|
178
|
+
| `queryEvents` | `events` query |
|
|
179
|
+
| `getCheckpoints` | `checkpoints` query |
|
|
180
|
+
| `getEpochs` | `epochs` query |
|
|
181
|
+
| `getCoinMetadata` | `coinMetadata` query (or gRPC `stateService.getCoinInfo`) |
|
|
182
|
+
| `getTotalSupply` | `coinMetadata` query (or gRPC `stateService.getCoinInfo`) |
|
|
183
|
+
| `getStakes` | `address.stakedSuis` query |
|
|
184
|
+
| `getStakesByIds` | `multiGetObjects` query |
|
|
185
|
+
| `tryGetPastObject` | Historical object queries |
|
|
186
|
+
| `getNetworkMetrics` | Use indexer |
|
|
187
|
+
| `getAddressMetrics` | Use indexer |
|
|
188
|
+
| `getMoveCallMetrics` | Use indexer |
|
|
164
189
|
|
|
165
190
|
### Setting up GraphQL client
|
|
166
191
|
|
|
@@ -364,6 +389,24 @@ const result = await graphqlClient.query({
|
|
|
364
389
|
});
|
|
365
390
|
```
|
|
366
391
|
|
|
392
|
+
## Validator APY
|
|
393
|
+
|
|
394
|
+
There is **no replacement** for `getValidatorsApy`, and one will not be added. There is no canonical
|
|
395
|
+
definition of validator APY — no other chain's core/general-purpose RPCs offer this endpoint — so it
|
|
396
|
+
must be computed client-side from validator staking-pool exchange rates.
|
|
397
|
+
|
|
398
|
+
The general approach: read each validator's `exchangeRates` (a table of `pool_token_amount` /
|
|
399
|
+
`sui_amount` per epoch) and estimate the annualized rate from the change in exchange rate over the
|
|
400
|
+
trailing epochs. Two concrete reference implementations:
|
|
401
|
+
|
|
402
|
+
- The `jsonrpc-alt` implementation in
|
|
403
|
+
[`sui-indexer-alt-jsonrpc`](https://github.com/MystenLabs/sui/blob/31537d4d9235b9f61dc07a3a71b05ed61a2bda7b/crates/sui-indexer-alt-jsonrpc/src/api/governance.rs#L422-L440),
|
|
404
|
+
which is compact and readable.
|
|
405
|
+
- [This GraphQL approach](https://github.com/MystenLabs/sui/issues/23832#issuecomment-4437791087),
|
|
406
|
+
which fetches the precursor exchange-rate information in a single query.
|
|
407
|
+
|
|
408
|
+
Treat whichever formula you adopt as _a_ definition of validator APY, not _the_ definition.
|
|
409
|
+
|
|
367
410
|
## Response format differences
|
|
368
411
|
|
|
369
412
|
The gRPC client uses the core API response format, which differs from JSON-RPC responses. See the
|
package/docs/plugins.md
CHANGED
|
@@ -148,7 +148,7 @@ Adding an intent is similar to adding any other command to a transaction:
|
|
|
148
148
|
const transaction = new Transaction();
|
|
149
149
|
|
|
150
150
|
transaction.add(
|
|
151
|
-
|
|
151
|
+
TransactionCommands.Intent({
|
|
152
152
|
name: 'TransferToSender',
|
|
153
153
|
inputs: {
|
|
154
154
|
objects: [transaction.object(someId)],
|
|
@@ -166,7 +166,7 @@ current transaction instance. This allows us to create a helper that automatical
|
|
|
166
166
|
function transferToSender(objects: TransactionObjectInput[]) {
|
|
167
167
|
return (tx: Transaction) => {
|
|
168
168
|
tx.add(
|
|
169
|
-
|
|
169
|
+
TransactionCommands.Intent({
|
|
170
170
|
name: 'TransferToSender',
|
|
171
171
|
inputs: {
|
|
172
172
|
objects: objects.map((obj) => tx.object(obj)),
|
|
@@ -214,7 +214,7 @@ async function resolveTransferToSender(
|
|
|
214
214
|
|
|
215
215
|
// This will replace the intent command with the correct TransferObjects command
|
|
216
216
|
transactionData.replaceCommand(index, [
|
|
217
|
-
|
|
217
|
+
TransactionCommands.TransferObjects(
|
|
218
218
|
// The inputs for intents are not currently typed, so we need to cast to the correct type here
|
|
219
219
|
transaction.$Intent.inputs.objects as Extract<
|
|
220
220
|
TransactionObjectArgument,
|
|
@@ -243,7 +243,7 @@ function transferToSender(objects: TransactionObjectInput[]) {
|
|
|
243
243
|
// As long as we are adding the same function reference, it will only be added once
|
|
244
244
|
tx.addIntentResolver('TransferToSender', resolveTransferToSender);
|
|
245
245
|
tx.add(
|
|
246
|
-
|
|
246
|
+
TransactionCommands.Intent({
|
|
247
247
|
name: 'TransferToSender',
|
|
248
248
|
inputs: {
|
|
249
249
|
objects: objects.map((obj) => tx.object(obj)),
|
|
@@ -255,4 +255,28 @@ function transferToSender(objects: TransactionObjectInput[]) {
|
|
|
255
255
|
|
|
256
256
|
const transaction = new Transaction();
|
|
257
257
|
transaction.add(transferToSender(['0x1234']));
|
|
258
|
-
```
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Copying transactions that use custom intents
|
|
261
|
+
|
|
262
|
+
`Transaction.from` creates a deep copy of a transaction. Copying is synchronous, so any unresolved
|
|
263
|
+
intents are carried over as-is and resolved later when the copy is built or serialized. To do that,
|
|
264
|
+
the copy needs the intent resolvers, but resolvers are functions and cannot be represented in the
|
|
265
|
+
serialized transaction data.
|
|
266
|
+
|
|
267
|
+
Built-in intents (such as the `CoinWithBalance` intent added by `tx.coin()`) are re-attached
|
|
268
|
+
automatically. For custom intents, pass the resolvers through the `intentResolvers` option so the
|
|
269
|
+
copy knows how to resolve them:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
|
|
273
|
+
const copy = Transaction.from(transaction, {
|
|
274
|
+
intentResolvers: {
|
|
275
|
+
TransferToSender: resolveTransferToSender,
|
|
276
|
+
},
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Without this, `Transaction.from` throws if the transaction still contains unresolved custom intents.
|
|
281
|
+
Alternatively, you can `await transaction.prepareForSerialization()` first to resolve the intents
|
|
282
|
+
before copying, but that requires an async call and (for some intents) a client.
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Building Transactions
|
|
2
|
+
|
|
3
|
+
> Construct programmable transaction blocks with the Transaction API
|
|
4
|
+
|
|
5
|
+
Every interaction with the Sui network goes through a transaction. Sui transactions are a sequence
|
|
6
|
+
of commands called
|
|
7
|
+
[programmable transaction blocks (PTBs)](https://docs.sui.io/guides/developer/transactions/prog-txn-blocks)
|
|
8
|
+
that execute on inputs to produce a result. Commands within a transaction can call Move functions,
|
|
9
|
+
transfer objects, split and merge coins, and more. You can chain the result of one command into a
|
|
10
|
+
subsequent command, composing complex operations in a single transaction.
|
|
11
|
+
|
|
12
|
+
All commands in a transaction execute atomically. If any command fails, the entire transaction is
|
|
13
|
+
rolled back and none of its effects are applied.
|
|
14
|
+
|
|
15
|
+
For more information on transaction model, see the
|
|
16
|
+
[Sui documentation on PTBs](https://docs.sui.io/guides/developer/transactions/prog-txn-blocks) and
|
|
17
|
+
[inputs and results](https://docs.sui.io/concepts/transactions/inputs-and-results).
|
|
18
|
+
|
|
19
|
+
## Creating a transaction
|
|
20
|
+
|
|
21
|
+
Import the `Transaction` class and create a new instance:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
|
|
25
|
+
const tx = new Transaction();
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Sending SUI
|
|
29
|
+
|
|
30
|
+
Use `tx.balance()` and `balance::send_funds` to send SUI; this deposits directly into the
|
|
31
|
+
recipient's address balance:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
|
|
35
|
+
const tx = new Transaction();
|
|
36
|
+
|
|
37
|
+
tx.moveCall({
|
|
38
|
+
target: '0x2::balance::send_funds',
|
|
39
|
+
typeArguments: ['0x2::sui::SUI'],
|
|
40
|
+
arguments: [tx.balance({ balance: 1n * MIST_PER_SUI }), tx.pure.address('0xRecipientAddress')],
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If the recipient needs a `Coin<T>` object, use `tx.coin()` with `transferObjects` instead:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
tx.transferObjects([tx.coin({ balance: 1n * MIST_PER_SUI })], '0xRecipientAddress');
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Both `tx.balance()` and `tx.coin()` automatically draw from your coin objects and address balances.
|
|
51
|
+
You don't need to manage individual coins yourself. See [Coins and Balances](./coins-and-balances)
|
|
52
|
+
for full details.
|
|
53
|
+
|
|
54
|
+
## Sending other tokens
|
|
55
|
+
|
|
56
|
+
For non-SUI tokens, use the same patterns for passing the coin type:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const tx = new Transaction();
|
|
60
|
+
|
|
61
|
+
// Send to address balance (preferred)
|
|
62
|
+
tx.moveCall({
|
|
63
|
+
target: '0x2::balance::send_funds',
|
|
64
|
+
typeArguments: ['0xPackageId::module::CoinType'],
|
|
65
|
+
arguments: [
|
|
66
|
+
tx.balance({ balance: 1_000_000, type: '0xPackageId::module::CoinType' }),
|
|
67
|
+
tx.pure.address('0xRecipientAddress'),
|
|
68
|
+
],
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Or send as a coin object
|
|
72
|
+
tx.transferObjects(
|
|
73
|
+
[tx.coin({ balance: 1_000_000, type: '0xPackageId::module::CoinType' })],
|
|
74
|
+
'0xRecipientAddress',
|
|
75
|
+
);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Calling Move functions
|
|
79
|
+
|
|
80
|
+
Use `moveCall` to call any function in a published Move package. The Sui framework at `0x2` provides
|
|
81
|
+
many built-in functions you can call directly. For example, to split a coin:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
const tx = new Transaction();
|
|
85
|
+
|
|
86
|
+
const [newCoin] = tx.moveCall({
|
|
87
|
+
target: '0x2::coin::split',
|
|
88
|
+
typeArguments: ['0x2::sui::SUI'],
|
|
89
|
+
arguments: [tx.object('0xCoinId'), tx.pure.u64(1000)],
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
tx.transferObjects([newCoin], '0xRecipientAddress');
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The `target` format is `packageId::moduleName::functionName`.
|
|
96
|
+
|
|
97
|
+
To call functions in your own published packages, use the same pattern with your package ID:
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
tx.moveCall({
|
|
101
|
+
target: '0xYourPackageId::module::function_name',
|
|
102
|
+
arguments: [tx.pure.string('hello'), tx.object('0xSomeObjectId')],
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Using codegen for type-safe calls
|
|
107
|
+
|
|
108
|
+
The [`@mysten/codegen`](/codegen) package generates type-safe TypeScript functions from your Move
|
|
109
|
+
packages. Instead of writing `moveCall` with string targets and manual argument construction, use
|
|
110
|
+
`tx.add()` with generated functions:
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
|
|
114
|
+
const tx = new Transaction();
|
|
115
|
+
tx.add(
|
|
116
|
+
counter.increment({
|
|
117
|
+
arguments: {
|
|
118
|
+
counter: '0x123...', // Counter object ID
|
|
119
|
+
},
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
This gives you IDE autocompletion, compile-time type checking for arguments, and eliminates
|
|
125
|
+
incorrect target strings. See the [codegen documentation](/codegen) for setup instructions.
|
|
126
|
+
|
|
127
|
+
### Return values
|
|
128
|
+
|
|
129
|
+
Commands return results that you can use as input to subsequent commands. For example, `splitCoins`
|
|
130
|
+
returns the new coins it creates:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const tx = new Transaction();
|
|
134
|
+
|
|
135
|
+
// splitCoins returns one result per amount
|
|
136
|
+
const [coin] = tx.splitCoins(tx.gas, [1_000_000]);
|
|
137
|
+
|
|
138
|
+
// Use that result as input to another command
|
|
139
|
+
tx.transferObjects([coin], '0xRecipientAddress');
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`moveCall` works the same way. When a Move function returns a value, you can capture it and pass it
|
|
143
|
+
to the next command:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const [nft] = tx.moveCall({
|
|
147
|
+
target: '0xPackageId::nft::mint',
|
|
148
|
+
arguments: [tx.pure.string('My NFT'), tx.pure.string('Description')],
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
tx.transferObjects([nft], '0xRecipientAddress');
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
When a command returns multiple values, destructure or index into the result:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// Destructuring
|
|
158
|
+
const [nft1, nft2] = tx.moveCall({ target: '0xPackageId::nft::mint_pair' });
|
|
159
|
+
|
|
160
|
+
// Or indexing
|
|
161
|
+
const result = tx.moveCall({ target: '0xPackageId::nft::mint_pair' });
|
|
162
|
+
const firstNft = result[0];
|
|
163
|
+
const secondNft = result[1];
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
> **Warning:** Always access elements by index or destructuring. Do not use the spread operator (`...result`) or
|
|
167
|
+
> pass results to `Array.from()`, which causes an infinite loop.
|
|
168
|
+
|
|
169
|
+
### Type arguments
|
|
170
|
+
|
|
171
|
+
Some Move functions have generic type parameters. Pass them with `typeArguments`:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
tx.moveCall({
|
|
175
|
+
target: '0x2::coin::split',
|
|
176
|
+
typeArguments: ['0x2::sui::SUI'],
|
|
177
|
+
arguments: [tx.object('0xCoinId'), tx.pure.u64(1000)],
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Chaining commands
|
|
182
|
+
|
|
183
|
+
The result of any command can be used as input to a subsequent command. This is what makes
|
|
184
|
+
transactions **programmable**. You can compose multiple operations into a single atomic transaction:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
const tx = new Transaction();
|
|
188
|
+
|
|
189
|
+
// Mint an NFT
|
|
190
|
+
const [nft] = tx.moveCall({
|
|
191
|
+
target: '0xPackageId::nft::mint',
|
|
192
|
+
arguments: [tx.pure.string('My NFT')],
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Set a property on it
|
|
196
|
+
tx.moveCall({
|
|
197
|
+
target: '0xPackageId::nft::set_description',
|
|
198
|
+
arguments: [nft, tx.pure.string('A nice NFT')],
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Transfer it to someone
|
|
202
|
+
tx.transferObjects([nft], '0xRecipientAddress');
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Batch transfers
|
|
206
|
+
|
|
207
|
+
Send tokens to multiple recipients in a single transaction:
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
|
|
211
|
+
const transfers = [
|
|
212
|
+
{ to: '0xAlice', amount: 1_000_000_000 },
|
|
213
|
+
{ to: '0xBob', amount: 2_000_000_000 },
|
|
214
|
+
{ to: '0xCarol', amount: 500_000_000 },
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
const tx = new Transaction();
|
|
218
|
+
|
|
219
|
+
for (const transfer of transfers) {
|
|
220
|
+
// Send to address balances (preferred)
|
|
221
|
+
tx.moveCall({
|
|
222
|
+
target: '0x2::balance::send_funds',
|
|
223
|
+
typeArguments: ['0x2::sui::SUI'],
|
|
224
|
+
arguments: [tx.balance({ balance: transfer.amount }), tx.pure.address(transfer.to)],
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Or send as coin objects
|
|
229
|
+
for (const transfer of transfers) {
|
|
230
|
+
tx.transferObjects([tx.coin({ balance: transfer.amount })], transfer.to);
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Composable transaction building with thunks
|
|
235
|
+
|
|
236
|
+
The `tx.add()` method accepts thunks, which are functions that receive the transaction and add
|
|
237
|
+
commands to it. This enables building reusable, composable transaction pieces:
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
function mintNft(name: string) {
|
|
241
|
+
return (tx: Transaction) => {
|
|
242
|
+
return tx.moveCall({
|
|
243
|
+
target: '0xPackage::nft::mint',
|
|
244
|
+
arguments: [tx.pure.string(name)],
|
|
245
|
+
});
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const tx = new Transaction();
|
|
250
|
+
const [nft] = tx.add(mintNft('My NFT'));
|
|
251
|
+
tx.transferObjects([nft], '0xRecipientAddress');
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
See [SDK Building](/sui/sdk-building) for more information on building composable transaction
|
|
255
|
+
libraries.
|
|
256
|
+
|
|
257
|
+
## Serializing transactions
|
|
258
|
+
|
|
259
|
+
Serialize a transaction to JSON for storage, transmission, or later reconstruction:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
// Serialize to JSON — with a client, resolves any unresolved data first
|
|
263
|
+
const json = await tx.toJSON({ client: grpcClient });
|
|
264
|
+
|
|
265
|
+
// Serialize without a client — intents like tx.coin() are preserved as-is
|
|
266
|
+
const json = await tx.toJSON();
|
|
267
|
+
|
|
268
|
+
// Reconstruct from JSON
|
|
269
|
+
const tx = Transaction.from(json);
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
This is useful for passing transactions between a frontend and backend, or for storing pre-built
|
|
273
|
+
transactions.
|
|
274
|
+
|
|
275
|
+
## Executing transactions
|
|
276
|
+
|
|
277
|
+
Once you've built a transaction, see [Signing and Execution](./signing-and-execution) for all the
|
|
278
|
+
ways to sign and submit it, such as keypairs, [`dapp-kit`](/dapp-kit) hooks, sponsored transactions,
|
|
279
|
+
and more.
|