diff --git a/.changeset/config.json b/.changeset/config.json index c47279e4c8..11187a0aca 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,9 +1,15 @@ { - "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", + "$schema": "https://unpkg.com/@changesets/config@3.0.5/schema.json", + "changelog": [ + "@svitejs/changesets-changelog-github-compact", + { "repo": "wevm/wagmi" } + ], + "commit": false, "access": "public", + "fixed": [], + "linked": [], "baseBranch": "main", - "changelog": ["@changesets/changelog-github", { "repo": "wevm/wagmi" }], - "commit": false, + "updateInternalDependencies": "minor", "ignore": [ "*-register", "@wagmi/test", @@ -11,9 +17,5 @@ "next-app", "nuxt-app", "vite-*" - ], - "updateInternalDependencies": "patch", - "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { - "onlyUpdatePeerDependentsWhenOutOfRange": true - } + ] } diff --git a/.changeset/cool-masks-hang.md b/.changeset/cool-masks-hang.md deleted file mode 100644 index 0c0ff73c79..0000000000 --- a/.changeset/cool-masks-hang.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@wagmi/connectors": patch ---- - -Added `rdns` property to Coinbase Wallet v3 connector diff --git a/.changeset/twenty-olives-admire.md b/.changeset/twenty-olives-admire.md new file mode 100644 index 0000000000..6523b46c46 --- /dev/null +++ b/.changeset/twenty-olives-admire.md @@ -0,0 +1,5 @@ +--- +"@wagmi/cli": patch +--- + +Use Sourcify v2 API in sourcify plugin diff --git a/.changeset/two-spies-beam.md b/.changeset/two-spies-beam.md new file mode 100644 index 0000000000..e1d0e13eb0 --- /dev/null +++ b/.changeset/two-spies-beam.md @@ -0,0 +1,5 @@ +--- +"@wagmi/connectors": patch +--- + +Bumped MetaMask SDK version in accordance with [security advisory](https://github.com/advisories/GHSA-qj3p-xc97-xw74). diff --git a/.changeset/young-houses-relate.md b/.changeset/young-houses-relate.md deleted file mode 100644 index 288ab44256..0000000000 --- a/.changeset/young-houses-relate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@wagmi/connectors": patch ---- - -Bumped `@safe-global/safe-apps-provider` version to `0.18.6`. diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000..d5d401c518 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,31 @@ +# Use the latest 2.1 version of CircleCI pipeline process engine. +# See: https://circleci.com/docs/configuration-reference +version: 2.1 + +# Define a job to be invoked later in a workflow. +# See: https://circleci.com/docs/jobs-steps/#jobs-overview & https://circleci.com/docs/configuration-reference/#jobs +jobs: + say-hello: + # Specify the execution environment. You can specify an image from Docker Hub or use one of our convenience images from CircleCI's Developer Hub. + # See: https://circleci.com/docs/executor-intro/ & https://circleci.com/docs/configuration-reference/#executor-job + docker: + # Specify the version you desire here + # See: https://circleci.com/developer/images/image/cimg/base + - image: cimg/base:current + + # Add steps to the job + # See: https://circleci.com/docs/jobs-steps/#steps-overview & https://circleci.com/docs/configuration-reference/#steps + steps: + # Checkout the code as the first step. + - checkout + - run: + name: "Say hello" + command: "echo Hello, World!" + +# Orchestrate jobs using workflows +# See: https://circleci.com/docs/workflows/ & https://circleci.com/docs/configuration-reference/#workflows +workflows: + say-hello-workflow: # This is the name of the workflow, feel free to change it to better match your workflow. + # Inside the workflow, you define the jobs you want to run. + jobs: + - say-hello diff --git a/.circleci/web3_defi_gamefi.yml b/.circleci/web3_defi_gamefi.yml new file mode 100644 index 0000000000..fed3e4e4d7 --- /dev/null +++ b/.circleci/web3_defi_gamefi.yml @@ -0,0 +1,26 @@ +# Use the latest 2.1 version of CircleCI pipeline process engine. +# See: https://circleci.com/docs/configuration-reference + +version: 2.1 +executors: + my-custom-executor: + docker: + - image: cimg/base:stable + auth: + # ensure you have first added these secrets + # visit app.circleci.com/settings/project/github/Dargon789/foundry/environment-variables + username: $DOCKER_HUB_USER + password: $DOCKER_HUB_PASSWORD +jobs: + web3-defi-game-project-: + + executor: my-custom-executor + steps: + - checkout + - run: | + echo "TODO: Add build and test steps for the web3 defi game project." + +workflows: + my-custom-workflow: + jobs: + - web3-defi-game-project diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000000..8a593f6ba2 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,99 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "sourceType": "module", + "project": [ + "./tsconfig.json", + "./references/tsconfig.json", + "./docs/tsconfig.json", + "./examples/*/tsconfig.json" + ] + }, + "plugins": ["@typescript-eslint", "import"], + "extends": [ + "eslint:recommended", + "plugin:eslint-comments/recommended", + "plugin:@typescript-eslint/recommended", + "plugin:import/recommended", + "plugin:import/typescript", + "plugin:react-hooks/recommended", + "plugin:testing-library/react", + "plugin:prettier/recommended", + "prettier" + ], + "rules": { + // `@typescript-eslint` + // https://github.com/typescript-eslint/typescript-eslint + "@typescript-eslint/consistent-type-assertions": "error", + "@typescript-eslint/consistent-type-exports": "error", + "@typescript-eslint/consistent-type-imports": "error", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-unused-vars": [ + 2, + { + "argsIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_", + "ignoreRestSiblings": true + } + ], + "@typescript-eslint/no-var-requires": "off", + // `eslint-plugin-import` + // https://github.com/benmosher/eslint-plugin-import + "import/order": [ + "error", + { + "groups": ["external", "internal"], + "newlines-between": "always-and-inside-groups", + "alphabetize": { + "order": "asc" + } + } + ], + "sort-imports": [ + "warn", + { + "ignoreCase": false, + "ignoreDeclarationSort": true, + "ignoreMemberSort": false + } + ] + }, + "overrides": [ + { + "files": "**/*.mdx/**", + "extends": ["plugin:mdx/recommended"], + "rules": { + "import/no-anonymous-default-export": "off", + "react/display-name": "off", + "react/jsx-no-undef": "off", + "no-undef": "off" + }, + "settings": { + "mdx/code-blocks": true + } + } + ], + "ignorePatterns": ["CHANGELOG.md", "build", "dist", "node_modules", "**/*.config.js", "**/*.config.mjs"], + "settings": { + "import/parsers": { + "@typescript-eslint/parser": [".ts", ".tsx", ".d.ts"] + }, + "import/resolver": { + "typescript": { + "alwaysTryTypes": true + } + }, + "react": { + "version": "detect" + } + }, + "env": { + "es6": true, + "browser": true, + "node": true + } +} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 12451d4bc9..0000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,5 +0,0 @@ -@tmm @jxom - -/packages/connectors/src/metaMask @ecp4224 @omridan159 @abretonc7s @elefantel @BjornGunnarsson @EdouardBougon -/packages/connectors/src/safe @DaniSomoza @dasanra @mikhailxyz @yagopv -/packages/connectors/src/walletConnect @ganchoradkov @glitch-txs @ignaciosantise @tomiir diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index d3ab387e17..065515d7aa 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1 +1,191 @@ -[View Contributing Guide on wagmi.sh](https://wagmi.sh/dev/contributing) \ No newline at end of file +# Contributing + +Thanks for your interest in contributing to wagmi! Please take a moment to review this document **before submitting a pull request.** + +If you want to contribute, but aren't sure where to start, you can create a [new discussion](https://github.com/wagmi-dev/wagmi/discussions). + +> **Note** +> +> **Please ask first before starting work on any significant new features. This includes things like adding new connectors, hooks, chains, API providers, etc.** +> +> It's never a fun experience to have your pull request declined after investing time and effort into a new feature. To avoid this from happening, we request that contributors create a [feature request](https://github.com/wagmi-dev/wagmi/discussions/new?category=ideas) to first discuss any API changes or significant new ideas. + +
+ +## Basic guide + +This guide is intended to help you get started with contributing. By following these steps, you will understand the development process and workflow. + +1. [Cloning the repository](#cloning-the-repository) +2. [Installing Node.js and pnpm](#installing-nodejs-and-pnpm) +3. [Installing dependencies](#installing-dependencies) +4. [Starting the development playground](#starting-the-development-playground) +5. [Running the test suite](#running-the-test-suite) +6. [Writing documentation](#writing-documentation) +7. [Submitting a pull request](#submitting-a-pull-request) + +## Advanced guide + +This guide covers more advanced topics. Pick the topics based on your needs. + +8. [Versioning](#versioning) + +
+ +--- + +
+ +## Cloning the repository + +To start contributing to the project, clone it to your local machine using git: + +```bash +git clone https://github.com/wagmi-dev/wagmi.git --recurse-submodules +``` + +Or the [GitHub CLI](https://cli.github.com): + +```bash +gh repo clone wagmi-dev/wagmi -- --recurse-submodules +``` + +
+ ↑ back to top +
+ +## Installing Node.js and pnpm + +wagmi uses [pnpm workspaces](https://pnpm.io/workspaces) to manage multiple projects. You need to install **Node.js v16 or higher** and **pnpm v7 or higher**. + +You can run the following commands in your terminal to check your local Node.js and npm versions: + +```bash +node -v +pnpm -v +``` + +If the versions are not correct or you don't have Node.js or pnpm installed, download and follow their setup instructions: + +- Install Node.js using [fnm](https://github.com/Schniz/fnm) or from the [official website](https://nodejs.org) +- Install [pnpm](https://pnpm.io/installation) + +
+ ↑ back to top +
+ +## Installing dependencies + +Once in the project's root directory, run the following command to install the project's dependencies: + +```bash +pnpm install +``` + +After the install completes, pnpm links packages across the project for development and [git hooks](https://github.com/toplenboren/simple-git-hooks) are set up. + +
+ ↑ back to top +
+ +## Starting the development playground + +To start the local development playground, run the following. This will run a [Next.js](https://nextjs.org) app (located at [`examples/_dev`](../examples/_dev)) that is set up for playing around with code while making changes. + +```bash +pnpm playground +``` + +Once the Next.js dev server is running, you can make changes to any of the package source files (e.g. `packages/react`) and it will automatically update the playground. (If the playground isn't automatically updating, try running `pnpm dev` to relink packages in development mode.) + +
+ ↑ back to top +
+ +## Running the test suite + +wagmi uses [Anvil](https://github.com/foundry-rs/foundry/tree/master/anvil) to execute tests against a local Ethereum node. First, install Anvil via [Foundry](https://book.getfoundry.sh/getting-started/installation). Next, add the following to your environment (recommended to use [`direnv`](https://github.com/direnv/direnv)): + +```bash +ANVIL_FORK_URL=https://eth-mainnet.alchemyapi.io/v2/ +``` + +`ANVIL_FORK_URL` can be for any RPC service provider (e.g. Alchemy or Infura). Now you are ready to run the tests! In one terminal session, spin up Anvil using `pnpm anvil`. Next, in a different terminal session, you have the following options for running tests: + +- `pnpm test` — runs tests in watch mode +- `pnpm test:run` — performs single run without watch mode + +When adding new features or fixing bugs, it's important to add test cases to cover the new/updated behavior. If snapshot tests fail, you can run the `test:update` command to update the snapshots. + +
+ ↑ back to top +
+ +## Writing documentation + +Documentation is crucial to helping developers of all experience levels use wagmi. wagmi uses [Nextra](https://github.com/shuding/nextra) and [MDX](https://mdxjs.com) for the documentation site (located at [`docs`](../docs)). To start the site in dev mode, run: + +```bash +pnpm docs:dev +``` + +Try to keep documentation brief and use plain language so folks of all experience levels can understand. If you think something is unclear or could be explained better, you are welcome to open a pull request. + +
+ ↑ back to top +
+ +## Submitting a pull request + +When you're ready to submit a pull request, you can follow these naming conventions: + +- Pull request titles use the [Imperative Mood](https://en.wikipedia.org/wiki/Imperative_mood) (e.g., `Add something`, `Fix something`). +- [Changesets](#versioning) use past tense verbs (e.g., `Added something`, `Fixed something`). + +When you submit a pull request, GitHub will automatically lint, build, and test your changes. If you see an ❌, it's most likely a bug in your code. Please, inspect the logs through the GitHub UI to find the cause. + +
+ ↑ back to top +
+ +
+ +--- + +
+ ✅ Now you're ready to contribute to wagmi! Follow the next steps if you need more advanced instructions. +
+ +--- + +
+ +## Versioning + +When adding new features or fixing bugs, we'll need to bump the package versions. We use [Changesets](https://github.com/changesets/changesets) to do this. + +> **Note** +> +> Only changes to the codebase that affect the public API or existing behavior (e.g. bugs) need changesets. + +Each changeset defines which package(s) should be published and whether the change should be a major/minor/patch release, as well as providing release notes that will be added to the changelog upon release. + +To create a new changeset, run `pnpm changeset`. This will run the Changesets CLI, prompting you for details about the change. You’ll be able to edit the file after it’s created — don’t worry about getting everything perfect up front. + +Since we’re currently in beta, all changes should be marked as a minor/patch release to keep us within the `v0.x` range. + +Even though you can technically use any markdown formatting you like, headings should be avoided since each changeset will ultimately be nested within a bullet list. Instead, bold text should be used as section headings. + +If your PR is making changes to an area that already has a changeset (e.g. there’s an existing changeset covering theme API changes but you’re making further changes to the same API), you should update the existing changeset in your PR rather than creating a new one. + +### Releasing + +The first time a PR with a changeset is merged after a release, a new PR will automatically be created called `chore: version packages`. Any subsequent PRs with changesets will automatically update this existing version packages PR. Merging this PR triggers the release process by publishing to npm and cleaning up the changeset files. + +### Creating a snapshot release + +If a PR has changesets, you can create a [snapshot release](https://github.com/changesets/changesets/blob/main/docs/snapshot-releases.md) by [manually dispatching](https://github.com/wagmi-dev/wagmi/actions/workflows/snapshot.yml) the Snapshot workflow. This publishes a tagged version to npm with the PR branch name and timestamp. + +
+ ↑ back to top +
diff --git a/.github/DISCUSSION_TEMPLATE/connector-request.yml b/.github/DISCUSSION_TEMPLATE/connector-request.yml deleted file mode 100644 index c1e31b1b6b..0000000000 --- a/.github/DISCUSSION_TEMPLATE/connector-request.yml +++ /dev/null @@ -1,51 +0,0 @@ -title: '[Connector Request] ' -body: - - type: markdown - attributes: - value: | - Thanks for your interest in contributing a new Connector to the Wagmi! If you haven't already, please read the [Contributing Guidelines](https://wagmi.sh/dev/contributing). Once you submit the form, the Wagmi team will follow up in the discussion thread to discuss next steps. - - Please note that in order for connector requests to be accepted, the team creating the Connector must [sponsor Wagmi](https://github.com/sponsors/wevm). It takes time and effort to maintain third-party connectors. Wagmi is an OSS project that depends on sponsors and grants to continue our work. Please get in touch via [dev@wevm.dev](mailto:dev@wevm.dev) if you have questions about sponsoring. - - - type: textarea - attributes: - label: What **novel use-case** does the Connector provide? - description: | - A novel use-case is likely one that is not already covered by or not easily extended from another Connector (such as the `injected` or `walletConnect`). - - Examples of **novel** use-cases could be a connector that integrates with: - - - the injected `window.ethereum` provider (a la `injected`) - - a series of wallets via QR Codes or Mobile Deep Links (a la `walletConnect`) - - a wallet with it's own SDK (a la `coinbaseWallet`) - - hardware wallet(s) via Web USB/Bluetooth - - an Externally Owned Account via a private key or some other method - - Examples of **nonnovel** use-cases would be a connector that: - - - extends another connector (e.g. `walletConnect`) with no significant differences in functionality other than branding, etc. - placeholder: Info on what makes this connector different. - validations: - required: true - - - type: textarea - attributes: - label: Are the Connector's integrations production-ready and generally available? - description: Connectors are intended to be used by consumers in production as part of Wagmi. As such, the Connector and all dependencies must be production-ready and generally available. This means your connector should not rely on non-production software or be restricted to a limited group of users. For example, if your connector requires a wallet that has a closed beta, it is not ready for inclusion in Wagmi. - placeholder: Info about the Connector and any dependencies (e.g. browser extension, wallet app, npm package). - validations: - required: true - - - type: checkboxes - attributes: - label: Are you committed to actively maintaining the Connector? - description: It is critical connectors are updated in a timely manner and actively maintained so that users of Wagmi can rely on them in production settings. The Wagmi core team will provide as much assistance as possible to keep connectors up-to-date with breaking changes from Wagmi, but it is your responsibility to ensure that any dependencies and issues/discussions related to the Connector are handled in a timely manner. If this is not done, the Connector could be removed from the future versions. - options: - - label: Yes, my team is or I am committed to actively maintaining the Connector. - required: true - - - type: textarea - attributes: - label: Additional comments - description: Feel free to jot down any additional info you think might be helpful. - placeholder: Additional comments, questions, feedback. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..d2eb2adc8f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '[BUG] ' +labels: 'bug' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior. A link to a minimal reproduction is highly recommended. You can use a service like [CodeSandbox](https://codesandbox.io/p/sandbox/wagmi-reproduction-template-15n57l) or [StackBlitz](https://stackblitz.com/fork/wagmi-reproduction-template). + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**System Info** + - `wagmi` version: + - `viem` version: + - OS: [e.g. Windows, macOS, Ubuntu] + - Browser: [e.g. chrome, safari] + - Framework: [e.g. Next.js, Vite, etc.] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 8a561abba1..ae99b344e6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,88 +1,65 @@ name: Bug Report -description: Report bugs or issues. +description: File a bug/issue +title: 'bug: ' body: - type: markdown attributes: value: | - Thanks for taking the time to fill out this bug report! The more info you provide, the more we can help you. - - If you are a [Wagmi Sponsor](https://github.com/sponsors/wevm?metadata_campaign=gh_issue), your issues are prioritized. + Thanks for taking the time to fill out this bug report! The more info you provide, the more we can help you. If you are a [Sponsor](https://github.com/sponsors/wagmi-dev?metadata_campaign=gh_issue), your issues are prioritized. - type: checkboxes attributes: - label: Check existing issues - description: By submitting this issue, you checked there isn't [already an issue](https://github.com/wevm/wagmi/issues) for this bug. + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the bug you encountered. options: - - label: I checked there isn't [already an issue](https://github.com/wevm/wagmi/issues) for the bug I encountered. + - label: I have searched the existing issues required: true - - type: textarea + - type: input attributes: - label: Describe the bug - description: Clear and concise description of the bug. If you intend to submit a PR for this issue, tell us in the description. Thanks! - placeholder: I am doing… What I expect is… What is actually happening… + label: Package Version + description: What version of wagmi are you using? + placeholder: 1.0.0 validations: required: true - - type: input - id: reproduction + - type: textarea attributes: - label: Link to Minimal Reproducible Example - description: "Please provide a link that can reproduce the problem: [new.wagmi.sh](https://new.wagmi.sh) for runtime issues or [TypeScript Playground](https://www.typescriptlang.org/play) for type issues. For most issues, you will likely get asked to provide a minimal reproducible example so why not add one now :) If a report is vague (e.g. just snippets, generic error message, screenshot, etc.) and has no reproduction, it will receive a \"Needs Reproduction\" label and be auto-closed." - placeholder: https://new.wagmi.sh + label: Current Behavior + description: A concise description of what you're experiencing. validations: required: false - type: textarea attributes: - label: Steps To Reproduce - description: Steps or code snippets to reproduce the behavior. + label: Expected Behavior + description: A concise description of what you expected to happen. validations: required: false - - type: dropdown - attributes: - label: What Wagmi package(s) are you using? - multiple: true - options: - - 'wagmi' - - '@wagmi/cli' - - '@wagmi/connectors' - - '@wagmi/core' - - '@wagmi/vue' - - 'create-wagmi' - validations: - required: true - - - type: input - attributes: - label: Wagmi Package(s) Version(s) - description: What version of the Wagmi packages you selected above are you using? If using multiple, separate with comma (e.g. `wagmi@x.y.z, @wagmi/cli@x.y.z`). - placeholder: x.y.z (do not write `latest`) - validations: - required: true - - - type: input + - type: textarea attributes: - label: Viem Version - description: What version of [Viem](https://viem.sh) are you using? - placeholder: x.y.z (do not write `latest`) + label: Steps To Reproduce + description: Steps or code snippets to reproduce the behavior. validations: - required: true + required: false - type: input attributes: - label: TypeScript Version - description: What version of TypeScript are you using? Wagmi requires `typescript@>=5`. - placeholder: x.y.z (do not write `latest`) + label: Link to Minimal Reproducible Example (StackBlitz, CodeSandbox, GitHub repo etc.) + description: | + Please provide a link via [new.wagmi.sh](https://new.wagmi.sh/) or a link to a minimal repository that can reproduce the problem you ran into. `npm create wagmi@latest` can also be used as a starter template. + This makes investigating issues and helping you out significantly easier! For most issues, you will likely get asked to provide one so why not add one now :) + placeholder: https://new.wagmi.sh/ validations: required: false - type: textarea attributes: label: Anything else? - description: Anything that will give us more context about the issue you are encountering. Framework version (e.g. React, Vue), app framework (e.g. Next.js, Nuxt), bundler, etc. + description: | + Browser info? Screenshots? Anything that will give us more context about the issue you are encountering! + + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. validations: required: false - - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index fc8027c871..bcbc79e6cc 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,14 +1,8 @@ blank_issues_enabled: false contact_links: - - name: Get Help - url: https://github.com/wevm/wagmi/discussions/new?category=q-a - about: Ask a question and discuss with other community members. - - - name: Feature Request - url: https://github.com/wevm/wagmi/discussions/new?category=ideas - about: Request features or brainstorm ideas for new functionality. - - - name: Connector Request - url: https://github.com/wevm/wagmi/discussions/new?category=connector-request - about: Kick off a request for a new connector - + - name: Ask Question + url: https://github.com/wagmi-dev/wagmi/discussions/new?category=q-a + about: Ask questions and discuss with other community members + - name: Request Feature + url: https://github.com/wagmi-dev/wagmi/discussions/new?category=ideas + about: Requests features or brainstorm ideas for new functionality diff --git a/.github/ISSUE_TEMPLATE/custom.md b/.github/ISSUE_TEMPLATE/custom.md new file mode 100644 index 0000000000..48d5f81fa4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/custom.md @@ -0,0 +1,10 @@ +--- +name: Custom issue template +about: Describe this issue template's purpose here. +title: '' +labels: '' +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/docs_issue.yml b/.github/ISSUE_TEMPLATE/docs_issue.yml deleted file mode 100644 index f2d53b8a98..0000000000 --- a/.github/ISSUE_TEMPLATE/docs_issue.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Documentation Issue -description: Tell us about missing or incorrect documentation. -labels: ['Area: Docs'] -body: - - type: markdown - attributes: - value: | - Thank you for submitting a documentation request. It helps make Wagmi better. - - If it's a small change, like misspelling or example that needs updating, feel free to submit a PR instead of creating this issue. - - - type: dropdown - attributes: - label: What is the type of issue? - multiple: true - options: - - Documentation is missing - - Documentation is incorrect - - Documentation is confusing - - Example code is not working - - Something else - - - type: textarea - attributes: - label: What is the issue? - validations: - required: true - - - type: textarea - attributes: - label: Where did you find it? - description: Please provide the URL(s) where you found this issue. - validations: - required: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..bc1428bce5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '[FEAT] ' +labels: 'enhancement' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/README.md b/.github/README.md index 6b5f336419..6a42bc8198 100644 --- a/.github/README.md +++ b/.github/README.md @@ -23,6 +23,19 @@ <img src="https://img.shields.io/npm/v/wagmi?colorA=f6f8fa&colorB=f6f8fa" alt="Version"> </picture> </a> + <a href="https://scorecard.dev/viewer/?uri=github.com/ossf/scorecard"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/ossf-scorecard/github.com/wevm/wagmi?label=openssf+scorecard&style=flat&color=21262d&labelColor=21262d"> + <img src="https://img.shields.io/ossf-scorecard/github.com/wevm/wagmi?label=openssf+scorecard&style=flat&color=f6f8fa&labelColor=f6f8fa" alt="OpenSSF Best Practices"> + </picture> + </a> + <a href="https://www.bestpractices.dev/en/projects/11233"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/badge/openssf_best_practices-passing-21262d?labelColor=21262d"> + <img src="https://img.shields.io/badge/openssf_best_practices-passing-f6f8fa?labelColor=f6f8fa" alt="OpenSSF Best Practices"> + </picture> + </a> + <br /> <a href="https://github.com/wevm/wagmi/blob/main/LICENSE"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/l/wagmi?colorA=21262d&colorB=21262d"> @@ -239,6 +252,12 @@ If you find Wagmi useful or use it for work, please consider [sponsoring Wagmi]( <img alt="sequence logo" src="https://raw.githubusercontent.com/wevm/.github/main/content/sponsors/sequence-light.svg" width="auto" height="50"> </picture> </a> + <a href="https://gemini.com"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wevm/.github/main/content/sponsors/gemini-dark.svg"> + <img alt="gemini logo" src="https://raw.githubusercontent.com/wevm/.github/main/content/sponsors/gemini-light.svg" width="auto" height="50"> + </picture> + </a> </p> [Sponsor Wagmi](https://github.com/sponsors/wevm?metadata_campaign=gh_readme_support_bottom) diff --git a/.github/SECURITY.md b/.github/SECURITY.md deleted file mode 100644 index 54f40f38df..0000000000 --- a/.github/SECURITY.md +++ /dev/null @@ -1,6 +0,0 @@ -# Security Policy - -## Reporting a Vulnerability - -Contact [dev@wevm.dev](mailto:dev@wevm.dev). - diff --git a/.github/logo-dark.svg b/.github/logo-dark.svg deleted file mode 100644 index 5d47cce337..0000000000 --- a/.github/logo-dark.svg +++ /dev/null @@ -1,27 +0,0 @@ -<svg - viewBox="0 0 561 132" - fill="none" - xmlns="http://www.w3.org/2000/svg" -> - <path - d="M561 12C561 18.6274 555.627 24 549 24C542.373 24 537 18.6274 537 12C537 5.37259 542.373 0 549 0C555.627 0 561 5.37259 561 12Z" - fill="#f3f4f6" - /> - <path - d="M414 105C418.971 105 423 100.971 423 96V60C423 55.0294 427.029 51 432 51H450C454.971 51 459 55.0294 459 60V96C459 100.971 463.029 105 468 105C472.971 105 477 100.971 477 96V60C477 55.0294 481.029 51 486 51H504C508.971 51 513 55.0294 513 60V96C513 100.971 517.029 105 522 105H549C553.971 105 558 100.971 558 96V42C558 37.0294 553.971 33 549 33C544.029 33 540 37.0294 540 42V82.5C540 84.9853 537.985 87 535.5 87C533.015 87 531 84.9853 531 82.5V42C531 37.0294 526.971 33 522 33H414C409.029 33 405 37.0294 405 42V96C405 100.971 409.029 105 414 105Z" - fill="#f3f4f6" - /> - <path - fill-rule="evenodd" - clip-rule="evenodd" - d="M27 87C22.0294 87 18 82.9706 18 78V42C18 37.0294 13.9706 33 9 33C4.02943 33 0 37.0294 0 42V96C0 100.971 4.02943 105 9 105H117C121.971 105 126 100.971 126 96V60C126 55.0294 130.029 51 135 51H238.5C240.985 51 243 53.0147 243 55.5C243 57.9853 240.985 60 238.5 60H144C139.029 60 135 64.0294 135 69V96C135 100.971 139.029 105 144 105H252C256.971 105 261 100.971 261 96V42C261 37.0294 256.971 33 252 33H117C112.029 33 108 37.0294 108 42V78C108 82.9706 103.971 87 99 87H81C76.0294 87 72 82.9706 72 78V42C72 37.0294 67.9706 33 63 33C58.0294 33 54 37.0294 54 42V78C54 82.9706 49.9706 87 45 87H27ZM243 82.5C243 84.9853 240.985 87 238.5 87H157.5C155.015 87 153 84.9853 153 82.5C153 80.0147 155.015 78 157.5 78H238.5C240.985 78 243 80.0147 243 82.5Z" - fill="#f3f4f6" - /> - <path - fill-rule="evenodd" - clip-rule="evenodd" - d="M270 96C270 100.971 274.029 105 279 105H373.5C375.985 105 378 107.015 378 109.5C378 111.985 375.985 114 373.5 114H279C274.029 114 270 118.029 270 123C270 127.971 274.029 132 279 132H387C391.971 132 396 127.971 396 123V42C396 37.0294 391.971 33 387 33H279C274.029 33 270 37.0294 270 42V96ZM297 51C292.029 51 288 55.0294 288 60V78C288 82.9706 292.029 87 297 87H369C373.971 87 378 82.9706 378 78V60C378 55.0294 373.971 51 369 51H297Z" - fill="#f3f4f6" - /> -</svg> - diff --git a/.github/logo-light.svg b/.github/logo-light.svg deleted file mode 100644 index 4e28590c36..0000000000 --- a/.github/logo-light.svg +++ /dev/null @@ -1,27 +0,0 @@ -<svg - viewBox="0 0 561 132" - fill="none" - xmlns="http://www.w3.org/2000/svg" -> - <path - d="M561 12C561 18.6274 555.627 24 549 24C542.373 24 537 18.6274 537 12C537 5.37259 542.373 0 549 0C555.627 0 561 5.37259 561 12Z" - fill="#1B1B1B" - /> - <path - d="M414 105C418.971 105 423 100.971 423 96V60C423 55.0294 427.029 51 432 51H450C454.971 51 459 55.0294 459 60V96C459 100.971 463.029 105 468 105C472.971 105 477 100.971 477 96V60C477 55.0294 481.029 51 486 51H504C508.971 51 513 55.0294 513 60V96C513 100.971 517.029 105 522 105H549C553.971 105 558 100.971 558 96V42C558 37.0294 553.971 33 549 33C544.029 33 540 37.0294 540 42V82.5C540 84.9853 537.985 87 535.5 87C533.015 87 531 84.9853 531 82.5V42C531 37.0294 526.971 33 522 33H414C409.029 33 405 37.0294 405 42V96C405 100.971 409.029 105 414 105Z" - fill="#1B1B1B" - /> - <path - fill-rule="evenodd" - clip-rule="evenodd" - d="M27 87C22.0294 87 18 82.9706 18 78V42C18 37.0294 13.9706 33 9 33C4.02943 33 0 37.0294 0 42V96C0 100.971 4.02943 105 9 105H117C121.971 105 126 100.971 126 96V60C126 55.0294 130.029 51 135 51H238.5C240.985 51 243 53.0147 243 55.5C243 57.9853 240.985 60 238.5 60H144C139.029 60 135 64.0294 135 69V96C135 100.971 139.029 105 144 105H252C256.971 105 261 100.971 261 96V42C261 37.0294 256.971 33 252 33H117C112.029 33 108 37.0294 108 42V78C108 82.9706 103.971 87 99 87H81C76.0294 87 72 82.9706 72 78V42C72 37.0294 67.9706 33 63 33C58.0294 33 54 37.0294 54 42V78C54 82.9706 49.9706 87 45 87H27ZM243 82.5C243 84.9853 240.985 87 238.5 87H157.5C155.015 87 153 84.9853 153 82.5C153 80.0147 155.015 78 157.5 78H238.5C240.985 78 243 80.0147 243 82.5Z" - fill="#1B1B1B" - /> - <path - fill-rule="evenodd" - clip-rule="evenodd" - d="M270 96C270 100.971 274.029 105 279 105H373.5C375.985 105 378 107.015 378 109.5C378 111.985 375.985 114 373.5 114H279C274.029 114 270 118.029 270 123C270 127.971 274.029 132 279 132H387C391.971 132 396 127.971 396 123V42C396 37.0294 391.971 33 387 33H279C274.029 33 270 37.0294 270 42V96ZM297 51C292.029 51 288 55.0294 288 60V78C288 82.9706 292.029 87 297 87H369C373.971 87 378 82.9706 378 78V60C378 55.0294 373.971 51 369 51H297Z" - fill="#1B1B1B" - /> -</svg> - diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 602a32d0a8..e0f29dc408 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,12 +1,9 @@ -<!-- What is this PR solving? Write a clear description or reference the issues it solves (e.g. `fixes #123`). What other alternatives have you explored? Are there any parts you think require more attention from reviewers? --> +## Description -<!---------------------------------------------------------------------- -Before creating the pull request, please make sure you do the following: +_Concise description of proposed changes_ -- Read the Contributing Guidelines at https://wagmi.sh/dev/contributing -- Check that there isn't already a PR that solves the problem the same way. If you find a duplicate, please help us review it. -- Update the corresponding documentation if needed. -- Include relevant tests that fail without this PR, but pass with it. +## Additional Information -Thank you for contributing to Wagmi! ------------------------------------------------------------------------> +- [ ] I read the [contributing docs](/wagmi-dev/wagmi/blob/main/.github/CONTRIBUTING.md) (if this is your first contribution) + +Your ENS/address: diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000000..e9301ec4f6 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 180 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - bug + - not stale +# Label to use when marking an issue as stale +staleLabel: stale +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.github/workflows/cache.yml b/.github/workflows/cache.yml new file mode 100644 index 0000000000..a5cd0c36f8 --- /dev/null +++ b/.github/workflows/cache.yml @@ -0,0 +1,29 @@ +name: Bust Actions Cache + +on: + workflow_dispatch: + +permissions: + actions: write + +jobs: + bust-cache: + runs-on: ubuntu-latest + steps: + - name: Bust actions cache + uses: actions/github-script@v6 + with: + script: | + console.log("Clearing cache…") + const caches = await github.rest.actions.getActionsCacheList({ + owner: context.repo.owner, + repo: context.repo.repo, + }) + for (const cache of caches.data.actions_caches) { + github.rest.actions.deleteActionsCacheById({ + owner: context.repo.owner, + repo: context.repo.repo, + cache_id: cache.id, + }) + } + console.log("Cache cleared.") diff --git a/.github/workflows/changesets.yml b/.github/workflows/changesets.yml index 34e945ddf0..3bcdc95fe8 100644 --- a/.github/workflows/changesets.yml +++ b/.github/workflows/changesets.yml @@ -10,28 +10,34 @@ concurrency: jobs: verify: name: Verify + permissions: + contents: write uses: ./.github/workflows/verify.yml secrets: inherit changesets: name: Publish needs: verify + # prevents this action from running on forks + if: github.repository == 'wevm/wagmi' permissions: - contents: write - id-token: write - pull-requests: write + contents: write # to create release (changesets/action) + id-token: write # OpenID Connect token needed for provenance + pull-requests: write # to create pull request (changesets/action) runs-on: ubuntu-latest timeout-minutes: 5 steps: - name: Clone repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 with: # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits fetch-depth: 0 - name: Install dependencies uses: wevm/actions/.github/actions/pnpm@main + with: + node-version: 24.5 - name: PR or publish uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc @@ -43,16 +49,13 @@ jobs: version: pnpm changeset:version env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Publish prerelease if: steps.changesets.outputs.published != 'true' continue-on-error: true env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - npm config set "//registry.npmjs.org/:_authToken" "$NPM_TOKEN" git reset --hard origin/main pnpm clean pnpm changeset version --no-git-tag --snapshot canary diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml index 39b98291d1..eaa28bfd01 100644 --- a/.github/workflows/issue-labeled.yml +++ b/.github/workflows/issue-labeled.yml @@ -1,4 +1,6 @@ name: Issue Labeled +permissions: + issues: write on: issues: @@ -7,7 +9,7 @@ on: jobs: issue-labeled: if: ${{ github.repository_owner == 'wevm' }} - uses: wevm/actions/.github/workflows/issue-labeled.yml@main + uses: wevm/actions/.github/workflows/issue-labeled.yml@f7ad7f00e16e73322562922c241f21f0c7ffbbec with: needs-reproduction-body: | Hello @${{ github.event.issue.user.login }}. diff --git a/.github/workflows/lock-issue.yml b/.github/workflows/lock-issue.yml index 279452d223..afce18e9fb 100644 --- a/.github/workflows/lock-issue.yml +++ b/.github/workflows/lock-issue.yml @@ -1,4 +1,6 @@ name: Lock Issue +permissions: + issues: write on: schedule: @@ -7,7 +9,7 @@ on: jobs: lock-issue: if: ${{ github.repository_owner == 'wevm' }} - uses: wevm/actions/.github/workflows/lock-issue.yml@main + uses: wevm/actions/.github/workflows/lock-issue.yml@f7ad7f00e16e73322562922c241f21f0c7ffbbec with: issue-comment: | This issue has been locked since it has been closed for more than 14 days. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000000..9f87dd5d92 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,208 @@ +name: Main +permissions: + contents: read + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + install: + name: Install + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [19] + pnpm-version: [8] + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - uses: pnpm/action-setup@v2.2.4 + with: + version: ${{ matrix.pnpm-version }} + - name: Set up Node ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + cache: 'pnpm' + node-version: ${{ matrix.node-version }} + - name: Cache pnpm + uses: actions/cache@v3 + with: + path: ~/.pnpm-store + key: pnpm-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: pnpm- + - name: Cache node_modules + uses: actions/cache@v3 + id: cache-node-modules + with: + path: | + node_modules + docs/node_modules + examples/**/node_modules + packages/**/node_modules + packages/**/dist + references/packages/**/node_modules + key: modules-${{ hashFiles('pnpm-lock.yaml') }} + - name: Install Dependencies + if: steps.cache-node-modules.outputs.cache-hit != 'true' + run: pnpm i + - name: Link Dependencies + if: steps.cache-node-modules.outputs.cache-hit == 'true' + run: pnpm dev + + lint: + permissions: + contents: write + name: Lint + needs: install + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [19] + pnpm-version: [8] + steps: + - uses: actions/checkout@v3 + with: + submodules: true + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + - uses: pnpm/action-setup@v2.2.4 + with: + version: ${{ matrix.pnpm-version }} + - name: Set up Node ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + cache: 'pnpm' + node-version: ${{ matrix.node-version }} + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: | + node_modules + docs/node_modules + examples/**/node_modules + packages/**/node_modules + packages/**/dist + references/packages/**/node_modules + key: modules-${{ hashFiles('pnpm-lock.yaml') }} + - name: Check types + run: pnpm typecheck + - name: Lint & format code + run: pnpm lint:fix && pnpm lint:format packages + - name: Commit + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + git add . + if [ -z "$(git status --porcelain)" ]; then + echo "no formatting changed" + exit 0 + fi + git commit -m "chore: format" + git push + echo "pushed formatting changes https://github.com/$GITHUB_REPOSITORY/commit/$(git rev-parse HEAD)" + + build: + name: Build + permissions: + contents: read + needs: lint + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [19] + pnpm-version: [8] + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - uses: pnpm/action-setup@v2.2.4 + with: + version: ${{ matrix.pnpm-version }} + - name: Set up Node ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + cache: 'pnpm' + node-version: ${{ matrix.node-version }} + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: | + node_modules + docs/node_modules + examples/**/node_modules + packages/**/node_modules + packages/**/dist + references/packages/**/node_modules + key: modules-${{ hashFiles('pnpm-lock.yaml') }} + - name: Build + run: pnpm build + + test: + name: Test + needs: lint + runs-on: ubuntu-latest + env: + ANVIL_BLOCK_NUMBER: 15578840 + strategy: + matrix: + node-version: [19] + pnpm-version: [8] + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - uses: pnpm/action-setup@v2.2.4 + with: + version: ${{ matrix.pnpm-version }} + - name: Set up Node ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + cache: 'pnpm' + node-version: ${{ matrix.node-version }} + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: | + node_modules + docs/node_modules + examples/**/node_modules + packages/**/node_modules + packages/**/dist + references/packages/**/node_modules + key: modules-${{ hashFiles('pnpm-lock.yaml') }} + - name: Cache Anvil + uses: 'actions/cache@v3' + with: + path: ~/.foundry/cache/rpc/**/${{ env.ANVIL_BLOCK_NUMBER }} + key: foundry-anvil-${{ env.ANVIL_BLOCK_NUMBER }} + - name: Install rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: wasm32-unknown-unknown + profile: minimal + override: true + - name: Install Anvil + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + - name: Launch Anvil + run: anvil --fork-url $ANVIL_FORK_URL --fork-block-number $ANVIL_BLOCK_NUMBER & + env: + ANVIL_FORK_URL: ${{ secrets.ANVIL_FORK_URL }} + - name: Test `@wagmi/cli`, `@wagmi/core`, and `wagmi` + run: pnpm test:coverage + - name: Test types + run: pnpm test:typecheck + # Need to shutdown Anvil so cache gets created + - name: Shutdown Anvil + run: pkill -2 anvil diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 9ff4c5bb76..9cf14e427a 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -10,20 +10,27 @@ concurrency: jobs: verify: name: Verify + permissions: + contents: write uses: ./.github/workflows/verify.yml secrets: inherit size: name: Size + permissions: + contents: read + pull-requests: write runs-on: ubuntu-latest timeout-minutes: 5 steps: - name: Clone repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install dependencies uses: wevm/actions/.github/actions/pnpm@main + with: + node-version: 24.5 - name: Report build size uses: preactjs/compressed-size-action@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..e1b1ae75a9 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,52 @@ +name: Release + +permissions: + contents: write + pull-requests: write + +on: + push: + branches: + - main + +jobs: + release: + name: Release + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [19] + pnpm-version: [8] + steps: + - uses: actions/checkout@v3 + with: + # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits + fetch-depth: 0 + submodules: true + + - uses: pnpm/action-setup@v2.2.4 + with: + version: ${{ matrix.pnpm-version }} + - name: Set up Node ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + cache: 'pnpm' + node-version: ${{ matrix.node-version }} + - name: Install Dependencies + run: pnpm i + + - name: Create Release Pull Request or Publish to npm + id: changesets + uses: changesets/action@v1.4.1 + with: + title: 'chore: version packages' + commit: 'chore: version packages' + version: pnpm changeset:version + publish: pnpm changeset:release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Publish CJS bundle to npm + if: steps.changesets.outputs.published == 'true' + run: pnpm cjs:release '${{ steps.changesets.outputs.publishedPackages }}' diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000000..ba176318ec --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,51 @@ +name: Scorecard +on: + # For Branch-Protection check. Only the default branch is supported. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection + branch_protection_rule: + # To guarantee Maintained check is occasionally updated. See + # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained + schedule: + - cron: '22 13 * * 0' + push: + branches: [ "main" ] + +# Declare default permissions as read only. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + # `publish_results: true` only works when run from the default branch. conditional can be removed if disabled. + if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request' + permissions: + # Needed to upload the results to code-scanning dashboard. + security-events: write + # Needed to publish results and get a badge (see publish_results below). + id-token: write + + steps: + - name: "Checkout code" + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 + with: + results_file: results.sarif + results_format: sarif + publish_results: true + + - name: "Upload artifact" + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@80cb6b56b93de3e779c7d476d9100d06fb87c877 # codeql-bundle-v2.23.2 + with: + sarif_file: results.sarif diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml deleted file mode 100644 index 39683bb684..0000000000 --- a/.github/workflows/snapshot.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Snapshot -on: - workflow_dispatch: - -jobs: - snapshot: - name: Release snapshot version - permissions: - contents: write - id-token: write - runs-on: ubuntu-latest - timeout-minutes: 5 - - steps: - - name: Clone repository - uses: actions/checkout@v4 - - - name: Install dependencies - uses: wevm/actions/.github/actions/pnpm@main - - - name: Publish Snapshots - continue-on-error: true - env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - snapshot=$(git branch --show-current | tr -cs '[:alnum:]-' '-' | tr '[:upper:]' '[:lower:]' | sed 's/-$//') - npm config set "//registry.npmjs.org/:_authToken" "$NPM_TOKEN" - pnpm clean - pnpm changeset version --no-git-tag --snapshot $snapshot - pnpm changeset:prepublish - pnpm changeset publish --no-git-tag --snapshot $snapshot --tag $snapshot diff --git a/.github/workflows/vercel.yml b/.github/workflows/vercel.yml new file mode 100644 index 0000000000..1c338a0ac7 --- /dev/null +++ b/.github/workflows/vercel.yml @@ -0,0 +1,85 @@ +# This workflow's name will appear on the GitHub Actions page. +name: Deploy to Vercel +permissions: + contents: read + +# This specifies when the workflow should run. +on: + # The workflow will run on every 'push' to the 'main' branch. + push: + branches: + - master + - main + - dev + + # This allows you to manually trigger the workflow from the GitHub Actions page. + workflow_dispatch: +# These are environment variables passed to the Vercel CLI. +# They must be set as GitHub Secrets for security. +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + + # Add any other environment variables your project needs here, + # such as API keys for the Coinbase SDK. + # Example: VITE_COINBASE_API_KEY: ${{ secrets.VITE_COINBASE_API_KEY }} +# Defines a job named 'deploy'. +jobs: + deploy: + # Specifies the runner environment for this job. + + runs-on: ubuntu-latest + + # The steps in the 'deploy' job. + steps: + # 1. Check out the project code from the repository. + # This is the first essential step to get access to your code. + - name: Checkout project code + uses: actions/checkout@v3 + # 2. Set up Node.js. + # The version should match the one in your project. + steps: + - uses: actions/setup-node@v4 + - name: Setup Node.js + - uses: actions/setup-node@v4 + with: + node-version: 18.x,20.x,22.x + strategy: + matrix: + node-version: [18.x, 20.x, 22.x] + steps: + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + # 3. Install the Vercel CLI. + # The Vercel CLI is the main tool for interacting with the Vercel platform. + with: + node-version: 22.x + name: Install Vercel CLI + run: npm install --global vercel@latest + + # 4. Pull Vercel project settings. + # This fetches Vercel project links and Org ID. + with: + - name: Pull Vercel environment variables + run: vercel pull --yes --environment=production + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + + # 5. Build the project. + # This command builds your project for a production environment. + # It will automatically use the build command defined in your project's `package.json`. + with: + - name: Build project + run: vercel build + + # 6. Deploy the project to Vercel. + # This step deploys the pre-built code to Vercel. +strategy: + matrix: + node-version: [18.x, 20.x, 22.x] + name: Deploy to Vercel + run: vercel deploy --prebuilt + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 2ec609c42c..6c074cc73c 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -13,12 +13,14 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: token: ${{ secrets.GH_PTOKEN }} - name: Install dependencies uses: wevm/actions/.github/actions/pnpm@main + with: + node-version: 24.5 - name: Check repo run: pnpm check:repo @@ -39,19 +41,21 @@ jobs: build: name: Build + permissions: + contents: read needs: check runs-on: ubuntu-latest timeout-minutes: 5 steps: - name: Clone repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install dependencies uses: wevm/actions/.github/actions/pnpm@main - name: Build - run: pnpm build + run: pnpm clean && pnpm build - name: Publint run: pnpm test:build @@ -61,17 +65,19 @@ jobs: types: name: Types + permissions: + contents: read needs: check runs-on: ubuntu-latest timeout-minutes: 5 strategy: matrix: - typescript-version: ['5.2.2', '5.3.3', '5.4.5', '5.5.2'] - viem-version: ['2.23.12', 'latest'] + typescript-version: ['5.7.3', '5.8.3', '5.9.2', 'latest'] + viem-version: ['2.31.7', 'latest'] steps: - name: Clone repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install dependencies uses: wevm/actions/.github/actions/pnpm@main @@ -84,6 +90,9 @@ jobs: - name: Check types run: pnpm check:types + - name: Bench types + run: pnpm bench:types + # Redundant with `pnpm check:types` # If Vitest adds special features in the future, e.g. type coverage, can add this back! # - name: Test types @@ -91,6 +100,8 @@ jobs: test: name: Test + permissions: + contents: read runs-on: ubuntu-latest timeout-minutes: 10 strategy: @@ -101,7 +112,7 @@ jobs: steps: - name: Clone repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install dependencies uses: wevm/actions/.github/actions/pnpm@main @@ -111,6 +122,9 @@ jobs: with: version: nightly + - name: Install Playwright + run: pnpx playwright@1.54.1 install --with-deps + - name: Run tests uses: nick-fields/retry@v3 with: diff --git a/.github/workflows/vhs.yml b/.github/workflows/vhs.yml new file mode 100644 index 0000000000..372c5672c9 --- /dev/null +++ b/.github/workflows/vhs.yml @@ -0,0 +1,79 @@ +name: vhs + +on: + push: + branches: + - main + paths: + - packages/**/*.tape + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +env: + VHS: true + +jobs: + vhs: + name: vhs + permissions: + contents: write + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [20] + pnpm-version: [9] + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + - uses: pnpm/action-setup@v2.2.4 + with: + version: ${{ matrix.pnpm-version }} + - name: Set up Node ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + cache: 'pnpm' + node-version: ${{ matrix.node-version }} + + - name: Cache pnpm + uses: actions/cache@v3 + with: + path: ~/.pnpm-store + key: pnpm-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: pnpm- + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: | + node_modules + docs/node_modules + examples/**/node_modules + packages/**/node_modules + references/packages/**/node_modules + key: modules-${{ hashFiles('pnpm-lock.yaml') }} + - name: Install Dependencies + run: pnpm i + + # TODO: Combine these steps once supported + # https://github.com/charmbracelet/vhs-action/issues/50 + - uses: charmbracelet/vhs-action@v1 + with: + path: 'packages/cli/vhs/init.tape' + - uses: charmbracelet/vhs-action@v1 + with: + path: 'packages/cli/vhs/generate.tape' + env: + ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }} + + - uses: stefanzweifel/git-auto-commit-action@v4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + commit_message: 'chore: update vhs' + commit_user_name: 'github-actions[bot]' + commit_user_email: 'github-actions[bot]@users.noreply.github.com' + file_pattern: '*.gif *.mp4' diff --git a/.gitignore b/.gitignore index 1834fe72ab..6a6c81ce98 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +.attest .next .nuxt .pnpm-debug.log* @@ -31,9 +32,11 @@ packages/react/chains packages/react/codegen packages/react/connectors packages/react/experimental +packages/react/internal packages/react/query packages/vue/actions packages/vue/chains packages/vue/connectors +packages/vue/internal packages/vue/nuxt packages/vue/query diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..6c786c571f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "references"] + path = references + url = https://github.com/wagmi-dev/references.git diff --git a/.npmrc b/.npmrc index 47687565bf..dcf42f4997 100644 --- a/.npmrc +++ b/.npmrc @@ -1,5 +1,4 @@ auto-install-peers=false enable-pre-post-scripts=true link-workspace-packages=deep -provenance=true strict-peer-dependencies=false diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..7e8a4896b3 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +node_modules +dist +generated +CHANGELOG.md + +// Once prettier fixes MDX ignore ranges +// https://github.com/prettier/prettier/pull/12208 +docs/pages/index.*.mdx +docs/pages/*/getting-started.en-US.mdx +docs/pages/*/module-types.en-US.mdx +docs/pages/cli/create-wagmi.en-US.mdx diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000..db48a0af6e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,9 @@ +{ + "arrowParens": "always", + "endOfLine": "lf", + "printWidth": 80, + "semi": false, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "all" +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 9cb435094a..9a23ed995d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,3 @@ { - "recommendations": [ - "biomejs.biome", - "orta.vscode-twoslash-queries", - "Vue.volar" - ] + "recommendations": ["dbaeumer.vscode-eslint", "orta.vscode-twoslash-queries"] } diff --git a/.vscode/settings.json b/.vscode/settings.json index c32e8fa4c3..6318c082c0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,8 +5,7 @@ "typescript.preferences.importModuleSpecifier": "shortest", "typescript.tsdk": "node_modules/typescript/lib", "editor.codeActionsOnSave": { - "quickfix.biome": "explicit", - "source.organizeImports.biome": "explicit" + "source.fixAll.biome": "explicit" }, "[javascript][javascriptreact][json][typescript][typescriptreact]": { "editor.defaultFormatter": "biomejs.biome" diff --git a/.vscode/workspace.code-workspace b/.vscode/workspace.code-workspace deleted file mode 100644 index 0d626129da..0000000000 --- a/.vscode/workspace.code-workspace +++ /dev/null @@ -1,16 +0,0 @@ -{ - "folders": [ - { - "name": "docs", - "path": "../docs" - }, - { - "name": "packages", - "path": "../packages" - }, - { - "name": "playgrounds", - "path": "../playgrounds" - } - ] -} diff --git a/FUNDING.json b/FUNDING.json deleted file mode 100644 index 5e01254162..0000000000 --- a/FUNDING.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "drips": { - "ethereum": { - "ownedBy": "0xd2135CfB216b74109775236E36d4b433F1DF507B" - } - }, - "opRetro": { - "projectId": "0xc0615947773148cbc340b175fb9afc98dbb4e0acd31d018b1ee41a5538785abf" - } -} diff --git a/LICENSE b/LICENSE index 650c3c1c00..bac2027ae9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022-present weth, LLC +Copyright (c) 2023-present weth, LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md new file mode 100644 index 0000000000..03e6554c80 --- /dev/null +++ b/README.md @@ -0,0 +1,237 @@ +<p align="center"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/logo-dark.svg"> + <img alt="wagmi logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/logo-light.svg" width="auto" height="60"> + </picture> +</p> + +<p align="center"> + React Hooks for Ethereum +<p> + +<p align="center"> + <a href="https://www.npmjs.com/package/wagmi"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/v/wagmi?colorA=21262d&colorB=21262d&style=flat"> + <img src="https://img.shields.io/npm/v/wagmi?colorA=f6f8fa&colorB=f6f8fa&style=flat" alt="Version"> + </picture> + </a> + <a href="https://github.com/wagmi-dev/wagmi/blob/main/LICENSE"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/l/wagmi?colorA=21262d&colorB=21262d&style=flat"> + <img src="https://img.shields.io/npm/l/wagmi?colorA=f6f8fa&colorB=f6f8fa&style=flat" alt="MIT License"> + </picture> + </a> + <a href="https://www.npmjs.com/package/wagmi"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/npm/dm/wagmi?colorA=21262d&colorB=21262d&style=flat"> + <img src="https://img.shields.io/npm/dm/wagmi?colorA=f6f8fa&colorB=f6f8fa&style=flat" alt="Downloads per month"> + </picture> + </a> + <a href="https://bestofjs.org/projects/wagmi"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://img.shields.io/endpoint?colorA=21262d&colorB=21262d&style=flat&url=https://bestofjs-serverless.now.sh/api/project-badge?fullName=wagmi-dev%2Fviem%26since=daily"> + <img src="https://img.shields.io/endpoint?colorA=f6f8fa&colorB=f6f8fa&style=flat&url=https://bestofjs-serverless.now.sh/api/project-badge?fullName=wagmi-dev%2Fviem%26since=daily" alt="Best of JS"> + </picture> + </a> +</p> + +<br> + +> **Note** +> +> wagmi is in the Gitcoin Grants Beta Round until May 9. [Click here to support development.](https://explorer.gitcoin.co/#/round/1/0xdf22a2c8f6ba9376ff17ee13e6154b784ee92094/0xdf22a2c8f6ba9376ff17ee13e6154b784ee92094-4) Thank you 🙏 + +## Features + +- 🚀 20+ hooks for working with wallets, ENS, contracts, transactions, signing, etc. +- 💼 Built-in wallet connectors for MetaMask, WalletConnect, Coinbase Wallet, Injected, and more +- 👟 Caching, request deduplication, multicall, batching, and persistence +- 🌀 Auto-refresh data on wallet, block, and network changes +- 🦄 TypeScript ready (infer types from ABIs and EIP-712 Typed Data) +- 📦 Command-line interface for managing ABIs and code generation +- 🌳 Test suite running against forked Ethereum network + +...and a lot more. + +## Documentation + +For full documentation and examples, visit [wagmi.sh](https://wagmi.sh). + +## Installation + +Install wagmi and its ethers peer dependency. + +```bash +npm install wagmi ethers@^5 +``` + +## Quick Start + +Connect a wallet in under 60 seconds. LFG. + +```tsx +import { WagmiConfig, createClient } from 'wagmi' +import { getDefaultProvider } from 'ethers' + +const client = createClient({ + autoConnect: true, + provider: getDefaultProvider(), +}) + +function App() { + return ( + <WagmiConfig client={client}> + <Profile /> + </WagmiConfig> + ) +} +``` + +```tsx +import { useAccount, useConnect, useDisconnect } from 'wagmi' +import { InjectedConnector } from 'wagmi/connectors/injected' + +function Profile() { + const { address } = useAccount() + const { connect } = useConnect({ + connector: new InjectedConnector(), + }) + const { disconnect } = useDisconnect() + + if (address) + return ( + <div> + Connected to {address} + <button onClick={() => disconnect()}>Disconnect</button> + </div> + ) + return <button onClick={() => connect()}>Connect Wallet</button> +} +``` + +In this example, we create a wagmi `Client` and pass it to the `WagmiConfig` React Context. The client is set up to use the ethers Default Provider and automatically connect to previously connected wallets. + +Next, we use the `useConnect` hook to connect an injected wallet (e.g. MetaMask) to the app. Finally, we show the connected account's address with `useAccount` and allow them to disconnect with `useDisconnect`. + +We've only scratched the surface for what you can do with wagmi! + +— + +Check out [ConnectKit](https://docs.family.co/connectkit?utm_source=wagmi-dev) or [Web3Modal](https://web3modal.com) to get started with pre-built interface on top of wagmi for managing wallet connections. + +## Community + +Check out the following places for more wagmi-related content: + +- Join the [discussions on GitHub](https://github.com/wagmi-dev/wagmi/discussions) +- Follow [@wagmi_sh](https://twitter.com/wagmi_sh) on Twitter for project updates +- Share [your project/organization](https://github.com/wagmi-dev/wagmi/discussions/201) using wagmi +- Browse the [awesome-wagmi](https://github.com/wagmi-dev/awesome-wagmi) list of awesome projects and resources + +## Support + +If you find wagmi useful, please consider supporting development. Thank you 🙏 + +- [GitHub Sponsors](https://github.com/sponsors/wagmi-dev?metadata_campaign=gh_readme_support) +- [Gitcoin Grant](https://wagmi.sh/gitcoin) +- [wagmi-dev.eth](https://etherscan.io/enslookup-search?search=wagmi-dev.eth) + +## Sponsors + +<a href="https://paradigm.xyz"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/paradigm-dark.svg"> + <img alt="paradigm logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/paradigm-light.svg" width="auto" height="70"> + </picture> +</a> + +<br> + +<a href="https://twitter.com/family"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/family-dark.svg"> + <img alt="family logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/family-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://twitter.com/context"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/context-dark.svg"> + <img alt="context logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/context-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://walletconnect.com"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/walletconnect-dark.svg"> + <img alt="WalletConnect logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/walletconnect-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://looksrare.org"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/looksrare-dark.svg"> + <img alt="LooksRare logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/8923685e23fe9708b74d456c3f9e7a2b90f6abd9/content/sponsors/looksrare-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://twitter.com/prtyDAO"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/partydao-dark.svg"> + <img alt="PartyDAO logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/partydao-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://dynamic.xyz"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/dynamic-dark.svg"> + <img alt="Dynamic logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/dynamic-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://sushi.com"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/sushi-dark.svg"> + <img alt="Sushi logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/sushi-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://stripe.com"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/stripe-dark.svg"> + <img alt="Stripe logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/stripe-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://bitkeep.com"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/bitkeep-dark.svg"> + <img alt="BitKeep logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/bitkeep-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://www.privy.io"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/privy-dark.svg"> + <img alt="Privy logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/privy-light.svg" width="auto" height="50"> + </picture> +</a> +<a href="https://www.spruceid.com"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/spruce-dark.svg"> + <img alt="Spruce logo" src="https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/spruce-light.svg" width="auto" height="50"> + </picture> +</a> + +## Contributing + +If you're interested in contributing, please read the [contributing docs](/.github/CONTRIBUTING.md) **before submitting a pull request**. + +## Authors + +- [@tmm](https://github.com/tmm) (awkweb.eth, [Twitter](https://twitter.com/awkweb)) +- [@jxom](https://github.com/jxom) (moxey.eth, [Twitter](https://twitter.com/jakemoxey)) + +Thanks to julianhutton.eth ([@julianjhutton](https://twitter.com/julianjhutton)) for providing the awesome logo! + +## License + +[MIT](/LICENSE) License + +<br /> + +<a href="https://vercel.com/?utm_source=wagmi-dev&utm_campaign=oss"> + <img src="https://www.datocms-assets.com/31049/1618983297-powered-by-vercel.svg" alt="Powered by Vercel" height="35"> +</a> diff --git a/biome.json b/biome.json index ce99662cb0..fedd8221fe 100644 --- a/biome.json +++ b/biome.json @@ -1,7 +1,12 @@ { "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", "files": { - "ignore": ["CHANGELOG.md", "pnpm-lock.yaml", "tsconfig.base.json"] + "includes": [ + "**", + "!**/CHANGELOG.md", + "!**/pnpm-lock.yaml", + "!**/tsconfig.base.json" + ] }, "formatter": { "enabled": true, @@ -11,13 +16,16 @@ "lineWidth": 80 }, "linter": { - "ignore": ["packages/create-wagmi/templates/*"], + "includes": ["**", "!**/packages/create-wagmi/templates/**/*"], "enabled": true, "rules": { "recommended": true, "a11y": { "useButtonType": "off" }, + "complexity": { + "noImportantStyles": "off" + }, "correctness": { "noUnusedVariables": "error", "useExhaustiveDependencies": "error" @@ -29,13 +37,34 @@ }, "style": { "noNonNullAssertion": "off", - "useShorthandArrayType": "error" + "noParameterAssign": "error", + "useAsConstAssertion": "error", + "useDefaultParameterLast": "error", + "useEnumInitializers": "error", + "useSelfClosingElements": "error", + "useSingleVarDeclarator": "error", + "noUnusedTemplateLiteral": "error", + "useNumberNamespace": "error", + "noInferrableTypes": "error", + "noUselessElse": "error", + "useConsistentArrayType": { + "level": "error", + "options": { + "syntax": "shorthand" + } + } }, "suspicious": { "noArrayIndexKey": "off", "noConfusingVoidType": "off", - "noConsoleLog": "error", - "noExplicitAny": "off" + "noExplicitAny": "off", + "noConsole": { + "level": "error", + "options": { + "allow": ["log"] + } + }, + "noTsIgnore": "off" } } }, @@ -46,32 +75,52 @@ "semicolons": "asNeeded" } }, - "organizeImports": { - "enabled": true + "assist": { + "actions": { + "source": { + "organizeImports": "on" + } + } }, "overrides": [ { - "include": ["*.vue"], + "includes": ["**/*.vue"], "linter": { "rules": { "correctness": { + "noUnusedImports": "off", "noUnusedVariables": "off" } } } }, { - "include": ["./scripts/**/*.ts"], + "includes": ["site/snippets/**"], + "linter": { + "rules": { + "correctness": { + "noUnusedImports": "off" + } + } + } + }, + { + "includes": ["scripts/**/*.ts"], "linter": { "rules": { "suspicious": { - "noConsoleLog": "off" + "noConsole": { + "level": "off", + "options": { + "allow": ["log"] + } + } } } } }, { - "include": ["./playgrounds/**"], + "includes": ["playgrounds/**"], "linter": { "rules": { "style": { diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..7a1bd50b7f --- /dev/null +++ b/codecov.yml @@ -0,0 +1,23 @@ +codecov: + notify: + wait_for_ci: true + require_ci_to_pass: true +comment: + behavior: default + layout: reach,diff,flags,tree,reach + show_carryforward_flags: false +coverage: + precision: 2 + range: + - 60.0 + - 80.0 + round: down + status: + changes: false + default_rules: + flag_coverage_not_uploaded_behavior: include + patch: true + project: true +github_checks: + annotations: true +slack_app: true diff --git a/docs/.env.example b/docs/.env.example new file mode 100644 index 0000000000..3e69067d5d --- /dev/null +++ b/docs/.env.example @@ -0,0 +1,4 @@ +NEXT_IRON_PASSWORD= +NEXT_PUBLIC_ALCHEMY_ID= +NEXT_PUBLIC_FATHOM_ID= +NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID= diff --git a/docs/components/blog/Authors.tsx b/docs/components/blog/Authors.tsx new file mode 100644 index 0000000000..e04b64e81e --- /dev/null +++ b/docs/components/blog/Authors.tsx @@ -0,0 +1,29 @@ +type AuthorsProps = { + date: string + children: React.ReactNode +} + +export function Authors({ date, children }: AuthorsProps) { + return ( + <div className="mt-4 mb-8 text-gray-400 text-sm"> + {date} by{children} + </div> + ) +} + +type AuthorProps = { name: string; link: string } + +export function Author({ name, link }: AuthorProps) { + return ( + <span className="after:content-[','] last:after:content-['']"> + <a + key={name} + href={link} + target="_blank" + className="mx-1 text-gray-800 dark:text-gray-100" + > + {name} + </a> + </span> + ) +} diff --git a/docs/components/blog/BlogIndex.tsx b/docs/components/blog/BlogIndex.tsx new file mode 100644 index 0000000000..55307c8655 --- /dev/null +++ b/docs/components/blog/BlogIndex.tsx @@ -0,0 +1,53 @@ +import Link from 'next/link' +import type { Page } from 'nextra' +// eslint-disable-next-line import/no-unresolved +import { getPagesUnderRoute } from 'nextra/context' + +export function BlogIndex({ more = 'Read more' }) { + return ( + <> + <h1 className="text-center font-extrabold text-3xl mb-10 md:text-5xl mt-10 md:mb-14"> + wagmi Blog + </h1> + + {getPagesUnderRoute('/blog').map( + ( + page: Page & { + frontMatter?: { + date?: string + description?: string + title?: string + } + }, + ) => { + return ( + <div className="mb-12"> + <h3 className="text-2xl font-bold mb-4"> + <Link + href={page.route} + style={{ color: 'inherit', textDecoration: 'none' }} + > + {page.meta?.title || page.frontMatter?.title || page.name} + </Link> + </h3> + + <p className="opacity-80 mb-3"> + {page.frontMatter?.description}{' '} + <Link + href={page.route} + className="nx-text-primary-500 underline" + > + {more + ' →'} + </Link> + </p> + + {page.frontMatter?.date ? ( + <p className="opacity-50 text-sm">{page.frontMatter.date}</p> + ) : null} + </div> + ) + }, + )} + </> + ) +} diff --git a/docs/components/blog/index.ts b/docs/components/blog/index.ts new file mode 100644 index 0000000000..c1e130136c --- /dev/null +++ b/docs/components/blog/index.ts @@ -0,0 +1,2 @@ +export { Authors, Author } from '../blog/Authors' +export { BlogIndex } from '../blog/BlogIndex' diff --git a/docs/components/core/LogoType.tsx b/docs/components/core/LogoType.tsx new file mode 100644 index 0000000000..4221895442 --- /dev/null +++ b/docs/components/core/LogoType.tsx @@ -0,0 +1,36 @@ +type Props = { + title?: string +} + +export function LogoType({ title = 'wagmi logo' }: Props) { + return ( + <svg + viewBox="0 0 561 132" + fill="none" + xmlns="http://www.w3.org/2000/svg" + className="fill-current h-full w-auto" + > + <title>{title} + + + + + + ) +} diff --git a/docs/components/core/PreviewWrapper.tsx b/docs/components/core/PreviewWrapper.tsx new file mode 100644 index 0000000000..e2b4372eef --- /dev/null +++ b/docs/components/core/PreviewWrapper.tsx @@ -0,0 +1,33 @@ +import { Box, useTheme } from 'degen' +import { useTheme as useNextThemes } from 'next-themes' +import * as React from 'react' + +type Props = { + children: React.ReactNode +} + +export function PreviewWrapper({ children }: Props) { + const { resolvedTheme } = useNextThemes() + const { setMode } = useTheme() + + React.useEffect(() => { + if (!resolvedTheme) return + if (resolvedTheme === 'system') return + setMode(resolvedTheme as any) + }, [resolvedTheme, setMode]) + + return ( + + {children} + + ) +} diff --git a/docs/components/core/Providers.tsx b/docs/components/core/Providers.tsx new file mode 100644 index 0000000000..5ba77d031a --- /dev/null +++ b/docs/components/core/Providers.tsx @@ -0,0 +1,57 @@ +import * as React from 'react' + +import { WagmiConfig, configureChains, createClient } from 'wagmi' +import { goerli, mainnet } from 'wagmi/chains' + +import { CoinbaseWalletConnector } from 'wagmi/connectors/coinbaseWallet' +import { InjectedConnector } from 'wagmi/connectors/injected' +import { MetaMaskConnector } from 'wagmi/connectors/metaMask' +import { WalletConnectConnector } from 'wagmi/connectors/walletConnect' + +import { alchemyProvider } from 'wagmi/providers/alchemy' + +const { chains, provider, webSocketProvider } = configureChains( + [mainnet, goerli], + [alchemyProvider({ apiKey: process.env.NEXT_PUBLIC_ALCHEMY_ID ?? '' })], +) + +const client = createClient({ + autoConnect: true, + connectors: [ + new MetaMaskConnector({ + chains, + options: { + UNSTABLE_shimOnConnectSelectAccount: true, + }, + }), + new CoinbaseWalletConnector({ + chains, + options: { + appName: 'wagmi', + }, + }), + new WalletConnectConnector({ + chains, + options: { + projectId: process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID ?? '', + }, + }), + new InjectedConnector({ + chains, + options: { + name: 'Injected', + shimDisconnect: true, + }, + }), + ], + provider, + webSocketProvider, +}) + +type Props = { + children?: React.ReactNode +} + +export function Providers({ children }: Props) { + return {children} +} diff --git a/docs/components/core/index.ts b/docs/components/core/index.ts new file mode 100644 index 0000000000..a5bb6b918a --- /dev/null +++ b/docs/components/core/index.ts @@ -0,0 +1,3 @@ +export { LogoType } from './LogoType' +export { PreviewWrapper } from './PreviewWrapper' +export { Providers } from './Providers' diff --git a/docs/components/docs/Header.tsx b/docs/components/docs/Header.tsx new file mode 100644 index 0000000000..1196d20690 --- /dev/null +++ b/docs/components/docs/Header.tsx @@ -0,0 +1,113 @@ +import { useRouter } from 'next/router' + +import { LogoType } from '../core' + +const TITLE_WITH_TRANSLATIONS: Record = { + 'en-US': 'React Hooks for Ethereum', +} + +export function Header() { + const { locale, defaultLocale = 'en-US' } = useRouter() + const resolvedLocale = locale || defaultLocale + const title = TITLE_WITH_TRANSLATIONS[resolvedLocale] + + return ( +
+
+

wagmi

+ + + + +
+ +

+ {title} +

+ + +
+ ) +} diff --git a/docs/components/docs/Sponsors.tsx b/docs/components/docs/Sponsors.tsx new file mode 100644 index 0000000000..e98cf39979 --- /dev/null +++ b/docs/components/docs/Sponsors.tsx @@ -0,0 +1,155 @@ +import { useTheme } from 'next-themes' + +const sponsors = [ + { + id: 'family', + name: 'Family', + href: 'https://twitter.com/family', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/family-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/family-light.svg', + }, + }, + { + id: 'context', + name: 'Context', + href: 'https://twitter.com/context', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/context-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/context-light.svg', + }, + }, + { + id: 'walletconnect', + name: 'WalletConnect', + href: 'https://walletconnect.com', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/walletconnect-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/walletconnect-light.svg', + }, + }, + { + id: 'looksrare', + name: 'LooksRare', + href: 'https://looksrare.org', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/looksrare-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/looksrare-light.svg', + }, + }, + { + id: 'partydao', + name: 'PartyDAO', + href: 'https://twitter.com/prtyDAO', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/partydao-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/partydao-light.svg', + }, + }, + { + id: 'dynamic', + name: 'Dynamic', + href: 'https://www.dynamic.xyz', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/dynamic-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/dynamic-light.svg', + }, + }, + { + id: 'sushi', + name: 'Sushi', + href: 'https://www.sushi.com', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/sushi-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/sushi-light.svg', + }, + }, + { + id: 'stripe', + name: 'Stripe', + href: 'https://www.stripe.com', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/stripe-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/stripe-light.svg', + }, + }, + { + id: 'bitkeep', + name: 'BitKeep', + href: 'https://bitkeep.com', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/bitkeep-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/bitkeep-light.svg', + }, + }, + { + id: 'privy', + name: 'Privy', + href: 'https://privy.io', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/privy-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/privy-light.svg', + }, + }, + { + id: 'spruce', + name: 'Spruce', + href: 'https://spruce.io', + logo: { + dark: 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/spruce-dark.svg', + light: + 'https://raw.githubusercontent.com/wagmi-dev/.github/main/content/sponsors/spruce-light.svg', + }, + }, +] as const + +export function Sponsors() { + const { resolvedTheme } = useTheme() + const mode = (resolvedTheme ?? 'dark') as 'dark' | 'light' + return ( +
+ +
+ {sponsors.map((sponsor) => ( + + + {sponsor.name} + + + ))} +
+
+ ) +} diff --git a/docs/components/docs/ValidationComparisonTable.tsx b/docs/components/docs/ValidationComparisonTable.tsx new file mode 100644 index 0000000000..f6749ee86c --- /dev/null +++ b/docs/components/docs/ValidationComparisonTable.tsx @@ -0,0 +1,47 @@ +export function ValidationComparisonTable() { + return ( + + + + + + + + + + + + + +
+ Validating after interaction + + Validating before interaction +
+
+
+
+
+
+
+ ) +} diff --git a/docs/components/docs/index.ts b/docs/components/docs/index.ts new file mode 100644 index 0000000000..3d5907b6cb --- /dev/null +++ b/docs/components/docs/index.ts @@ -0,0 +1,2 @@ +export { Header } from './Header' +export { Sponsors } from './Sponsors' diff --git a/docs/components/examples/ConnectWallet.tsx b/docs/components/examples/ConnectWallet.tsx new file mode 100644 index 0000000000..9c89cc478b --- /dev/null +++ b/docs/components/examples/ConnectWallet.tsx @@ -0,0 +1,21 @@ +import { useAccount } from 'wagmi' + +import { PreviewWrapper } from '../core' +import { Account, WalletSelector } from '../web3' + +export function ConnectWallet() { + const { isConnected } = useAccount() + + if (isConnected) + return ( + + + + ) + + return ( + + + + ) +} diff --git a/docs/components/examples/ContractWrite.tsx b/docs/components/examples/ContractWrite.tsx new file mode 100644 index 0000000000..fb067514cf --- /dev/null +++ b/docs/components/examples/ContractWrite.tsx @@ -0,0 +1,84 @@ +import { Button, Stack, Text } from 'degen' +import { + useAccount, + useContractWrite, + useNetwork, + usePrepareContractWrite, + useWaitForTransaction, +} from 'wagmi' + +import { PreviewWrapper } from '../core' +import { Account, SwitchNetwork, WalletSelector } from '../web3' + +export function ContractWrite() { + const { isConnected } = useAccount() + + const { + config, + error: prepareError, + isError: isPrepareError, + isLoading: isPreparing, + } = usePrepareContractWrite({ + address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', + abi: [ + { + name: 'mint', + type: 'function', + stateMutability: 'nonpayable', + inputs: [], + outputs: [], + }, + ], + functionName: 'mint', + }) + const { + data, + error, + isLoading: isWriteLoading, + isError: isWriteError, + write, + } = useContractWrite(config) + const { isLoading: isConfirming, isSuccess } = useWaitForTransaction({ + hash: data?.hash, + }) + const { chain } = useNetwork() + + if (isConnected) + return ( + + + + + {isPrepareError && ( + Error: {prepareError?.message} + )} + {isWriteError && Error: {error?.message}} + {isSuccess && ( + + Success!{' '} + + Etherscan + + + )} + + + + ) + + return ( + + + + ) +} diff --git a/docs/components/examples/ContractWriteDynamic.tsx b/docs/components/examples/ContractWriteDynamic.tsx new file mode 100644 index 0000000000..3d66bc0f57 --- /dev/null +++ b/docs/components/examples/ContractWriteDynamic.tsx @@ -0,0 +1,104 @@ +import { Button, Input, Stack, Text } from 'degen' +import * as React from 'react' +import { + useAccount, + useContractWrite, + useNetwork, + usePrepareContractWrite, + useWaitForTransaction, +} from 'wagmi' + +import { useDebounce } from '../../hooks' + +import { PreviewWrapper } from '../core' +import { Account, SwitchNetwork, WalletSelector } from '../web3' + +export function ContractWriteDynamic() { + const { isConnected } = useAccount() + + const [tokenId, setTokenId] = React.useState('') + const debouncedTokenId = useDebounce(tokenId) + + const { + config, + error: prepareError, + isError: isPrepareError, + isLoading: isPreparing, + } = usePrepareContractWrite({ + address: '0xFBA3912Ca04dd458c843e2EE08967fC04f3579c2', + abi: [ + { + name: 'mint', + type: 'function', + stateMutability: 'nonpayable', + inputs: [{ internalType: 'uint32', name: 'tokenId', type: 'uint32' }], + outputs: [], + }, + ], + functionName: 'mint', + args: [parseInt(debouncedTokenId)], + enabled: Boolean(debouncedTokenId), + }) + const { + data, + error, + isLoading: isWriteLoading, + isError: isWriteError, + write, + } = useContractWrite(config) + const { isLoading: isConfirming, isSuccess } = useWaitForTransaction({ + hash: data?.hash, + }) + const { chain } = useNetwork() + + if (isConnected) + return ( + +
{ + e.preventDefault() + write?.() + }} + > + + + setTokenId(e.target.value)} + placeholder="69" + value={tokenId} + /> + + {isPrepareError && ( + Error: {prepareError?.message} + )} + {isWriteError && Error: {error?.message}} + {isSuccess && ( + + Success!{' '} + + Etherscan + + + )} + + +
+
+ ) + + return ( + + + + ) +} diff --git a/docs/components/examples/SendTransaction.tsx b/docs/components/examples/SendTransaction.tsx new file mode 100644 index 0000000000..fe236c9538 --- /dev/null +++ b/docs/components/examples/SendTransaction.tsx @@ -0,0 +1,111 @@ +import { Box, Button, Input, Stack, Text } from 'degen' +import { parseEther } from 'ethers/lib/utils' +import * as React from 'react' +import { + useAccount, + usePrepareSendTransaction, + useSendTransaction, + useWaitForTransaction, +} from 'wagmi' + +import { PreviewWrapper } from '../core' +import { Account, WalletSelector } from '../web3' + +function useDebounce(value: any, delay: number) { + const [debouncedValue, setDebouncedValue] = React.useState(value) + + React.useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value) + }, delay) + + return () => clearTimeout(handler) + }, [value, delay]) + + return debouncedValue +} + +export function SendTransaction() { + const { isConnected } = useAccount() + + const [to, setTo] = React.useState('') + const debouncedTo = useDebounce(to, 500) + + const [value, setValue] = React.useState('') + const debouncedValue = useDebounce(value, 500) + + const { + config, + error: prepareError, + isError: isPrepareError, + isLoading: isPreparing, + } = usePrepareSendTransaction({ + request: { + to: debouncedTo, + value: debouncedValue ? parseEther(debouncedValue) : undefined, + }, + }) + const { data, error, isLoading, isError, sendTransaction } = + useSendTransaction(config) + const { isLoading: isConfirming, isSuccess } = useWaitForTransaction({ + hash: data?.hash, + }) + + if (isConnected) + return ( + + { + e.preventDefault() + if (isLoading || isConfirming) return + sendTransaction?.() + }} + > + + + setTo(e.target.value)} + label="Recipient" + placeholder="0xA0Cf…251e" + value={to} + /> + setValue(e.target.value)} + label="Amount (ether)" + placeholder="0.05" + type="number" + value={value} + /> + + {isSuccess && ( + + Success!{' '} + Etherscan + + )} + {isPrepareError && ( + Error: {prepareError?.message} + )} + {isError && Error: {error?.message}} + + + + ) + + return ( + + + + ) +} diff --git a/docs/components/examples/SignInWithEthereum.tsx b/docs/components/examples/SignInWithEthereum.tsx new file mode 100644 index 0000000000..755e49a564 --- /dev/null +++ b/docs/components/examples/SignInWithEthereum.tsx @@ -0,0 +1,75 @@ +import { Box, Button, Skeleton, Stack } from 'degen' +import * as React from 'react' +import { mainnet, useAccount, useNetwork } from 'wagmi' + +import { formatAddress } from '../../lib/address' +import { PreviewWrapper } from '../core' +import { Account, SiweButton, WalletSelector } from '../web3' + +export function SignInWithEthereum() { + const [address, setAddress] = React.useState() + const accountData = useAccount() + const { chain: activeChain } = useNetwork() + + React.useEffect(() => { + const handler = async () => { + try { + const res = await fetch('/api/me') + const json = await res.json() + setAddress(json.address) + } catch (error) { + console.log({ error }) + } + } + handler() + + window.addEventListener('focus', handler) + return () => window.removeEventListener('focus', handler) + }, []) + + const signedInContent = address ? ( + + Signed in as {formatAddress(address)} + + + ) : null + + if (accountData.isConnected) + return ( + + + + + {address ? ( + signedInContent + ) : ( + + setAddress(address)} + /> + + )} + + + ) + + return ( + + + + {signedInContent} + + + ) +} diff --git a/docs/components/examples/SignMessage.tsx b/docs/components/examples/SignMessage.tsx new file mode 100644 index 0000000000..deb0968865 --- /dev/null +++ b/docs/components/examples/SignMessage.tsx @@ -0,0 +1,72 @@ +import { Box, Button, Text, Textarea } from 'degen' +import { verifyMessage } from 'ethers/lib/utils' +import * as React from 'react' +import { useAccount, useSignMessage } from 'wagmi' + +import { PreviewWrapper } from '../core' +import { Account, WalletSelector } from '../web3' + +export function SignMessage() { + const recoveredAddress = React.useRef() + + const { isConnected } = useAccount() + const { + data: signMessageData, + error, + isLoading, + signMessage, + } = useSignMessage({ + onSuccess(data, variables) { + const address = verifyMessage(variables.message, data) + recoveredAddress.current = address + }, + }) + + if (isConnected) + return ( + + + { + event.preventDefault() + const formData = new FormData(event.target as HTMLFormElement) + const message = formData.get('message') as string + signMessage({ message }) + }} + > +