@mysten/pas 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +1 -0
  2. package/dist/client.d.mts +117 -0
  3. package/dist/client.d.mts.map +1 -0
  4. package/dist/client.mjs +89 -0
  5. package/dist/client.mjs.map +1 -0
  6. package/dist/constants.mjs +9 -0
  7. package/dist/constants.mjs.map +1 -0
  8. package/dist/contracts/pas/deps/std/type_name.mjs +17 -0
  9. package/dist/contracts/pas/deps/std/type_name.mjs.map +1 -0
  10. package/dist/contracts/pas/deps/sui/vec_map.mjs +37 -0
  11. package/dist/contracts/pas/deps/sui/vec_map.mjs.map +1 -0
  12. package/dist/contracts/pas/deps/sui/vec_set.mjs +26 -0
  13. package/dist/contracts/pas/deps/sui/vec_set.mjs.map +1 -0
  14. package/dist/contracts/pas/policy.mjs +33 -0
  15. package/dist/contracts/pas/policy.mjs.map +1 -0
  16. package/dist/contracts/pas/versioning.mjs +25 -0
  17. package/dist/contracts/pas/versioning.mjs.map +1 -0
  18. package/dist/contracts/ptb/ptb.mjs +162 -0
  19. package/dist/contracts/ptb/ptb.mjs.map +1 -0
  20. package/dist/contracts/sui/dynamic_field.mjs +22 -0
  21. package/dist/contracts/sui/dynamic_field.mjs.map +1 -0
  22. package/dist/contracts/utils/index.mjs +37 -0
  23. package/dist/contracts/utils/index.mjs.map +1 -0
  24. package/dist/derivation.mjs +70 -0
  25. package/dist/derivation.mjs.map +1 -0
  26. package/dist/error.d.mts +16 -0
  27. package/dist/error.d.mts.map +1 -0
  28. package/dist/error.mjs +26 -0
  29. package/dist/error.mjs.map +1 -0
  30. package/dist/index.d.mts +4 -0
  31. package/dist/index.mjs +4 -0
  32. package/dist/intents.mjs +494 -0
  33. package/dist/intents.mjs.map +1 -0
  34. package/dist/resolution.mjs +185 -0
  35. package/dist/resolution.mjs.map +1 -0
  36. package/dist/types.d.mts +34 -0
  37. package/dist/types.d.mts.map +1 -0
  38. package/package.json +59 -0
  39. package/src/client.ts +173 -0
  40. package/src/constants.ts +15 -0
  41. package/src/contracts/pas/account.ts +343 -0
  42. package/src/contracts/pas/clawback_funds.ts +114 -0
  43. package/src/contracts/pas/deps/std/type_name.ts +24 -0
  44. package/src/contracts/pas/deps/sui/vec_map.ts +33 -0
  45. package/src/contracts/pas/deps/sui/vec_set.ts +22 -0
  46. package/src/contracts/pas/keys.ts +90 -0
  47. package/src/contracts/pas/namespace.ts +207 -0
  48. package/src/contracts/pas/policy.ts +212 -0
  49. package/src/contracts/pas/request.ts +87 -0
  50. package/src/contracts/pas/send_funds.ts +174 -0
  51. package/src/contracts/pas/templates.ts +101 -0
  52. package/src/contracts/pas/unlock_funds.ts +155 -0
  53. package/src/contracts/pas/versioning.ts +69 -0
  54. package/src/contracts/ptb/ptb.ts +821 -0
  55. package/src/contracts/sui/dynamic_field.ts +171 -0
  56. package/src/contracts/utils/index.ts +235 -0
  57. package/src/derivation.ts +107 -0
  58. package/src/error.ts +29 -0
  59. package/src/index.ts +6 -0
  60. package/src/intents.ts +852 -0
  61. package/src/resolution.ts +294 -0
  62. package/src/types.ts +34 -0
@@ -0,0 +1,294 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { SuiClientTypes } from '@mysten/sui/client';
5
+ import { Inputs, TransactionCommands } from '@mysten/sui/transactions';
6
+ import type { Argument, CallArg, Command as SdkCommand } from '@mysten/sui/transactions';
7
+ import { normalizeStructTag } from '@mysten/sui/utils';
8
+
9
+ import { TypeName } from './contracts/pas/deps/std/type_name.js';
10
+ import { Policy } from './contracts/pas/policy.js';
11
+ import { Command, MoveCall } from './contracts/ptb/ptb.js';
12
+ import { PASClientError } from './error.js';
13
+ import { Field } from './contracts/sui/dynamic_field.js';
14
+
15
+ const OBJECT_BY_ID_EXT = 'object_by_id';
16
+ const OBJECT_BY_TYPE_EXT = 'object_by_type';
17
+ const RECEIVING_BY_ID_EXT = 'receiving_by_id';
18
+
19
+ type ParsedTemplateCommand = ReturnType<typeof parseCommand>;
20
+
21
+ /**
22
+ * Extracts all object IDs referenced by template commands, regardless of
23
+ * how they are specified (fully resolved refs, shared refs, or ext lookups).
24
+ */
25
+ export function collectTemplateObjectIds(commands: ParsedTemplateCommand[]): Set<string> {
26
+ const ids = new Set<string>();
27
+ for (const cmd of commands) {
28
+ for (const arg of cmd.arguments) {
29
+ const obj = arg.Input?.Object;
30
+ if (!obj) continue;
31
+
32
+ switch (obj.$kind) {
33
+ case 'ImmOrOwnedObject':
34
+ ids.add(obj.ImmOrOwnedObject.object_id);
35
+ break;
36
+ case 'SharedObject':
37
+ ids.add(obj.SharedObject.object_id);
38
+ break;
39
+ case 'Receiving':
40
+ ids.add(obj.Receiving.object_id);
41
+ break;
42
+ case 'Ext': {
43
+ const [kind, value] = obj.Ext.split(':');
44
+ switch (kind) {
45
+ case OBJECT_BY_ID_EXT:
46
+ case RECEIVING_BY_ID_EXT:
47
+ ids.add(value);
48
+ break;
49
+ default:
50
+ throw new PASClientError(`Unsupported external object kind: ${kind}`);
51
+ }
52
+ break;
53
+ }
54
+ default:
55
+ throw new PASClientError(
56
+ 'Invariant violation: unhandled variant in `collectTemplateObjectIds`',
57
+ );
58
+ }
59
+ }
60
+ }
61
+ return ids;
62
+ }
63
+ /**
64
+ * Supported PAS action types that can be resolved via Policies.
65
+ */
66
+ export type PASActionType = 'send_funds' | 'unlock_funds' | 'clawback_funds';
67
+
68
+ /**
69
+ * Parses the Policy object to extract the required approval type names for a given action.
70
+ *
71
+ * The Policy's `required_approvals` is a `VecMap<String, VecSet<TypeName>>` where:
72
+ * - Key is the action name (e.g., "send_funds")
73
+ * - Value is a set of approval TypeNames that must be satisfied
74
+ *
75
+ * @param policyObject - The Policy object fetched with content
76
+ * @returns The list of approval TypeName strings for the given action, or undefined if not found
77
+ */
78
+ export function getRequiredApprovals(
79
+ policyObject: SuiClientTypes.Object<{ content: true }>,
80
+ actionType: PASActionType,
81
+ ): string[] | undefined {
82
+ const policy = Policy.parse(policyObject.content);
83
+
84
+ const entry = policy.required_approvals.contents.find((e) => e.key === actionType);
85
+
86
+ if (!entry) return undefined;
87
+
88
+ return entry.value.contents.map((tn) => tn.name);
89
+ }
90
+
91
+ /**
92
+ * Parses a Command from a Template dynamic field object.
93
+ *
94
+ * Each Template DF is a `Field<TypeName, Command>` where:
95
+ * - TypeName is the approval type (e.g., the `with_defining_ids` of `TransferApproval`)
96
+ * - Command is the move call instruction to execute for that approval
97
+ *
98
+ * @param templateDF - The Template DF object fetched with content
99
+ * @returns The parsed Command, or undefined if parsing fails
100
+ */
101
+ export function getCommandFromTemplate(
102
+ template: SuiClientTypes.Object<{ content: true }>,
103
+ ): ParsedTemplateCommand {
104
+ const df = Field(TypeName, Command).parse(template.content);
105
+ return parseCommand(df.value);
106
+ }
107
+
108
+ function parseCommand([key, cmd]: ReturnType<typeof Command.parse>) {
109
+ // Support only `Command` for now.
110
+ if (key !== 0) throw new PASClientError(`Unknown command type: ${key}`);
111
+
112
+ // TODO: switch to support more commands like `TransferObjects` etc.
113
+ return MoveCall.parse(new Uint8Array(cmd));
114
+ }
115
+
116
+ // ---------------------------------------------------------------------------
117
+ // Command builder (for use with TransactionDataBuilder / replaceCommand)
118
+ // ---------------------------------------------------------------------------
119
+
120
+ /**
121
+ * Arguments for building a MoveCall Command from a template.
122
+ * Used by the intent resolver which works directly with TransactionDataBuilder.
123
+ */
124
+ interface RawCommandBuildArgs {
125
+ /** Adds an input to the parent transaction and returns the Argument ref. */
126
+ addInput: (type: 'object' | 'pure', arg: CallArg) => Argument;
127
+ /** The sender account argument (already resolved) */
128
+ senderAccount?: Argument;
129
+ /** The receiver account argument (already resolved) */
130
+ receiverAccount?: Argument;
131
+ /** The policy argument (already resolved) */
132
+ policy?: Argument;
133
+ /** The request argument (already resolved) */
134
+ request?: Argument;
135
+ }
136
+
137
+ /**
138
+ * Builds a `Command` (TransactionCommands.MoveCall) from a parsed template command,
139
+ * suitable for use with `transactionData.replaceCommand()`.
140
+ *
141
+ * Resolves template argument placeholders (pas:request, pas:policy, etc.) into
142
+ * concrete Argument references, and converts object/pure inputs via the provided
143
+ * `addInput` callback.
144
+ *
145
+ * @param command - The parsed MoveCall from a template object
146
+ * @param args - The resolved arguments and addInput helper
147
+ * @param commandOffset - Absolute PTB index where the first template command will
148
+ * land. Raw `Result` and `NestedResult` values from the on-chain BCS are
149
+ * template-relative (i.e. `Result(0)` means "first command in this template").
150
+ * We rebase them by adding this offset so they point at the correct position
151
+ * in the final transaction.
152
+ * @returns A Command object ready for `replaceCommand`
153
+ */
154
+ export function buildMoveCallCommandFromTemplate(
155
+ command: ParsedTemplateCommand,
156
+ args: RawCommandBuildArgs,
157
+ commandOffset: number,
158
+ ): SdkCommand {
159
+ const resolvedArgs: Argument[] = [];
160
+
161
+ for (const arg of command.arguments) {
162
+ if (arg.Ext) throw new PASClientError(`There are no supported ext arguments in this client.`);
163
+ else if (arg.GasCoin) throw new PASClientError(`Gas coin is not supported in PAS client.`);
164
+ else if (arg.NestedResult != null)
165
+ resolvedArgs.push({
166
+ $kind: 'NestedResult',
167
+ NestedResult: [arg.NestedResult[0] + commandOffset, arg.NestedResult[1]],
168
+ });
169
+ else if (arg.Result != null)
170
+ resolvedArgs.push({ $kind: 'Result', Result: arg.Result + commandOffset });
171
+ else if (arg.Input) {
172
+ if (arg.Input.Pure)
173
+ resolvedArgs.push(args.addInput('pure', Inputs.Pure(new Uint8Array(arg.Input.Pure))));
174
+ else if (arg.Input.Object) {
175
+ switch (arg.Input.Object.$kind) {
176
+ case 'ImmOrOwnedObject':
177
+ resolvedArgs.push(
178
+ args.addInput(
179
+ 'object',
180
+ Inputs.ObjectRef({
181
+ objectId: arg.Input.Object.ImmOrOwnedObject.object_id,
182
+ version: arg.Input.Object.ImmOrOwnedObject.sequence_number,
183
+ digest: arg.Input.Object.ImmOrOwnedObject.digest,
184
+ }),
185
+ ),
186
+ );
187
+ break;
188
+ case 'SharedObject':
189
+ resolvedArgs.push(
190
+ args.addInput(
191
+ 'object',
192
+ Inputs.SharedObjectRef({
193
+ objectId: arg.Input.Object.SharedObject.object_id,
194
+ initialSharedVersion: arg.Input.Object.SharedObject.initial_shared_version,
195
+ mutable: arg.Input.Object.SharedObject.is_mutable,
196
+ }),
197
+ ),
198
+ );
199
+ break;
200
+ case 'Receiving':
201
+ resolvedArgs.push(
202
+ args.addInput(
203
+ 'object',
204
+ Inputs.ReceivingRef({
205
+ objectId: arg.Input.Object.Receiving.object_id,
206
+ version: arg.Input.Object.Receiving.sequence_number,
207
+ digest: arg.Input.Object.Receiving.digest,
208
+ }),
209
+ ),
210
+ );
211
+ break;
212
+ case 'Ext':
213
+ const [kind, value] = arg.Input.Object.Ext.split(':');
214
+
215
+ switch (kind) {
216
+ case OBJECT_BY_ID_EXT:
217
+ case RECEIVING_BY_ID_EXT:
218
+ resolvedArgs.push(
219
+ args.addInput('object', {
220
+ $kind: 'UnresolvedObject',
221
+ UnresolvedObject: { objectId: value },
222
+ } as CallArg),
223
+ );
224
+ break;
225
+ case OBJECT_BY_TYPE_EXT:
226
+ throw new PASClientError(
227
+ `There are no supported object by type arguments in this client.`,
228
+ );
229
+ default:
230
+ throw new PASClientError(`Unknown external object argument: ${kind}`);
231
+ }
232
+ break;
233
+ default:
234
+ throw new PASClientError(
235
+ `Not supported object argument: ${JSON.stringify(arg.Input.Object)}`,
236
+ );
237
+ }
238
+ } else if (arg.Input.Ext) {
239
+ resolvedArgs.push(
240
+ resolveRawPasRequest(args, {
241
+ namespace: arg.Input.Ext[0],
242
+ value: arg.Input.Ext[1],
243
+ }),
244
+ );
245
+ } else {
246
+ throw new PASClientError(`Unsupported input kind: ${arg.Input.$kind}`);
247
+ }
248
+ }
249
+ }
250
+
251
+ const typeArgs: string[] = [];
252
+ for (const typeArg of command.type_arguments)
253
+ typeArgs.push(normalizeStructTag(typeArg).toString());
254
+
255
+ if (!command.module_name || !command.function)
256
+ throw new PASClientError(
257
+ 'Module name or function name is missing from the on-chain policy. This means that the issuer has not set up the policy correctly.',
258
+ );
259
+
260
+ return TransactionCommands.MoveCall({
261
+ package: command.package_id,
262
+ module: command.module_name,
263
+ function: command.function,
264
+ arguments: resolvedArgs,
265
+ typeArguments: typeArgs.length > 0 ? typeArgs : [],
266
+ });
267
+ }
268
+
269
+ function resolveRawPasRequest(
270
+ args: RawCommandBuildArgs,
271
+ extInput: { namespace: string; value: string },
272
+ ): Argument {
273
+ if (!extInput.namespace.endsWith('templates::PAS'))
274
+ throw new PASClientError(`Unsupported namespace: ${extInput.namespace}`);
275
+
276
+ switch (extInput.value) {
277
+ case 'request':
278
+ if (!args.request) throw new PASClientError(`Request is not set in the context.`);
279
+ return args.request;
280
+ case 'policy':
281
+ if (!args.policy) throw new PASClientError(`Policy is not set in the context.`);
282
+ return args.policy;
283
+ case 'sender_account':
284
+ if (!args.senderAccount)
285
+ throw new PASClientError(`Sender account is not set in the context.`);
286
+ return args.senderAccount;
287
+ case 'receiver_account':
288
+ if (!args.receiverAccount)
289
+ throw new PASClientError(`Receiver account is not set in the context.`);
290
+ return args.receiverAccount;
291
+ default:
292
+ throw new PASClientError(`Unknown pas request: ${extInput.value}`);
293
+ }
294
+ }
package/src/types.ts ADDED
@@ -0,0 +1,34 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import type { ClientWithCoreApi } from '@mysten/sui/client';
5
+
6
+ /**
7
+ * Configuration for the PAS package on a specific network
8
+ */
9
+ export interface PASPackageConfig {
10
+ /** The package ID of the PAS package */
11
+ packageId: string;
12
+ /** The namespace ID of the PAS package */
13
+ namespaceId: string;
14
+ }
15
+
16
+ /**
17
+ * Configuration for the PAS client
18
+ */
19
+ export interface PASClientConfig {
20
+ /** The Sui client to use */
21
+ suiClient: ClientWithCoreApi;
22
+ /** The package configuration (if network is not provided or supported) */
23
+ packageConfig?: PASPackageConfig;
24
+ }
25
+
26
+ /**
27
+ * Options for creating a PAS client plugin
28
+ */
29
+ export interface PASOptions<Name extends string = 'pas'> {
30
+ /** The name of the plugin */
31
+ name?: Name;
32
+ /** The package configuration */
33
+ packageConfig?: PASPackageConfig;
34
+ }