├── packages ├── docs │ ├── .gitignore │ ├── README.md │ ├── pages │ │ ├── meta.json │ │ ├── index.mdx │ │ ├── _app.tsx │ │ └── packages │ │ │ ├── wen-actions.mdx │ │ │ └── wen-react.mdx │ ├── next-env.d.ts │ ├── next.config.js │ ├── tsconfig.json │ ├── components │ │ └── PreviewTheme.tsx │ ├── theme.config.js │ └── package.json ├── wen_store_app │ ├── .dockerignore │ ├── Cargo.toml │ ├── package.json │ ├── src │ │ └── main.rs │ ├── fly.toml │ ├── Dockerfile │ └── Cargo.lock ├── react │ ├── src │ │ ├── index.ts │ │ ├── style.css │ │ ├── state.ts │ │ ├── types.d.ts │ │ ├── components │ │ │ ├── Modal │ │ │ │ ├── Connect.tsx │ │ │ │ ├── Content.tsx │ │ │ │ ├── ChangeNetwork.tsx │ │ │ │ ├── Header.tsx │ │ │ │ └── Container.tsx │ │ │ ├── Pills.tsx │ │ │ ├── Button.tsx │ │ │ ├── ConnectButton │ │ │ │ └── Metamask.tsx │ │ │ ├── ButtonProvider.tsx │ │ │ └── theme.tsx │ │ ├── chains.ts │ │ └── helpers.ts │ ├── postcss.config.js │ ├── tsconfig.json │ ├── tailwind.config.js │ ├── rollup.config.js │ ├── package.json │ └── README.md ├── playground-ssr │ ├── .eslintrc.json │ ├── public │ │ ├── favicon.ico │ │ └── vercel.svg │ ├── next.config.js │ ├── next-env.d.ts │ ├── pages │ │ ├── _app.tsx │ │ ├── api │ │ │ └── hello.ts │ │ └── index.tsx │ ├── styles │ │ ├── globals.css │ │ └── Home.module.css │ ├── .gitignore │ ├── tsconfig.json │ ├── package.json │ └── README.md ├── actions │ ├── postcss.config.js │ ├── test │ │ └── actions.test.ts │ ├── src │ │ ├── index.ts │ │ ├── helpers.ts │ │ ├── types.d.ts │ │ ├── state.ts │ │ └── actions.ts │ ├── tsconfig.json │ ├── tailwind.config.js │ ├── rollup.config.js │ ├── README.md │ └── package.json └── wen_store │ ├── Cargo.toml │ └── src │ └── lib.rs ├── pnpm-workspace.yaml ├── .husky └── pre-commit ├── .vscode ├── wen-metamask.code-workspace └── extensions.json ├── .gitignore ├── package.json ├── turbo.json ├── README.md └── .github └── workflows ├── install.yml └── publish.yml /packages/docs/.gitignore: -------------------------------------------------------------------------------- 1 | .vercel 2 | -------------------------------------------------------------------------------- /packages/wen_store_app/.dockerignore: -------------------------------------------------------------------------------- 1 | /target -------------------------------------------------------------------------------- /packages/docs/README.md: -------------------------------------------------------------------------------- 1 | ## Wen-Tools docs 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/*" 3 | -------------------------------------------------------------------------------- /packages/docs/pages/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": "Introduction" 3 | } 4 | -------------------------------------------------------------------------------- /packages/react/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./components/ButtonProvider"; 2 | -------------------------------------------------------------------------------- /packages/playground-ssr/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | pnpm lint 5 | pnpm format 6 | -------------------------------------------------------------------------------- /packages/actions/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/playground-ssr/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GuiBibeau/wen-tools/HEAD/packages/playground-ssr/public/favicon.ico -------------------------------------------------------------------------------- /packages/react/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/react/src/style.css: -------------------------------------------------------------------------------- 1 | /* Tailwind's base directive to later be picked up in the build phase */ 2 | @tailwind base; 3 | @tailwind components; 4 | @tailwind utilities; 5 | -------------------------------------------------------------------------------- /packages/actions/test/actions.test.ts: -------------------------------------------------------------------------------- 1 | import { assert, expect, test } from "vitest"; 2 | 3 | test("Wen Actions", () => { 4 | expect("hello world").toBe("hello world"); 5 | }); 6 | -------------------------------------------------------------------------------- /packages/playground-ssr/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | swcMinify: true, 5 | } 6 | 7 | module.exports = nextConfig 8 | -------------------------------------------------------------------------------- /packages/wen_store/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wen_store" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /packages/docs/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /packages/playground-ssr/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /packages/actions/src/index.ts: -------------------------------------------------------------------------------- 1 | export { useWen, state } from "./state"; 2 | export { 3 | connectWallet, 4 | stopListening, 5 | listen, 6 | changeChain, 7 | disconnect, 8 | } from "./actions"; 9 | export { toChainHexadecimal } from "./helpers"; 10 | -------------------------------------------------------------------------------- /packages/playground-ssr/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import "../styles/globals.css"; 2 | import type { AppProps } from "next/app"; 3 | 4 | function MyApp({ Component, pageProps }: AppProps) { 5 | return ; 6 | } 7 | 8 | export default MyApp; 9 | -------------------------------------------------------------------------------- /packages/wen_store_app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wen_store_app" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Gui Bibeau "] 6 | 7 | [dependencies] 8 | tokio = { version = "1", features = ["full"] } 9 | warp = "0.3.2" -------------------------------------------------------------------------------- /packages/react/src/state.ts: -------------------------------------------------------------------------------- 1 | import { proxy } from "valtio"; 2 | 3 | export const state = proxy({ 4 | open: false, 5 | }); 6 | 7 | export const open = () => { 8 | state.open = true; 9 | }; 10 | 11 | export const close = () => { 12 | state.open = false; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/wen_store/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub fn add(left: usize, right: usize) -> usize { 2 | left + right 3 | } 4 | 5 | #[cfg(test)] 6 | mod tests { 7 | use super::*; 8 | 9 | #[test] 10 | fn it_works() { 11 | let result = add(2, 2); 12 | assert_eq!(result, 4); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/wen_store_app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wen-tools/store-app", 3 | "version": "0.0.1", 4 | "description": "", 5 | "scripts": { 6 | "build": "", 7 | "dev": "" 8 | }, 9 | "author": "Gui Bibeau (https://www.web3-fullstack.com/)", 10 | "license": "MIT" 11 | } 12 | -------------------------------------------------------------------------------- /packages/docs/pages/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Starting 3 | --- 4 | 5 | # Wen Tools 6 | 7 | **Wen Tools are under heavy development** 8 | 9 | Wen tools is a collection of simple and performant primitives for writting Dapps. 10 | 11 | ## The tools: 12 | 13 | - [@wen-tools/actions](/packages/wen-actions) 14 | - [@wen-tools/react](/packages/wen-react) 15 | -------------------------------------------------------------------------------- /.vscode/wen-metamask.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": ".." 5 | } 6 | ], 7 | "settings": {}, 8 | "eslint.workingDirectories": [ 9 | { "directory": "./app", "changeProcessCWD": true }, 10 | { "directory": "./worker", "changeProcessCWD": true }, 11 | { "directory": "./crawler", "changeProcessCWD": true } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /packages/wen_store_app/src/main.rs: -------------------------------------------------------------------------------- 1 | #![deny(warnings)] 2 | use warp::Filter; 3 | 4 | #[tokio::main] 5 | async fn main() { 6 | // Match any request and return hello world! 7 | let routes = warp::any().map(|| "Hello, World!"); 8 | 9 | warp::serve(routes) 10 | // ipv6 + ipv6 any addr 11 | .run(([0, 0, 0, 0, 0, 0, 0, 0], 8080)) 12 | .await; 13 | } -------------------------------------------------------------------------------- /packages/playground-ssr/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /packages/playground-ssr/pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'John Doe' }) 13 | } 14 | -------------------------------------------------------------------------------- /packages/react/src/types.d.ts: -------------------------------------------------------------------------------- 1 | type InjectedProviders = { 2 | isMetaMask?: true; 3 | }; 4 | 5 | interface Window { 6 | ethereum?: 7 | & InjectedProviders 8 | & { 9 | on: (...args: any[]) => void; 10 | removeListener?: (...args: any[]) => void; 11 | request(args: RequestArguments): Promise; 12 | }; 13 | } 14 | 15 | type ChainId = "0x1" | "0x4"; 16 | 17 | type ChainMap = Record; 18 | -------------------------------------------------------------------------------- /packages/docs/pages/_app.tsx: -------------------------------------------------------------------------------- 1 | import { GeistProvider, CssBaseline } from "@geist-ui/core"; 2 | import "nextra-theme-docs/style.css"; 3 | import Prism from "prism-react-renderer/prism"; 4 | 5 | (typeof global !== "undefined" ? global : window).Prism = Prism; 6 | 7 | export default function Nextra({ Component, pageProps }) { 8 | return ( 9 | 10 | 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | 5 | // List of extensions which should be recommended for users of this workspace. 6 | "recommendations": [ 7 | 8 | ], 9 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 10 | "unwantedRecommendations": [ 11 | 12 | ] 13 | } -------------------------------------------------------------------------------- /packages/docs/next.config.js: -------------------------------------------------------------------------------- 1 | // next.config.js 2 | const withNextra = require("nextra")({ 3 | theme: "nextra-theme-docs", 4 | themeConfig: "./theme.config.js", 5 | // optional: add `unstable_staticImage: true` to enable Nextra's auto image import 6 | }); 7 | module.exports = withNextra({ 8 | typescript: { 9 | // !! WARN !! 10 | // Dangerously allow production builds to successfully complete even if 11 | // your project has type errors. 12 | // !! WARN !! 13 | ignoreBuildErrors: true, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /packages/actions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "esnext", 5 | "jsx": "react", 6 | "sourceMap": true, 7 | "outDir": "dist", 8 | "strict": true, 9 | "moduleResolution": "node", 10 | "allowSyntheticDefaultImports": true, 11 | "esModuleInterop": true, 12 | "skipLibCheck": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "declaration": true, 15 | "declarationDir": "types", 16 | "emitDeclarationOnly": true, 17 | "composite": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/actions/src/helpers.ts: -------------------------------------------------------------------------------- 1 | export const isEthereumDefined = (): boolean => { 2 | if (typeof window === "undefined") { 3 | return false; 4 | } 5 | return window.ethereum !== undefined; 6 | }; 7 | 8 | /** 9 | * It takes a number and returns a hexadecimal string 10 | * @param {number} chainId - The chain ID of the network you want to connect to. 11 | * @returns A string that is the hexadecimal representation of the chainId. 12 | */ 13 | export const toChainHexadecimal = (chainId: number): string => { 14 | return `0x${chainId.toString(16)}`; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/playground-ssr/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | -------------------------------------------------------------------------------- /packages/react/src/components/Modal/Connect.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { MetamaskButton } from "../ConnectButton/Metamask"; 3 | 4 | export const ConnectModalBody = () => { 5 | return ( 6 |
7 |
8 |
9 | 12 |
13 |
14 |
15 |
16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "esnext", 5 | "jsx": "react", 6 | "sourceMap": true, 7 | "outDir": "dist", 8 | "strict": true, 9 | "moduleResolution": "node", 10 | "allowSyntheticDefaultImports": true, 11 | "esModuleInterop": true, 12 | "skipLibCheck": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "declaration": true, 15 | "declarationDir": "types", 16 | "emitDeclarationOnly": true, 17 | "composite": true 18 | }, 19 | "references": [{ "path": "../actions" }] 20 | } 21 | -------------------------------------------------------------------------------- /packages/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": false, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "incremental": true, 11 | "esModuleInterop": true, 12 | "module": "esnext", 13 | "isolatedModules": true, 14 | "jsx": "preserve", 15 | "moduleResolution": "node", 16 | "resolveJsonModule": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/playground-ssr/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true 17 | }, 18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 19 | "exclude": ["node_modules"] 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # Testing 9 | /coverage 10 | 11 | # Next.js 12 | .next 13 | /out/ 14 | 15 | # Production 16 | build 17 | dist 18 | .swc 19 | 20 | node_modules 21 | # Misc 22 | .DS_Store 23 | *.pem 24 | 25 | # Debug 26 | npm-debug.log* 27 | yarn-debug.log* 28 | yarn-error.log* 29 | 30 | # Local ENV files 31 | .env.local 32 | .env.development.local 33 | .env.test.local 34 | .env.production.local 35 | 36 | # Vercel 37 | .vercel 38 | 39 | # Turborepo 40 | .turbo 41 | 42 | # Rollup 43 | .rollup.cache -------------------------------------------------------------------------------- /packages/actions/src/types.d.ts: -------------------------------------------------------------------------------- 1 | type InjectedProviders = { 2 | isMetaMask?: true; 3 | }; 4 | 5 | interface Window { 6 | ethereum: 7 | & InjectedProviders 8 | & { 9 | on: (...args: any[]) => void; 10 | removeListener?: (...args: any[]) => void; 11 | request(args: RequestArguments): Promise; 12 | }; 13 | } 14 | 15 | type ChainId = "0x1" | "0x4"; 16 | 17 | type ChainMap = Record; 18 | 19 | type State = { 20 | metamaskPresent: Promise; 21 | address: string | null; 22 | balance: string | null; 23 | connected: boolean; 24 | chainId: string | null; 25 | requesting: boolean; 26 | }; 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wen-metamask", 3 | "version": "1.0.0", 4 | "description": "A minimalist UI library to connect easily to metamask", 5 | "license": "MIT", 6 | "private": true, 7 | "workspaces": { 8 | "packages": [ 9 | "packages/*" 10 | ] 11 | }, 12 | "scripts": { 13 | "build": "turbo run build", 14 | "dev": "turbo run dev", 15 | "start": "turbo run start", 16 | "lint": "turbo run lint", 17 | "format": "turbo run format", 18 | "format:fix": "turbo run format:fix", 19 | "prepare": "husky install" 20 | }, 21 | "devDependencies": { 22 | "husky": "^8.0.1", 23 | "turbo": "^1.3.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/playground-ssr/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "playground-ssr", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@wen-tools/react": "workspace:1.10.0-beta.4", 13 | "next": "12.2.2", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "18.0.6", 19 | "@types/react": "18.0.15", 20 | "@types/react-dom": "^18.0.6", 21 | "eslint": "8.20.0", 22 | "eslint-config-next": "12.2.2", 23 | "typescript": "4.7.4" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/playground-ssr/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import type { NextPage } from "next"; 2 | import Head from "next/head"; 3 | import styles from "../styles/Home.module.css"; 4 | 5 | import { ConnectButton } from "@wen-tools/react"; 6 | 7 | const Home: NextPage = () => { 8 | return ( 9 |
10 | 11 | Create Next App 12 | 13 | 14 | 15 |
16 | 17 |
18 |
19 | ); 20 | }; 21 | 22 | export default Home; 23 | -------------------------------------------------------------------------------- /packages/react/src/components/Modal/Content.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useWen } from "@wen-tools/actions"; 3 | import { useDesiredChainId } from "../ButtonProvider"; 4 | import { ConnectModalBody } from "./Connect"; 5 | import { ModalHeader } from "./Header"; 6 | import { ChangeNetwork } from "./ChangeNetwork"; 7 | 8 | export const ModalContent = () => { 9 | const { chainId, connected, requesting } = useWen(); 10 | const desiredChainId = useDesiredChainId(); 11 | const wrongNetwork = `0x${desiredChainId.toString(16)}` !== chainId; 12 | 13 | return ( 14 | <> 15 | 16 | {!connected && } 17 | {connected && wrongNetwork && !requesting && } 18 | 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turborepo.org/schema.json", 3 | "baseBranch": "origin/main", 4 | "pipeline": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "outputs": [".next/**", "dist/**"] 8 | }, 9 | "test": { 10 | "dependsOn": ["build"], 11 | "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts", "test/**/*.tsx"] 12 | }, 13 | "format": { 14 | "cache": false, 15 | "outputs": [] 16 | }, 17 | "format:fix": { 18 | "cache": false, 19 | "outputs": [] 20 | }, 21 | "lint": { 22 | "outputs": [], 23 | "cache": false 24 | }, 25 | "dev": { 26 | "cache": false 27 | }, 28 | "start": { 29 | "cache": false 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/react/src/components/Pills.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useTheme } from "./ButtonProvider"; 3 | 4 | export const ConnectedPill = () => { 5 | const { connectedPill } = useTheme(); 6 | return Connected; 7 | }; 8 | 9 | export const NotConnectedPill = () => { 10 | const { notConnectedPill } = useTheme(); 11 | 12 | return Not Connected; 13 | }; 14 | 15 | export const LoadingPill = () => { 16 | const { loadingPill } = useTheme(); 17 | return ( 18 | 19 |

Loading

20 |
24 | 25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | wen-tools 3 |

4 | 5 |
6 |
7 | 8 | # Wen Tools 9 | 10 | **Wen Tools are under heavy development** 11 | 12 | Wen tools is a collection of simple and performant primitives for writing Dapps. 13 | 14 | ## The tools: 15 | 16 | - [@wen-tools/actions](./packages/actions/) - Wallet connection primitives used in all the other tools. 17 | - [@wen-tools/react](./packages/react/) - Connecting to wallets in 1 line of code in any React 18 app. 18 | - @wen-tools/react-kit - (work in progress) Complete full stack solution to web3 identity in React. SSR and edge compatible. 19 | - wen-svelte - (work in progress) Connecting to wallets in 1 line of code in any Svelte app. 20 | - wen-svelte-kit - (work in progress) Complete full stack solution to web3 identity in React. 21 | - More to come 22 | -------------------------------------------------------------------------------- /packages/actions/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{tsx,ts}"], 4 | theme: { 5 | extend: { 6 | colors: { 7 | "metamask-blue-100": "#037DD6", 8 | "metamask-blue-200": "rgb(21, 101, 192)", 9 | "metamask-grey": "#3D3D3D", 10 | }, 11 | }, 12 | keyframes: { 13 | "slide-from-right": { 14 | "0%": { transform: "translate(300px, 0)" }, 15 | "100%": { transform: "translate(0, 0)" }, 16 | }, 17 | spinner: { 18 | "0%": { transform: "rotate(0deg)" }, 19 | "100%": { transform: "rotate(360deg)" }, 20 | }, 21 | }, 22 | animation: { 23 | "slide-from-right": "slide-from-right 250ms linear", 24 | spinner: "spinner 2s linear infinite", 25 | }, 26 | }, 27 | plugins: [], 28 | }; 29 | -------------------------------------------------------------------------------- /packages/react/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{tsx,ts}"], 4 | theme: { 5 | extend: { 6 | colors: { 7 | "gray-001": "#EEEEEE", 8 | "gray-002": "#DDDDDD", 9 | "gray-003": "#CCCCCC", 10 | "gray-004": "#BBBBBB", 11 | "gray-005": "#333333", 12 | }, 13 | }, 14 | keyframes: { 15 | "slide-from-right": { 16 | "0%": { transform: "translate(300px, 0)" }, 17 | "100%": { transform: "translate(0, 0)" }, 18 | }, 19 | spinner: { 20 | "0%": { transform: "rotate(0deg)" }, 21 | "100%": { transform: "rotate(360deg)" }, 22 | }, 23 | }, 24 | animation: { 25 | "slide-from-right": "slide-from-right 250ms linear", 26 | spinner: "spinner 4s linear infinite", 27 | }, 28 | }, 29 | plugins: [], 30 | }; 31 | -------------------------------------------------------------------------------- /packages/docs/components/PreviewTheme.tsx: -------------------------------------------------------------------------------- 1 | import { Select } from "@geist-ui/core"; 2 | import { ConnectButton } from "@wen-tools/react"; 3 | import React from "react"; 4 | 5 | export const PreviewTheme = () => { 6 | const [theme, setTheme] = React.useState("base"); 7 | return ( 8 | <> 9 | 23 | 24 | 25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /packages/wen_store_app/fly.toml: -------------------------------------------------------------------------------- 1 | # fly.toml file generated for holy-glitter-8513 on 2022-08-22T20:51:44-10:00 2 | 3 | app = "holy-glitter-8513" 4 | kill_signal = "SIGINT" 5 | kill_timeout = 5 6 | processes = [] 7 | 8 | [env] 9 | 10 | [experimental] 11 | cmd = "./wen_store_app" 12 | allowed_public_ports = [] 13 | auto_rollback = true 14 | 15 | 16 | [[services]] 17 | http_checks = [] 18 | internal_port = 8080 19 | processes = ["app"] 20 | protocol = "tcp" 21 | script_checks = [] 22 | [services.concurrency] 23 | hard_limit = 25 24 | soft_limit = 20 25 | type = "connections" 26 | 27 | [[services.ports]] 28 | force_https = true 29 | handlers = ["http"] 30 | port = 80 31 | 32 | [[services.ports]] 33 | handlers = ["tls", "http"] 34 | port = 443 35 | 36 | [[services.tcp_checks]] 37 | grace_period = "1s" 38 | interval = "15s" 39 | restart_limit = 0 40 | timeout = "2s" 41 | -------------------------------------------------------------------------------- /packages/wen_store_app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest as builder 2 | 3 | # Make a fake Rust app to keep a cached layer of compiled crates 4 | RUN USER=root cargo new app 5 | WORKDIR /usr/src/app 6 | COPY Cargo.toml Cargo.lock ./ 7 | # Needs at least a main.rs file with a main function 8 | RUN mkdir src && echo "fn main(){}" > src/main.rs 9 | # Will build all dependent crates in release mode 10 | RUN --mount=type=cache,target=/usr/local/cargo/registry \ 11 | --mount=type=cache,target=/usr/src/app/target \ 12 | cargo build --release 13 | 14 | # Copy the rest 15 | COPY . . 16 | # Build (install) the actual binaries 17 | RUN cargo install --path . 18 | 19 | # Runtime image 20 | FROM debian:bullseye-slim 21 | 22 | # Run as "app" user 23 | RUN useradd -ms /bin/bash app 24 | 25 | USER app 26 | WORKDIR /app 27 | 28 | # Get compiled binaries from builder's cargo install directory 29 | COPY --from=builder /usr/local/cargo/bin/wen_store_app /app/wen_store_app 30 | 31 | # No CMD or ENTRYPOINT, see fly.toml with `cmd` override. 32 | -------------------------------------------------------------------------------- /packages/actions/rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from "@rollup/plugin-node-resolve"; 2 | import commonjs from "@rollup/plugin-commonjs"; 3 | import typescript from "@rollup/plugin-typescript"; 4 | import { terser } from "rollup-plugin-terser"; 5 | import external from "rollup-plugin-peer-deps-external"; 6 | import postcss from "rollup-plugin-postcss"; 7 | 8 | const packageJson = require("./package.json"); 9 | 10 | export default [ 11 | { 12 | input: "src/index.ts", 13 | output: [ 14 | { 15 | file: packageJson.module, 16 | format: "esm", 17 | sourcemap: true, 18 | }, 19 | ], 20 | plugins: [ 21 | external(), 22 | resolve(), 23 | commonjs(), 24 | typescript({ tsconfig: "./tsconfig.json" }), 25 | postcss({ 26 | config: { 27 | path: "./postcss.config.js", 28 | }, 29 | extensions: [".css"], 30 | minimize: true, 31 | inject: { 32 | insertAt: "top", 33 | }, 34 | }), 35 | , 36 | terser(), 37 | ], 38 | }, 39 | ]; 40 | -------------------------------------------------------------------------------- /.github/workflows/install.yml: -------------------------------------------------------------------------------- 1 | on: 2 | - pull_request 3 | 4 | jobs: 5 | quality: 6 | runs-on: ubuntu-latest 7 | 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v3 11 | 12 | - name: Install Node.js 13 | uses: actions/setup-node@v3 14 | with: 15 | node-version: 16 16 | 17 | - uses: pnpm/action-setup@v2.0.1 18 | name: Install pnpm 19 | id: pnpm-install 20 | with: 21 | version: 7 22 | run_install: false 23 | 24 | - name: Get pnpm store directory 25 | id: pnpm-cache 26 | run: | 27 | echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" 28 | 29 | - uses: actions/cache@v3 30 | name: Setup pnpm cache 31 | with: 32 | path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} 33 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 34 | restore-keys: | 35 | ${{ runner.os }}-pnpm-store- 36 | 37 | - name: Install dependencies 38 | run: pnpm install 39 | -------------------------------------------------------------------------------- /packages/playground-ssr/public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /packages/docs/theme.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | projectLink: "https://github.com/GuiBibeau/wen-tools", // GitHub link in the navbar 3 | github: "https://github.com/GuiBibeau/wen-tools", 4 | docsRepositoryBase: 5 | "https://github.com/GuiBibeau/wen-tools/tree/main/packages/docs", // base URL for the docs repository 6 | titleSuffix: " – Wen", 7 | nextLinks: true, 8 | prevLinks: true, 9 | search: true, 10 | customSearch: null, // customizable, you can use algolia for example 11 | darkMode: true, 12 | footer: true, 13 | footerText: `MIT ${new Date().getFullYear()} © Gui Bibeau.`, 14 | footerEditLink: `Edit this page on GitHub`, 15 | logo: ( 16 | <> 17 | Wen Tools 18 | 19 | ), 20 | head: ( 21 | <> 22 | 23 | 27 | 31 | 32 | ), 33 | }; 34 | -------------------------------------------------------------------------------- /packages/react/rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from "@rollup/plugin-node-resolve"; 2 | import commonjs from "@rollup/plugin-commonjs"; 3 | import path from "node:path" 4 | import typescript from "@rollup/plugin-typescript"; 5 | import { terser } from "rollup-plugin-terser"; 6 | import external from "rollup-plugin-peer-deps-external"; 7 | import postcss from "rollup-plugin-postcss"; 8 | 9 | const packageJson = require("./package.json"); 10 | 11 | export default [ 12 | { 13 | input: "src/index.ts", 14 | output: [ 15 | { 16 | file: packageJson.module, 17 | format: "esm", 18 | sourceMap: true 19 | }, 20 | ], 21 | plugins: [ 22 | external(), 23 | resolve({ 24 | rootDir: path.join(process.cwd(), '../..') 25 | } 26 | ), 27 | commonjs(), 28 | typescript({ tsconfig: "./tsconfig.json" }), 29 | postcss({ 30 | config: { 31 | path: "./postcss.config.js", 32 | }, 33 | extensions: [".css"], 34 | minimize: true, 35 | inject: { 36 | insertAt: "top", 37 | }, 38 | }), 39 | , 40 | terser(), 41 | ], 42 | }, 43 | ]; 44 | -------------------------------------------------------------------------------- /packages/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wen-tools/docs", 3 | "version": "0.0.4", 4 | "description": "A collection of react components.", 5 | "main": "dist/cjs/index.js", 6 | "module": "dist/esm/index.js", 7 | "types": "dist/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "package.json", 11 | "README.md" 12 | ], 13 | "private": false, 14 | "scripts": { 15 | "build": "next build", 16 | "dev": "next dev --port 3001" 17 | }, 18 | "keywords": [ 19 | "react", 20 | "typescript", 21 | "rollup", 22 | "metamask" 23 | ], 24 | "author": "Gui Bibeau (https://www.web3-fullstack.com/)", 25 | "license": "MIT", 26 | "devDependencies": { 27 | "@types/node": "18.0.6", 28 | "@types/react": "18.0.14", 29 | "typescript": "^4.7.4" 30 | }, 31 | "dependencies": { 32 | "@geist-ui/core": "^2.3.8", 33 | "@wen-tools/actions": "1.10.0-beta.2", 34 | "@wen-tools/react": "1.10.0-beta.6", 35 | "next": "^12.2.0", 36 | "nextra": "2.0.0-beta.5", 37 | "nextra-theme-docs": "2.0.0-beta.5", 38 | "prism-react-renderer": "^1.3.5", 39 | "prismjs": "^1.28.0", 40 | "react": "^18.2.0", 41 | "react-dom": "^18.2.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/react/src/components/Modal/ChangeNetwork.tsx: -------------------------------------------------------------------------------- 1 | import { Dialog } from "@headlessui/react"; 2 | import React from "react"; 3 | import { changeChain } from "@wen-tools/actions"; 4 | 5 | import { close } from "../../state"; 6 | import { 7 | useDesiredChainDisplayName, 8 | useDesiredChainId, 9 | useTheme, 10 | } from "../ButtonProvider"; 11 | 12 | export const ChangeNetwork = () => { 13 | const desiredChainId = useDesiredChainId(); 14 | const desiredChainDisplayName = useDesiredChainDisplayName(); 15 | const { button, header, text } = useTheme(); 16 | const handleClick = async () => { 17 | await changeChain(`0x${desiredChainId.toString(16)}`); 18 | close(); 19 | }; 20 | return ( 21 | <> 22 |
23 |
24 | Wrong network 25 |
26 |

27 | Please connect to the 28 | {` ${desiredChainDisplayName} `} 29 | network to use this app. 30 |

31 | 34 |
35 |
36 |
37 | 38 | ); 39 | }; 40 | -------------------------------------------------------------------------------- /packages/react/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { getShortenedAddress } from "../helpers"; 3 | import { open } from "../state"; 4 | 5 | import { useWen } from "@wen-tools/actions"; 6 | 7 | import "../style.css"; 8 | import { useDesiredChainId, useTheme } from "./ButtonProvider"; 9 | 10 | const Skeleton = () => { 11 | const theme = useTheme(); 12 | 13 | return ( 14 | 17 | ); 18 | }; 19 | 20 | export const Button = () => { 21 | const [loading, setLoading] = React.useState(true); 22 | const { metamaskPresent, address, chainId } = useWen(); 23 | const theme = useTheme(); 24 | const desiredChainId = useDesiredChainId(); 25 | 26 | const wrongNetwork = `0x${desiredChainId.toString(16)}` !== chainId; 27 | 28 | useEffect(() => { 29 | setTimeout(() => setLoading(false), 600); 30 | }, [metamaskPresent]); 31 | 32 | if (loading) { 33 | return ; 34 | } 35 | 36 | return ( 37 | 44 | ); 45 | }; 46 | -------------------------------------------------------------------------------- /packages/react/src/components/Modal/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { LoadingPill, NotConnectedPill, ConnectedPill } from "../Pills"; 3 | import { useWen, disconnect } from "@wen-tools/actions"; 4 | import { getShortenedAddress } from "../../helpers"; 5 | import { useTheme } from "../ButtonProvider"; 6 | 7 | export const ModalHeader = () => { 8 | const { requesting, connected, address } = useWen(); 9 | const { button, header, text } = useTheme(); 10 | 11 | const handleClick = () => { 12 | disconnect(); 13 | }; 14 | return ( 15 |
16 |
17 |
18 |

{window.location.hostname}

19 | {address ? ( 20 | <> 21 |

Connected with 22 | {` ${getShortenedAddress(address)}`}

23 | 26 | 27 | ) :

Connect your wallet to use this app.

} 28 |
29 |
32 | {requesting && } 33 | {!(requesting || connected) && } 34 | {!requesting && connected && } 35 |
36 |
37 |
38 | ); 39 | }; 40 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package to npmjs 2 | on: workflow_dispatch 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | 9 | - uses: actions/setup-node@v3 10 | with: 11 | node-version: '16.x' 12 | registry-url: 'https://registry.npmjs.org' 13 | 14 | - name: Install pnpm 15 | uses: pnpm/action-setup@v2.0.1 16 | id: pnpm-install 17 | with: 18 | version: 7 19 | run_install: false 20 | 21 | - name: Get pnpm store directory 22 | id: pnpm-cache 23 | run: | 24 | echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" 25 | 26 | - name: Setup pnpm cache 27 | uses: actions/cache@v3 28 | with: 29 | path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} 30 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 31 | restore-keys: | 32 | ${{ runner.os }}-pnpm-store- 33 | 34 | - name: Install dependencies 35 | run: pnpm install 36 | 37 | - name: Publish Actions 38 | working-directory: packages/actions 39 | run: pnpm publish 40 | env: 41 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 42 | 43 | - name: Publish React 44 | working-directory: packages/react 45 | run: pnpm publish 46 | env: 47 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 48 | 49 | -------------------------------------------------------------------------------- /packages/react/src/components/Modal/Container.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Fragment } from "react"; 3 | import { Dialog, Transition } from "@headlessui/react"; 4 | import { useSnapshot } from "valtio"; 5 | import { state, close } from "../../state"; 6 | import { ModalContent } from "./Content"; 7 | import { useTheme } from "../ButtonProvider"; 8 | 9 | export const Modal = (): JSX.Element => { 10 | const { open } = useSnapshot(state); 11 | const { modal } = useTheme(); 12 | 13 | return ( 14 | 15 | 16 | 25 |
28 | 29 |
30 | 39 | 40 | 41 |
42 |
43 |
44 | ); 45 | }; 46 | 47 | export default Modal; 48 | -------------------------------------------------------------------------------- /packages/react/src/components/ConnectButton/Metamask.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { connectWallet } from "@wen-tools/actions"; 3 | import { detectMetamask } from "../../helpers"; 4 | 5 | import { close } from "../../state"; 6 | import { useTheme } from "../ButtonProvider"; 7 | 8 | export const MetamaskButton = () => { 9 | const [isMetamaskInstalled] = useState(detectMetamask()); 10 | const { connectPill, text } = useTheme(); 11 | 12 | const handleClick = async () => { 13 | try { 14 | await connectWallet(); 15 | } catch (e) { 16 | console.error(e); 17 | } finally { 18 | setTimeout(close, 300); 19 | } 20 | }; 21 | 22 | return ( 23 |
24 |
25 |
26 | Metamask Logo 31 |
32 | 41 |
42 | {isMetamaskInstalled ? ( 43 | 44 | ) : ( 45 | 50 | Download 51 | 52 | )} 53 |
54 |
55 |
56 | ); 57 | }; 58 | -------------------------------------------------------------------------------- /packages/react/src/chains.ts: -------------------------------------------------------------------------------- 1 | export const chainsMap = { 2 | 0: "kardia", 3 | 1: "ethereum", 4 | 2: "expanse", 5 | 4: "rinkeby", 6 | 5: "goerli", 7 | 6: "kovan", 8 | 7: "classic testnet", 9 | 8: "ubiq", 10 | 9: "callisto", 11 | 10: "optimism", 12 | 11: "metadium", 13 | 12: "metadium testnet", 14 | 19: "songbird", 15 | 20: "elastos", 16 | 25: "cronos", 17 | 30: "rsk", 18 | 40: "telos", 19 | 50: "xdc", 20 | 52: "csc", 21 | 55: "zyx", 22 | 56: "binance", 23 | 57: "syscoin", 24 | 60: "gochain", 25 | 61: "ethereumclassic", 26 | 66: "okexchain", 27 | 70: "hoo", 28 | 82: "meter", 29 | 87: "nova network", 30 | 88: "tomochain", 31 | 100: "xdai", 32 | 106: "velas", 33 | 108: "thundercore", 34 | 122: "fuse", 35 | 128: "heco", 36 | 137: "polygon", 37 | 200: "xdaiarb", 38 | 246: "energyweb", 39 | 250: "fantom", 40 | 269: "hpb", 41 | 288: "boba", 42 | 321: "kucoin", 43 | 336: "shiden", 44 | 361: "theta", 45 | 416: "sx", 46 | 534: "candle", 47 | 592: "astar", 48 | 820: "callisto", 49 | 888: "wanchain", 50 | 1088: "metis", 51 | 1246: "omchain", 52 | 1284: "moonbeam", 53 | 1285: "moonriver", 54 | 2020: "ronin", 55 | 2222: "kava", 56 | 2612: "ezchain", 57 | 4181: "phi", 58 | 4689: "iotex", 59 | 5050: "xlc", 60 | 5551: "nahmii", 61 | 7777: "nmactest", 62 | 8217: "klaytn", 63 | 9001: "evmos", 64 | 10000: "smartbch", 65 | 103090: "crystaleum", 66 | 32659: "fusion", 67 | 42161: "arbitrum", 68 | 42220: "celo", 69 | 42262: "oasis", 70 | 43114: "avalanche", 71 | 71402: "godwoken", 72 | 200625: "akroma", 73 | 333999: "polis", 74 | 1313161554: "aurora", 75 | 1666600000: "harmony", 76 | 11297108109: "palm", 77 | 836542336838601: "curio", 78 | }; 79 | -------------------------------------------------------------------------------- /packages/playground-ssr/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /packages/actions/README.md: -------------------------------------------------------------------------------- 1 | # Wen Actions 2 | 3 | **Wen Tools are under heavy development** 4 | 5 | Straight forward, batteries includes utilities to build dapps. 6 | 7 | _For turnkey connect component see: [Wen React](/packages/@wen-tools/react)_ 8 | 9 | ## Getting started 10 | 11 | Wen Actions depends on no other libraries to get started. It can completely be used as a standalone library but it works well with ethers.jsx 12 | 13 | ```sh 14 | npm i @wen-tools/actions 15 | # or 16 | yarn add @wen-tools/actions 17 | # or 18 | pnpm i @wen-tools/actions 19 | ``` 20 | 21 | ## Interacting with a user's wallet 22 | 23 | All functions are asynchronous. 24 | 25 | ```jsx 26 | import { connectWallet, changeChain } from "@wen-tools/actions"; 27 | 28 | // request a connection 29 | connectWallet(); 30 | // request the user to change to ethereum 31 | changeChain("0x1"); 32 | ``` 33 | 34 | ## Reading data from the user's wallet 35 | 36 | Wen Actions support both vanilla js and react. 37 | 38 | ### JS/TS 39 | 40 | A readonly proxy object is exposed to work. 41 | 42 | ```ts 43 | import { state } from "@wen-tools/actions"; 44 | 45 | // state is an instance of State 46 | type State = { 47 | metamaskPresent: Promise; 48 | address: string | null; 49 | balance: string | null; 50 | connected: boolean; 51 | chainId: string | null; 52 | // anytime the state is waiting on an updte from metamask, requesting is true 53 | requesting: boolean; 54 | }; 55 | ``` 56 | 57 | ### React 58 | 59 | For reactive updates use the React hook. It exposes the same state as the vanilla js/ts proxy object. 60 | 61 | ```tsx 62 | import { useWen } from "@wen-tools/react"; 63 | 64 | export default function Home() { 65 | // anytime the state is waiting on an updte from metamask, requesting is true 66 | const { address, balance, connected, chainId, requesting } = useWen(); 67 | return
{address}
; 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /packages/actions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wen-tools/actions", 3 | "version": "1.1.0", 4 | "description": "The engine behind all the wen tools", 5 | "module": "dist/esm/index.js", 6 | "types": "dist/esm/types/src/index.d.ts", 7 | "files": [ 8 | "dist", 9 | "package.json", 10 | "README.md" 11 | ], 12 | "private": false, 13 | "scripts": { 14 | "format": "rome format ./src", 15 | "format:fix": "rome format --write ./src", 16 | "lint": "rome check ./src", 17 | "lint:fix": "rome check --apply ./src", 18 | "prebuild": "rm -rf dist", 19 | "test": "vitest", 20 | "dev": "rollup -c -w", 21 | "build": "npm run prebuild && rollup -c" 22 | }, 23 | "keywords": [ 24 | "react", 25 | "typescript", 26 | "rollup", 27 | "metamask" 28 | ], 29 | "author": "Gui Bibeau (https://www.web3-fullstack.com/)", 30 | "license": "MIT", 31 | "devDependencies": { 32 | "@babel/core": "^7.18.6", 33 | "@rollup/plugin-commonjs": "^22.0.1", 34 | "@rollup/plugin-node-resolve": "^13.3.0", 35 | "@rollup/plugin-typescript": "^8.3.3", 36 | "@types/react": "18.0.14", 37 | "@types/rebass": "^4.0.10", 38 | "@vitest/ui": "latest", 39 | "autoprefixer": "^10.4.4", 40 | "babel-loader": "^8.2.5", 41 | "next": "canary", 42 | "postcss": "^8.4.12", 43 | "react": "^18.2.0", 44 | "react-dom": "^18.2.0", 45 | "rollup": "^2.75.0", 46 | "rollup-plugin-dts": "^4.2.2", 47 | "rollup-plugin-peer-deps-external": "^2.2.4", 48 | "rollup-plugin-postcss": "^4.0.2", 49 | "rollup-plugin-terser": "^7.0.2", 50 | "rome": "0.7.0-next.f6510d6", 51 | "typescript": "^4.7.4", 52 | "vite": "^2.9.9", 53 | "vitest": "latest" 54 | }, 55 | "peerDependencies": { 56 | "react": "^18.2.0", 57 | "react-dom": "^18.2.0" 58 | }, 59 | "dependencies": { 60 | "valtio": "^1.6.1" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /packages/docs/pages/packages/wen-actions.mdx: -------------------------------------------------------------------------------- 1 | # Wen Actions 2 | 3 | **Wen Tools are under heavy development** 4 | 5 | Straight forward, batteries includes utilities to build dapps. 6 | 7 | _For a turnkey connect component see: [Wen React](/packages/wen-react)_ 8 | 9 | ## Getting started 10 | 11 | Wen Actions depends on no other libraries to get started. It can completely be used as a standalone library but it works well with ethers.jsx 12 | 13 | ```sh 14 | npm i @wen-tools/actions 15 | # or 16 | yarn add @wen-tools/actions 17 | # or 18 | pnpm i @wen-tools/actions 19 | ``` 20 | 21 | ## Interacting with a user's wallet 22 | 23 | All functions are asynchronous. 24 | 25 | ```jsx 26 | import { connectWallet, changeChain } from "@wen-tools/actions"; 27 | 28 | // request a connection 29 | connectWallet(); 30 | // request the user to change to ethereum 31 | changeChain("0x1"); 32 | ``` 33 | 34 | ## Reading data from the user's wallet 35 | 36 | Wen Actions support both vanilla js and react. 37 | 38 | ### JS/TS 39 | 40 | A readonly proxy object is exposed to work. 41 | 42 | ```ts 43 | import { state } from "@wen-tools/actions"; 44 | 45 | // state is an instance of State 46 | type State = { 47 | metamaskPresent: Promise; 48 | address: string | null; 49 | balance: string | null; 50 | connected: boolean; 51 | chainId: string | null; 52 | // anytime the state is waiting on an updte from metamask, requesting is true 53 | requesting: boolean; 54 | }; 55 | ``` 56 | 57 | ### React 58 | 59 | For reactive updates use the React hook. It exposes the same state as the vanilla js/ts proxy object. 60 | 61 | ```tsx 62 | import { useWen } from "@wen-tools/react"; 63 | 64 | export default function Home() { 65 | // anytime the state is waiting on an updte from metamask, requesting is true 66 | const { address, balance, connected, chainId, requesting } = useWen(); 67 | return
{address}
; 68 | } 69 | ``` 70 | -------------------------------------------------------------------------------- /packages/react/src/components/ButtonProvider.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { Button } from "./Button"; 3 | import { listen, stopListening } from "@wen-tools/actions"; 4 | import { detectMetamask, parseChainId, parseChainName } from "../helpers"; 5 | import Modal from "./Modal/Container"; 6 | import { Theme, themeMap } from "./theme"; 7 | 8 | type Props = { 9 | chainId?: number | string; 10 | chainDisplayName?: string; 11 | theme?: Theme; 12 | }; 13 | 14 | const ChainContext = React.createContext({ 15 | chainId: 1, 16 | chainDisplayName: "Ethereum", 17 | theme: "base", 18 | }); 19 | 20 | export const ConnectButton = ( 21 | { chainId = 1, chainDisplayName = "Ethereum", theme = "base" }: { 22 | chainId?: number; 23 | chainDisplayName?: string; 24 | theme?: Theme; 25 | }, 26 | ) => { 27 | useEffect(() => { 28 | if (detectMetamask()) { 29 | listen(); 30 | } 31 | return () => { 32 | stopListening(); 33 | }; 34 | }, []); 35 | const chainContext = { 36 | chainId: parseChainId(chainId), 37 | chainDisplayName: parseChainName(chainId), 38 | theme, 39 | }; 40 | return ( 41 | 42 |