@mysten/create-dapp 0.5.13 → 0.6.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 (43) hide show
  1. package/CHANGELOG.md +49 -2
  2. package/README.md +0 -1
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +32 -8
  6. package/dist/index.js.map +1 -1
  7. package/package.json +10 -10
  8. package/src/index.ts +58 -36
  9. package/templates/.oxlintrc.json +5 -0
  10. package/templates/react-client-dapp/README.md +31 -4
  11. package/templates/react-client-dapp/index.html +2 -48
  12. package/templates/react-client-dapp/package.json +14 -17
  13. package/templates/react-client-dapp/prettier.config.cjs +0 -1
  14. package/templates/react-client-dapp/src/App.tsx +12 -30
  15. package/templates/react-client-dapp/src/OwnedObjects.tsx +58 -31
  16. package/templates/react-client-dapp/src/WalletStatus.tsx +38 -13
  17. package/templates/react-client-dapp/src/components/ui/card.tsx +75 -0
  18. package/templates/react-client-dapp/src/dApp-kit.ts +24 -0
  19. package/templates/react-client-dapp/src/index.css +39 -0
  20. package/templates/react-client-dapp/src/lib/utils.ts +6 -0
  21. package/templates/react-client-dapp/src/main.tsx +8 -14
  22. package/templates/react-client-dapp/vite.config.mts +2 -1
  23. package/templates/react-e2e-counter/.gitattributes +2 -0
  24. package/templates/react-e2e-counter/README.md +53 -7
  25. package/templates/react-e2e-counter/index.html +2 -48
  26. package/templates/react-e2e-counter/package.json +18 -20
  27. package/templates/react-e2e-counter/prettier.config.cjs +0 -1
  28. package/templates/react-e2e-counter/src/App.tsx +29 -30
  29. package/templates/react-e2e-counter/src/Counter.tsx +147 -74
  30. package/templates/react-e2e-counter/src/CreateCounter.tsx +84 -43
  31. package/templates/react-e2e-counter/src/components/ui/button.tsx +52 -0
  32. package/templates/react-e2e-counter/src/components/ui/card.tsx +75 -0
  33. package/templates/react-e2e-counter/src/constants.ts +4 -3
  34. package/templates/react-e2e-counter/src/contracts/counter/counter.ts +96 -0
  35. package/templates/react-e2e-counter/src/contracts/utils/index.ts +243 -0
  36. package/templates/react-e2e-counter/src/dApp-kit.ts +48 -0
  37. package/templates/react-e2e-counter/src/index.css +39 -0
  38. package/templates/react-e2e-counter/src/lib/utils.ts +6 -0
  39. package/templates/react-e2e-counter/src/main.tsx +8 -14
  40. package/templates/react-e2e-counter/sui-codegen.config.ts +13 -0
  41. package/templates/react-e2e-counter/vite.config.mts +2 -1
  42. package/templates/react-client-dapp/src/networkConfig.ts +0 -17
  43. package/templates/react-e2e-counter/src/networkConfig.ts +0 -31
@@ -0,0 +1,243 @@
1
+ import {
2
+ bcs,
3
+ BcsType,
4
+ TypeTag,
5
+ TypeTagSerializer,
6
+ BcsStruct,
7
+ BcsEnum,
8
+ BcsTuple,
9
+ } from "@mysten/sui/bcs";
10
+ import { normalizeSuiAddress } from "@mysten/sui/utils";
11
+ import { TransactionArgument, isArgument } from "@mysten/sui/transactions";
12
+ import { ClientWithCoreApi, SuiClientTypes } from "@mysten/sui/client";
13
+
14
+ const MOVE_STDLIB_ADDRESS = normalizeSuiAddress("0x1");
15
+ const SUI_FRAMEWORK_ADDRESS = normalizeSuiAddress("0x2");
16
+
17
+ export type RawTransactionArgument<T> = T | TransactionArgument;
18
+
19
+ export interface GetOptions<
20
+ Include extends Omit<SuiClientTypes.ObjectInclude, "content"> = {},
21
+ > extends SuiClientTypes.GetObjectOptions<Include> {
22
+ client: ClientWithCoreApi;
23
+ }
24
+
25
+ export interface GetManyOptions<
26
+ Include extends Omit<SuiClientTypes.ObjectInclude, "content"> = {},
27
+ > extends SuiClientTypes.GetObjectsOptions<Include> {
28
+ client: ClientWithCoreApi;
29
+ }
30
+
31
+ export function getPureBcsSchema(
32
+ typeTag: string | TypeTag,
33
+ ): BcsType<any> | null {
34
+ const parsedTag =
35
+ typeof typeTag === "string"
36
+ ? TypeTagSerializer.parseFromStr(typeTag)
37
+ : typeTag;
38
+
39
+ if ("u8" in parsedTag) {
40
+ return bcs.U8;
41
+ } else if ("u16" in parsedTag) {
42
+ return bcs.U16;
43
+ } else if ("u32" in parsedTag) {
44
+ return bcs.U32;
45
+ } else if ("u64" in parsedTag) {
46
+ return bcs.U64;
47
+ } else if ("u128" in parsedTag) {
48
+ return bcs.U128;
49
+ } else if ("u256" in parsedTag) {
50
+ return bcs.U256;
51
+ } else if ("address" in parsedTag) {
52
+ return bcs.Address;
53
+ } else if ("bool" in parsedTag) {
54
+ return bcs.Bool;
55
+ } else if ("vector" in parsedTag) {
56
+ const type = getPureBcsSchema(parsedTag.vector);
57
+ return type ? bcs.vector(type) : null;
58
+ } else if ("struct" in parsedTag) {
59
+ const structTag = parsedTag.struct;
60
+ const pkg = normalizeSuiAddress(structTag.address);
61
+
62
+ if (pkg === MOVE_STDLIB_ADDRESS) {
63
+ if (
64
+ (structTag.module === "ascii" || structTag.module === "string") &&
65
+ structTag.name === "String"
66
+ ) {
67
+ return bcs.String;
68
+ }
69
+
70
+ if (structTag.module === "option" && structTag.name === "Option") {
71
+ const type = getPureBcsSchema(structTag.typeParams[0]);
72
+ return type ? bcs.option(type) : null;
73
+ }
74
+ }
75
+
76
+ if (
77
+ pkg === SUI_FRAMEWORK_ADDRESS &&
78
+ structTag.module === "object" &&
79
+ (structTag.name === "ID" || structTag.name === "UID")
80
+ ) {
81
+ return bcs.Address;
82
+ }
83
+ }
84
+
85
+ return null;
86
+ }
87
+
88
+ export function normalizeMoveArguments(
89
+ args: unknown[] | object,
90
+ argTypes: readonly (string | null)[],
91
+ parameterNames?: string[],
92
+ ) {
93
+ const argLen = Array.isArray(args) ? args.length : Object.keys(args).length;
94
+ if (parameterNames && argLen !== parameterNames.length) {
95
+ throw new Error(
96
+ `Invalid number of arguments, expected ${parameterNames.length}, got ${argLen}`,
97
+ );
98
+ }
99
+
100
+ const normalizedArgs: TransactionArgument[] = [];
101
+
102
+ let index = 0;
103
+ for (const [i, argType] of argTypes.entries()) {
104
+ if (argType === "0x2::clock::Clock") {
105
+ normalizedArgs.push((tx) => tx.object.clock());
106
+ continue;
107
+ }
108
+
109
+ if (argType === "0x2::random::Random") {
110
+ normalizedArgs.push((tx) => tx.object.random());
111
+ continue;
112
+ }
113
+
114
+ if (argType === "0x2::deny_list::DenyList") {
115
+ normalizedArgs.push((tx) => tx.object.denyList());
116
+ continue;
117
+ }
118
+
119
+ if (argType === "0x3::sui_system::SuiSystemState") {
120
+ normalizedArgs.push((tx) => tx.object.system());
121
+ continue;
122
+ }
123
+
124
+ let arg;
125
+ if (Array.isArray(args)) {
126
+ if (index >= args.length) {
127
+ throw new Error(
128
+ `Invalid number of arguments, expected at least ${index + 1}, got ${args.length}`,
129
+ );
130
+ }
131
+ arg = args[index];
132
+ } else {
133
+ if (!parameterNames) {
134
+ throw new Error(`Expected arguments to be passed as an array`);
135
+ }
136
+ const name = parameterNames[index];
137
+ arg = args[name as keyof typeof args];
138
+
139
+ if (arg === undefined) {
140
+ throw new Error(`Parameter ${name} is required`);
141
+ }
142
+ }
143
+
144
+ index += 1;
145
+
146
+ if (typeof arg === "function" || isArgument(arg)) {
147
+ normalizedArgs.push(arg as TransactionArgument);
148
+ continue;
149
+ }
150
+
151
+ const type = argTypes[i];
152
+ const bcsType = type === null ? null : getPureBcsSchema(type);
153
+
154
+ if (bcsType) {
155
+ const bytes = bcsType.serialize(arg as never);
156
+ normalizedArgs.push((tx) => tx.pure(bytes));
157
+ continue;
158
+ } else if (typeof arg === "string") {
159
+ normalizedArgs.push((tx) => tx.object(arg));
160
+ continue;
161
+ }
162
+
163
+ throw new Error(`Invalid argument ${stringify(arg)} for type ${type}`);
164
+ }
165
+
166
+ return normalizedArgs;
167
+ }
168
+
169
+ export class MoveStruct<
170
+ T extends Record<string, BcsType<any>>,
171
+ const Name extends string = string,
172
+ > extends BcsStruct<T, Name> {
173
+ async get<
174
+ Include extends Omit<SuiClientTypes.ObjectInclude, "content" | "json"> = {},
175
+ >({
176
+ objectId,
177
+ ...options
178
+ }: GetOptions<Include>): Promise<
179
+ SuiClientTypes.Object<Include & { content: true; json: true }> & {
180
+ json: BcsStruct<T>["$inferType"];
181
+ }
182
+ > {
183
+ const [res] = await this.getMany<Include>({
184
+ ...options,
185
+ objectIds: [objectId],
186
+ });
187
+
188
+ return res;
189
+ }
190
+
191
+ async getMany<
192
+ Include extends Omit<SuiClientTypes.ObjectInclude, "content" | "json"> = {},
193
+ >({
194
+ client,
195
+ ...options
196
+ }: GetManyOptions<Include>): Promise<
197
+ Array<
198
+ SuiClientTypes.Object<Include & { content: true; json: true }> & {
199
+ json: BcsStruct<T>["$inferType"];
200
+ }
201
+ >
202
+ > {
203
+ const response = (await client.core.getObjects({
204
+ ...options,
205
+ include: {
206
+ ...options.include,
207
+ content: true,
208
+ },
209
+ })) as SuiClientTypes.GetObjectsResponse<Include & { content: true }>;
210
+
211
+ return response.objects.map((obj) => {
212
+ if (obj instanceof Error) {
213
+ throw obj;
214
+ }
215
+
216
+ return {
217
+ ...obj,
218
+ json: this.parse(obj.content),
219
+ };
220
+ });
221
+ }
222
+ }
223
+
224
+ export class MoveEnum<
225
+ T extends Record<string, BcsType<any> | null>,
226
+ const Name extends string,
227
+ > extends BcsEnum<T, Name> {}
228
+
229
+ export class MoveTuple<
230
+ T extends readonly BcsType<any>[],
231
+ const Name extends string,
232
+ > extends BcsTuple<T, Name> {}
233
+
234
+ function stringify(val: unknown) {
235
+ if (typeof val === "object") {
236
+ return JSON.stringify(val, (val: unknown) => val);
237
+ }
238
+ if (typeof val === "bigint") {
239
+ return val.toString();
240
+ }
241
+
242
+ return val;
243
+ }
@@ -0,0 +1,48 @@
1
+ import { createDAppKit } from "@mysten/dapp-kit-react";
2
+ import { SuiGrpcClient } from "@mysten/sui/grpc";
3
+ import {
4
+ DEVNET_COUNTER_PACKAGE_ID,
5
+ TESTNET_COUNTER_PACKAGE_ID,
6
+ MAINNET_COUNTER_PACKAGE_ID,
7
+ } from "./constants.ts";
8
+
9
+ const GRPC_URLS = {
10
+ mainnet: "https://fullnode.mainnet.sui.io:443",
11
+ testnet: "https://fullnode.testnet.sui.io:443",
12
+ devnet: "https://fullnode.devnet.sui.io:443",
13
+ };
14
+
15
+ // MVR overrides per network - map local package names to deployed addresses
16
+ const MVR_OVERRIDES = {
17
+ mainnet: MAINNET_COUNTER_PACKAGE_ID && {
18
+ packages: {
19
+ "@local-pkg/counter": MAINNET_COUNTER_PACKAGE_ID,
20
+ },
21
+ },
22
+ testnet: TESTNET_COUNTER_PACKAGE_ID && {
23
+ packages: { "@local-pkg/counter": TESTNET_COUNTER_PACKAGE_ID },
24
+ },
25
+ devnet: DEVNET_COUNTER_PACKAGE_ID && {
26
+ packages: { "@local-pkg/counter": DEVNET_COUNTER_PACKAGE_ID },
27
+ },
28
+ } as const;
29
+
30
+ export const dAppKit = createDAppKit({
31
+ enableBurnerWallet: import.meta.env.DEV,
32
+ networks: ["mainnet", "testnet", "devnet"],
33
+ defaultNetwork: "testnet",
34
+ createClient(network) {
35
+ return new SuiGrpcClient({
36
+ network,
37
+ baseUrl: GRPC_URLS[network],
38
+ mvr: MVR_OVERRIDES[network] ? { overrides: MVR_OVERRIDES[network] } : {},
39
+ });
40
+ },
41
+ });
42
+
43
+ // global type registration necessary for the hooks to work correctly
44
+ declare module "@mysten/dapp-kit-react" {
45
+ interface Register {
46
+ dAppKit: typeof dAppKit;
47
+ }
48
+ }
@@ -0,0 +1,39 @@
1
+ @import "tailwindcss";
2
+
3
+ @theme {
4
+ --color-background: oklch(0.145 0 0);
5
+ --color-foreground: oklch(0.985 0 0);
6
+ --color-card: oklch(0.145 0 0);
7
+ --color-card-foreground: oklch(0.985 0 0);
8
+ --color-primary: oklch(0.985 0 0);
9
+ --color-primary-foreground: oklch(0.205 0 0);
10
+ --color-secondary: oklch(0.269 0 0);
11
+ --color-secondary-foreground: oklch(0.985 0 0);
12
+ --color-muted: oklch(0.269 0 0);
13
+ --color-muted-foreground: oklch(0.708 0 0);
14
+ --color-accent: oklch(0.269 0 0);
15
+ --color-accent-foreground: oklch(0.985 0 0);
16
+ --color-destructive: oklch(0.396 0.141 25.723);
17
+ --color-destructive-foreground: oklch(0.637 0.237 25.331);
18
+ --color-border: oklch(0.269 0 0);
19
+ --color-input: oklch(0.269 0 0);
20
+ --color-ring: oklch(0.556 0 0);
21
+ --color-sui: oklch(0.7 0.2 220);
22
+
23
+ --radius-sm: 0.25rem;
24
+ --radius-md: 0.375rem;
25
+ --radius-lg: 0.5rem;
26
+ --radius-xl: 0.75rem;
27
+ }
28
+
29
+ * {
30
+ border-color: var(--color-border);
31
+ }
32
+
33
+ body {
34
+ background-color: var(--color-background);
35
+ color: var(--color-foreground);
36
+ font-family:
37
+ ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
38
+ "Segoe UI Symbol", "Noto Color Emoji";
39
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -1,26 +1,20 @@
1
1
  import React from "react";
2
2
  import ReactDOM from "react-dom/client";
3
- import "@mysten/dapp-kit/dist/index.css";
4
- import "@radix-ui/themes/styles.css";
3
+ import "./index.css";
5
4
 
6
- import { SuiClientProvider, WalletProvider } from "@mysten/dapp-kit";
5
+ import { DAppKitProvider } from "@mysten/dapp-kit-react";
7
6
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
8
- import { Theme } from "@radix-ui/themes";
9
7
  import App from "./App.tsx";
10
- import { networkConfig } from "./networkConfig.ts";
8
+ import { dAppKit } from "./dApp-kit.ts";
11
9
 
12
10
  const queryClient = new QueryClient();
13
11
 
14
12
  ReactDOM.createRoot(document.getElementById("root")!).render(
15
13
  <React.StrictMode>
16
- <Theme appearance="dark">
17
- <QueryClientProvider client={queryClient}>
18
- <SuiClientProvider networks={networkConfig} defaultNetwork="testnet">
19
- <WalletProvider autoConnect>
20
- <App />
21
- </WalletProvider>
22
- </SuiClientProvider>
23
- </QueryClientProvider>
24
- </Theme>
14
+ <QueryClientProvider client={queryClient}>
15
+ <DAppKitProvider dAppKit={dAppKit}>
16
+ <App />
17
+ </DAppKitProvider>
18
+ </QueryClientProvider>
25
19
  </React.StrictMode>,
26
20
  );
@@ -0,0 +1,13 @@
1
+ import type { SuiCodegenConfig } from "@mysten/codegen";
2
+
3
+ const config: SuiCodegenConfig = {
4
+ output: "./src/contracts",
5
+ packages: [
6
+ {
7
+ package: "@local-pkg/counter",
8
+ path: "./move/counter",
9
+ },
10
+ ],
11
+ };
12
+
13
+ export default config;
@@ -1,7 +1,8 @@
1
1
  import { defineConfig } from "vite";
2
2
  import react from "@vitejs/plugin-react-swc";
3
+ import tailwindcss from "@tailwindcss/vite";
3
4
 
4
5
  // https://vitejs.dev/config/
5
6
  export default defineConfig({
6
- plugins: [react()],
7
+ plugins: [react(), tailwindcss()],
7
8
  });
@@ -1,17 +0,0 @@
1
- import { getFullnodeUrl } from "@mysten/sui/client";
2
- import { createNetworkConfig } from "@mysten/dapp-kit";
3
-
4
- const { networkConfig, useNetworkVariable, useNetworkVariables } =
5
- createNetworkConfig({
6
- devnet: {
7
- url: getFullnodeUrl("devnet"),
8
- },
9
- testnet: {
10
- url: getFullnodeUrl("testnet"),
11
- },
12
- mainnet: {
13
- url: getFullnodeUrl("mainnet"),
14
- },
15
- });
16
-
17
- export { useNetworkVariable, useNetworkVariables, networkConfig };
@@ -1,31 +0,0 @@
1
- import { getFullnodeUrl } from "@mysten/sui/client";
2
- import {
3
- DEVNET_COUNTER_PACKAGE_ID,
4
- TESTNET_COUNTER_PACKAGE_ID,
5
- MAINNET_COUNTER_PACKAGE_ID,
6
- } from "./constants.ts";
7
- import { createNetworkConfig } from "@mysten/dapp-kit";
8
-
9
- const { networkConfig, useNetworkVariable, useNetworkVariables } =
10
- createNetworkConfig({
11
- devnet: {
12
- url: getFullnodeUrl("devnet"),
13
- variables: {
14
- counterPackageId: DEVNET_COUNTER_PACKAGE_ID,
15
- },
16
- },
17
- testnet: {
18
- url: getFullnodeUrl("testnet"),
19
- variables: {
20
- counterPackageId: TESTNET_COUNTER_PACKAGE_ID,
21
- },
22
- },
23
- mainnet: {
24
- url: getFullnodeUrl("mainnet"),
25
- variables: {
26
- counterPackageId: MAINNET_COUNTER_PACKAGE_ID,
27
- },
28
- },
29
- });
30
-
31
- export { useNetworkVariable, useNetworkVariables, networkConfig };