@iota/create-dapp 0.0.0-dev-20251015065834

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 (40) hide show
  1. package/CHANGELOG.md +207 -0
  2. package/LICENSE +201 -0
  3. package/README.md +35 -0
  4. package/bin/index.js +7 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +103 -0
  7. package/dist/index.js.map +1 -0
  8. package/package.json +45 -0
  9. package/src/index.ts +131 -0
  10. package/templates/react-client-dapp/README.md +35 -0
  11. package/templates/react-client-dapp/eslint.config.js +28 -0
  12. package/templates/react-client-dapp/index.html +59 -0
  13. package/templates/react-client-dapp/package.json +37 -0
  14. package/templates/react-client-dapp/prettier.config.cjs +4 -0
  15. package/templates/react-client-dapp/src/App.tsx +39 -0
  16. package/templates/react-client-dapp/src/OwnedObjects.tsx +42 -0
  17. package/templates/react-client-dapp/src/WalletStatus.tsx +23 -0
  18. package/templates/react-client-dapp/src/main.tsx +26 -0
  19. package/templates/react-client-dapp/src/networkConfig.ts +17 -0
  20. package/templates/react-client-dapp/src/vite-env.d.ts +1 -0
  21. package/templates/react-client-dapp/tsconfig.json +25 -0
  22. package/templates/react-client-dapp/tsconfig.node.json +10 -0
  23. package/templates/react-client-dapp/vite.config.ts +7 -0
  24. package/templates/react-e2e-counter/README.md +100 -0
  25. package/templates/react-e2e-counter/eslint.config.js +28 -0
  26. package/templates/react-e2e-counter/index.html +59 -0
  27. package/templates/react-e2e-counter/move/counter/Move.toml +10 -0
  28. package/templates/react-e2e-counter/move/counter/sources/counter.move +37 -0
  29. package/templates/react-e2e-counter/package.json +38 -0
  30. package/templates/react-e2e-counter/prettier.config.cjs +4 -0
  31. package/templates/react-e2e-counter/src/App.tsx +61 -0
  32. package/templates/react-e2e-counter/src/Counter.tsx +108 -0
  33. package/templates/react-e2e-counter/src/CreateCounter.tsx +65 -0
  34. package/templates/react-e2e-counter/src/constants.ts +3 -0
  35. package/templates/react-e2e-counter/src/main.tsx +26 -0
  36. package/templates/react-e2e-counter/src/networkConfig.ts +31 -0
  37. package/templates/react-e2e-counter/src/vite-env.d.ts +1 -0
  38. package/templates/react-e2e-counter/tsconfig.json +25 -0
  39. package/templates/react-e2e-counter/tsconfig.node.json +10 -0
  40. package/templates/react-e2e-counter/vite.config.ts +7 -0
@@ -0,0 +1,10 @@
1
+ [package]
2
+ name = "counter"
3
+ version = "0.0.1"
4
+ edition = "2024"
5
+
6
+ [dependencies]
7
+ Iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "devnet" }
8
+
9
+ [addresses]
10
+ counter = "0x0"
@@ -0,0 +1,37 @@
1
+ // Copyright (c) Mysten Labs, Inc.
2
+ // Modifications Copyright (c) 2024 IOTA Stiftung
3
+ // SPDX-License-Identifier: Apache-2.0
4
+
5
+ /// This example demonstrates a basic use of a shared object.
6
+ /// Rules:
7
+ /// - anyone can create and share a counter
8
+ /// - everyone can increment a counter by 1
9
+ /// - the owner of the counter can reset it to any value
10
+ module counter::counter {
11
+ /// A shared counter.
12
+ public struct Counter has key {
13
+ id: UID,
14
+ owner: address,
15
+ value: u64
16
+ }
17
+
18
+ /// Create and share a Counter object.
19
+ public fun create(ctx: &mut TxContext) {
20
+ transfer::share_object(Counter {
21
+ id: object::new(ctx),
22
+ owner: ctx.sender(),
23
+ value: 0
24
+ })
25
+ }
26
+
27
+ /// Increment a counter by 1.
28
+ public fun increment(counter: &mut Counter) {
29
+ counter.value = counter.value + 1;
30
+ }
31
+
32
+ /// Set value (only runnable by the Counter owner)
33
+ public fun set_value(counter: &mut Counter, value: u64, ctx: &TxContext) {
34
+ assert!(counter.owner == ctx.sender(), 0);
35
+ counter.value = value;
36
+ }
37
+ }
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@iota/template-react-e2e-coinflip",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview",
11
+ "format": "prettier -w ."
12
+ },
13
+ "dependencies": {
14
+ "@iota/dapp-kit": "workspace:*",
15
+ "@iota/iota-sdk": "workspace:*",
16
+ "@radix-ui/themes": "^3.1.1",
17
+ "@tanstack/react-query": "^5.50.1",
18
+ "react": "^18.3.1",
19
+ "react-dom": "^18.3.1",
20
+ "react-spinners": "^0.14.1"
21
+ },
22
+ "devDependencies": {
23
+ "@eslint/js": "^9.17.0",
24
+ "@types/react": "^18.3.3",
25
+ "@types/react-dom": "^18.3.0",
26
+ "@typescript-eslint/eslint-plugin": "^8.18.0",
27
+ "@typescript-eslint/parser": "^8.18.0",
28
+ "@vitejs/plugin-react-swc": "^3.7.0",
29
+ "eslint": "^9.17.0",
30
+ "eslint-plugin-react-hooks": "^5.1.0",
31
+ "eslint-plugin-react-refresh": "^0.4.7",
32
+ "eslint-plugin-react": "^7.37.2",
33
+ "typescript-eslint": "^8.18.0",
34
+ "prettier": "^3.3.2",
35
+ "typescript": "^5.5.3",
36
+ "vite": "^5.4.12"
37
+ }
38
+ }
@@ -0,0 +1,4 @@
1
+ // eslint-disable-next-line no-undef
2
+ module.exports = {
3
+ proseWrap: "always",
4
+ };
@@ -0,0 +1,61 @@
1
+ import { ConnectButton, useCurrentAccount } from "@iota/dapp-kit";
2
+ import { isValidIotaObjectId } from "@iota/iota-sdk/utils";
3
+ import { Box, Container, Flex, Heading } from "@radix-ui/themes";
4
+ import { useState } from "react";
5
+ import { Counter } from "./Counter";
6
+ import { CreateCounter } from "./CreateCounter";
7
+
8
+ function App() {
9
+ const currentAccount = useCurrentAccount();
10
+ const [counterId, setCounter] = useState(() => {
11
+ const hash = window.location.hash.slice(1);
12
+ return isValidIotaObjectId(hash) ? hash : null;
13
+ });
14
+
15
+ return (
16
+ <>
17
+ <Flex
18
+ position="sticky"
19
+ px="4"
20
+ py="2"
21
+ justify="between"
22
+ style={{
23
+ borderBottom: "1px solid var(--gray-a2)",
24
+ }}
25
+ >
26
+ <Box>
27
+ <Heading>dApp Starter Template</Heading>
28
+ </Box>
29
+
30
+ <Box>
31
+ <ConnectButton />
32
+ </Box>
33
+ </Flex>
34
+ <Container>
35
+ <Container
36
+ mt="5"
37
+ pt="2"
38
+ px="4"
39
+ style={{ background: "var(--gray-a2)", minHeight: 500 }}
40
+ >
41
+ {currentAccount ? (
42
+ counterId ? (
43
+ <Counter id={counterId} />
44
+ ) : (
45
+ <CreateCounter
46
+ onCreated={(id) => {
47
+ window.location.hash = id;
48
+ setCounter(id);
49
+ }}
50
+ />
51
+ )
52
+ ) : (
53
+ <Heading>Please connect your wallet</Heading>
54
+ )}
55
+ </Container>
56
+ </Container>
57
+ </>
58
+ );
59
+ }
60
+
61
+ export default App;
@@ -0,0 +1,108 @@
1
+ import {
2
+ useCurrentAccount,
3
+ useSignAndExecuteTransaction,
4
+ useIotaClient,
5
+ useIotaClientQuery,
6
+ } from "@iota/dapp-kit";
7
+ import type { IotaObjectData } from "@iota/iota-sdk/client";
8
+ import { Transaction } from "@iota/iota-sdk/transactions";
9
+ import { Button, Flex, Heading, Text } from "@radix-ui/themes";
10
+ import { useNetworkVariable } from "./networkConfig";
11
+ import { useState } from "react";
12
+ import ClipLoader from "react-spinners/ClipLoader";
13
+
14
+ export function Counter({ id }: { id: string }) {
15
+ const counterPackageId = useNetworkVariable("counterPackageId");
16
+ const iotaClient = useIotaClient();
17
+ const currentAccount = useCurrentAccount();
18
+ const { mutate: signAndExecute } = useSignAndExecuteTransaction();
19
+ const { data, isPending, error, refetch } = useIotaClientQuery("getObject", {
20
+ id,
21
+ options: {
22
+ showContent: true,
23
+ showOwner: true,
24
+ },
25
+ });
26
+
27
+ const [waitingForTxn, setWaitingForTxn] = useState("");
28
+
29
+ const executeMoveCall = (method: "increment" | "reset") => {
30
+ setWaitingForTxn(method);
31
+
32
+ const tx = new Transaction();
33
+
34
+ if (method === "reset") {
35
+ tx.moveCall({
36
+ arguments: [tx.object(id), tx.pure.u64(0)],
37
+ target: `${counterPackageId}::counter::set_value`,
38
+ });
39
+ } else {
40
+ tx.moveCall({
41
+ arguments: [tx.object(id)],
42
+ target: `${counterPackageId}::counter::increment`,
43
+ });
44
+ }
45
+
46
+ signAndExecute(
47
+ {
48
+ transaction: tx,
49
+ },
50
+ {
51
+ onSuccess: (tx) => {
52
+ iotaClient
53
+ .waitForTransaction({ digest: tx.digest })
54
+ .then(async () => {
55
+ await refetch();
56
+ setWaitingForTxn("");
57
+ });
58
+ },
59
+ },
60
+ );
61
+ };
62
+
63
+ if (isPending) return <Text>Loading...</Text>;
64
+
65
+ if (error) return <Text>Error: {error.message}</Text>;
66
+
67
+ if (!data.data) return <Text>Not found</Text>;
68
+
69
+ const ownedByCurrentAccount =
70
+ getCounterFields(data.data)?.owner === currentAccount?.address;
71
+
72
+ return (
73
+ <>
74
+ <Heading size="3">Counter {id}</Heading>
75
+
76
+ <Flex direction="column" gap="2">
77
+ <Text>Count: {getCounterFields(data.data)?.value}</Text>
78
+ <Flex direction="row" gap="2">
79
+ <Button
80
+ onClick={() => executeMoveCall("increment")}
81
+ disabled={waitingForTxn !== ""}
82
+ >
83
+ {waitingForTxn === "increment" ? (
84
+ <ClipLoader size={20} />
85
+ ) : (
86
+ "Increment"
87
+ )}
88
+ </Button>
89
+ {ownedByCurrentAccount ? (
90
+ <Button
91
+ onClick={() => executeMoveCall("reset")}
92
+ disabled={waitingForTxn !== ""}
93
+ >
94
+ {waitingForTxn === "reset" ? <ClipLoader size={20} /> : "Reset"}
95
+ </Button>
96
+ ) : null}
97
+ </Flex>
98
+ </Flex>
99
+ </>
100
+ );
101
+ }
102
+ function getCounterFields(data: IotaObjectData) {
103
+ if (data.content?.dataType !== "moveObject") {
104
+ return null;
105
+ }
106
+
107
+ return data.content.fields as { value: number; owner: string };
108
+ }
@@ -0,0 +1,65 @@
1
+ import { Transaction } from "@iota/iota-sdk/transactions";
2
+ import { Button, Container } from "@radix-ui/themes";
3
+ import { useSignAndExecuteTransaction, useIotaClient } from "@iota/dapp-kit";
4
+ import { useNetworkVariable } from "./networkConfig";
5
+ import ClipLoader from "react-spinners/ClipLoader";
6
+
7
+ export function CreateCounter({
8
+ onCreated,
9
+ }: {
10
+ onCreated: (id: string) => void;
11
+ }) {
12
+ const counterPackageId = useNetworkVariable("counterPackageId");
13
+ const iotaClient = useIotaClient();
14
+ const {
15
+ mutate: signAndExecute,
16
+ isSuccess,
17
+ isPending,
18
+ } = useSignAndExecuteTransaction();
19
+
20
+ function create() {
21
+ const tx = new Transaction();
22
+
23
+ tx.moveCall({
24
+ arguments: [],
25
+ target: `${counterPackageId}::counter::create`,
26
+ });
27
+
28
+ signAndExecute(
29
+ {
30
+ transaction: tx,
31
+ },
32
+ {
33
+ onSuccess: async ({ digest }) => {
34
+ const { effects } = await iotaClient.waitForTransaction({
35
+ digest: digest,
36
+ options: {
37
+ showEffects: true,
38
+ },
39
+ });
40
+
41
+ const objectId = effects?.created?.[0]?.reference?.objectId;
42
+ if (objectId) {
43
+ onCreated(objectId);
44
+ } else {
45
+ console.error("Failed to get objectId from transaction effects");
46
+ }
47
+ },
48
+ },
49
+ );
50
+ }
51
+
52
+ return (
53
+ <Container>
54
+ <Button
55
+ size="3"
56
+ onClick={() => {
57
+ create();
58
+ }}
59
+ disabled={isSuccess || isPending}
60
+ >
61
+ {isSuccess || isPending ? <ClipLoader size={20} /> : "Create Counter"}
62
+ </Button>
63
+ </Container>
64
+ );
65
+ }
@@ -0,0 +1,3 @@
1
+ export const DEVNET_COUNTER_PACKAGE_ID = "0xTODO";
2
+ export const TESTNET_COUNTER_PACKAGE_ID = "0xTODO";
3
+ export const MAINNET_COUNTER_PACKAGE_ID = "0xTODO";
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import "@iota/dapp-kit/dist/index.css";
4
+ import "@radix-ui/themes/styles.css";
5
+
6
+ import { IotaClientProvider, WalletProvider } from "@iota/dapp-kit";
7
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
8
+ import { Theme } from "@radix-ui/themes";
9
+ import App from "./App.tsx";
10
+ import { networkConfig } from "./networkConfig.ts";
11
+
12
+ const queryClient = new QueryClient();
13
+
14
+ ReactDOM.createRoot(document.getElementById("root")!).render(
15
+ <React.StrictMode>
16
+ <Theme appearance="dark">
17
+ <QueryClientProvider client={queryClient}>
18
+ <IotaClientProvider networks={networkConfig} defaultNetwork="testnet">
19
+ <WalletProvider autoConnect>
20
+ <App />
21
+ </WalletProvider>
22
+ </IotaClientProvider>
23
+ </QueryClientProvider>
24
+ </Theme>
25
+ </React.StrictMode>,
26
+ );
@@ -0,0 +1,31 @@
1
+ import { getFullnodeUrl } from "@iota/iota-sdk/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 "@iota/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 };
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,25 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+ "jsx": "react-jsx",
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true
22
+ },
23
+ "include": ["src"],
24
+ "references": [{ "path": "./tsconfig.node.json" }]
25
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true
8
+ },
9
+ "include": ["vite.config.ts"]
10
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react-swc";
3
+
4
+ // https://vitejs.dev/config/
5
+ export default defineConfig({
6
+ plugins: [react()],
7
+ });