Skip to content

Commit 73097de

Browse files
committed
Migrate suins to sdk-v2 (#743)
1 parent 6664eba commit 73097de

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+7300
-354
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
'@mysten/suins': major
3+
---
4+
5+
Update SuinsClient to use ClientWithCoreApi for transport-agnostic client support (JSON-RPC, GraphQL, gRPC).
6+
7+
**Breaking changes:**
8+
9+
- `SuinsClient` now requires a client implementing `ClientWithCoreApi` instead of `SuiClient`
10+
- Package ID extraction now correctly uses `upgrade_cap.package` from state objects instead of object type
11+
12+
**Migration:**
13+
14+
```diff
15+
- import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';
16+
+ import { SuiJsonRpcClient, getJsonRpcFullnodeUrl } from '@mysten/sui/jsonRpc';
17+
import { SuinsClient } from '@mysten/suins';
18+
19+
- const suiClient = new SuiClient({ url: getFullnodeUrl('mainnet') });
20+
+ const suiClient = new SuiJsonRpcClient({
21+
+ url: getJsonRpcFullnodeUrl('mainnet'),
22+
+ network: 'mainnet',
23+
+ });
24+
25+
const suinsClient = new SuinsClient({
26+
client: suiClient,
27+
network: 'mainnet',
28+
});
29+
```
30+
31+
This change allows SuinsClient to work with any Sui client implementation (JSON-RPC, GraphQL, or gRPC).

packages/codegen/src/config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,38 @@ import { isValidNamedPackage, isValidSuiObjectId } from '@mysten/sui/utils';
55
import { cosmiconfig } from 'cosmiconfig';
66
import * as z from 'zod/v4';
77

8+
export const moduleIncludeSchema = z.object({
9+
types: z.array(z.string()).optional(),
10+
functions: z.array(z.string()).optional(),
11+
});
12+
13+
export const packageIncludeSchema = z.union([
14+
z.array(z.string()),
15+
z.record(z.string(), moduleIncludeSchema),
16+
]);
17+
818
export const onChainPackageSchema = z.object({
919
package: z.string().refine((name) => isValidNamedPackage(name) || isValidSuiObjectId(name), {
1020
message: 'Invalid package name or package ID',
1121
}),
1222
packageName: z.string(),
1323
path: z.never().optional(),
1424
network: z.enum(['mainnet', 'testnet']),
25+
include: packageIncludeSchema.optional(),
1526
});
1627

1728
export const localPackageSchema = z.object({
1829
path: z.string(),
1930
package: z.string(),
2031
packageName: z.string().optional(),
32+
include: packageIncludeSchema.optional(),
2133
});
2234

2335
export const packageConfigSchema = z.union([onChainPackageSchema, localPackageSchema]);
2436

37+
export type ModuleInclude = z.infer<typeof moduleIncludeSchema>;
38+
export type PackageInclude = z.infer<typeof packageIncludeSchema>;
39+
2540
export const importExtensionSchema = z.union([z.literal('.js'), z.literal('.ts'), z.literal('')]);
2641
export type ImportExtension = z.infer<typeof importExtensionSchema>;
2742

packages/codegen/src/index.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { MoveModuleBuilder } from './move-module-builder.js';
77
import { existsSync, statSync } from 'node:fs';
88
import { utilsContent } from './generate-utils.js';
99
import { parse } from 'toml';
10-
import type { ImportExtension, PackageConfig } from './config.js';
10+
import type { ImportExtension, PackageConfig, PackageInclude } from './config.js';
1111
export { type SuiCodegenConfig } from './config.js';
1212

1313
export async function generateFromPackageSummary({
@@ -108,11 +108,43 @@ export async function generateFromPackageSummary({
108108
modules.map((mod) => [`${mod.package}::${mod.module}`, mod.builder]),
109109
);
110110

111+
const include: PackageInclude | undefined = 'include' in pkg ? pkg.include : undefined;
112+
111113
modules.forEach((mod) => {
112-
if (mod.isMainPackage || !prune) {
114+
if (!mod.isMainPackage && prune) {
115+
return;
116+
}
117+
118+
// If include is an array, it specifies which modules to include
119+
if (Array.isArray(include)) {
120+
if (!include.includes(mod.module)) {
121+
return;
122+
}
113123
mod.builder.includeAllTypes(moduleBuilders);
114124
mod.builder.includeAllFunctions({ privateMethods });
125+
return;
126+
}
127+
128+
// If include is a record, it specifies types/functions per module
129+
if (include && mod.module in include) {
130+
const moduleInclude = include[mod.module];
131+
if (moduleInclude.types) {
132+
mod.builder.includeTypes(moduleInclude.types, moduleBuilders);
133+
}
134+
if (moduleInclude.functions) {
135+
mod.builder.includeFunctions({ names: moduleInclude.functions, privateMethods });
136+
}
137+
return;
115138
}
139+
140+
// If include is specified but this module isn't in it, skip
141+
if (include) {
142+
return;
143+
}
144+
145+
// Default: include everything
146+
mod.builder.includeAllTypes(moduleBuilders);
147+
mod.builder.includeAllFunctions({ privateMethods });
116148
});
117149

118150
await generateUtils({ outputDir });

packages/codegen/src/move-module-builder.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,27 @@ export class MoveModuleBuilder extends FileBuilder {
117117
}
118118

119119
includeAllFunctions({ privateMethods = 'entry' }: { privateMethods?: 'none' | 'entry' | 'all' }) {
120-
for (const [name, func] of Object.entries(this.summary.functions)) {
120+
this.includeFunctions({
121+
names: Object.keys(this.summary.functions),
122+
privateMethods,
123+
});
124+
}
125+
126+
includeFunctions({
127+
names,
128+
privateMethods = 'entry',
129+
}: {
130+
names: string[];
131+
privateMethods?: 'none' | 'entry' | 'all';
132+
}) {
133+
for (const name of names) {
134+
const func = this.summary.functions[name];
135+
if (!func) {
136+
throw new Error(
137+
`Function ${name} not found in ${this.summary.id.address}::${this.summary.id.name}`,
138+
);
139+
}
140+
121141
if (func.macro_) {
122142
continue;
123143
}
@@ -212,9 +232,17 @@ export class MoveModuleBuilder extends FileBuilder {
212232
this.#orderedTypes.push(name);
213233
}
214234

235+
includeTypes(names: string[], moduleBuilders: Record<string, MoveModuleBuilder>) {
236+
for (const name of names) {
237+
this.includeType(name, moduleBuilders);
238+
}
239+
}
240+
215241
includeAllTypes(moduleBuilders: Record<string, MoveModuleBuilder>) {
216-
Object.keys(this.summary.structs).forEach((name) => this.includeType(name, moduleBuilders));
217-
Object.keys(this.summary.enums).forEach((name) => this.includeType(name, moduleBuilders));
242+
this.includeTypes(
243+
[...Object.keys(this.summary.structs), ...Object.keys(this.summary.enums)],
244+
moduleBuilders,
245+
);
218246
}
219247

220248
async renderBCSTypes() {

packages/docs/content/sui/migrations/sui-2.0.mdx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,3 +387,51 @@ If you were using the plugin with `@mysten/mvr-static`:
387387

388388
The client will now automatically resolve `.move` names in transactions using the configured
389389
overrides or by querying the MVR API if no override is provided.
390+
391+
## @mysten/suins: ClientWithCoreApi Support
392+
393+
The `@mysten/suins` package now uses the transport-agnostic `ClientWithCoreApi` interface, allowing
394+
it to work with any Sui client implementation (JSON-RPC, GraphQL, or gRPC).
395+
396+
**Breaking changes:**
397+
398+
- `SuinsClient` now requires a client implementing `ClientWithCoreApi` instead of `SuiClient`
399+
- Internal package ID resolution now correctly extracts `upgrade_cap.package` from state objects
400+
401+
**Migration:**
402+
403+
Update your imports and client initialization:
404+
405+
```diff
406+
- import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';
407+
+ import { SuiJsonRpcClient, getJsonRpcFullnodeUrl } from '@mysten/sui/jsonRpc';
408+
import { SuinsClient } from '@mysten/suins';
409+
410+
- const suiClient = new SuiClient({ url: getFullnodeUrl('mainnet') });
411+
+ const suiClient = new SuiJsonRpcClient({
412+
+ url: getJsonRpcFullnodeUrl('mainnet'),
413+
+ network: 'mainnet',
414+
+ });
415+
416+
const suinsClient = new SuinsClient({
417+
client: suiClient,
418+
network: 'mainnet',
419+
});
420+
```
421+
422+
You can also use GraphQL or gRPC clients:
423+
424+
```ts
425+
import { SuiGraphQLClient } from '@mysten/sui/graphql';
426+
import { SuinsClient } from '@mysten/suins';
427+
428+
const graphqlClient = new SuiGraphQLClient({
429+
url: 'https://sui-mainnet.mystenlabs.com/graphql',
430+
network: 'mainnet',
431+
});
432+
433+
const suinsClient = new SuinsClient({
434+
client: graphqlClient,
435+
network: 'mainnet',
436+
});
437+
```

packages/sui/src/client/core.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { normalizeStructTag, parseStructTag, SUI_ADDRESS_LENGTH } from '../utils
88
import { BaseClient } from './client.js';
99
import type { ClientWithExtensions, SuiClientTypes } from './types.js';
1010
import { MvrClient } from './mvr.js';
11+
import { bcs } from '../bcs/index.js';
1112

1213
export type ClientWithCoreApi = ClientWithExtensions<{
1314
core: CoreClient;
@@ -163,6 +164,34 @@ export abstract class CoreClient extends BaseClient implements SuiClientTypes.Tr
163164
};
164165
}
165166

167+
async getDynamicObjectField<Include extends SuiClientTypes.ObjectInclude = object>(
168+
options: SuiClientTypes.GetDynamicObjectFieldOptions<Include>,
169+
): Promise<SuiClientTypes.GetDynamicObjectFieldResponse<Include>> {
170+
const resolvedNameType = (
171+
await this.core.mvr.resolveType({
172+
type: options.name.type,
173+
})
174+
).type;
175+
const wrappedType = `0x2::dynamic_object_field::Wrapper<${resolvedNameType}>`;
176+
177+
const { dynamicField } = await this.getDynamicField({
178+
parentId: options.parentId,
179+
name: {
180+
type: wrappedType,
181+
bcs: options.name.bcs,
182+
},
183+
signal: options.signal,
184+
});
185+
186+
const { object } = await this.getObject({
187+
objectId: bcs.Address.parse(dynamicField.value.bcs),
188+
signal: options.signal,
189+
include: options.include,
190+
});
191+
192+
return { object };
193+
}
194+
166195
async waitForTransaction<Include extends SuiClientTypes.TransactionInclude = object>(
167196
options: SuiClientTypes.WaitForTransactionOptions<Include>,
168197
): Promise<SuiClientTypes.TransactionResult<Include>> {

packages/sui/src/client/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,18 @@ export namespace SuiClientTypes {
168168
};
169169
}
170170

171+
export interface GetDynamicObjectFieldOptions<
172+
Include extends ObjectInclude = {},
173+
> extends CoreClientMethodOptions {
174+
parentId: string;
175+
name: DynamicFieldName;
176+
include?: Include;
177+
}
178+
179+
export interface GetDynamicObjectFieldResponse<out Include extends ObjectInclude = {}> {
180+
object: Object<Include>;
181+
}
182+
171183
export interface DynamicFieldName {
172184
type: string;
173185
bcs: Uint8Array;

packages/suins/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"src"
2727
],
2828
"scripts": {
29+
"codegen": "sui-ts-codegen generate && pnpm lint:fix",
2930
"clean": "rm -rf tsconfig.tsbuildinfo ./dist",
3031
"build": "rm -rf dist && tsc --noEmit && tsdown",
3132
"prettier:check": "prettier -c --ignore-unknown .",
@@ -45,6 +46,7 @@
4546
"axios-retry": "^4.5.0"
4647
},
4748
"devDependencies": {
49+
"@mysten/codegen": "workspace:*",
4850
"@types/tmp": "^0.2.6",
4951
"ts-retry-promise": "^0.8.1",
5052
"typescript": "^5.9.3",
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**************************************************************
2+
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
3+
**************************************************************/
4+
import { MoveStruct } from '../utils/index.js';
5+
import { bcs } from '@mysten/sui/bcs';
6+
import * as external_address from './deps/0xf47329f4344f3bf0f8e436e2f7b485466cff300f12a166563995d3888c296a94/external_address.js';
7+
const $moduleName =
8+
'0xabf837e98c26087cba0883c0a7a28326b1fa3c5e1e2c5abdb486f9e8f594c837::data_source';
9+
export const DataSource = new MoveStruct({
10+
name: `${$moduleName}::DataSource`,
11+
fields: {
12+
emitter_chain: bcs.u64(),
13+
emitter_address: external_address.ExternalAddress,
14+
},
15+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**************************************************************
2+
* THIS FILE IS GENERATED AND SHOULD NOT BE MANUALLY MODIFIED *
3+
**************************************************************/
4+
import { MoveStruct } from '../../../utils/index.js';
5+
import { bcs } from '@mysten/sui/bcs';
6+
const $moduleName = '0x2::object';
7+
export const UID = new MoveStruct({
8+
name: `${$moduleName}::UID`,
9+
fields: {
10+
id: bcs.Address,
11+
},
12+
});

0 commit comments

Comments
 (0)