@mysten/sui 2.27.1 → 2.29.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 +32 -0
- package/dist/bcs/bcs.d.mts +6 -6
- package/dist/bcs/bcs.d.mts.map +1 -1
- package/dist/bcs/bcs.mjs +29 -2
- package/dist/bcs/bcs.mjs.map +1 -1
- package/dist/bcs/effects.mjs +2 -1
- package/dist/bcs/effects.mjs.map +1 -1
- package/dist/bcs/index.d.mts +102 -6
- package/dist/bcs/index.d.mts.map +1 -1
- package/dist/bcs/transactions.mjs +2 -1
- package/dist/bcs/transactions.mjs.map +1 -1
- package/dist/client/transaction-resolver.mjs +45 -9
- package/dist/client/transaction-resolver.mjs.map +1 -1
- package/dist/cryptography/signature.d.mts +14 -14
- package/dist/grpc/client.d.mts +1 -1
- package/dist/grpc/client.d.mts.map +1 -1
- package/dist/grpc/client.mjs +3 -5
- package/dist/grpc/client.mjs.map +1 -1
- package/dist/grpc/core.d.mts.map +1 -1
- package/dist/grpc/core.mjs +10 -10
- package/dist/grpc/core.mjs.map +1 -1
- package/dist/grpc/index.d.mts +4 -3
- package/dist/grpc/index.mjs +4 -2
- package/dist/grpc/proto/sui/forking/v1alpha/forking_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/execution_status.d.mts +9 -1
- package/dist/grpc/proto/sui/rpc/v2/execution_status.d.mts.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/execution_status.mjs +8 -0
- package/dist/grpc/proto/sui/rpc/v2/execution_status.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/move_package_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/name_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/state_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/subscription_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/transaction.d.mts +50 -2
- package/dist/grpc/proto/sui/rpc/v2/transaction.d.mts.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/transaction.mjs +36 -1
- package/dist/grpc/proto/sui/rpc/v2/transaction.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/transaction_execution_service.client.d.mts +4 -4
- package/dist/grpc/proto/types.d.mts +2 -2
- package/dist/grpc/proto/types.mjs +2 -1
- package/dist/grpc/transport.d.mts +18 -0
- package/dist/grpc/transport.d.mts.map +1 -0
- package/dist/grpc/transport.mjs +97 -0
- package/dist/grpc/transport.mjs.map +1 -0
- package/dist/transactions/Transaction.d.mts +19 -7
- package/dist/transactions/Transaction.d.mts.map +1 -1
- package/dist/transactions/data/internal.d.mts +133 -109
- package/dist/transactions/data/internal.d.mts.map +1 -1
- package/dist/transactions/data/internal.mjs +11 -2
- package/dist/transactions/data/internal.mjs.map +1 -1
- package/dist/transactions/data/v1.d.mts +22 -0
- package/dist/transactions/data/v1.d.mts.map +1 -1
- package/dist/transactions/data/v1.mjs +27 -4
- package/dist/transactions/data/v1.mjs.map +1 -1
- package/dist/transactions/data/v2.d.mts +12 -0
- package/dist/transactions/data/v2.d.mts.map +1 -1
- package/dist/transactions/data/v2.mjs +3 -2
- package/dist/transactions/data/v2.mjs.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/dist/zklogin/bcs.d.mts +14 -14
- package/docs/clients/grpc.md +31 -7
- package/package.json +1 -1
- package/src/bcs/bcs.ts +45 -0
- package/src/bcs/effects.ts +3 -0
- package/src/bcs/transactions.ts +1 -0
- package/src/bcs/types.ts +10 -1
- package/src/client/transaction-resolver.ts +79 -9
- package/src/grpc/client.ts +12 -4
- package/src/grpc/core.ts +18 -14
- package/src/grpc/index.ts +7 -3
- package/src/grpc/proto/sui/rpc/v2/execution_status.ts +8 -0
- package/src/grpc/proto/sui/rpc/v2/transaction.ts +68 -0
- package/src/grpc/transport.ts +160 -0
- package/src/transactions/data/internal.ts +19 -0
- package/src/transactions/data/v1.ts +51 -12
- package/src/transactions/data/v2.ts +2 -0
- package/src/version.ts +1 -1
package/src/bcs/transactions.ts
CHANGED
|
@@ -188,6 +188,7 @@ export const EndOfEpochTransactionKind = bcs.enum('EndOfEpochTransactionKind', {
|
|
|
188
188
|
DisplayRegistryCreate: null,
|
|
189
189
|
AddressAliasStateCreate: null,
|
|
190
190
|
WriteAccumulatorStorageCost: WriteAccumulatorStorageCost,
|
|
191
|
+
ForwardingAddressRegistryCreate: null,
|
|
191
192
|
});
|
|
192
193
|
|
|
193
194
|
// Rust: crates/sui-types/src/transaction.rs
|
package/src/bcs/types.ts
CHANGED
|
@@ -126,10 +126,19 @@ type ValidDuring = {
|
|
|
126
126
|
nonce: number;
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
+
type AllowedProposers = {
|
|
130
|
+
epoch: number | string;
|
|
131
|
+
proposers: number[];
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
type Validity = ValidDuring & {
|
|
135
|
+
allowedProposers: { None: null } | { Some: AllowedProposers };
|
|
136
|
+
};
|
|
137
|
+
|
|
129
138
|
/**
|
|
130
139
|
* TransactionExpiration
|
|
131
140
|
*
|
|
132
141
|
* Indications the expiration time for a transaction.
|
|
133
142
|
*/
|
|
134
143
|
export type TransactionExpiration =
|
|
135
|
-
{ None: null } | { Epoch: number } | { ValidDuring: ValidDuring };
|
|
144
|
+
{ None: null } | { Epoch: number } | { ValidDuring: ValidDuring } | { Validity: Validity };
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
import { fromBase64, toBase64 } from '@mysten/bcs';
|
|
5
5
|
|
|
6
6
|
import type { bcs } from '../bcs/index.js';
|
|
7
|
+
import {
|
|
8
|
+
assertAllowedProposersNotEmpty,
|
|
9
|
+
assertAllowedProposersStrictlyIncreasing,
|
|
10
|
+
} from '../bcs/bcs.js';
|
|
7
11
|
import { TransactionDataBuilder } from '../transactions/TransactionData.js';
|
|
8
12
|
import type {
|
|
9
13
|
CallArg,
|
|
@@ -23,6 +27,18 @@ import type { Argument } from '../grpc/proto/sui/rpc/v2/argument.js';
|
|
|
23
27
|
import { Argument_ArgumentKind } from '../grpc/proto/sui/rpc/v2/argument.js';
|
|
24
28
|
import { Transaction } from '../transactions/Transaction.js';
|
|
25
29
|
|
|
30
|
+
function millisecondsToGrpcTimestamp(value: string | number) {
|
|
31
|
+
const milliseconds = BigInt(value);
|
|
32
|
+
return {
|
|
33
|
+
seconds: milliseconds / 1000n,
|
|
34
|
+
nanos: Number(milliseconds % 1000n) * 1_000_000,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function grpcTimestampToMilliseconds(timestamp: { seconds: bigint; nanos: number }) {
|
|
39
|
+
return (timestamp.seconds * 1000n + BigInt(Math.floor(timestamp.nanos / 1_000_000))).toString();
|
|
40
|
+
}
|
|
41
|
+
|
|
26
42
|
/**
|
|
27
43
|
* Converts CallArg (TypeScript internal format) to gRPC Input format
|
|
28
44
|
*/
|
|
@@ -263,14 +279,36 @@ export function transactionDataToGrpcTransaction(data: TransactionData): GrpcTra
|
|
|
263
279
|
kind: TransactionExpiration_TransactionExpirationKind.EPOCH,
|
|
264
280
|
epoch: BigInt(data.expiration.Epoch),
|
|
265
281
|
};
|
|
266
|
-
} else if (data.expiration.$kind === 'ValidDuring') {
|
|
267
|
-
const
|
|
282
|
+
} else if (data.expiration.$kind === 'ValidDuring' || data.expiration.$kind === 'Validity') {
|
|
283
|
+
const validity =
|
|
284
|
+
data.expiration.$kind === 'ValidDuring'
|
|
285
|
+
? data.expiration.ValidDuring
|
|
286
|
+
: data.expiration.Validity;
|
|
287
|
+
const allowedProposers =
|
|
288
|
+
data.expiration.$kind === 'Validity' ? data.expiration.Validity.allowedProposers : null;
|
|
268
289
|
transaction.expiration = {
|
|
269
|
-
kind:
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
290
|
+
kind:
|
|
291
|
+
data.expiration.$kind === 'ValidDuring'
|
|
292
|
+
? TransactionExpiration_TransactionExpirationKind.VALID_DURING
|
|
293
|
+
: TransactionExpiration_TransactionExpirationKind.VALIDITY,
|
|
294
|
+
minEpoch: validity.minEpoch != null ? BigInt(validity.minEpoch) : undefined,
|
|
295
|
+
epoch: validity.maxEpoch != null ? BigInt(validity.maxEpoch) : undefined,
|
|
296
|
+
minTimestamp:
|
|
297
|
+
validity.minTimestamp != null
|
|
298
|
+
? millisecondsToGrpcTimestamp(validity.minTimestamp)
|
|
299
|
+
: undefined,
|
|
300
|
+
maxTimestamp:
|
|
301
|
+
validity.maxTimestamp != null
|
|
302
|
+
? millisecondsToGrpcTimestamp(validity.maxTimestamp)
|
|
303
|
+
: undefined,
|
|
304
|
+
chain: validity.chain,
|
|
305
|
+
nonce: validity.nonce,
|
|
306
|
+
allowedProposers: allowedProposers
|
|
307
|
+
? {
|
|
308
|
+
epoch: BigInt(allowedProposers.epoch),
|
|
309
|
+
proposers: assertAllowedProposersStrictlyIncreasing(allowedProposers.proposers),
|
|
310
|
+
}
|
|
311
|
+
: undefined,
|
|
274
312
|
};
|
|
275
313
|
}
|
|
276
314
|
}
|
|
@@ -529,13 +567,45 @@ export function grpcTransactionToTransactionData(grpcTx: GrpcTransaction): Trans
|
|
|
529
567
|
ValidDuring: {
|
|
530
568
|
minEpoch: grpcTx.expiration.minEpoch?.toString() ?? null,
|
|
531
569
|
maxEpoch: grpcTx.expiration.epoch?.toString() ?? null,
|
|
532
|
-
minTimestamp:
|
|
533
|
-
|
|
570
|
+
minTimestamp: grpcTx.expiration.minTimestamp
|
|
571
|
+
? grpcTimestampToMilliseconds(grpcTx.expiration.minTimestamp)
|
|
572
|
+
: null,
|
|
573
|
+
maxTimestamp: grpcTx.expiration.maxTimestamp
|
|
574
|
+
? grpcTimestampToMilliseconds(grpcTx.expiration.maxTimestamp)
|
|
575
|
+
: null,
|
|
576
|
+
chain: grpcTx.expiration.chain ?? '',
|
|
577
|
+
nonce: grpcTx.expiration.nonce ?? 0,
|
|
578
|
+
},
|
|
579
|
+
};
|
|
580
|
+
break;
|
|
581
|
+
case TransactionExpiration_TransactionExpirationKind.VALIDITY:
|
|
582
|
+
expiration = {
|
|
583
|
+
$kind: 'Validity',
|
|
584
|
+
Validity: {
|
|
585
|
+
minEpoch: grpcTx.expiration.minEpoch?.toString() ?? null,
|
|
586
|
+
maxEpoch: grpcTx.expiration.epoch?.toString() ?? null,
|
|
587
|
+
minTimestamp: grpcTx.expiration.minTimestamp
|
|
588
|
+
? grpcTimestampToMilliseconds(grpcTx.expiration.minTimestamp)
|
|
589
|
+
: null,
|
|
590
|
+
maxTimestamp: grpcTx.expiration.maxTimestamp
|
|
591
|
+
? grpcTimestampToMilliseconds(grpcTx.expiration.maxTimestamp)
|
|
592
|
+
: null,
|
|
534
593
|
chain: grpcTx.expiration.chain ?? '',
|
|
535
594
|
nonce: grpcTx.expiration.nonce ?? 0,
|
|
595
|
+
allowedProposers: grpcTx.expiration.allowedProposers
|
|
596
|
+
? {
|
|
597
|
+
epoch: grpcTx.expiration.allowedProposers.epoch?.toString() ?? '0',
|
|
598
|
+
proposers: assertAllowedProposersNotEmpty(
|
|
599
|
+
grpcTx.expiration.allowedProposers.proposers,
|
|
600
|
+
),
|
|
601
|
+
}
|
|
602
|
+
: null,
|
|
536
603
|
},
|
|
537
604
|
};
|
|
538
605
|
break;
|
|
606
|
+
default:
|
|
607
|
+
// Leaving `expiration` null here would drop a restriction the server did send.
|
|
608
|
+
throw new Error(`Unknown transaction expiration kind: ${grpcTx.expiration.kind}`);
|
|
539
609
|
}
|
|
540
610
|
}
|
|
541
611
|
|
package/src/grpc/client.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import type { GrpcWebOptions } from '@protobuf-ts/grpcweb-transport';
|
|
5
|
-
import { GrpcWebFetchTransport } from '@protobuf-ts/grpcweb-transport';
|
|
6
5
|
import { TransactionExecutionServiceClient } from './proto/sui/rpc/v2/transaction_execution_service.client.js';
|
|
7
6
|
import { LedgerServiceClient } from './proto/sui/rpc/v2/ledger_service.client.js';
|
|
8
7
|
import { MovePackageServiceClient } from './proto/sui/rpc/v2/move_package_service.client.js';
|
|
@@ -19,6 +18,7 @@ import { fromBase64, toBase64 } from '@mysten/utils';
|
|
|
19
18
|
import { NameServiceClient } from './proto/sui/rpc/v2/name_service.client.js';
|
|
20
19
|
import { ForkingServiceClient } from './proto/sui/forking/v1alpha/forking_service.client.js';
|
|
21
20
|
import type { TransactionPlugin } from '../transactions/index.js';
|
|
21
|
+
import { GrpcWebFetchTransport } from './transport.js';
|
|
22
22
|
|
|
23
23
|
interface SuiGrpcTransportOptions extends GrpcWebOptions {
|
|
24
24
|
transport?: never;
|
|
@@ -157,9 +157,17 @@ export class SuiGrpcClient extends BaseClient implements SuiClientTypes.Transpor
|
|
|
157
157
|
|
|
158
158
|
constructor(options: SuiGrpcClientOptions) {
|
|
159
159
|
super({ network: options.network });
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
const {
|
|
161
|
+
network: _network,
|
|
162
|
+
mvr: _mvr,
|
|
163
|
+
// Not forwarded: every Core API call passes its own `signal`, which would overwrite it.
|
|
164
|
+
abort: _abort,
|
|
165
|
+
transport: providedTransport,
|
|
166
|
+
...transportOptions
|
|
167
|
+
} = options as SuiGrpcClientOptions & SuiGrpcTransportOptions & { transport?: RpcTransport };
|
|
168
|
+
|
|
169
|
+
// A caller-supplied transport is used as given. See ./transport.ts for the default.
|
|
170
|
+
const transport = providedTransport ?? new GrpcWebFetchTransport(transportOptions);
|
|
163
171
|
this.transactionExecutionService = new TransactionExecutionServiceClient(transport);
|
|
164
172
|
this.ledgerService = new LedgerServiceClient(transport);
|
|
165
173
|
this.stateService = new StateServiceClient(transport);
|
package/src/grpc/core.ts
CHANGED
|
@@ -69,24 +69,28 @@ import {
|
|
|
69
69
|
validateTransactionQuery,
|
|
70
70
|
} from '../client/query-filters.js';
|
|
71
71
|
import { toGrpcEventFilter, toGrpcTransactionFilter } from './filters.js';
|
|
72
|
+
import { hasDecodedStatusMessage } from './transport.js';
|
|
72
73
|
|
|
73
74
|
export interface GrpcCoreClientOptions extends CoreClientOptions {
|
|
74
75
|
client: SuiGrpcClient;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
function isNameServiceResolutionMiss(error: unknown): boolean {
|
|
78
|
-
|
|
79
|
-
if (error
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
79
|
+
// Read by shape, so an error from another copy of runtime-rpc is still recognised.
|
|
80
|
+
if (typeof error !== 'object' || error === null) return false;
|
|
81
|
+
|
|
82
|
+
const { code, message } = error as { code?: unknown; message?: unknown };
|
|
83
|
+
if (typeof code !== 'string' || typeof message !== 'string') return false;
|
|
84
|
+
|
|
85
|
+
if (code === GrpcStatusCode[GrpcStatusCode.NOT_FOUND]) return true;
|
|
86
|
+
if (code !== GrpcStatusCode[GrpcStatusCode.RESOURCE_EXHAUSTED]) return false;
|
|
87
|
+
|
|
88
|
+
// The service reports an expired name as RESOURCE_EXHAUSTED with no structured reason, so match
|
|
89
|
+
// the status text and leave other RESOURCE_EXHAUSTED failures alone. A transport this package did
|
|
90
|
+
// not build leaves `grpc-message` encoded, hence the second form.
|
|
91
|
+
if (message === 'name has expired') return true;
|
|
92
|
+
|
|
93
|
+
return !hasDecodedStatusMessage(error) && message === 'name%20has%20expired';
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
export class GrpcCoreClient extends CoreClient {
|
|
@@ -987,9 +991,9 @@ export class GrpcCoreClient extends CoreClient {
|
|
|
987
991
|
});
|
|
988
992
|
response = result.response;
|
|
989
993
|
} catch (error) {
|
|
990
|
-
//
|
|
994
|
+
// The transport owns the status text. See ./transport.ts.
|
|
991
995
|
if (error instanceof Error && error.message) {
|
|
992
|
-
throw new SimulationError(
|
|
996
|
+
throw new SimulationError(error.message, { cause: error });
|
|
993
997
|
}
|
|
994
998
|
throw error;
|
|
995
999
|
}
|
package/src/grpc/index.ts
CHANGED
|
@@ -23,10 +23,14 @@ export type {
|
|
|
23
23
|
} from './client.js';
|
|
24
24
|
export type { GrpcCoreClientOptions } from './core.js';
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
// Subclasses `@protobuf-ts/grpcweb-transport`'s transport to fix its error handling.
|
|
27
|
+
export { GrpcWebFetchTransport } from './transport.js';
|
|
28
|
+
|
|
29
|
+
// Re-exported so users can configure a transport, and narrow and code the errors it produces,
|
|
30
|
+
// without adding @protobuf-ts/* as a dependency.
|
|
31
|
+
export { GrpcStatusCode } from '@protobuf-ts/grpcweb-transport';
|
|
29
32
|
export type { GrpcWebOptions } from '@protobuf-ts/grpcweb-transport';
|
|
33
|
+
export { RpcError } from '@protobuf-ts/runtime-rpc';
|
|
30
34
|
export type { RpcTransport } from '@protobuf-ts/runtime-rpc';
|
|
31
35
|
|
|
32
36
|
// Export all gRPC proto types as a namespace
|
|
@@ -727,6 +727,14 @@ export enum CommandArgumentError_CommandArgumentErrorKind {
|
|
|
727
727
|
* @generated from protobuf enum value: INVALID_REFERENCE_ARGUMENT = 19;
|
|
728
728
|
*/
|
|
729
729
|
INVALID_REFERENCE_ARGUMENT = 19,
|
|
730
|
+
/**
|
|
731
|
+
* Invalid usage of TxContext in the function signature. TxContext can only be used by
|
|
732
|
+
* reference, `&TxContext` or `&mut TxContext`. If used mutably, it must be the only
|
|
733
|
+
* TxContext parameter, and TxContext can never be returned from a Move call.
|
|
734
|
+
*
|
|
735
|
+
* @generated from protobuf enum value: INVALID_TX_CONTEXT = 20;
|
|
736
|
+
*/
|
|
737
|
+
INVALID_TX_CONTEXT = 20,
|
|
730
738
|
}
|
|
731
739
|
/**
|
|
732
740
|
* An error with upgrading a package.
|
|
@@ -145,6 +145,13 @@ export interface TransactionExpiration {
|
|
|
145
145
|
* @generated from protobuf field: optional uint32 nonce = 7;
|
|
146
146
|
*/
|
|
147
147
|
nonce?: number;
|
|
148
|
+
/**
|
|
149
|
+
* The validators allowed to propose this transaction in consensus. Only set when `kind`
|
|
150
|
+
* is `VALIDITY`. Leave unset to let any validator propose the transaction.
|
|
151
|
+
*
|
|
152
|
+
* @generated from protobuf field: optional sui.rpc.v2.AllowedProposers allowed_proposers = 8;
|
|
153
|
+
*/
|
|
154
|
+
allowedProposers?: AllowedProposers;
|
|
148
155
|
}
|
|
149
156
|
/**
|
|
150
157
|
* @generated from protobuf enum sui.rpc.v2.TransactionExpiration.TransactionExpirationKind
|
|
@@ -181,6 +188,40 @@ export enum TransactionExpiration_TransactionExpirationKind {
|
|
|
181
188
|
* @generated from protobuf enum value: VALID_DURING = 3;
|
|
182
189
|
*/
|
|
183
190
|
VALID_DURING = 3,
|
|
191
|
+
/**
|
|
192
|
+
* Everything in VALID_DURING, plus a restriction on which validators may
|
|
193
|
+
* propose the transaction in consensus.
|
|
194
|
+
*
|
|
195
|
+
* @generated from protobuf enum value: VALIDITY = 4;
|
|
196
|
+
*/
|
|
197
|
+
VALIDITY = 4,
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* The validators allowed to propose a transaction in consensus.
|
|
201
|
+
*
|
|
202
|
+
* Proposal by any other validator is byzantine behavior and invalidates the whole block.
|
|
203
|
+
*
|
|
204
|
+
* @generated from protobuf message sui.rpc.v2.AllowedProposers
|
|
205
|
+
*/
|
|
206
|
+
export interface AllowedProposers {
|
|
207
|
+
/**
|
|
208
|
+
* The epoch whose committee `proposers` indexes into.
|
|
209
|
+
*
|
|
210
|
+
* Committee indices are only meaningful against one committee, so a set recorded for any
|
|
211
|
+
* other epoch is ignored and the transaction is treated as naming no proposers.
|
|
212
|
+
*
|
|
213
|
+
* @generated from protobuf field: optional uint64 epoch = 1;
|
|
214
|
+
*/
|
|
215
|
+
epoch?: bigint;
|
|
216
|
+
/**
|
|
217
|
+
* Committee indices of the allowed proposers, strictly increasing and non-empty.
|
|
218
|
+
*
|
|
219
|
+
* An empty list names no validator and is rejected; omit `allowed_proposers` entirely to
|
|
220
|
+
* let any validator propose the transaction.
|
|
221
|
+
*
|
|
222
|
+
* @generated from protobuf field: repeated uint32 proposers = 2;
|
|
223
|
+
*/
|
|
224
|
+
proposers: number[];
|
|
184
225
|
}
|
|
185
226
|
/**
|
|
186
227
|
* Transaction type.
|
|
@@ -1314,6 +1355,7 @@ class TransactionExpiration$Type extends MessageType<TransactionExpiration> {
|
|
|
1314
1355
|
{ no: 5, name: 'max_timestamp', kind: 'message', T: () => Timestamp },
|
|
1315
1356
|
{ no: 6, name: 'chain', kind: 'scalar', opt: true, T: 9 /*ScalarType.STRING*/ },
|
|
1316
1357
|
{ no: 7, name: 'nonce', kind: 'scalar', opt: true, T: 13 /*ScalarType.UINT32*/ },
|
|
1358
|
+
{ no: 8, name: 'allowed_proposers', kind: 'message', T: () => AllowedProposers },
|
|
1317
1359
|
]);
|
|
1318
1360
|
}
|
|
1319
1361
|
}
|
|
@@ -1322,6 +1364,32 @@ class TransactionExpiration$Type extends MessageType<TransactionExpiration> {
|
|
|
1322
1364
|
*/
|
|
1323
1365
|
export const TransactionExpiration = new TransactionExpiration$Type();
|
|
1324
1366
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
1367
|
+
class AllowedProposers$Type extends MessageType<AllowedProposers> {
|
|
1368
|
+
constructor() {
|
|
1369
|
+
super('sui.rpc.v2.AllowedProposers', [
|
|
1370
|
+
{
|
|
1371
|
+
no: 1,
|
|
1372
|
+
name: 'epoch',
|
|
1373
|
+
kind: 'scalar',
|
|
1374
|
+
opt: true,
|
|
1375
|
+
T: 4 /*ScalarType.UINT64*/,
|
|
1376
|
+
L: 0 /*LongType.BIGINT*/,
|
|
1377
|
+
},
|
|
1378
|
+
{
|
|
1379
|
+
no: 2,
|
|
1380
|
+
name: 'proposers',
|
|
1381
|
+
kind: 'scalar',
|
|
1382
|
+
repeat: 1 /*RepeatType.PACKED*/,
|
|
1383
|
+
T: 13 /*ScalarType.UINT32*/,
|
|
1384
|
+
},
|
|
1385
|
+
]);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* @generated MessageType for protobuf message sui.rpc.v2.AllowedProposers
|
|
1390
|
+
*/
|
|
1391
|
+
export const AllowedProposers = new AllowedProposers$Type();
|
|
1392
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1325
1393
|
class TransactionKind$Type extends MessageType<TransactionKind> {
|
|
1326
1394
|
constructor() {
|
|
1327
1395
|
super('sui.rpc.v2.TransactionKind', [
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Copyright (c) Mysten Labs, Inc.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { GrpcStatusCode } from '@protobuf-ts/grpcweb-transport';
|
|
5
|
+
import { GrpcWebFetchTransport as UpstreamGrpcWebFetchTransport } from '@protobuf-ts/grpcweb-transport';
|
|
6
|
+
import type {
|
|
7
|
+
MethodInfo,
|
|
8
|
+
RpcOptions,
|
|
9
|
+
ServerStreamingCall,
|
|
10
|
+
UnaryCall,
|
|
11
|
+
} from '@protobuf-ts/runtime-rpc';
|
|
12
|
+
import { RpcError } from '@protobuf-ts/runtime-rpc';
|
|
13
|
+
|
|
14
|
+
// A failed call rejects four promises with the same error, so it is only decoded once. Registered
|
|
15
|
+
// globally so another installed copy of this package sees the same marker.
|
|
16
|
+
const MESSAGE_DECODED = Symbol.for('@mysten/sui/grpc/decoded-status-message');
|
|
17
|
+
|
|
18
|
+
// `grpc-message` is percent-encoded on the wire and the upstream transport does not decode it:
|
|
19
|
+
// https://github.com/timostamm/protobuf-ts/pull/739
|
|
20
|
+
function decodeGrpcStatusMessage(message: string): string {
|
|
21
|
+
if (!message.includes('%')) return message;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
return decodeURIComponent(message);
|
|
25
|
+
} catch {
|
|
26
|
+
return message;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function markStatusMessageRead(error: RpcError): boolean {
|
|
31
|
+
if (MESSAGE_DECODED in error) return false;
|
|
32
|
+
Object.defineProperty(error, MESSAGE_DECODED, { value: true, configurable: true });
|
|
33
|
+
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function decodeStatusMessageOnce(error: RpcError): void {
|
|
38
|
+
if (markStatusMessageRead(error)) error.message = decodeGrpcStatusMessage(error.message);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Whether this package's transport decoded the error's status text. */
|
|
42
|
+
export function hasDecodedStatusMessage(error: object): boolean {
|
|
43
|
+
return MESSAGE_DECODED in error;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// An abort reason is arbitrary, and reading a property on it runs code the caller wrote. A read
|
|
47
|
+
// that throws counts as absent, so one bad accessor does not decide the status.
|
|
48
|
+
function readProperty(value: unknown, key: 'code' | 'name' | 'message'): unknown {
|
|
49
|
+
if (typeof value !== 'object' || value === null) return undefined;
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
return (value as Record<string, unknown>)[key];
|
|
53
|
+
} catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// The reason is read by shape, since another copy of runtime-rpc or another realm fails
|
|
59
|
+
// `instanceof`. `AbortSignal.timeout` aborts with a `TimeoutError`.
|
|
60
|
+
function abortStatus(reason: unknown): string {
|
|
61
|
+
const code = readProperty(reason, 'code');
|
|
62
|
+
|
|
63
|
+
// A status name maps to a number; `in` would also match the enum's reverse mapping.
|
|
64
|
+
if (
|
|
65
|
+
typeof code === 'string' &&
|
|
66
|
+
typeof GrpcStatusCode[code as keyof typeof GrpcStatusCode] === 'number'
|
|
67
|
+
) {
|
|
68
|
+
return code;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return readProperty(reason, 'name') === 'TimeoutError'
|
|
72
|
+
? GrpcStatusCode[GrpcStatusCode.DEADLINE_EXCEEDED]
|
|
73
|
+
: GrpcStatusCode[GrpcStatusCode.CANCELLED];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// The transport reuses the abort reason's message, so matching it says the text is local. A fetch
|
|
77
|
+
// that substitutes its own error (node-fetch) gives text of its own, which holds nothing to decode.
|
|
78
|
+
// The reason is never coerced: a symbol or a throwing hook would throw here.
|
|
79
|
+
function isAbortReasonText(message: string, reason: unknown): boolean {
|
|
80
|
+
if (typeof reason === 'string') return message === reason;
|
|
81
|
+
|
|
82
|
+
const reasonMessage = readProperty(reason, 'message');
|
|
83
|
+
|
|
84
|
+
return typeof reasonMessage === 'string' && message === reasonMessage;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Rewritten in place, so every promise a call rejects surfaces the same error. Only the two codes
|
|
88
|
+
// upstream uses for an abort are re-coded; a failure that raced the abort is relabelled with it.
|
|
89
|
+
function normalizeGrpcError(error: unknown, signal: AbortSignal | undefined): void {
|
|
90
|
+
try {
|
|
91
|
+
normalize(error, signal);
|
|
92
|
+
} catch {
|
|
93
|
+
// Never an unhandled rejection from a discarded handler: the call reports what it was going
|
|
94
|
+
// to report.
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function normalize(error: unknown, signal: AbortSignal | undefined): void {
|
|
99
|
+
if (!(error instanceof RpcError)) return;
|
|
100
|
+
|
|
101
|
+
if (
|
|
102
|
+
signal?.aborted &&
|
|
103
|
+
(error.code === GrpcStatusCode[GrpcStatusCode.INTERNAL] ||
|
|
104
|
+
error.code === GrpcStatusCode[GrpcStatusCode.CANCELLED])
|
|
105
|
+
) {
|
|
106
|
+
error.code = abortStatus(signal.reason);
|
|
107
|
+
|
|
108
|
+
// Text the abort reason supplied is local and holds nothing to decode; anything else came off
|
|
109
|
+
// the wire, even though the abort is what the caller sees. Settled here for the other promises
|
|
110
|
+
// the call rejects, which no longer match the codes above.
|
|
111
|
+
if (isAbortReasonText(error.message, signal.reason)) markStatusMessageRead(error);
|
|
112
|
+
else decodeStatusMessageOnce(error);
|
|
113
|
+
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
decodeStatusMessageOnce(error);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function normalizeRejections(promises: Promise<unknown>[], signal: AbortSignal | undefined) {
|
|
121
|
+
for (const promise of promises) {
|
|
122
|
+
// Registered before the call is returned, so it runs before the consumer's own await.
|
|
123
|
+
promise.then(undefined, (error: unknown) => normalizeGrpcError(error, signal));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* `GrpcWebFetchTransport` from `@protobuf-ts/grpcweb-transport`, subclassed to decode status
|
|
129
|
+
* messages and to code an aborted call from its reason rather than as `INTERNAL`.
|
|
130
|
+
*
|
|
131
|
+
* `SuiGrpcClient` builds one by default. A transport imported from `@protobuf-ts/grpcweb-transport`
|
|
132
|
+
* keeps that package's behaviour.
|
|
133
|
+
*/
|
|
134
|
+
export class GrpcWebFetchTransport extends UpstreamGrpcWebFetchTransport {
|
|
135
|
+
override unary<I extends object, O extends object>(
|
|
136
|
+
method: MethodInfo<I, O>,
|
|
137
|
+
input: I,
|
|
138
|
+
options: RpcOptions,
|
|
139
|
+
): UnaryCall<I, O> {
|
|
140
|
+
const call = super.unary(method, input, options);
|
|
141
|
+
|
|
142
|
+
normalizeRejections([call.headers, call.response, call.status, call.trailers], options.abort);
|
|
143
|
+
|
|
144
|
+
return call;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
override serverStreaming<I extends object, O extends object>(
|
|
148
|
+
method: MethodInfo<I, O>,
|
|
149
|
+
input: I,
|
|
150
|
+
options: RpcOptions,
|
|
151
|
+
): ServerStreamingCall<I, O> {
|
|
152
|
+
const call = super.serverStreaming(method, input, options);
|
|
153
|
+
|
|
154
|
+
// A finite stream is often read through `responses` without awaiting `status`.
|
|
155
|
+
call.responses.onError((error) => normalizeGrpcError(error, options.abort));
|
|
156
|
+
normalizeRejections([call.headers, call.status, call.trailers], options.abort);
|
|
157
|
+
|
|
158
|
+
return call;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -343,10 +343,29 @@ export const ValidDuringSchema = object({
|
|
|
343
343
|
});
|
|
344
344
|
export type ValidDuring = InferOutput<typeof ValidDuringSchema>;
|
|
345
345
|
|
|
346
|
+
// Rust: crates/sui-types/src/transaction.rs
|
|
347
|
+
export const AllowedProposersSchema = object({
|
|
348
|
+
epoch: JsonU64,
|
|
349
|
+
// Shared by `setExpiration` and `restore`, so this can only carry the invariant true on both.
|
|
350
|
+
proposers: pipe(
|
|
351
|
+
array(U32),
|
|
352
|
+
check((proposers) => proposers.length > 0, 'Allowed proposers must not be empty'),
|
|
353
|
+
),
|
|
354
|
+
});
|
|
355
|
+
export type AllowedProposers = InferOutput<typeof AllowedProposersSchema>;
|
|
356
|
+
|
|
357
|
+
// Rust: crates/sui-types/src/transaction.rs
|
|
358
|
+
export const ValiditySchema = object({
|
|
359
|
+
...ValidDuringSchema.entries,
|
|
360
|
+
allowedProposers: nullable(AllowedProposersSchema),
|
|
361
|
+
});
|
|
362
|
+
export type Validity = InferOutput<typeof ValiditySchema>;
|
|
363
|
+
|
|
346
364
|
export const TransactionExpiration = safeEnum({
|
|
347
365
|
None: literal(true),
|
|
348
366
|
Epoch: JsonU64,
|
|
349
367
|
ValidDuring: ValidDuringSchema,
|
|
368
|
+
Validity: ValiditySchema,
|
|
350
369
|
});
|
|
351
370
|
|
|
352
371
|
export type TransactionExpiration = InferOutput<typeof TransactionExpiration>;
|
|
@@ -26,7 +26,14 @@ import {
|
|
|
26
26
|
|
|
27
27
|
import { TypeTagSerializer } from '../../bcs/index.js';
|
|
28
28
|
import type { StructTag as StructTagType, TypeTag as TypeTagType } from '../../bcs/types.js';
|
|
29
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
JsonU64,
|
|
31
|
+
ObjectID,
|
|
32
|
+
safeEnum,
|
|
33
|
+
TransactionDataSchema,
|
|
34
|
+
ValidDuringSchema,
|
|
35
|
+
ValiditySchema,
|
|
36
|
+
} from './internal.js';
|
|
30
37
|
import type { Argument, ArgumentSchema, TransactionData } from './internal.js';
|
|
31
38
|
|
|
32
39
|
export const ObjectRef = object({
|
|
@@ -65,11 +72,52 @@ const TransactionInput = union([
|
|
|
65
72
|
}),
|
|
66
73
|
]);
|
|
67
74
|
|
|
75
|
+
// Carried here rather than collapsed to `{ None: true }`, which silently dropped the expiration
|
|
76
|
+
// (and its allowed proposers) from a `serialize()` -> `from()` round trip before signing.
|
|
68
77
|
const TransactionExpiration = union([
|
|
69
78
|
object({ Epoch: pipe(number(), integer()) }),
|
|
70
79
|
object({ None: nullable(literal(true)) }),
|
|
80
|
+
object({ ValidDuring: ValidDuringSchema }),
|
|
81
|
+
object({ Validity: ValiditySchema }),
|
|
71
82
|
]);
|
|
72
83
|
|
|
84
|
+
function expirationToV1(
|
|
85
|
+
expiration: TransactionData['expiration'],
|
|
86
|
+
): InferOutput<typeof TransactionExpiration> | null {
|
|
87
|
+
if (!expiration) return null;
|
|
88
|
+
|
|
89
|
+
switch (expiration.$kind) {
|
|
90
|
+
case 'Epoch':
|
|
91
|
+
return { Epoch: Number(expiration.Epoch) };
|
|
92
|
+
case 'ValidDuring':
|
|
93
|
+
return { ValidDuring: expiration.ValidDuring };
|
|
94
|
+
case 'Validity':
|
|
95
|
+
return { Validity: expiration.Validity };
|
|
96
|
+
case 'None':
|
|
97
|
+
return { None: true };
|
|
98
|
+
default:
|
|
99
|
+
// Representing a new variant here is not optional: this fails to compile without it.
|
|
100
|
+
expiration satisfies never;
|
|
101
|
+
throw new Error(`Unknown transaction expiration: ${JSON.stringify(expiration)}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function expirationFromV1(
|
|
106
|
+
expiration: SerializedTransactionDataV1['expiration'],
|
|
107
|
+
): InferInput<typeof TransactionDataSchema>['expiration'] {
|
|
108
|
+
if (!expiration) return null;
|
|
109
|
+
if ('Epoch' in expiration) return { Epoch: expiration.Epoch };
|
|
110
|
+
if ('ValidDuring' in expiration) return { ValidDuring: expiration.ValidDuring };
|
|
111
|
+
if ('Validity' in expiration) return { Validity: expiration.Validity };
|
|
112
|
+
if ('None' in expiration) return { None: true };
|
|
113
|
+
|
|
114
|
+
// `restore` does not validate v1 payloads against the schema, so this is the only place an
|
|
115
|
+
// unrecognised expiration can be caught rather than silently becoming `{ None: true }`.
|
|
116
|
+
throw new Error(
|
|
117
|
+
`Unknown transaction expiration in v1 transaction data: ${Object.keys(expiration).join(', ')}`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
73
121
|
const StringEncodedBigint = pipe(
|
|
74
122
|
union([number(), string(), bigint()]),
|
|
75
123
|
check((val) => {
|
|
@@ -267,12 +315,7 @@ export function serializeV1TransactionData(
|
|
|
267
315
|
return {
|
|
268
316
|
version: 1,
|
|
269
317
|
sender: transactionData.sender ?? undefined,
|
|
270
|
-
expiration:
|
|
271
|
-
transactionData.expiration?.$kind === 'Epoch'
|
|
272
|
-
? { Epoch: Number(transactionData.expiration.Epoch) }
|
|
273
|
-
: transactionData.expiration
|
|
274
|
-
? { None: true }
|
|
275
|
-
: null,
|
|
318
|
+
expiration: expirationToV1(transactionData.expiration),
|
|
276
319
|
gasConfig: {
|
|
277
320
|
owner: transactionData.gasData.owner ?? undefined,
|
|
278
321
|
budget: transactionData.gasData.budget ?? undefined,
|
|
@@ -373,11 +416,7 @@ export function transactionDataFromV1(data: SerializedTransactionDataV1): Transa
|
|
|
373
416
|
return parse(TransactionDataSchema, {
|
|
374
417
|
version: 2,
|
|
375
418
|
sender: data.sender ?? null,
|
|
376
|
-
expiration: data.expiration
|
|
377
|
-
? 'Epoch' in data.expiration
|
|
378
|
-
? { Epoch: data.expiration.Epoch }
|
|
379
|
-
: { None: true }
|
|
380
|
-
: null,
|
|
419
|
+
expiration: expirationFromV1(data.expiration),
|
|
381
420
|
gasData: {
|
|
382
421
|
owner: data.gasConfig.owner ?? null,
|
|
383
422
|
budget: data.gasConfig.budget?.toString() ?? null,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
ObjectRefSchema,
|
|
30
30
|
SuiAddress,
|
|
31
31
|
ValidDuringSchema,
|
|
32
|
+
ValiditySchema,
|
|
32
33
|
} from './internal.js';
|
|
33
34
|
import type { Simplify } from '@mysten/utils';
|
|
34
35
|
|
|
@@ -143,6 +144,7 @@ const TransactionExpiration = enumUnion({
|
|
|
143
144
|
None: literal(true),
|
|
144
145
|
Epoch: JsonU64,
|
|
145
146
|
ValidDuring: ValidDuringSchema,
|
|
147
|
+
Validity: ValiditySchema,
|
|
146
148
|
});
|
|
147
149
|
|
|
148
150
|
export const SerializedTransactionDataV2Schema = object({
|