diff --git a/create-aleo-app/src/index.ts b/create-aleo-app/src/index.ts index 33de7fa71..1e8d1bb6c 100755 --- a/create-aleo-app/src/index.ts +++ b/create-aleo-app/src/index.ts @@ -48,6 +48,11 @@ const FRAMEWORKS: Framework[] = [ display: "JavaScript + Leo", color: lightGreen, }, + { + name: 'react-ts', + display: "React + TypeScript", + color: red + }, { name: "nextjs-ts", display: "TypeScript + Next.js", diff --git a/create-aleo-app/template-react-ts/.babelrc b/create-aleo-app/template-react-ts/.babelrc new file mode 100644 index 000000000..f292b5026 --- /dev/null +++ b/create-aleo-app/template-react-ts/.babelrc @@ -0,0 +1,7 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-typescript", + ["@babel/preset-react", { "runtime": "automatic" }] + ] +} diff --git a/create-aleo-app/template-react-ts/.eslintrc.cjs b/create-aleo-app/template-react-ts/.eslintrc.cjs new file mode 100644 index 000000000..4dcb43901 --- /dev/null +++ b/create-aleo-app/template-react-ts/.eslintrc.cjs @@ -0,0 +1,20 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:react/recommended', + 'plugin:react/jsx-runtime', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, + settings: { react: { version: '18.2' } }, + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, +} diff --git a/create-aleo-app/template-react-ts/README.md b/create-aleo-app/template-react-ts/README.md new file mode 100644 index 000000000..2b48090db --- /dev/null +++ b/create-aleo-app/template-react-ts/README.md @@ -0,0 +1,90 @@ +# React + Aleo + Leo + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/fork/github/AleoHQ/sdk/tree/testnet3/create-aleo-app/template-react) + +This template provides a minimal setup to get React and Aleo working in Vite +with HMR and some ESLint rules. + +This template includes a Leo program that is loaded by the web app located in +the `helloworld` directory. + +Note: Webpack is currently used for production builds due to a +[bug](https://github.com/vitejs/vite/issues/13367) with Vite related to nested +workers. + +### Start in development mode + +```bash +npm run dev +``` + +Your app should be running on http://localhost:5173/ + +### Build Leo program + +1. Copy the `helloworld/.env.example` to `helloworld/.env` (this will be ignored + by Git): + + ```bash + cd helloworld + cp .env.example .env + ``` + +2. Replace `PRIVATE_KEY=user1PrivateKey` in the `.env` with your own key (you + can use an existing one or generate your own at https://aleo.tools/account) + +3. Follow instructions to install Leo here: https://github.com/AleoHQ/leo + +4. You can edit `helloworld/src/main.leo` and run `leo run` to compile and update the + Aleo instructions under `build` which are loaded by the web app. + +## Deploy program from web app + +> [!WARNING] +> This is for demonstration purposes or local testing only, in production applications you +> should avoid building a public facing web app with private key information + +Information on generating a private key, seeding a wallet with funds, and finding a spendable record can be found here +if you are unfamiliar: https://developer.aleo.org/testnet/getting_started/deploy_execute_demo + +Aleo programs deployed require unique names, make sure to edit the program's name to something unique in `helloworld/src/main.leo`, `helloworld/program.json`, rename `helloworld/inputs/helloworld.in` and rebuild. + +1. In the `worker.js` file modify the privateKey to be an account with available + funds + + ```js + // Use existing account with funds + const account = new Account({ + privateKey: "user1PrivateKey", + }); + ``` + +2. (Optional) Provide a fee record manually (located in commented code within `worker.js`) + + If you do not provide a manual fee record, the SDK will attempt to scan for a record starting at the latest block. A simple way to speed this up would be to make a public transaction to this account right before deploying. + +3. Run the web app and hit the deploy button + +## Production deployment + +### Build + +`npm run build` + +Upload `dist` folder to your host of choice. + +### ⚠️ Header warnings + +`DOMException: Failed to execute 'postMessage' on 'Worker': SharedArrayBuffer transfer requires self.crossOriginIsolated` + +If you get a warning similar to this when deploying your application, you need +to make sure your web server is configured with the following headers: + +``` +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp +``` + +We've included a `_headers` file that works with some web hosts (e.g. Netlify) +but depending on your host / server setup you may need to configure the headers +manually. diff --git a/create-aleo-app/template-react-ts/_gitignore b/create-aleo-app/template-react-ts/_gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/create-aleo-app/template-react-ts/_gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/create-aleo-app/template-react-ts/_headers b/create-aleo-app/template-react-ts/_headers new file mode 100644 index 000000000..6e0d001fd --- /dev/null +++ b/create-aleo-app/template-react-ts/_headers @@ -0,0 +1,3 @@ +/* + Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/helloworld/.env.example b/create-aleo-app/template-react-ts/helloworld/.env.example new file mode 100644 index 000000000..11b672e98 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/.env.example @@ -0,0 +1,2 @@ +NETWORK=testnet3 +PRIVATE_KEY=user1PrivateKey \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/helloworld/.gitignore b/create-aleo-app/template-react-ts/helloworld/.gitignore new file mode 100644 index 000000000..f721f7f6f --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/.gitignore @@ -0,0 +1,5 @@ +.env +*.avm +*.prover +*.verifier +outputs/ diff --git a/create-aleo-app/template-react-ts/helloworld/README.md b/create-aleo-app/template-react-ts/helloworld/README.md new file mode 100644 index 000000000..2456ef654 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/README.md @@ -0,0 +1,13 @@ +# helloworld.aleo + +## Build Guide + +To compile this Aleo program, run: +```bash +snarkvm build +``` + +To execute this Aleo program, run: +```bash +snarkvm run hello +``` diff --git a/create-aleo-app/template-react-ts/helloworld/build/main.aleo b/create-aleo-app/template-react-ts/helloworld/build/main.aleo new file mode 100644 index 000000000..88fd8a3f5 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/build/main.aleo @@ -0,0 +1,7 @@ +program helloworld.aleo; + +function main: + input r0 as u32.public; + input r1 as u32.private; + add r0 r1 into r2; + output r2 as u32.private; diff --git a/create-aleo-app/template-react-ts/helloworld/build/program.json b/create-aleo-app/template-react-ts/helloworld/build/program.json new file mode 100644 index 000000000..df13181a2 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/build/program.json @@ -0,0 +1,6 @@ +{ + "program": "helloworld.aleo", + "version": "0.0.0", + "description": "", + "license": "MIT" +} diff --git a/create-aleo-app/template-react-ts/helloworld/inputs/helloworld.in b/create-aleo-app/template-react-ts/helloworld/inputs/helloworld.in new file mode 100644 index 000000000..2908f3dee --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/inputs/helloworld.in @@ -0,0 +1,4 @@ +// The program input for helloworld/src/main.leo +[main] +public a: u32 = 1u32; +b: u32 = 2u32; diff --git a/create-aleo-app/template-react-ts/helloworld/program.json b/create-aleo-app/template-react-ts/helloworld/program.json new file mode 100644 index 000000000..df13181a2 --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/program.json @@ -0,0 +1,6 @@ +{ + "program": "helloworld.aleo", + "version": "0.0.0", + "description": "", + "license": "MIT" +} diff --git a/create-aleo-app/template-react-ts/helloworld/src/main.leo b/create-aleo-app/template-react-ts/helloworld/src/main.leo new file mode 100644 index 000000000..9aa61dacf --- /dev/null +++ b/create-aleo-app/template-react-ts/helloworld/src/main.leo @@ -0,0 +1,7 @@ +// The 'helloworld' program. +program helloworld.aleo { + transition main(public a: u32, b: u32) -> u32 { + let c: u32 = a + b; + return c; + } +} diff --git a/create-aleo-app/template-react-ts/index.html b/create-aleo-app/template-react-ts/index.html new file mode 100644 index 000000000..4da12f5b5 --- /dev/null +++ b/create-aleo-app/template-react-ts/index.html @@ -0,0 +1,88 @@ + + +
+ + + ++ +
++ +
+
+ Edit src/App.jsx
and save to test HMR
+
+ Deployment on Aleo requires certain prerequisites like seeding your + wallet with credits and retrieving a fee record. Check README for more + details. +
++ +
++ Click on the Aleo and React logos to learn more +
+ > + ); +} + +export default App; diff --git a/create-aleo-app/template-react-ts/src/assets/aleo.svg b/create-aleo-app/template-react-ts/src/assets/aleo.svg new file mode 100644 index 000000000..d507e1eb4 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/assets/aleo.svg @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/src/assets/react.svg b/create-aleo-app/template-react-ts/src/assets/react.svg new file mode 100644 index 000000000..6c87de9bb --- /dev/null +++ b/create-aleo-app/template-react-ts/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/src/custom.d.ts b/create-aleo-app/template-react-ts/src/custom.d.ts new file mode 100644 index 000000000..3aa72e286 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/custom.d.ts @@ -0,0 +1,16 @@ +declare module '*.svg' { + const content: any; + export default content; + } + + declare module '*.aleo' { + const content: string; + export default content; + } + + declare module '*?raw' { + const content: string; + export default content; + } + + \ No newline at end of file diff --git a/create-aleo-app/template-react-ts/src/index.css b/create-aleo-app/template-react-ts/src/index.css new file mode 100644 index 000000000..2c3fac689 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/index.css @@ -0,0 +1,69 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/create-aleo-app/template-react-ts/src/main.tsx b/create-aleo-app/template-react-ts/src/main.tsx new file mode 100644 index 000000000..e2aaf9ff6 --- /dev/null +++ b/create-aleo-app/template-react-ts/src/main.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import "./index.css"; + +ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( +