├── .editorconfig ├── .github ├── PULL_REQUEST_TEMPLATE │ ├── default.md │ └── project.md └── workflows │ ├── build.yml │ ├── release-documentation.yml │ ├── release.yml │ └── stale.yml ├── .gitignore ├── CODEOWNERS ├── CONTRIBUTING.md ├── FUNDING.json ├── LICENSE ├── README.md ├── biome.json ├── commitlint.config.js ├── docs ├── .gitignore ├── components │ ├── demo │ │ ├── account.tsx │ │ ├── add-chain.tsx │ │ ├── balance.tsx │ │ ├── change-default-network.tsx │ │ ├── declare-contract.tsx │ │ ├── deploy-contract.tsx │ │ ├── estimate-fees.tsx │ │ ├── events.tsx │ │ ├── index.ts │ │ ├── nonce-for-address.tsx │ │ ├── read-contract.tsx │ │ ├── send-transaction.tsx │ │ ├── sign-typed-data.tsx │ │ ├── stark-address.tsx │ │ ├── stark-name.tsx │ │ ├── stark-profile.tsx │ │ ├── starknetkit.tsx │ │ ├── switch-chain.tsx │ │ └── wallet-permission.tsx │ ├── starknet │ │ ├── bar.tsx │ │ ├── index.tsx │ │ └── provider.tsx │ ├── starknetkit │ │ ├── index.ts │ │ └── starknetkit-connectors.ts │ └── ui │ │ ├── button.tsx │ │ ├── checkbox.tsx │ │ ├── input.tsx │ │ ├── label.tsx │ │ └── select.tsx ├── lib │ ├── erc20_class_abi.ts │ └── utils.ts ├── package.json ├── pages │ ├── demo │ │ ├── account.mdx │ │ ├── add-chain.mdx │ │ ├── balance.mdx │ │ ├── change-default-network.mdx │ │ ├── declare-contract.mdx │ │ ├── deploy-contract.mdx │ │ ├── estimate-fees.mdx │ │ ├── events.mdx │ │ ├── index.mdx │ │ ├── nonce-for-address.mdx │ │ ├── read-contract.mdx │ │ ├── send-transaction.mdx │ │ ├── sign-typed-data.mdx │ │ ├── stark-address.mdx │ │ ├── stark-name.mdx │ │ ├── stark-profile.mdx │ │ ├── starknetkit.mdx │ │ ├── switch-chain.mdx │ │ └── wallet-permission.mdx │ ├── docs │ │ ├── deploying-contracts.mdx │ │ ├── explorers.mdx │ │ ├── getting-started.mdx │ │ ├── hooks │ │ │ ├── use-account.mdx │ │ │ ├── use-add-chain.mdx │ │ │ ├── use-balance.mdx │ │ │ ├── use-block-number.mdx │ │ │ ├── use-block.mdx │ │ │ ├── use-call.mdx │ │ │ ├── use-connect.mdx │ │ │ ├── use-contract-factory.mdx │ │ │ ├── use-contract.mdx │ │ │ ├── use-declare-contract.mdx │ │ │ ├── use-deploy-account.mdx │ │ │ ├── use-disconnect.mdx │ │ │ ├── use-estimate-fees.mdx │ │ │ ├── use-events.mdx │ │ │ ├── use-explorer.mdx │ │ │ ├── use-injected-connectors.mdx │ │ │ ├── use-invalidate-on-block.mdx │ │ │ ├── use-network.mdx │ │ │ ├── use-nonce-for-address.mdx │ │ │ ├── use-provider.mdx │ │ │ ├── use-read-contract.mdx │ │ │ ├── use-send-transaction.mdx │ │ │ ├── use-sign-typed-data.mdx │ │ │ ├── use-stark-address.mdx │ │ │ ├── use-stark-name.mdx │ │ │ ├── use-stark-profile.mdx │ │ │ ├── use-switch-chain.mdx │ │ │ ├── use-transaction-receipt.mdx │ │ │ ├── use-universal-deployer-contract.mdx │ │ │ └── use-wallet-request.mdx │ │ ├── providers.mdx │ │ ├── starknet-config.mdx │ │ ├── upgrading-to-v3.mdx │ │ └── wallets.mdx │ └── index.mdx ├── sidebar.ts ├── styles.css ├── tailwind.config.cjs ├── tsconfig.json ├── vercel.json └── vocs.config.ts ├── flake.lock ├── flake.nix ├── package.json ├── packages ├── chains │ ├── CHANGELOG.json │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── devnet.ts │ │ ├── index.ts │ │ ├── slot.ts │ │ ├── starknet.ts │ │ └── types.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── core │ ├── CHANGELOG.json │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── connectors │ │ │ ├── base.ts │ │ │ ├── discovery.ts │ │ │ ├── helpers.ts │ │ │ ├── index.ts │ │ │ ├── injected.ts │ │ │ ├── legacy.ts │ │ │ └── mock.ts │ │ ├── context │ │ │ ├── account.tsx │ │ │ ├── index.tsx │ │ │ ├── starknet.test.tsx │ │ │ └── starknet.tsx │ │ ├── errors.ts │ │ ├── explorers │ │ │ ├── cartridge.ts │ │ │ ├── explorer.ts │ │ │ ├── index.ts │ │ │ ├── starkscan.ts │ │ │ ├── viewblock.ts │ │ │ └── voyager.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── use-account.test.ts │ │ │ ├── use-account.ts │ │ │ ├── use-add-chain.test.ts │ │ │ ├── use-add-chain.ts │ │ │ ├── use-balance.test.ts │ │ │ ├── use-balance.ts │ │ │ ├── use-block-number.test.ts │ │ │ ├── use-block-number.ts │ │ │ ├── use-block.test.ts │ │ │ ├── use-block.ts │ │ │ ├── use-call.test.ts │ │ │ ├── use-call.ts │ │ │ ├── use-connect.test.ts │ │ │ ├── use-connect.ts │ │ │ ├── use-contract-factory.ts │ │ │ ├── use-contract.test.ts │ │ │ ├── use-contract.ts │ │ │ ├── use-declare-contract.test.ts │ │ │ ├── use-declare-contract.ts │ │ │ ├── use-deploy-account.ts │ │ │ ├── use-disconnect.ts │ │ │ ├── use-estimate-fees.test.ts │ │ │ ├── use-estimate-fees.ts │ │ │ ├── use-events.test.ts │ │ │ ├── use-events.ts │ │ │ ├── use-explorer.ts │ │ │ ├── use-invalidate-on-block.ts │ │ │ ├── use-network.ts │ │ │ ├── use-nonce-for-address.test.ts │ │ │ ├── use-nonce-for-address.ts │ │ │ ├── use-provider.ts │ │ │ ├── use-read-contract.test-d.ts │ │ │ ├── use-read-contract.test.ts │ │ │ ├── use-read-contract.ts │ │ │ ├── use-send-transaction.test.ts │ │ │ ├── use-send-transaction.ts │ │ │ ├── use-sign.test.ts │ │ │ ├── use-sign.ts │ │ │ ├── use-stark-address.ts │ │ │ ├── use-stark-name.ts │ │ │ ├── use-stark-profile.ts │ │ │ ├── use-switch-chain.test.ts │ │ │ ├── use-switch-chain.ts │ │ │ ├── use-transaction-receipt.ts │ │ │ ├── use-universal-deployer-contract.tsx │ │ │ ├── use-wallet-request.test.ts │ │ │ ├── use-wallet-request.ts │ │ │ ├── use-watch-asset.test.ts │ │ │ └── use-watch-asset.ts │ │ ├── index.ts │ │ ├── providers │ │ │ ├── alchemy.ts │ │ │ ├── blast.ts │ │ │ ├── cartridge.ts │ │ │ ├── factory.ts │ │ │ ├── index.ts │ │ │ ├── infura.ts │ │ │ ├── jsonrpc.test.ts │ │ │ ├── jsonrpc.ts │ │ │ ├── lava.ts │ │ │ ├── public.test.ts │ │ │ ├── public.ts │ │ │ ├── reddio.ts │ │ │ └── slot.ts │ │ ├── query.ts │ │ └── utils.ts │ ├── test │ │ ├── devnet.ts │ │ ├── react.tsx │ │ ├── setup.ts │ │ └── test-abi.ts │ ├── tsconfig.json │ ├── tsup.config.ts │ └── vitest.config.ts ├── create-starknet │ ├── CHANGELOG.json │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── helpers │ │ │ ├── installation.ts │ │ │ ├── packageManager.ts │ │ │ └── validate.ts │ │ ├── index.ts │ │ └── templates │ │ │ ├── next │ │ │ ├── .eslintrc.json │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── next.config.mjs │ │ │ ├── package.json │ │ │ ├── postcss.config.mjs │ │ │ ├── public │ │ │ │ ├── next.svg │ │ │ │ └── vercel.svg │ │ │ ├── src │ │ │ │ ├── app │ │ │ │ │ ├── favicon.ico │ │ │ │ │ ├── globals.css │ │ │ │ │ ├── layout.tsx │ │ │ │ │ └── page.tsx │ │ │ │ └── components │ │ │ │ │ ├── starknet-provider.tsx │ │ │ │ │ ├── ui │ │ │ │ │ └── Button.tsx │ │ │ │ │ └── wallet-bar.tsx.tsx │ │ │ ├── tailwind.config.ts │ │ │ └── tsconfig.json │ │ │ └── vite │ │ │ ├── .gitignore │ │ │ ├── README.md │ │ │ ├── eslint.config.js │ │ │ ├── index.html │ │ │ ├── package.json │ │ │ ├── postcss.config.js │ │ │ ├── public │ │ │ └── vite.svg │ │ │ ├── src │ │ │ ├── App.tsx │ │ │ ├── components │ │ │ │ ├── Header.tsx │ │ │ │ ├── starknet │ │ │ │ │ └── ConnectModal.tsx │ │ │ │ └── ui │ │ │ │ │ ├── Button.tsx │ │ │ │ │ └── Dialog.tsx │ │ │ ├── global.css │ │ │ ├── main.tsx │ │ │ └── vite-env.d.ts │ │ │ ├── tailwind.config.js │ │ │ ├── tsconfig.app.json │ │ │ ├── tsconfig.json │ │ │ ├── tsconfig.node.json │ │ │ └── vite.config.ts │ ├── tsconfig.json │ └── tsup.config.ts └── typescript-config │ ├── CHANGELOG.json │ ├── CHANGELOG.md │ ├── base.json │ ├── package.json │ └── react-library.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── turbo.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | max_line_length = 80 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | max_line_length = 0 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/default.md: -------------------------------------------------------------------------------- 1 | ## Context 2 | 3 | ## Changes in this Pull Request 4 | 5 | ## Test Plan 6 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/project.md: -------------------------------------------------------------------------------- 1 | ## Checklist 2 | 3 | - [ ] The project uses Starknet React. 4 | - [ ] The project list is in alphabetical order. 5 | - [ ] The project contains a short description (all lowercase) and ends with a period. For example, `Bitmap Box - on-chain 2D block building game.` 6 | - [ ] Avoid using `A / An` at the start of the description. 7 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - develop 8 | push: 9 | branches: 10 | - main 11 | - develop 12 | 13 | jobs: 14 | test: 15 | services: 16 | devnet: 17 | image: shardlabs/starknet-devnet-rs:0.0.6-seed0 18 | ports: 19 | - 5050:5050 20 | runs-on: ubuntu-latest 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v3 24 | - name: Set Node version 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version: 20 28 | - uses: pnpm/action-setup@v4 29 | with: 30 | version: 9.10.0 31 | - name: Install dependencies 32 | run: pnpm install --strict-peer-dependencies=false --no-frozen-lockfile 33 | - name: Run check format 34 | run: pnpm format:check 35 | - name: Run lint 36 | run: pnpm lint 37 | - name: Run build 38 | run: pnpm build 39 | - name: Run test 40 | run: pnpm test:ci 41 | - name: Check change files 42 | run: pnpm beachball check 43 | -------------------------------------------------------------------------------- /.github/workflows/release-documentation.yml: -------------------------------------------------------------------------------- 1 | name: Release documentation 2 | env: 3 | VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} 4 | VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} 5 | VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} 6 | 7 | on: 8 | push: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | release-documentation: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v3 18 | - name: Set Node version 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: 20 22 | - uses: pnpm/action-setup@v4 23 | with: 24 | version: 9.10.0 25 | - name: Install dependencies 26 | run: pnpm install --strict-peer-dependencies=false --no-frozen-lockfile 27 | - name: Build Project Artifacts 28 | run: pnpm build --filter=@starknet-react/docs 29 | - name: Pull Vercel Environment Information 30 | run: pnpm dlx vercel pull --cwd=docs --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} 31 | - name: Build Project Artifacts 32 | run: pnpm dlx vercel build --cwd=docs --prod --token=${{ secrets.VERCEL_TOKEN }} 33 | - name: Deploy Project Artifacts to Vercel 34 | run: pnpm dlx vercel deploy --cwd=docs --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} 35 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | release: 10 | environment: Release 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | - name: Set Node version 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: 20 19 | - uses: pnpm/action-setup@v4 20 | with: 21 | version: 9.10.0 22 | - name: Install dependencies 23 | run: pnpm install --strict-peer-dependencies=false --no-frozen-lockfile 24 | - name: Run build 25 | run: pnpm build 26 | - name: Setup git 27 | run: | 28 | git config user.name "Capy Bot" 29 | git config user.email "capy-bot@apibara.com" 30 | git remote set-url origin "https://${GIT_TOKEN}@github.com/apibara/starknet-react" 31 | env: 32 | GIT_TOKEN: ${{ secrets.GIT_TOKEN }} 33 | - name: Install dependencies 34 | run: pnpm install --strict-peer-dependencies=false --no-frozen-lockfile 35 | - name: Publish package 36 | run: pnpm beachball publish --access public --token "${NPM_TOKEN}" --tag next 37 | env: 38 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 39 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: "Mark and close stale issues and PRs" 2 | 3 | on: 4 | schedule: 5 | - cron: "0 2 * * *" # every day at 2am UTC 6 | 7 | permissions: 8 | issues: write 9 | pull-requests: write 10 | 11 | jobs: 12 | stale: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/stale@v9 16 | with: 17 | repo-token: ${{ secrets.GITHUB_TOKEN }} 18 | ascending: true 19 | # issues 20 | days-before-issue-stale: 180 21 | days-before-issue-close: 14 22 | stale-issue-label: stale 23 | exempt-issue-labels: "no stale" 24 | stale-issue-message: > 25 | This issue has been automatically marked as stale because it has not 26 | had activity in the six months. It will be closed in 2 weeks if no 27 | further activity occurs. Please feel free to leave a comment if you 28 | believe the issue is still relevant. 29 | close-issue-message: > 30 | This issue has been automatically closed because it has not had any 31 | further activity in the last 14 days. 32 | # PRs 33 | days-before-pr-stale: 30 34 | days-before-pr-close: 14 35 | stale-pr-label: stale 36 | exempt-pr-labels: "no stale" 37 | stale-pr-message: > 38 | This pull request has been automatically marked as stale because it 39 | has not had activity in the last 30 days. It will be closed in 2 40 | weeks if no further activity occurs. Please feel free to give a 41 | status update or ping for review. 42 | close-pr-message: > 43 | This pull request has been automatically closed because it has not 44 | had any further activity in the last 2 weeks. 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | build 5 | .DS_Store 6 | *.tgz 7 | *.pem 8 | my-app* 9 | lerna-debug.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | /.changelog 14 | .npm/ 15 | .parcel-cache 16 | dist 17 | .docusaurus 18 | .cache-loader 19 | .eslintcache 20 | .next 21 | .turbo 22 | .pnpm-debug.log 23 | .tamagui 24 | .expo 25 | website/generated 26 | website/out 27 | website/.contentlayer 28 | web-build/ 29 | *.orig.* 30 | *.jks 31 | *.p8 32 | *.p12 33 | *.key 34 | *.mobileprovision 35 | .metro-health-check* 36 | coverage 37 | out/ 38 | .pnp 39 | .pnp.js 40 | .yarn/install-state.gz 41 | .env*.local 42 | .env 43 | *.tsbuildinfo 44 | next-env.d.ts 45 | demos/arcade-factory/target 46 | demos/demo-contracts/target 47 | .vercel 48 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @fracek 2 | 3 | packages/core/src/starknetid.ts @th0rgal 4 | -------------------------------------------------------------------------------- /FUNDING.json: -------------------------------------------------------------------------------- 1 | { 2 | "drips": { 3 | "ethereum": { 4 | "ownedBy": "0x5696462DFf0D6C24b53772374Aa8bCA21a01F179" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 GNC Labs Limited and the Starknet React contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Starknet React 2 | 3 |

4 | 5 | @starknet-react/core 6 | 7 | 8 | Release Status 9 | 10 | 11 | MIT LICENSE 12 | 13 |

14 | 15 | **Starknet React** is a collection of React hooks for Starknet. It is inspired by 16 | [wagmi](https://github.com/tmm/wagmi), powered by [starknet.js](https://github.com/0xs34n/starknet.js). 17 | 18 | ## Documentation 19 | 20 | Documentation, including demos, [is available online](https://starknet-react.com/). 21 | 22 | ## Getting Started 23 | 24 | 1. Add `@starknet-react/chains` and `@starknet-react/core` to your dependencies. 25 | 26 | ```shell 27 | pnpm add @starknet-react/chains @starknet-react/core 28 | ``` 29 | 30 | You also need to add `get-starknet-core` and `starknet` to your dependencies. 31 | 32 | ```shell 33 | pnpm add get-starknet-core starknet 34 | ``` 35 | 36 | 2. Wrap your app with `StarknetConfig` 37 | 38 | ```typescript 39 | import { sepolia } from "@starknet-react/chains"; 40 | import { 41 | StarknetConfig, 42 | publicProvider, 43 | argent, 44 | braavos, 45 | } from "@starknet-react/core"; 46 | 47 | function App() { 48 | const chains = [sepolia]; 49 | const provider = publicProvider(); 50 | const connectors = [braavos(), argent()]; 51 | 52 | return ( 53 | 54 | 55 | 56 | ); 57 | } 58 | ``` 59 | 60 | 3. Access the hooks from your components. 61 | 62 | ```typescript 63 | import { useAccount } from "@starknet-react/core"; 64 | 65 | function YourComponent() { 66 | const { address } = useAccount(); 67 | 68 | return
gm {address}
; 69 | } 70 | ``` 71 | 72 | ## License 73 | 74 | This library is licensed under the MIT license. 75 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", 3 | "linter": { 4 | "enabled": true, 5 | "rules": { 6 | "recommended": true, 7 | "complexity": { 8 | "useLiteralKeys": "off" 9 | }, 10 | "correctness": { 11 | "noUnusedImports": "error" 12 | }, 13 | "a11y": { 14 | "useAltText": "off", 15 | "noBlankTarget": "off", 16 | "useButtonType": "off", 17 | "useKeyWithClickEvents": "off" 18 | } 19 | } 20 | }, 21 | "formatter": { 22 | "enabled": true, 23 | "formatWithErrors": false, 24 | "indentWidth": 2, 25 | "indentStyle": "space", 26 | "lineWidth": 80 27 | }, 28 | "javascript": { 29 | "formatter": { 30 | "quoteStyle": "double", 31 | "semicolons": "always" 32 | } 33 | }, 34 | "organizeImports": { 35 | "enabled": true 36 | }, 37 | "json": { 38 | "formatter": { 39 | "enabled": false 40 | } 41 | }, 42 | "files": { 43 | "ignore": [ 44 | "**/node_modules", 45 | "**/dist", 46 | "CHANGELOG.md", 47 | "pnpm-lock.yaml", 48 | "contracts/*.json", 49 | "abi/*.json", 50 | ".contentlayer", 51 | ".next", 52 | "out", 53 | "generated" 54 | ] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'] 3 | } 4 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | .vercel 2 | -------------------------------------------------------------------------------- /docs/components/demo/account.tsx: -------------------------------------------------------------------------------- 1 | import { useAccount } from "@starknet-react/core"; 2 | import stringify from "safe-stable-stringify"; 3 | import { DemoContainer } from "../starknet"; 4 | 5 | export function Account() { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | } 12 | 13 | function AccountInner() { 14 | const { address, connector, account } = useAccount(); 15 | 16 | return ( 17 |
18 |
19 |         {stringify(
20 |           {
21 |             address: address ?? "Connect wallet first",
22 |             connector: connector?.id ?? "Connect wallet first",
23 |             account: account ? typeof account : "Connect wallet first",
24 |           },
25 |           null,
26 |           2,
27 |         )}
28 |       
29 |
30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /docs/components/demo/add-chain.tsx: -------------------------------------------------------------------------------- 1 | import { type UseAddChainArgs, useAddChain } from "@starknet-react/core"; 2 | import stringify from "safe-stable-stringify"; 3 | import { shortString } from "starknet"; 4 | import { DemoContainer } from "../starknet"; 5 | import { Button } from "../ui/button"; 6 | 7 | export function AddChain() { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | 15 | function AddChainInner() { 16 | const chainData: UseAddChainArgs = { 17 | id: "ZORG", 18 | chain_id: shortString.encodeShortString("ZORG"), 19 | chain_name: "ZORG", 20 | rpc_urls: ["http://192.168.1.44:6060"], 21 | native_currency: { 22 | type: "ERC20", 23 | options: { 24 | address: 25 | "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", 26 | name: "ETHER", 27 | symbol: "ETH", 28 | decimals: 18, 29 | }, 30 | }, 31 | }; 32 | const { isError, isPending, data, error, addChain } = useAddChain({ 33 | params: chainData, 34 | }); 35 | return ( 36 |
37 |

Chain to Add

38 |
{stringify(chainData, null, 2)}
39 | 40 |

Response

41 |
42 |         {stringify(
43 |           {
44 |             data,
45 |             isPending,
46 |             isError,
47 |             error: error?.message,
48 |           },
49 |           null,
50 |           2,
51 |         )}
52 |       
53 | 54 | 55 | 56 |

57 | Important: This does not work with Braavos wallet, as they don't support 58 | the API at the moment. 59 |

60 |
61 | ); 62 | } 63 | -------------------------------------------------------------------------------- /docs/components/demo/balance.tsx: -------------------------------------------------------------------------------- 1 | import { useAccount, useBalance } from "@starknet-react/core"; 2 | import { DemoContainer } from "../starknet"; 3 | 4 | function AccountBalance({ account }: { account: `0x${string}` }) { 5 | const { data, error } = useBalance({ 6 | address: account, 7 | }); 8 | 9 | if (data) { 10 | return ( 11 |
12 |

13 | Address: 14 | {account.slice(0, 6)}...{account.slice(-4)} 15 |

16 |

17 | Balance: 18 | {`${data.formatted} ${data.symbol}`} 19 |

20 |
21 | ); 22 | } 23 | 24 | if (error) { 25 | return ( 26 |
27 |

Error fetching balance

28 |
{error.message}
29 |
30 | ); 31 | } 32 | 33 | return ( 34 |
35 |

Loading balance...

36 |
37 | ); 38 | } 39 | 40 | function BalanceInner() { 41 | const { address } = useAccount(); 42 | 43 | return ( 44 |
45 | {address ? ( 46 | 47 | ) : ( 48 |

Connect wallet to display its balance.

49 | )} 50 |
51 | ); 52 | } 53 | 54 | export function Balance() { 55 | return ( 56 | 57 | 58 | 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /docs/components/demo/change-default-network.tsx: -------------------------------------------------------------------------------- 1 | import { type Chain, mainnet, sepolia } from "@starknet-react/chains"; 2 | import { useAccount, useNetwork } from "@starknet-react/core"; 3 | import { useState } from "react"; 4 | import { DemoContainer } from "../starknet"; 5 | import { Button } from "../ui/button"; 6 | 7 | export function ChangeDefaultNetwork() { 8 | const [defaultChain, setDefaultChain] = useState(sepolia); 9 | 10 | return ( 11 | 12 | 16 | 17 | ); 18 | } 19 | 20 | function ChangeNetworkInner({ 21 | defaultChain, 22 | setDefaultChain, 23 | }: { 24 | defaultChain: Chain; 25 | setDefaultChain: (chain: Chain) => void; 26 | }) { 27 | const { chain } = useNetwork(); 28 | const chains = [sepolia, mainnet]; 29 | const { isConnected } = useAccount(); 30 | 31 | return ( 32 |
33 |
34 |

Current Chain:

35 |
{chain.name}
36 |
37 | 38 |
39 |

Default Chain:

40 |
{defaultChain.name}
41 |
42 | 43 |
44 |

Change Default Chain:

45 |
46 | {chains.map((chain) => ( 47 | 54 | ))} 55 |
56 |
57 | 58 |
59 |

Behavior Explanation:

60 |
61 |           {isConnected
62 |             ? "Connected: Changing default chain won't affect current chain"
63 |             : "Not Connected: Changing default chain will update current chain"}
64 |         
65 |
66 |
67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /docs/components/demo/declare-contract.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | type UseDeclareContractArgs, 3 | useDeclareContract, 4 | } from "@starknet-react/core"; 5 | import stringify from "safe-stable-stringify"; 6 | import { DemoContainer } from "../starknet"; 7 | import { Button } from "../ui/button"; 8 | 9 | export function DeclareContract() { 10 | return ( 11 | 12 | 13 | 14 | ); 15 | } 16 | 17 | function DeclareContractInner() { 18 | const { isError, isPending, data, error, declare } = useDeclareContract({ 19 | params, 20 | }); 21 | return ( 22 |
23 |

Params

24 |
{stringify(params, null, 2)}
25 | 26 |

Response

27 |
28 |         {stringify(
29 |           {
30 |             data,
31 |             isPending,
32 |             isError,
33 |             error: error?.message,
34 |           },
35 |           null,
36 |           2,
37 |         )}
38 |       
39 | 40 | 43 |
44 | ); 45 | } 46 | 47 | // TODO 48 | const params: UseDeclareContractArgs = { 49 | compiled_class_hash: "", 50 | contract_class: { 51 | abi: "", 52 | contract_class_version: "", 53 | sierra_program: [""], 54 | entry_points_by_type: { 55 | CONSTRUCTOR: [ 56 | { 57 | function_idx: 1, 58 | selector: "", 59 | }, 60 | ], 61 | EXTERNAL: [ 62 | { 63 | function_idx: 1, 64 | selector: "", 65 | }, 66 | ], 67 | L1_HANDLER: [ 68 | { 69 | function_idx: 1, 70 | selector: "", 71 | }, 72 | ], 73 | }, 74 | }, 75 | }; 76 | -------------------------------------------------------------------------------- /docs/components/demo/estimate-fees.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | type Abi, 3 | useAccount, 4 | useContract, 5 | useEstimateFees, 6 | useNetwork, 7 | } from "@starknet-react/core"; 8 | import stringify from "safe-stable-stringify"; 9 | import { DemoContainer } from "../starknet"; 10 | 11 | export function EstimateFees() { 12 | return ( 13 | 14 | 15 | 16 | ); 17 | } 18 | 19 | function EstimateFeesInner() { 20 | const { address } = useAccount(); 21 | const { chain } = useNetwork(); 22 | const { contract } = useContract({ 23 | abi: abi, 24 | address: chain.nativeCurrency.address, 25 | }); 26 | 27 | const { data, isError, isLoading, isPending, error } = useEstimateFees({ 28 | calls: 29 | contract && address 30 | ? [contract.populate("transfer", [address, 1n])] 31 | : undefined, 32 | }); 33 | 34 | return ( 35 |
36 |

Calls

37 |
[contract.populate("transfer", [address, 1n])]
38 | 39 |

Response

40 |
41 |         {stringify(
42 |           {
43 |             data,
44 |             isLoading,
45 |             isPending,
46 |             isError,
47 |             error: error?.message,
48 |             suggestedMaxFee: `${formatAmount(
49 |               data?.suggestedMaxFee,
50 |               chain.nativeCurrency.decimals,
51 |             )} ${chain.nativeCurrency.symbol}`,
52 |           },
53 |           null,
54 |           2,
55 |         )}
56 |       
57 |
58 | ); 59 | } 60 | 61 | const abi = [ 62 | { 63 | type: "function", 64 | name: "transfer", 65 | state_mutability: "external", 66 | inputs: [ 67 | { 68 | name: "recipient", 69 | type: "core::starknet::contract_address::ContractAddress", 70 | }, 71 | { 72 | name: "amount", 73 | type: "core::integer::u256", 74 | }, 75 | ], 76 | outputs: [], 77 | }, 78 | ] as const satisfies Abi; 79 | 80 | const formatAmount = ( 81 | unformattedAmount: bigint | unknown, 82 | decimals: number, 83 | ) => { 84 | return Number(BigInt(unformattedAmount?.toString() || 0)) / 10 ** decimals; 85 | }; 86 | -------------------------------------------------------------------------------- /docs/components/demo/events.tsx: -------------------------------------------------------------------------------- 1 | import { useBlockNumber, useEvents, useNetwork } from "@starknet-react/core"; 2 | import stringify from "safe-stable-stringify"; 3 | import { BlockTag } from "starknet"; 4 | import { DemoContainer } from "../starknet"; 5 | import { Button } from "../ui/button"; 6 | 7 | function EventsInner() { 8 | const eventName = "Transfer"; 9 | const { chain } = useNetwork(); 10 | const address = chain.nativeCurrency.address; 11 | const blockNumber = useBlockNumber(); 12 | const fromBlock = blockNumber.data ? blockNumber.data - 10 : 0; 13 | const toBlock = BlockTag.LATEST; 14 | 15 | const pageSize = 3; 16 | const { 17 | data, 18 | error, 19 | fetchNextPage, 20 | hasNextPage, 21 | isFetchingNextPage, 22 | status, 23 | } = useEvents({ address, eventName, fromBlock, toBlock, pageSize }); 24 | 25 | const response = 26 | status === "pending" ? ( 27 |

Loading first events ...

28 | ) : status === "error" ? ( 29 | <> 30 |

Error: {error?.message}

31 |
{stringify({ data, error }, null, 2)}
32 | 33 | ) : ( 34 | <> 35 |
36 | 46 |
47 | 48 | {data?.pages 49 | .slice(0) 50 | .reverse() 51 | .map((page, i) => ( 52 |
53 |

Chunk: {data.pages.length - i}

54 |
{stringify({ page }, null, 2)}
55 |
56 | ))} 57 | 58 | ); 59 | 60 | return ( 61 |
62 |

Fetching events for

63 |
64 |         {stringify(
65 |           { address, eventName, fromBlock, toBlock, pageSize },
66 |           null,
67 |           2,
68 |         )}
69 |       
70 | {response} 71 |
72 | ); 73 | } 74 | 75 | export function Events() { 76 | return ( 77 | 78 | 79 | 80 | ); 81 | } 82 | -------------------------------------------------------------------------------- /docs/components/demo/index.ts: -------------------------------------------------------------------------------- 1 | import { Account } from "./account"; 2 | import { AddChain } from "./add-chain"; 3 | import { Balance } from "./balance"; 4 | import { ChangeDefaultNetwork } from "./change-default-network"; 5 | import { DeclareContract } from "./declare-contract"; 6 | import { DeployContract } from "./deploy-contract"; 7 | import { EstimateFees } from "./estimate-fees"; 8 | import { NonceForAddress } from "./nonce-for-address"; 9 | import { ReadContract } from "./read-contract"; 10 | import { SendTransaction } from "./send-transaction"; 11 | import { SignTypedData } from "./sign-typed-data"; 12 | import { StarkAddress } from "./stark-address"; 13 | import { StarkName } from "./stark-name"; 14 | import { StarkProfile } from "./stark-profile"; 15 | import { StarknetKit } from "./starknetkit"; 16 | import { SwitchChain } from "./switch-chain"; 17 | import { WalletPermission } from "./wallet-permission"; 18 | import { Events } from "./events"; 19 | 20 | export default { 21 | Account, 22 | WalletPermission, 23 | Balance, 24 | ReadContract, 25 | SendTransaction, 26 | EstimateFees, 27 | StarkAddress, 28 | StarkName, 29 | StarkProfile, 30 | SwitchChain, 31 | AddChain, 32 | SignTypedData, 33 | DeclareContract, 34 | NonceForAddress, 35 | StarknetKit, 36 | ChangeDefaultNetwork, 37 | DeployContract, 38 | Events, 39 | }; 40 | -------------------------------------------------------------------------------- /docs/components/demo/nonce-for-address.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | type Address, 3 | useAccount, 4 | useNonceForAddress, 5 | } from "@starknet-react/core"; 6 | import stringify from "safe-stable-stringify"; 7 | import { DemoContainer } from "../starknet"; 8 | 9 | export function NonceForAddress() { 10 | return ( 11 | 12 | 13 | 14 | ); 15 | } 16 | 17 | function NonceForAddressInner() { 18 | const { account } = useAccount(); 19 | 20 | const { data, isLoading, isError, error, isPending } = useNonceForAddress({ 21 | address: account?.address as Address, 22 | }); 23 | 24 | return ( 25 |
26 |
27 |         {stringify(
28 |           {
29 |             data,
30 |             isLoading,
31 |             isPending,
32 |             isError,
33 |             error: error?.message,
34 |           },
35 |           null,
36 |           2,
37 |         )}
38 |       
39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /docs/components/demo/send-transaction.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | useAccount, 3 | useContract, 4 | useNetwork, 5 | useSendTransaction, 6 | } from "@starknet-react/core"; 7 | import stringify from "safe-stable-stringify"; 8 | import type { Abi } from "starknet"; 9 | import { DemoContainer } from "../starknet"; 10 | import { Button } from "../ui/button"; 11 | 12 | export function SendTransaction() { 13 | return ( 14 | 15 | 16 | 17 | ); 18 | } 19 | 20 | function SendTransactionInner() { 21 | const { address } = useAccount(); 22 | const { chain } = useNetwork(); 23 | const { contract } = useContract({ 24 | abi, 25 | address: chain.nativeCurrency.address, 26 | }); 27 | 28 | const { isError, error, send, data, isPending } = useSendTransaction({ 29 | calls: 30 | contract && address 31 | ? [contract.populate("transfer", [address, 1n])] 32 | : undefined, 33 | }); 34 | 35 | return ( 36 |
37 |

Response

38 |
39 |         {stringify(
40 |           {
41 |             data,
42 |             isPending,
43 |             isError,
44 |             error: error?.message,
45 |           },
46 |           null,
47 |           2,
48 |         )}
49 |       
50 | 51 |
52 | ); 53 | } 54 | 55 | const abi = [ 56 | { 57 | type: "function", 58 | name: "transfer", 59 | state_mutability: "external", 60 | inputs: [ 61 | { 62 | name: "recipient", 63 | type: "core::starknet::contract_address::ContractAddress", 64 | }, 65 | { 66 | name: "amount", 67 | type: "core::integer::u256", 68 | }, 69 | ], 70 | outputs: [], 71 | }, 72 | ] as const satisfies Abi; 73 | -------------------------------------------------------------------------------- /docs/components/demo/stark-address.tsx: -------------------------------------------------------------------------------- 1 | import { useStarkAddress } from "@starknet-react/core"; 2 | import { useState } from "react"; 3 | import stringify from "safe-stable-stringify"; 4 | import { DemoContainer } from "../starknet"; 5 | import { Input } from "../ui/input"; 6 | 7 | export function StarkAddress() { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | 15 | function StarkAddressInner() { 16 | const [name, setName] = useState("vitalik.stark"); 17 | 18 | const { data, isLoading, isPending, isError, error } = useStarkAddress({ 19 | name, 20 | }); 21 | 22 | return ( 23 |
24 |
25 |

Starkname

26 | setName(e.target.value)} 32 | /> 33 |
34 |
35 |

Response

36 |
37 |           {stringify(
38 |             {
39 |               data,
40 |               isLoading,
41 |               isPending,
42 |               isError,
43 |               error: error?.message,
44 |             },
45 |             null,
46 |             2,
47 |           )}
48 |         
49 |
50 |
51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /docs/components/demo/stark-name.tsx: -------------------------------------------------------------------------------- 1 | import { type Address, useStarkName } from "@starknet-react/core"; 2 | import { useState } from "react"; 3 | import stringify from "safe-stable-stringify"; 4 | import { DemoContainer } from "../starknet"; 5 | import { Input } from "../ui/input"; 6 | 7 | export function StarkName() { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | 15 | function StarkNameInner() { 16 | const [address, setAddress] = useState( 17 | "0x7cffe72748da43594c5924129b4f18bffe643270a96b8760a6f2e2db49d9732", 18 | ); 19 | 20 | const { data, isLoading, isPending, isError, error } = useStarkName({ 21 | address: address as Address, 22 | }); 23 | 24 | return ( 25 |
26 |
27 |

Address

28 | setAddress(e.target.value)} 33 | />{" "} 34 |
35 | 36 |
37 |

Response

38 |
39 |           {stringify(
40 |             {
41 |               data,
42 |               isLoading,
43 |               isPending,
44 |               isError,
45 |               error: error?.message,
46 |             },
47 |             null,
48 |             2,
49 |           )}
50 |         
51 |
52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /docs/components/demo/stark-profile.tsx: -------------------------------------------------------------------------------- 1 | import { type Address, useStarkProfile } from "@starknet-react/core"; 2 | import { useState } from "react"; 3 | import stringify from "safe-stable-stringify"; 4 | import { DemoContainer } from "../starknet"; 5 | import { Input } from "../ui/input"; 6 | 7 | export function StarkProfile() { 8 | return ( 9 | 10 | 11 | 12 | ); 13 | } 14 | 15 | function StarkProfileInner() { 16 | const [address, setAddress] = useState( 17 | "0x061b6c0a78f9edf13cea17b50719f3344533fadd470b8cb29c2b4318014f52d3", 18 | ); 19 | 20 | const { data, isLoading, isError, isPending, error } = useStarkProfile({ 21 | address: address as Address, 22 | }); 23 | 24 | return ( 25 |
26 |
27 |

Address

28 | setAddress(e.target.value)} 33 | />{" "} 34 |
35 | 36 |
37 |

Response

38 |
39 |           {stringify(
40 |             {
41 |               data,
42 |               isLoading,
43 |               isPending,
44 |               isError,
45 |               error: error?.message,
46 |             },
47 |             null,
48 |             2,
49 |           )}
50 |         
51 |
52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /docs/components/demo/switch-chain.tsx: -------------------------------------------------------------------------------- 1 | import { sepolia } from "@starknet-react/chains"; 2 | import { useNetwork, useSwitchChain } from "@starknet-react/core"; 3 | import stringify from "safe-stable-stringify"; 4 | import { constants } from "starknet"; 5 | import { DemoContainer } from "../starknet"; 6 | import { Button } from "../ui/button"; 7 | 8 | export function SwitchChain() { 9 | return ( 10 | 11 | 12 | 13 | ); 14 | } 15 | 16 | function SwitchChainInner() { 17 | const { chain } = useNetwork(); 18 | const { isError, isPending, data, error, switchChain } = useSwitchChain({ 19 | params: { 20 | chainId: 21 | chain.id === sepolia.id 22 | ? constants.StarknetChainId.SN_MAIN 23 | : constants.StarknetChainId.SN_SEPOLIA, 24 | }, 25 | }); 26 | 27 | return ( 28 |
29 |

Current Chain:

30 |
{chain.name}
31 | 32 |

Response

33 |
34 |         {stringify(
35 |           {
36 |             data,
37 |             isPending,
38 |             isError,
39 |             error: error?.message,
40 |           },
41 |           null,
42 |           2,
43 |         )}
44 |       
45 | 46 | 49 | 56 | 63 | 64 |

65 | Important: This does not work with Braavos wallet, as they don't support 66 | the API at the moment. 67 |

68 |
69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /docs/components/demo/wallet-permission.tsx: -------------------------------------------------------------------------------- 1 | import { useWalletRequest } from "@starknet-react/core"; 2 | import stringify from "safe-stable-stringify"; 3 | import { DemoContainer } from "../starknet"; 4 | import { Button } from "../ui/button"; 5 | 6 | export function WalletPermission() { 7 | return ( 8 | 9 | 10 | 11 | ); 12 | } 13 | 14 | function WalletRequest() { 15 | const { request, data, isPending, isError, error } = useWalletRequest({ 16 | type: "wallet_getPermissions", 17 | }); 18 | 19 | return ( 20 |
21 |

Response

22 |
23 |         {stringify(
24 |           {
25 |             data,
26 |             isPending,
27 |             isError,
28 |             error: error?.message,
29 |           },
30 |           null,
31 |           2,
32 |         )}
33 |       
34 | 35 | 36 | * Wallet connection required 37 |
38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /docs/components/starknet/bar.tsx: -------------------------------------------------------------------------------- 1 | import { useAccount, useConnect, useDisconnect } from "@starknet-react/core"; 2 | import { Button } from "../ui/button"; 3 | 4 | export function WalletBar() { 5 | const { address } = useAccount(); 6 | 7 | return ( 8 |
9 | {address ? : } 10 |
11 | ); 12 | } 13 | 14 | function ConnectedWallet({ address }: { address: `0x${string}` }) { 15 | const { disconnect } = useDisconnect(); 16 | return ( 17 |
18 |

Connected Address:

19 |
20 |
21 |           {address.slice(0, 25)}...{address.slice(-25)}
22 |         
23 | 31 |
32 |
33 | ); 34 | } 35 | 36 | function ConnectWallet() { 37 | const { connectAsync, connectors, status } = useConnect(); 38 | 39 | return ( 40 |
41 |

Connect Wallet

42 |
43 | {connectors.map((connector) => ( 44 | 54 | ))} 55 |
56 |
57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /docs/components/starknet/index.tsx: -------------------------------------------------------------------------------- 1 | import { WalletBar } from "./bar"; 2 | import { StarknetProvider } from "./provider"; 3 | 4 | export function DemoContainer({ 5 | defaultChainId, 6 | hasWallet, 7 | children, 8 | }: { 9 | defaultChainId?: bigint; 10 | hasWallet?: boolean; 11 | children: React.ReactNode; 12 | }) { 13 | return ( 14 | 15 |
16 | {hasWallet ? : null} 17 |
{children}
18 | {hasWallet ? ( 19 | * Wallet connection required 20 | ) : null} 21 |
22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /docs/components/starknet/provider.tsx: -------------------------------------------------------------------------------- 1 | import { mainnet, sepolia } from "@starknet-react/chains"; 2 | import { 3 | type ExplorerFactory, 4 | StarknetConfig, 5 | argent, 6 | braavos, 7 | publicProvider, 8 | useInjectedConnectors, 9 | } from "@starknet-react/core"; 10 | 11 | export function StarknetProvider({ 12 | defaultChainId, 13 | children, 14 | explorer, 15 | }: { 16 | children: React.ReactNode; 17 | defaultChainId?: bigint; 18 | explorer?: ExplorerFactory; 19 | }) { 20 | const chains = [sepolia, mainnet]; 21 | 22 | const provider = publicProvider(); 23 | const { connectors } = useInjectedConnectors({ 24 | // Show these connectors if the user has no connector installed. 25 | recommended: [argent(), braavos()], 26 | // Hide recommended connectors if the user has any connector installed. 27 | includeRecommended: "always", 28 | // Randomize the order of the connectors. 29 | order: "alphabetical", 30 | shimLegacyConnectors: ["okxwallet"], 31 | }); 32 | 33 | return ( 34 | 41 | {children} 42 | 43 | ); 44 | } 45 | -------------------------------------------------------------------------------- /docs/components/starknetkit/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./starknetkit-connectors"; 2 | -------------------------------------------------------------------------------- /docs/components/starknetkit/starknetkit-connectors.ts: -------------------------------------------------------------------------------- 1 | import { constants } from "starknet"; 2 | import { 3 | ArgentMobileConnector, 4 | isInArgentMobileAppBrowser, 5 | } from "starknetkit/argentMobile"; 6 | import { InjectedConnector } from "starknetkit/injected"; 7 | import { WebWalletConnector } from "starknetkit/webwallet"; 8 | 9 | export const availableConnectors = isInArgentMobileAppBrowser() 10 | ? [ 11 | ArgentMobileConnector.init({ 12 | options: { 13 | url: typeof window !== "undefined" ? window.location.href : "", 14 | dappName: "Example dapp", 15 | chainId: constants.NetworkName.SN_SEPOLIA, 16 | }, 17 | }), 18 | ] 19 | : [ 20 | new InjectedConnector({ options: { id: "argentX" } }), 21 | new InjectedConnector({ options: { id: "braavos" } }), 22 | ArgentMobileConnector.init({ 23 | options: { 24 | url: typeof window !== "undefined" ? window.location.href : "", 25 | dappName: "Example dapp", 26 | chainId: constants.NetworkName.SN_MAIN, 27 | }, 28 | }), 29 | new WebWalletConnector({ url: "https://web.argent.xyz" }), 30 | ]; 31 | -------------------------------------------------------------------------------- /docs/components/ui/button.tsx: -------------------------------------------------------------------------------- 1 | import { Slot } from "@radix-ui/react-slot"; 2 | import { type VariantProps, cva } from "class-variance-authority"; 3 | import * as React from "react"; 4 | import { cn } from "../../lib/utils"; 5 | 6 | const buttonVariants = cva( 7 | "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", 8 | { 9 | variants: { 10 | variant: { 11 | default: "bg-primary text-primary-foreground hover:bg-primary/90", 12 | destructive: 13 | "bg-destructive text-destructive-foreground hover:bg-destructive/90", 14 | outline: 15 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground", 16 | secondary: 17 | "bg-secondary text-secondary-foreground hover:bg-secondary/80", 18 | ghost: "hover:bg-accent hover:text-accent-foreground", 19 | link: "text-primary underline-offset-4 hover:underline", 20 | }, 21 | size: { 22 | default: "h-10 px-4 py-2", 23 | sm: "h-9 rounded-md px-3", 24 | lg: "h-11 rounded-md px-8", 25 | icon: "h-10 w-10", 26 | }, 27 | }, 28 | defaultVariants: { 29 | variant: "default", 30 | size: "default", 31 | }, 32 | }, 33 | ); 34 | 35 | export interface ButtonProps 36 | extends React.ButtonHTMLAttributes, 37 | VariantProps { 38 | asChild?: boolean; 39 | } 40 | 41 | const Button = React.forwardRef( 42 | ({ className, variant, size, asChild = false, ...props }, ref) => { 43 | const Comp = asChild ? Slot : "button"; 44 | return ( 45 | 50 | ); 51 | }, 52 | ); 53 | Button.displayName = "Button"; 54 | 55 | export { Button, buttonVariants }; 56 | -------------------------------------------------------------------------------- /docs/components/ui/checkbox.tsx: -------------------------------------------------------------------------------- 1 | import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; 2 | import { Check } from "lucide-react"; 3 | import * as React from "react"; 4 | 5 | import { cn } from "../../lib/utils"; 6 | 7 | const Checkbox = React.forwardRef< 8 | React.ElementRef, 9 | React.ComponentPropsWithoutRef 10 | >(({ className, ...props }, ref) => ( 11 | 19 | 22 | 23 | 24 | 25 | )); 26 | Checkbox.displayName = CheckboxPrimitive.Root.displayName; 27 | 28 | export { Checkbox }; 29 | -------------------------------------------------------------------------------- /docs/components/ui/input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "../../lib/utils"; 4 | 5 | export interface InputProps 6 | extends React.InputHTMLAttributes {} 7 | 8 | const Input = React.forwardRef( 9 | ({ className, type, ...props }, ref) => { 10 | return ( 11 | 20 | ); 21 | }, 22 | ); 23 | Input.displayName = "Input"; 24 | 25 | export { Input }; 26 | -------------------------------------------------------------------------------- /docs/components/ui/label.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import * as LabelPrimitive from "@radix-ui/react-label"; 4 | import { type VariantProps, cva } from "class-variance-authority"; 5 | import * as React from "react"; 6 | 7 | import { cn } from "../../lib/utils"; 8 | 9 | const labelVariants = cva( 10 | "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", 11 | ); 12 | 13 | const Label = React.forwardRef< 14 | React.ElementRef, 15 | React.ComponentPropsWithoutRef & 16 | VariantProps 17 | >(({ className, ...props }, ref) => ( 18 | 23 | )); 24 | Label.displayName = LabelPrimitive.Root.displayName; 25 | 26 | export { Label }; 27 | -------------------------------------------------------------------------------- /docs/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx"; 2 | import { twMerge } from "tailwind-merge"; 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)); 6 | } 7 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@starknet-react/docs", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "dev": "vocs dev", 7 | "build": "vocs build", 8 | "preview": "vocs preview", 9 | "lint": "biome lint components", 10 | "lint:fix": "biome lint components --write", 11 | "format:check": "biome format components", 12 | "format": "biome format components --write" 13 | }, 14 | "dependencies": { 15 | "@cartridge/connector": "^0.7.12", 16 | "@cartridge/controller": "^0.7.12", 17 | "@radix-ui/react-checkbox": "^1.1.1", 18 | "@radix-ui/react-label": "^2.1.0", 19 | "@radix-ui/react-select": "^2.1.1", 20 | "@radix-ui/react-slot": "^1.1.0", 21 | "@starknet-react/chains": "workspace:*", 22 | "@starknet-react/core": "workspace:*", 23 | "class-variance-authority": "^0.7.0", 24 | "clsx": "^2.1.1", 25 | "lucide-react": "^0.438.0", 26 | "react": "^18.2.0", 27 | "safe-stable-stringify": "^2.5.0", 28 | "starknet": "^7.1.0", 29 | "starknetkit": "^2.10.4", 30 | "tailwind-merge": "^2.5.2", 31 | "tailwindcss-animate": "^1.0.7", 32 | "vocs": "1.0.0-alpha.55" 33 | }, 34 | "devDependencies": { 35 | "@starknet-react/typescript-config": "workspace:*", 36 | "@types/react": "^18.2.0", 37 | "@types/react-dom": "^18.2.0", 38 | "tailwindcss": "^3.4.10" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /docs/pages/demo/account.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Account 4 | 5 | 6 | 7 | This demo shows how to access the currently connected account and its address. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/account.tsx) 10 | 11 | Hook(s) 12 | - `useAccount` 13 | -------------------------------------------------------------------------------- /docs/pages/demo/add-chain.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Add Chain 4 | 5 | 6 | 7 | This demo shows how to add a new chain to the wallet. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/add-chain.tsx) 10 | 11 | Hook(s) 12 | - `useAddChain` 13 | -------------------------------------------------------------------------------- /docs/pages/demo/balance.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Token Balance 4 | 5 | 6 | 7 | This demo shows how to fetch an ERC-20 token balance. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/balance.tsx) 10 | 11 | Hooks 12 | - `useAccount` 13 | - `useBalance` 14 | -------------------------------------------------------------------------------- /docs/pages/demo/change-default-network.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Change Default Network 4 | 5 | 6 | 7 | This demo shows how to change the default network. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/change-default-network.tsx) 10 | 11 | Hooks 12 | 13 | - `publicProvider` 14 | - `useAccount` 15 | - `useNetwork` 16 | -------------------------------------------------------------------------------- /docs/pages/demo/declare-contract.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Declare Contract (Todo) 4 | 5 | 6 | 7 | This demo shows how to declare a contract. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/declare-contract.tsx) 10 | 11 | Hooks 12 | 13 | - `useAccount` 14 | - `useDeclareContract` 15 | -------------------------------------------------------------------------------- /docs/pages/demo/deploy-contract.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Deploy Contract 4 | 5 | 6 | 7 | This demo shows how to use the `useUniversalDeployerContract` with `useSendTransaction` to deploy a contract. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/deploy-contract.tsx) 10 | 11 | Hooks 12 | 13 | - `useUniversalDeployerContract` 14 | - `useSendTransaction` 15 | -------------------------------------------------------------------------------- /docs/pages/demo/estimate-fees.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Estimate Fees 4 | 5 | 6 | 7 | This demo shows a fee estimate fees for smart contract calls. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/estimate-fees.tsx) 10 | 11 | Hooks 12 | - `useAccount` 13 | - `useContract` 14 | - `useEstimateFees` 15 | - `useNetwork` 16 | -------------------------------------------------------------------------------- /docs/pages/demo/events.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Events 4 | 5 | 6 | 7 | This demo shows how to fetch events continuously. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/events.tsx) 10 | 11 | Hook(s) 12 | - `useEvents` 13 | -------------------------------------------------------------------------------- /docs/pages/demo/index.mdx: -------------------------------------------------------------------------------- 1 | # Demos 2 | 3 | This section contains a list of demos showing how to use Starknet React. 4 | 5 | You can find the source code for these demos [on GitHub](https://github.com/apibara/starknet-react/tree/main/docs/components/demo). 6 | 7 | ## Common Hooks 8 | 9 | **[Account](/demo/account)**: Shows how to access the current account and its address. 10 | 11 | **[Balance](/demo/balance)**: Shows how to fetch an ERC-20 token balance. 12 | 13 | **[Estimate Fees](/demo/estimate-fees)**: Shows how to estimate fees for smart contract calls. 14 | 15 | **[Nonce for Address](/demo/nonce-for-address)**: Shows how to get the nonce for an address. 16 | 17 | **[Read contract](/demo/read-contract)**: Shows how to use the `useReadContract` type-safe API to query a Starknet contract. 18 | 19 | **[Declare contract](/demo/declare-contract)**: Shows how to declare a contract. 20 | 21 | **[Deploy contract](/demo/deploy-contract)**: Shows how to use the `useUniversalDeployerContract` with `useSendTransaction` hooks to deploy a contract. 22 | 23 | **[Send transaction](/demo/send-transaction)**: Shows how to use the `useContract` and `useSendTransaction` hooks to send transactions to the network. 24 | 25 | **[Sign Typed Data](/demo/sign-typed-data)**: Shows how to request users to sign a piece of data. 26 | 27 | **[Change Default Network](/demo/change-default-network)**: Shows how to change the default network. 28 | 29 | **[Events](/demo/events)**: Shows how to fetch events continuously. 30 | 31 | ## New APIs 32 | 33 | **[Request wallet permissions](/demo/wallet-permission)**: Shows how to request wallet permissions. 34 | 35 | **[Add Chain](/demo/add-chain)**: Shows how to add a new chain to the wallet. 36 | 37 | **[Switch Chain](/demo/switch-chain)**: Shows how to switch between chains. 38 | 39 | ## Starknet ID 40 | 41 | **[Stark Address](/demo/stark-address)**: Shows how to get the address associated to a Starknet ID. 42 | 43 | **[Stark Name](/demo/stark-name)**: Shows how to get the Starknet ID associated to an address. 44 | 45 | **[Stark Profile](/demo/stark-profile)**: Shows how to get the Starknet ID profile associated to an address. 46 | 47 | ## Integrations 48 | 49 | **[StarknetKit Integration](/demo/starknetkit)**: Shows how to integrate Starknet React with StarknetKit. 50 | -------------------------------------------------------------------------------- /docs/pages/demo/nonce-for-address.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Nonce for Address 4 | 5 | 6 | 7 | This demo shows how to get the nonce for an address. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/nonce-for-address.tsx) 10 | 11 | Hooks 12 | - `useAccount` 13 | - `useNonceForAddress` 14 | -------------------------------------------------------------------------------- /docs/pages/demo/read-contract.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Read Contract 4 | 5 | 6 | 7 | This demo shows how to use the `useReadContract` type-safe API to query a Starknet contract. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/read-contract.tsx) 10 | 11 | Hooks 12 | - `useNetwork` 13 | - `useReadContract` 14 | -------------------------------------------------------------------------------- /docs/pages/demo/send-transaction.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Send Transaction 4 | 5 | 6 | 7 | This demo shows how to send transactions to the network. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/send-transaction.tsx) 10 | 11 | Hooks 12 | - `useContract` 13 | - `useSendTransaction` 14 | -------------------------------------------------------------------------------- /docs/pages/demo/sign-typed-data.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Sign Typed Data 4 | 5 | 6 | 7 | This demo shows how to sign typed data via the wallet of the connected account. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/sign-typed-data.tsx) 10 | 11 | Hook(s) 12 | - `useSignTypedData` 13 | -------------------------------------------------------------------------------- /docs/pages/demo/stark-address.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Stark Address 4 | 5 | 6 | 7 | This demo shows how to get the address associated to a Starknet ID. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/stark-address.tsx) 10 | 11 | Hook(s) 12 | - `useStarkAddress` 13 | -------------------------------------------------------------------------------- /docs/pages/demo/stark-name.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Stark Name 4 | 5 | 6 | 7 | This demo shows how to get the Starknet ID associated to an address. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/stark-name.tsx) 10 | 11 | Hook(s) 12 | - `useStarkName` 13 | -------------------------------------------------------------------------------- /docs/pages/demo/stark-profile.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Stark Profile 4 | 5 | 6 | 7 | This demo shows how to get the Starknet ID profile associated to an address. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/stark-profile.tsx) 10 | 11 | Hook(s) 12 | - `useStarkProfile` 13 | -------------------------------------------------------------------------------- /docs/pages/demo/starknetkit.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # StarknetKit Integration 4 | 5 | 6 | 7 | This demo shows how to integrate Starknet React with StarknetKit. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/starknetkit.tsx) 10 | 11 | Hooks 12 | - starknet-react 13 | -`publicProvider` 14 | - `useAccount` 15 | - `useConnect` 16 | - `useNetwork`, 17 | - starknetkitconnector 18 | - `useStarknetkitConnectModal` 19 | -------------------------------------------------------------------------------- /docs/pages/demo/switch-chain.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Switch Chain 4 | 5 | 6 | 7 | This demo shows how to switch between chains. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/switch-chain.tsx) 10 | 11 | Hooks 12 | - `useAccount` 13 | - `useNetwork` 14 | - `useSwitchChain` 15 | -------------------------------------------------------------------------------- /docs/pages/demo/wallet-permission.mdx: -------------------------------------------------------------------------------- 1 | import Demo from "../../components/demo"; 2 | 3 | # Wallet Permission 4 | 5 | 6 | 7 | This demo shows how to request wallet permissions. 8 | 9 | [Link to GitHub](https://github.com/apibara/starknet-react/blob/main/docs/components/demo/wallet-permission.tsx) 10 | 11 | Hook(s) 12 | - `useWalletRequest` 13 | -------------------------------------------------------------------------------- /docs/pages/docs/explorers.mdx: -------------------------------------------------------------------------------- 1 | # Explorers 2 | 3 | The `StarknetConfig` provider accepts an optional `explorer` property to 4 | configure the block explorer used by the `useExplorer` hook. 5 | 6 | Starknet React ships with the following block explorers (in alphabetical order): 7 | 8 | - Cartridge Explorer 9 | - Starkscan 10 | - Viewblock 11 | - Voyager 12 | 13 | ## The `Explorer` interface 14 | 15 | The `Explorer` interface is used to generate links to the block explorer. 16 | It provides the following properties and methods. 17 | 18 | - `name: string`: human-friendly explorer name. 19 | - `block({ hash?: string, number?: number }): string`: link to the specified 20 | block, either by hash or number. 21 | - `transaction(hash: string): string`: link to the specified transaction. 22 | - `contract(address: string): string`: link to the specified contract. 23 | - `class(hash: string): string`: link to the specified class. 24 | 25 | ## Explorer factory 26 | 27 | `StarknetConfig` expects an __explorer factory__, that is a function with the 28 | following signature: 29 | 30 | ```ts 31 | 32 | type ExplorerFactory = ( 33 | chain: Chain, 34 | ) => T | null; 35 | ``` 36 | 37 | Starknet React ships with the following explorer factories: 38 | 39 | - `cartridge` 40 | - `starkscan` 41 | - `viewblock` 42 | - `voyager` 43 | 44 | ## `useExplorer` hook 45 | 46 | You can get an instance of the current explorer already initialized for the current chain 47 | using the `useExplorer` hook. 48 | 49 | ```tsx twoslash 50 | import { useExplorer } from "@starknet-react/core"; 51 | 52 | const explorer = useExplorer(); 53 | 54 | const name = explorer.name 55 | const link = explorer.block({ number: 123 }) 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-account.mdx: -------------------------------------------------------------------------------- 1 | # useAccount 2 | 3 | Access the currently connected account, if any. 4 | 5 | ## Usage 6 | 7 | ```ts twoslash 8 | import { useAccount } from "@starknet-react/core"; 9 | 10 | const { address, status } = useAccount(); 11 | ``` 12 | 13 | ### Listening for changes 14 | 15 | You can listen for the connection/disconnection events using the `useEffect` hook. 16 | 17 | ```ts twoslash 18 | import { useEffect } from "react"; 19 | import { useAccount } from "@starknet-react/core"; 20 | 21 | const { address, status } = useAccount(); 22 | 23 | useEffect(() => { 24 | if (status === "disconnected") { 25 | // on disconnect 26 | } else if (status === "connected") { 27 | // on connect 28 | } 29 | }, [address, status]) 30 | ``` 31 | 32 | ## Returns 33 | 34 | ### account 35 | 36 | * Type: `AccountInterface | undefined` 37 | 38 | The currently connected account. 39 | 40 | ### address 41 | 42 | * Type: `0x${string} | undefined` 43 | 44 | The address of the currently connected account. 45 | 46 | ### connector 47 | 48 | * Type: `Connector | undefined` 49 | 50 | The connector used to connect the account. 51 | 52 | ### chainId 53 | 54 | * Type: `bigint | undefined` 55 | 56 | The account's chain id. 57 | 58 | ### status 59 | 60 | * Type: `"connected" | "disconnected" | "connecting" | "reconnecting"` 61 | 62 | Account connection status. 63 | 64 | ### isConnecting 65 | 66 | * Type: `boolean | undefined` 67 | 68 | Derived from `status`. 69 | 70 | ### isReconnecting 71 | 72 | * Type: `boolean | undefined` 73 | 74 | Derived from `status`. 75 | 76 | ### isConnected 77 | 78 | * Type: `boolean | undefined` 79 | 80 | Derived from `status`. 81 | 82 | ### isDisconnected 83 | 84 | * Type: `boolean | undefined` 85 | 86 | Derived from `status`. 87 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-block-number.mdx: -------------------------------------------------------------------------------- 1 | # useBlockNumber 2 | 3 | Fetch a single block number. 4 | 5 | By default this hook fetches the latest block, but you can change it with the `blockIdentifier` argument. 6 | 7 | ## Usage 8 | 9 | ```ts twoslash 10 | import { useBlockNumber } from "@starknet-react/core"; 11 | 12 | const { data, error } = useBlockNumber(); 13 | ``` 14 | 15 | ## Data 16 | 17 | - Type: `number` 18 | 19 | The block number. 20 | 21 | ## Arguments 22 | 23 | ### blockIdentifier 24 | 25 | - Type: `BlockNumber | undefined` 26 | 27 | Perform the query against the provided block, e.g. `BlockTag.LATEST`. 28 | 29 | ### enabled 30 | 31 | - Type: `boolean | undefined` 32 | 33 | If `false`, don't perform the query. 34 | 35 | ### refetchInterval 36 | 37 | - Type: `number | false | ((query: Query) => number | false | undefined)` 38 | 39 | If set to a number, the query is refetched at the provided interval (in milliseconds). 40 | 41 | If set to a function, the callback will be used to determine the refetch interval. 42 | 43 | ## Returns 44 | 45 | ### data 46 | 47 | - Type: `Data | undefined` 48 | 49 | The resolved data. 50 | 51 | ### error 52 | 53 | - Type: `Error | null` 54 | 55 | Any error thrown by the query. 56 | 57 | ### reset 58 | 59 | - Type: `() => void` 60 | 61 | Reset the query status. 62 | 63 | ### status 64 | 65 | - Type: `"error" | "pending" | "success"` 66 | 67 | The mutation status. 68 | 69 | - `pending`: the query is being executed. 70 | - `success`: the query executed without an error. 71 | - `error`: the query threw an error. 72 | 73 | ### isError 74 | 75 | - Type: `boolean` 76 | 77 | Derived from `status`. 78 | 79 | ### isPending 80 | 81 | - Type: `boolean` 82 | 83 | Derived from `status`. 84 | 85 | ### isSuccess 86 | 87 | - Type: `boolean` 88 | 89 | Derived from `status`. 90 | 91 | ### fetchStatus 92 | 93 | - Type: `"fetching" | "paused" | "idle"` 94 | 95 | - `fetching`: the query is fetching. 96 | - `paused`: the query is paused. 97 | - `idle`: the query is not fetching. 98 | 99 | ### isFetching 100 | 101 | - Type: `boolean` 102 | 103 | Derived from `fetchStatus`. 104 | 105 | ### isPaused 106 | 107 | - Type: `boolean` 108 | 109 | Derived from `fetchStatus`. 110 | 111 | ### isIdle 112 | 113 | - Type: `boolean` 114 | 115 | Derived from `fetchStatus`. 116 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-connect.mdx: -------------------------------------------------------------------------------- 1 | # useConnect 2 | 3 | Hook for connecting to a StarkNet wallet. 4 | 5 | ## Usage 6 | 7 | ```ts twoslash 8 | import { useConnect } from "@starknet-react/core"; 9 | 10 | const { connect, error } = useConnect({}); 11 | ``` 12 | 13 | ## Arguments 14 | 15 | No arguments are required 16 | 17 | ## Returns 18 | 19 | ### connect 20 | 21 | - Type: `(args?: ConnectVariables) => void` 22 | 23 | Function to send the request to the user, optionally overriding the arguments to the hook. 24 | 25 | ### connectAsync 26 | 27 | - Type: `(args?: ConnectVariables) => Promise` 28 | 29 | Send the request to the user and block until it receives a response. 30 | 31 | ### data 32 | 33 | - Type: `boolean | undefined` 34 | 35 | The resolved data. 36 | 37 | ### error 38 | 39 | - Type: `Error | null` 40 | 41 | Any error thrown by the mutation. 42 | 43 | ### reset 44 | 45 | - Type: `() => void` 46 | 47 | Reset the mutation status. 48 | 49 | ### variables 50 | 51 | - Type: `ConnectVariables | undefined` 52 | 53 | The variables passed to `connect` or `connectAsync`. 54 | 55 | ### status 56 | 57 | - Type: `"error" | "idle" | "pending" | "success"` 58 | 59 | The mutation status. 60 | 61 | - `idle`: the mutation has not been triggered yet. 62 | - `pending`: the mutation is being executed, e.g. waiting for the user to confirm in their wallet. 63 | - `success`: the mutation executed without an error. 64 | - `error`: the mutation threw an error. 65 | 66 | ### isError 67 | 68 | - Type: `boolean` 69 | 70 | Derived from `status`. 71 | 72 | ### isIdle 73 | 74 | - Type: `boolean` 75 | 76 | Derived from `status`. 77 | 78 | ### isPending 79 | 80 | - Type: `boolean` 81 | 82 | Derived from `status`. 83 | 84 | ### isSuccess 85 | 86 | - Type: `boolean` 87 | 88 | Derived from `status`. 89 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-contract-factory.mdx: -------------------------------------------------------------------------------- 1 | # useContractFactory 2 | 3 | Hook to create a `ContractFactory` 4 | 5 | ## Usage 6 | 7 | ```tsx 8 | import { useContractFactory } from "@starknet-react/core"; 9 | 10 | const { contractFactory } = useContractFactory({ 11 | compiledContract: compiledErc20, 12 | classHash: erc20ClassHash, 13 | abi: compiledErc20.abi, 14 | }); 15 | ``` 16 | 17 | ## Data 18 | 19 | - Type: `ContractFactory` 20 | 21 | Type `ContractFactory` from `starknet`. 22 | 23 | ## Arguments 24 | 25 | ### compiledContract 26 | 27 | - Type: `CompiledContract` 28 | 29 | Type `CompiledContract` from `starknet`. 30 | 31 | ### classHash 32 | 33 | - Type: `string` 34 | 35 | The class hash. 36 | 37 | ### abi 38 | 39 | - Type: `Abi` 40 | 41 | The contract abi. 42 | 43 | ## Returns 44 | 45 | ### contractFactory 46 | 47 | - Type: `ContractFactory | undefined` 48 | 49 | The contract factory. 50 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-contract.mdx: -------------------------------------------------------------------------------- 1 | # useContract 2 | 3 | Get a typed contract. 4 | 5 | This hook is equivalent to creating a new `Contract` instance with the 6 | current provider and then calling `typedv2` with the provided ABI. 7 | 8 | ## Usage 9 | 10 | ```ts twoslash 11 | import { useContract } from "@starknet-react/core"; 12 | 13 | const testAddress = 14 | "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"; 15 | 16 | const abi = [ 17 | { 18 | members: [ 19 | { 20 | name: "low", 21 | type: "felt", 22 | }, 23 | { 24 | name: "high", 25 | type: "felt", 26 | }, 27 | ], 28 | name: "Uint256", 29 | type: "struct", 30 | }, 31 | { 32 | inputs: [ 33 | { 34 | name: "name", 35 | type: "felt", 36 | }, 37 | { 38 | name: "symbol", 39 | type: "felt", 40 | }, 41 | { 42 | name: "recipient", 43 | type: "felt", 44 | }, 45 | ], 46 | name: "constructor", 47 | type: "constructor", 48 | }, 49 | { 50 | inputs: [], 51 | name: "name", 52 | outputs: [ 53 | { 54 | type: "felt", 55 | }, 56 | ], 57 | state_mutability: "view", 58 | type: "function", 59 | }, 60 | ] as const; 61 | 62 | const { contract } = useContract({ 63 | abi, 64 | address: testAddress, 65 | }); 66 | ``` 67 | 68 | ## Data 69 | 70 | - Type: `StarknetTypedContract` 71 | 72 | Typed contract with `abi-wan-kanabi` types. 73 | 74 | ## Arguments 75 | 76 | ### address 77 | 78 | - Type: `0x${string}` 79 | 80 | The contract address. 81 | 82 | ### abi 83 | 84 | - Type: `Abi` 85 | 86 | The contract abi. 87 | 88 | ### provider 89 | 90 | - Type: `ProviderInterface | undefined` 91 | 92 | ProviderInterface is from starknet.js. by default it will be the current one 93 | 94 | ## Returns 95 | 96 | ### contract 97 | 98 | - Type: `StarknetTypedContract | undefined` 99 | 100 | Typed Contract 101 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-disconnect.mdx: -------------------------------------------------------------------------------- 1 | # useDisconnect 2 | 3 | Hook for disconnecting connected StarkNet wallet. 4 | 5 | ## Usage 6 | 7 | ```ts twoslash 8 | import { useDisconnect } from "@starknet-react/core"; 9 | 10 | const { disconnect, error } = useDisconnect({}); 11 | ``` 12 | 13 | ## Returns 14 | 15 | ### disconnect 16 | 17 | - Type: `() => void` 18 | 19 | Function to send the request to the user, optionally overriding the arguments to the hook. 20 | 21 | ### disconnectAsync 22 | 23 | - Type: `() => Promise` 24 | 25 | Send the request to the user and block until it receives a response. 26 | 27 | ### data 28 | 29 | - Type: `void | undefined` 30 | 31 | The resolved data. 32 | 33 | ### error 34 | 35 | - Type: `Error | null` 36 | 37 | Any error thrown by the mutation. 38 | 39 | ### reset 40 | 41 | - Type: `() => void` 42 | 43 | Reset the mutation status. 44 | 45 | ### variables 46 | 47 | - Type: `void | undefined` 48 | 49 | The variables passed to `disconnect` or `disconnectAsync`. 50 | 51 | ### status 52 | 53 | - Type: `"error" | "idle" | "pending" | "success"` 54 | 55 | The mutation status. 56 | 57 | - `idle`: the mutation has not been triggered yet. 58 | - `pending`: the mutation is being executed, e.g. waiting for the user to confirm in their wallet. 59 | - `success`: the mutation executed without an error. 60 | - `error`: the mutation threw an error. 61 | 62 | ### isError 63 | 64 | - Type: `boolean` 65 | 66 | Derived from `status`. 67 | 68 | ### isIdle 69 | 70 | - Type: `boolean` 71 | 72 | Derived from `status`. 73 | 74 | ### isPending 75 | 76 | - Type: `boolean` 77 | 78 | Derived from `status`. 79 | 80 | ### isSuccess 81 | 82 | - Type: `boolean` 83 | 84 | Derived from `status`. 85 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-explorer.mdx: -------------------------------------------------------------------------------- 1 | # useExplorer 2 | 3 | Access the current explorer, should be inside a `StarknetConfig`. 4 | 5 | ## Usage 6 | 7 | ```ts twoslash 8 | import { useExplorer } from "@starknet-react/core"; 9 | 10 | const explorer = useExplorer(); 11 | ``` 12 | 13 | ## Returns 14 | 15 | ### explorer 16 | 17 | - Type: `Explorer` 18 | 19 | The current explorer, can be starkscan, voyager. 20 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-injected-connectors.mdx: -------------------------------------------------------------------------------- 1 | # useInjectedConnectors 2 | 3 | Hook for discovering injected wallets. 4 | 5 | ## Usage 6 | 7 | ```ts twoslash 8 | import { useInjectedConnectors, argent, braavos } from "@starknet-react/core"; 9 | 10 | const { connectors } = useInjectedConnectors({ 11 | // Show these connectors if the user has no connector installed. 12 | recommended: [argent(), braavos()], 13 | // Hide recommended connectors if the user has any connector installed. 14 | includeRecommended: "onlyIfNoConnectors", 15 | // Randomize the order of the connectors. 16 | order: "random", 17 | }); 18 | ``` 19 | 20 | ## Arguments 21 | 22 | ### recommended 23 | 24 | - Type: `Connector[]` 25 | 26 | Connectors recommended by Starknet React. 27 | 28 | ### includeRecommended 29 | 30 | - Type: `"always" | "onlyIfNoConnectors"` 31 | 32 | Whether to include recommended connectors in the list. 33 | 34 | ### order 35 | 36 | - Type: `"random" | "alphabetical"` 37 | 38 | How to order connectors. 39 | 40 | ## Returns 41 | 42 | ### connectors 43 | 44 | - Type: `Connector[]` 45 | 46 | List of injected wallets. 47 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-invalidate-on-block.mdx: -------------------------------------------------------------------------------- 1 | # useInvalidateOnBlock 2 | 3 | Invalidate the given query on every new block. 4 | 5 | ## Usage 6 | 7 | ```ts twoslash 8 | import { useInvalidateOnBlock } from "@starknet-react/core"; 9 | // TODO 10 | useInvalidateOnBlock({ queryKey: ["somekey"] }); 11 | ``` 12 | 13 | ## Arguments 14 | 15 | ### enabled 16 | 17 | - enabled: `boolean` 18 | 19 | Enable or disable the query from automatically running. `true` by default 20 | 21 | ### queryKey 22 | 23 | - queryKey: `QueryKey` 24 | 25 | Type from `@tanstack/react-query` 26 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-network.mdx: -------------------------------------------------------------------------------- 1 | # useNetwork 2 | 3 | Hook for accessing the current connected chain. 4 | 5 | ## Usage 6 | 7 | ```ts twoslash 8 | import { useNetwork } from "@starknet-react/core"; 9 | 10 | const { chain, chains } = useNetwork(); 11 | ``` 12 | 13 | ## Returns 14 | 15 | ### chain 16 | 17 | - Type: `Chain` 18 | 19 | The current chain. 20 | 21 | ### chains 22 | 23 | - Type: `Chain[]` 24 | 25 | List of supported chains. 26 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-provider.mdx: -------------------------------------------------------------------------------- 1 | # useProvider 2 | 3 | Hook for accessing the current provider. 4 | 5 | ## Usage 6 | 7 | ```ts twoslash 8 | import { useProvider } from "@starknet-react/core"; 9 | 10 | const { provider } = useProvider(); 11 | ``` 12 | 13 | ## Returns 14 | 15 | ### provider 16 | 17 | - Type: `ProviderInterface` 18 | 19 | The current provider. 20 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-switch-chain.mdx: -------------------------------------------------------------------------------- 1 | # useSwitchChain 2 | 3 | Hook to change the current network of the wallet. 4 | 5 | ## Usage 6 | 7 | ```ts twoslash 8 | import { useSwitchChain } from "@starknet-react/core"; 9 | import { constants } from "starknet"; 10 | 11 | const { switchChain, error } = useSwitchChain({ 12 | params: { 13 | chainId: constants.StarknetChainId.SN_SEPOLIA, 14 | }, 15 | }); 16 | ``` 17 | 18 | :::warning 19 | This hook is not supported by Braavos wallet at the moment. 20 | ::: 21 | 22 | ## Arguments 23 | 24 | ### params 25 | 26 | - Type: `SwitchStarknetChainParameters` 27 | 28 | Chain id on which to change. This type is defined in the Starknet Types package. 29 | 30 | ## Returns 31 | 32 | ### switchChain 33 | 34 | - Type: `(args?: SwitchStarknetChainParameters) => void` 35 | 36 | Function to send the request to the user, optionally overriding the arguments to the hook. 37 | 38 | ### switchChainAsync 39 | 40 | - Type: `(args?: SwitchStarknetChainParameters) => Promise` 41 | 42 | Send the request to the user and block until it receives a response. 43 | 44 | ### data 45 | 46 | - Type: `boolean | undefined` 47 | 48 | The resolved data. This type is defined in the Starknet Types package. 49 | 50 | ### error 51 | 52 | - Type: `Error | null` 53 | 54 | Any error thrown by the mutation. 55 | 56 | ### reset 57 | 58 | - Type: `() => void` 59 | 60 | Reset the mutation status. 61 | 62 | ### variables 63 | 64 | - Type: `TypedData | undefined` 65 | 66 | The variables passed to `switchChain` or `switchChainAsync`. 67 | 68 | ### status 69 | 70 | - Type: `"error" | "idle" | "pending" | "success"` 71 | 72 | The mutation status. 73 | 74 | - `idle`: the mutation has not been triggered yet. 75 | - `pending`: the mutation is being executed, e.g. waiting for the user to confirm in their wallet. 76 | - `success`: the mutation executed without an error. 77 | - `error`: the mutation threw an error. 78 | 79 | ### isError 80 | 81 | - Type: `boolean` 82 | 83 | Derived from `status`. 84 | 85 | ### isIdle 86 | 87 | - Type: `boolean` 88 | 89 | Derived from `status`. 90 | 91 | ### isPending 92 | 93 | - Type: `boolean` 94 | 95 | Derived from `status`. 96 | 97 | ### isSuccess 98 | 99 | - Type: `boolean` 100 | 101 | Derived from `status`. 102 | -------------------------------------------------------------------------------- /docs/pages/docs/hooks/use-universal-deployer-contract.mdx: -------------------------------------------------------------------------------- 1 | # useUniversalDeployerContract 2 | 3 | Get a typed contract for the Universal Deployer contract. 4 | 5 | This hook internally calls `useContract` with the Universal Deployer contract address and it's ABI. 6 | 7 | ## Usage 8 | 9 | ```ts twoslash 10 | import { useUniversalDeployerContract } from "@starknet-react/core"; 11 | 12 | const { udc } = useUniversalDeployerContract(); 13 | ``` 14 | 15 | ## Data 16 | 17 | ### udc 18 | 19 | - Type: `StarknetTypedContract` 20 | 21 | Typed contract with `abi-wan-kanabi` types. 22 | 23 | ## Arguments 24 | 25 | ### address 26 | 27 | - Type: `0x${string}` 28 | 29 | The contract address. 30 | 31 | ### provider 32 | 33 | - Type: `ProviderInterface | undefined` 34 | 35 | ProviderInterface is from starknet.js. by default it will be the current one 36 | 37 | ## Returns 38 | 39 | ### contract 40 | 41 | - Type: `StarknetTypedContract | undefined` 42 | 43 | Typed Contract 44 | -------------------------------------------------------------------------------- /docs/pages/docs/starknet-config.mdx: -------------------------------------------------------------------------------- 1 | # StarknetConfig 2 | 3 | The React Context provider for Starknet. 4 | 5 | ## Usage 6 | 7 | ```tsx twoslash 8 | "use client"; 9 | import React from "react"; 10 | 11 | import { mainnet } from "@starknet-react/chains"; 12 | import { StarknetConfig, publicProvider } from "@starknet-react/core"; 13 | 14 | function App() { 15 | return ( 16 | 17 | {/* your app here */} 18 | 19 | ); 20 | } 21 | ``` 22 | 23 | ## Arguments 24 | 25 | ### chains 26 | 27 | - Type: `Chain[]` 28 | 29 | List of supported chains. 30 | 31 | ### provider 32 | 33 | - Type: `ChainProviderFactory` 34 | 35 | The JSON-RPC provider you want to use. See [the RPC providers page](/docs/providers) for more information. 36 | 37 | ### connectors 38 | 39 | - Type: `Connector[]` 40 | 41 | List of wallet connectors you want to use. See [the wallets page](/docs/wallets) for more information. 42 | 43 | ### explorer 44 | 45 | - Type: `ExplorerFactory` 46 | 47 | Explorer factory to use. See [the explorers page](/docs/explorers) for more information. 48 | 49 | ### autoConnect 50 | 51 | - Type: `boolean | undefined` 52 | 53 | Whether to automatically connect to the first available wallet. 54 | 55 | ### queryClient 56 | 57 | - Type: `QueryClient` 58 | 59 | React Query client to use. 60 | 61 | ### defaultChainId 62 | 63 | - Type: `bigint | undefined` 64 | 65 | Default chain to use when no wallet is connected. This chain must be included in the `chains` array. 66 | -------------------------------------------------------------------------------- /docs/pages/index.mdx: -------------------------------------------------------------------------------- 1 | # Welcome 2 | -------------------------------------------------------------------------------- /docs/styles.css: -------------------------------------------------------------------------------- 1 | @layer vocs_preflight { 2 | @tailwind base; 3 | 4 | :root { 5 | --background: 242 100% 95%; 6 | --foreground: 242 5% 0%; 7 | --card: 242 50% 90%; 8 | --card-foreground: 242 5% 10%; 9 | --popover: 242 100% 95%; 10 | --popover-foreground: 242 100% 0%; 11 | --primary: 242 50.2% 55.1%; 12 | --primary-foreground: 0 0% 100%; 13 | --secondary: 242 30% 70%; 14 | --secondary-foreground: 0 0% 0%; 15 | --muted: 204 30% 85%; 16 | --muted-foreground: 242 5% 35%; 17 | --accent: 204 30% 80%; 18 | --accent-foreground: 242 5% 10%; 19 | --destructive: 0 100% 30%; 20 | --destructive-foreground: 242 5% 90%; 21 | --border: 242 30% 50%; 22 | --input: 242 30% 18%; 23 | --ring: 242 50.2% 55.1%; 24 | --radius: 0.5rem; 25 | } 26 | 27 | .dark { 28 | --background: 242 50% 5%; 29 | --foreground: 242 5% 90%; 30 | --card: 242 50% 0%; 31 | --card-foreground: 242 5% 90%; 32 | --popover: 242 50% 5%; 33 | --popover-foreground: 242 5% 90%; 34 | --primary: 242 50.2% 55.1%; 35 | --primary-foreground: 0 0% 100%; 36 | --secondary: 242 30% 10%; 37 | --secondary-foreground: 0 0% 100%; 38 | --muted: 204 30% 15%; 39 | --muted-foreground: 242 5% 60%; 40 | --accent: 204 30% 15%; 41 | --accent-foreground: 242 5% 90%; 42 | --destructive: 0 100% 30%; 43 | --destructive-foreground: 242 5% 90%; 44 | --border: 242 30% 18%; 45 | --input: 242 30% 18%; 46 | --ring: 242 50.2% 55.1%; 47 | --radius: 0.5rem; 48 | } 49 | } 50 | @tailwind components; 51 | @tailwind utilities; 52 | 53 | @layer base { 54 | * { 55 | @apply border-border; 56 | } 57 | body { 58 | /* @apply bg-background text-foreground; */ 59 | font-feature-settings: "rlig" 1, "calt" 1; 60 | } 61 | } 62 | 63 | pre { 64 | @apply dark:bg-white/5 bg-black/5 rounded-lg p-2 !text-sm; 65 | tab-size: 4; 66 | white-space: break-spaces; 67 | } 68 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@starknet-react/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "module": "ESNext", 9 | "moduleResolution": "Bundler", 10 | "resolveJsonModule": true, 11 | "target": "ES2022", 12 | "strict": true, 13 | "allowJs": true, 14 | "skipLibCheck": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "baseUrl": ".", 17 | "noEmit": true 18 | }, 19 | "include": ["**/*.ts", "**/*.tsx"] 20 | } 21 | -------------------------------------------------------------------------------- /docs/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "redirects": [ 3 | { 4 | "source": "/", 5 | "destination": "/docs/getting-started", 6 | "permanent": true 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /docs/vocs.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vocs"; 2 | 3 | import { sidebar } from "./sidebar"; 4 | 5 | export default defineConfig({ 6 | rootDir: ".", 7 | title: "Starknet React", 8 | sidebar, 9 | topNav: [ 10 | { text: "Docs", link: "/docs/getting-started", match: "/docs" }, 11 | { text: "Demo", link: "/demo", match: "/docs" }, 12 | ], 13 | }); 14 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1726560853, 9 | "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1727811607, 24 | "narHash": "sha256-2ByOBflaIUJKeF9q6efVcYHljZXGZ7MnCWtseRvmpm8=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "1839883cd0068572aed75fb9442b508bbd9ef09c", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NixOS", 32 | "ref": "nixpkgs-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 4 | flake-utils.url = "github:numtide/flake-utils"; 5 | }; 6 | 7 | outputs = { self, nixpkgs, flake-utils, ... }: 8 | flake-utils.lib.eachDefaultSystem(system: 9 | let 10 | pkgs = import nixpkgs { 11 | inherit system; 12 | }; 13 | in 14 | { 15 | devShells.default = pkgs.mkShell { 16 | nativeBuildInputs = [ 17 | pkgs.nodejs_20 18 | pkgs.biome 19 | pkgs.nodePackages.pnpm 20 | pkgs.nodePackages.typescript 21 | pkgs.nodePackages.typescript-language-server 22 | ]; 23 | }; 24 | } 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "starknet-react", 3 | "private": true, 4 | "version": "0.0.0", 5 | "license": "MIT", 6 | "scripts": { 7 | "build": "turbo run build", 8 | "dev": "turbo run dev", 9 | "test": "turbo run test --parallel", 10 | "test:ci": "turbo run test:ci --parallel", 11 | "lint": "turbo run lint --parallel", 12 | "lint:fix": "turbo run lint:fix --parallel", 13 | "format": "turbo run format --parallel", 14 | "format:check": "turbo run format:check --parallel", 15 | "clean": "turbo run clean --parallel" 16 | }, 17 | "devDependencies": { 18 | "@biomejs/biome": "^1.9.4", 19 | "@types/react": "^18.3.16", 20 | "beachball": "^2.51.0", 21 | "turbo": "^2.3.3", 22 | "typescript": "^5.7.2" 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/apibara/starknet-react.git" 27 | }, 28 | "engines": { 29 | "node": ">=20", 30 | "pnpm": ">=9" 31 | }, 32 | "packageManager": "pnpm@9.10.0", 33 | "beachball": { 34 | "prereleasePrefix": "beta", 35 | "groups": [ 36 | { 37 | "name": "v4-prerelease", 38 | "include": [ 39 | "packages/chains", 40 | "packages/core", 41 | "packages/create-starknet" 42 | ] 43 | } 44 | ], 45 | "ignorePatterns": [ 46 | "docs/**" 47 | ] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/chains/README.md: -------------------------------------------------------------------------------- 1 | # `@starknet-react/chains` 2 | 3 | References to popular Starknet chains. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install @starknet-react/chains 9 | # or 10 | yarn add @starknet-react/chains 11 | ``` 12 | 13 | ## Usage 14 | 15 | Simply import any chain you want to use. 16 | 17 | ```ts 18 | import { mainnet } from '@starknet-react/chains` 19 | ``` 20 | 21 | ## Contributing 22 | 23 | Want to add your Starknet Appchain to the list? 24 | 25 | - Add your appchain information to a new file in `src`. 26 | - Export the definitions from `src/index.ts`. 27 | - Open a PR with your changes. 28 | 29 | -------------------------------------------------------------------------------- /packages/chains/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@starknet-react/chains", 3 | "version": "4.0.1-beta.1", 4 | "license": "MIT", 5 | "repository": "apibara/starknet-react", 6 | "homepage": "https://www.starknet-react.com/", 7 | "keywords": [ 8 | "starknet", 9 | "ethereum", 10 | "l2" 11 | ], 12 | "type": "module", 13 | "main": "./src/index.ts", 14 | "exports": "./src/index.ts", 15 | "publishConfig": { 16 | "main": "dist/index.js", 17 | "types": "dist/index.d.ts", 18 | "exports": { 19 | ".": { 20 | "types": "./dist/index.d.ts", 21 | "import": "./dist/index.js", 22 | "default": "./dist/index.js" 23 | } 24 | }, 25 | "files": [ 26 | "dist", 27 | "src", 28 | "README.md" 29 | ] 30 | }, 31 | "scripts": { 32 | "build": "tsup", 33 | "clean": "rimraf dist", 34 | "lint": "biome check src", 35 | "lint:fix": "pnpm lint --write", 36 | "format:check": "biome format .", 37 | "format": "biome format . --write" 38 | }, 39 | "devDependencies": { 40 | "@starknet-react/typescript-config": "workspace:*", 41 | "rimraf": "^4.1.2", 42 | "tsup": "^8.0.2" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/chains/src/devnet.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "./types"; 2 | 3 | export const devnet = { 4 | id: BigInt("0x534e5f5345504f4c4941"), 5 | network: "devnet", 6 | name: "Starknet Devnet", 7 | nativeCurrency: { 8 | address: 9 | "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", 10 | name: "Ether", 11 | symbol: "ETH", 12 | decimals: 18, 13 | }, 14 | testnet: true, 15 | rpcUrls: { 16 | default: { 17 | http: [], 18 | }, 19 | public: { 20 | http: ["http://localhost:5050/rpc"], 21 | }, 22 | }, 23 | } as const satisfies Chain; 24 | -------------------------------------------------------------------------------- /packages/chains/src/index.ts: -------------------------------------------------------------------------------- 1 | export type { Address, Chain, NativeCurrency, RpcUrls } from "./types"; 2 | 3 | export { devnet } from "./devnet"; 4 | export { mainnet, sepolia } from "./starknet"; 5 | export { getSlotChain } from "./slot"; 6 | -------------------------------------------------------------------------------- /packages/chains/src/slot.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "./types"; 2 | 3 | export function getSlotChain(projectId: string) { 4 | return { 5 | id: BigInt(projectId), 6 | network: `slot-${projectId}`, 7 | name: `${projectId}`, 8 | nativeCurrency: { 9 | address: 10 | "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", 11 | name: "Ether", 12 | symbol: "ETH", 13 | decimals: 18, 14 | }, 15 | testnet: true, 16 | rpcUrls: { 17 | default: { 18 | http: [], 19 | }, 20 | public: { 21 | http: [`https://api.cartridge.gg/x/${projectId}/katana`], 22 | }, 23 | }, 24 | } as const satisfies Chain; 25 | } 26 | -------------------------------------------------------------------------------- /packages/chains/src/types.ts: -------------------------------------------------------------------------------- 1 | // These types are taken from `@wagmi/chains`, but since they don't export them 2 | // we have to copy them here. 3 | // All copyright belongs to weth LLC. 4 | // 5 | // Notice that `Chain.id` is a bigint, because Starknet chain ids are outside of 6 | // the number safe range. 7 | 8 | export type Address = `0x${string}`; 9 | 10 | export type Chain = { 11 | /** ID in number form */ 12 | id: bigint; 13 | 14 | /** Human-readable name */ 15 | name: string; 16 | 17 | /** Internal network name */ 18 | network: string; 19 | 20 | /** Currency used by the chain */ 21 | nativeCurrency: NativeCurrency; 22 | 23 | /** Collection of RPC endpoints */ 24 | rpcUrls: { 25 | [key: string]: RpcUrls; 26 | default: RpcUrls; 27 | public: RpcUrls; 28 | }; 29 | 30 | /** Flag for testnet networks */ 31 | testnet?: boolean; 32 | 33 | /** Explorer links*/ 34 | explorers?: { 35 | [key: string]: readonly string[]; 36 | }; 37 | }; 38 | 39 | export type NativeCurrency = { 40 | /** Token address */ 41 | address: Address; 42 | 43 | /** Human-readable name */ 44 | name: string; 45 | 46 | /** Currency symbol */ 47 | symbol: string; 48 | 49 | /** Number of decimals */ 50 | decimals: number; 51 | }; 52 | 53 | export type RpcUrls = { 54 | http: readonly string[]; 55 | websocket?: readonly string[]; 56 | }; 57 | -------------------------------------------------------------------------------- /packages/chains/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@starknet-react/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist" 5 | }, 6 | "include": ["src"], 7 | "exclude": ["node_modules", "dist"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/chains/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.ts"], 5 | splitting: false, 6 | sourcemap: true, 7 | dts: true, 8 | clean: true, 9 | format: ["esm"], 10 | }); 11 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # `@starknet-react/core` 2 | 3 | Starknet React is a collection of React hooks for Starknet. 4 | 5 | ## Installation 6 | 7 | ``` 8 | npm install @starknet-react/core 9 | # or 10 | yarn add @starknet-react/core 11 | ``` 12 | 13 | ## Documentation 14 | 15 | Documentation [is available online](https://apibara.github.io/starknet-react/). 16 | 17 | ## Development 18 | 19 | Start by installing `pnpm`, then run the following command from the root of the project: 20 | 21 | ``` 22 | pnpm install 23 | ``` 24 | 25 | Running tests requires to have `starknet-devnet` running locally. 26 | The easiest way is to use docker with: 27 | 28 | ``` 29 | docker run --rm -p 5050:5050 shardlabs/starknet-devnet:latest 30 | ``` 31 | 32 | After that, you can run tests with `pnpm test`. 33 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@starknet-react/core", 3 | "version": "4.0.1-beta.1", 4 | "license": "MIT", 5 | "repository": "apibara/starknet-react", 6 | "homepage": "https://www.starknet-react.com", 7 | "keywords": [ 8 | "starknet", 9 | "ethereum", 10 | "l2" 11 | ], 12 | "type": "module", 13 | "main": "./src/index.ts", 14 | "exports": "./src/index.ts", 15 | "publishConfig": { 16 | "main": "dist/index.js", 17 | "types": "dist/index.d.ts", 18 | "exports": { 19 | ".": { 20 | "types": "./dist/index.d.ts", 21 | "import": "./dist/index.js", 22 | "default": "./dist/index.js" 23 | } 24 | }, 25 | "files": [ 26 | "dist", 27 | "src", 28 | "README.md" 29 | ] 30 | }, 31 | "scripts": { 32 | "build": "tsup", 33 | "clean": "rimraf dist", 34 | "test": "vitest", 35 | "test:ci": "vitest run", 36 | "lint": "biome check src", 37 | "lint:fix": "pnpm lint --write", 38 | "format:check": "biome format .", 39 | "format": "biome format . --write" 40 | }, 41 | "peerDependencies": { 42 | "get-starknet-core": "^4.0.0", 43 | "react": "^18.0", 44 | "starknet": "^7.1.0" 45 | }, 46 | "devDependencies": { 47 | "@starknet-react/typescript-config": "workspace:*", 48 | "@testing-library/jest-dom": "^6.4.2", 49 | "@testing-library/react": "^15.0.4", 50 | "@vitejs/plugin-react": "^4.2.1", 51 | "jsdom": "^24.0.0", 52 | "react": "^18.2.0", 53 | "react-dom": "^18.2.0", 54 | "rimraf": "^4.1.2", 55 | "starknet": "^7.1.0", 56 | "tsup": "^8.0.2", 57 | "vite-tsconfig-paths": "^4.3.2", 58 | "vitest": "^1.5.2" 59 | }, 60 | "dependencies": { 61 | "@starknet-io/types-js": "^0.7.10", 62 | "@starknet-react/chains": "workspace:^", 63 | "@tanstack/react-query": "^5.25.0", 64 | "abi-wan-kanabi": "^2.2.4", 65 | "eventemitter3": "^5.0.1", 66 | "viem": "^2.21.1", 67 | "zod": "^3.22.4" 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /packages/core/src/connectors/base.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | RequestFnCall, 3 | RpcMessage, 4 | RpcTypeToMessageMap, 5 | StarknetWindowObject, 6 | } from "@starknet-io/types-js"; 7 | import EventEmitter from "eventemitter3"; 8 | import type { AccountInterface, ProviderInterface } from "starknet"; 9 | 10 | /** Connector icons, as base64 encoded svg. */ 11 | export type ConnectorIcons = StarknetWindowObject["icon"]; 12 | 13 | /** Connector data. */ 14 | export type ConnectorData = { 15 | /** Connector account. */ 16 | account?: string; 17 | /** Connector network. */ 18 | chainId?: bigint; 19 | }; 20 | 21 | /** Connector events. */ 22 | export interface ConnectorEvents { 23 | /** Emitted when account or network changes. */ 24 | change(data: ConnectorData): void; 25 | /** Emitted when connection is established. */ 26 | connect(data: ConnectorData): void; 27 | /** Emitted when connection is lost. */ 28 | disconnect(): void; 29 | } 30 | 31 | export type ConnectArgs = { 32 | chainIdHint?: bigint; 33 | }; 34 | 35 | export abstract class Connector extends EventEmitter { 36 | /** Unique connector id. */ 37 | abstract get id(): string; 38 | /** Connector name. */ 39 | abstract get name(): string; 40 | /** Connector icons. */ 41 | abstract get icon(): ConnectorIcons; 42 | 43 | /** Whether connector is available for use */ 44 | abstract available(): boolean; 45 | /** Whether connector is already authorized */ 46 | abstract ready(): Promise; 47 | /** Connect wallet. */ 48 | abstract connect(args: ConnectArgs): Promise; 49 | /** Disconnect wallet. */ 50 | abstract disconnect(): Promise; 51 | /** Get current account. */ 52 | abstract account(provider: ProviderInterface): Promise; 53 | /** Get current chain id. */ 54 | abstract chainId(): Promise; 55 | /** Create request call to wallet */ 56 | abstract request( 57 | call: RequestFnCall, 58 | ): Promise; 59 | } 60 | -------------------------------------------------------------------------------- /packages/core/src/connectors/helpers.ts: -------------------------------------------------------------------------------- 1 | import { InjectedConnector } from "./injected"; 2 | import { LegacyInjectedConnector } from "./legacy"; 3 | 4 | export function argent(): InjectedConnector { 5 | return new InjectedConnector({ 6 | options: { 7 | id: "argentX", 8 | name: "Argent X", 9 | }, 10 | }); 11 | } 12 | 13 | export function braavos(): InjectedConnector { 14 | return new InjectedConnector({ 15 | options: { 16 | id: "braavos", 17 | name: "Braavos", 18 | }, 19 | }); 20 | } 21 | 22 | export function injected({ id }: { id: string }): InjectedConnector { 23 | return new InjectedConnector({ 24 | options: { 25 | id, 26 | }, 27 | }); 28 | } 29 | 30 | export function legacyInjected({ 31 | id, 32 | }: { id: string }): LegacyInjectedConnector { 33 | return new LegacyInjectedConnector({ 34 | options: { 35 | id, 36 | }, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /packages/core/src/connectors/index.ts: -------------------------------------------------------------------------------- 1 | export { Connector, type ConnectArgs } from "./base"; 2 | export { InjectedConnector, type InjectedConnectorOptions } from "./injected"; 3 | export { 4 | LegacyInjectedConnector, 5 | type LegacyInjectedConnectorOptions, 6 | } from "./legacy"; 7 | export { 8 | type UseInjectedConnectorsProps, 9 | type UseInjectedConnectorsResult, 10 | useInjectedConnectors, 11 | } from "./discovery"; 12 | export { 13 | MockConnector, 14 | type MockConnectorAccounts, 15 | type MockConnectorOptions, 16 | } from "./mock"; 17 | export { argent, braavos, injected, legacyInjected } from "./helpers"; 18 | -------------------------------------------------------------------------------- /packages/core/src/context/account.tsx: -------------------------------------------------------------------------------- 1 | import type { Address } from "@starknet-react/chains"; 2 | import React, { useContext } from "react"; 3 | 4 | import type { AccountInterface } from "starknet"; 5 | 6 | const AccountContext = React.createContext<{ 7 | account: AccountInterface | undefined; 8 | address: Address | undefined; 9 | }>({ 10 | account: undefined, 11 | address: undefined, 12 | }); 13 | 14 | export function useStarknetAccount() { 15 | const { account, address } = useContext(AccountContext); 16 | return { account, address }; 17 | } 18 | 19 | export function AccountProvider({ 20 | address, 21 | account, 22 | children, 23 | }: { 24 | address?: Address; 25 | account?: AccountInterface; 26 | children: React.ReactNode; 27 | }) { 28 | return ( 29 | 30 | {children} 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /packages/core/src/context/index.tsx: -------------------------------------------------------------------------------- 1 | import { StarknetProvider, type StarknetProviderProps } from "./starknet"; 2 | 3 | export { starknetChainId } from "./starknet"; 4 | export { AccountProvider as OverrideAccount } from "./account"; 5 | 6 | export type StarknetConfigProps = StarknetProviderProps; 7 | 8 | export function StarknetConfig({ children, ...config }: StarknetConfigProps) { 9 | return {children}; 10 | } 11 | -------------------------------------------------------------------------------- /packages/core/src/errors.ts: -------------------------------------------------------------------------------- 1 | export class ConnectorAlreadyConnectedError extends Error { 2 | override name = "ConnectorAlreadyConnectedError"; 3 | override message = "Connector already connected"; 4 | } 5 | 6 | export class ConnectorNotConnectedError extends Error { 7 | override name = "ConnectorNotConnectedError"; 8 | override message = "Connector not connected"; 9 | } 10 | 11 | export class ConnectorNotFoundError extends Error { 12 | override name = "ConnectorNotFoundError"; 13 | override message = "Connector not found"; 14 | } 15 | 16 | export class UserRejectedRequestError extends Error { 17 | override name = "UserRejectedRequestError"; 18 | override message = "User rejected request"; 19 | } 20 | 21 | export class WalletRequestError extends Error { 22 | constructor(error?: string | Error | unknown, cause?: Error | unknown) { 23 | super( 24 | error instanceof Error 25 | ? error.message 26 | : typeof error === "string" 27 | ? error 28 | : "Unknown Request Error", 29 | ); 30 | this.name = "WalletRequestError"; 31 | this.stack = error instanceof Error ? error.stack : undefined; 32 | } 33 | } 34 | 35 | export class UserNotConnectedError extends Error { 36 | override name = "UserNotConnectedError"; 37 | override message = "User not connected"; 38 | } 39 | 40 | export class UnsupportedAccountInterfaceError extends Error { 41 | override name = "UnsupportedAccountInterfaceError"; 42 | override message = 43 | "Unsupported account interface. starknet-react v1 only supports the starknet.js v5 account interface"; 44 | } 45 | -------------------------------------------------------------------------------- /packages/core/src/explorers/cartridge.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "@starknet-react/chains"; 2 | import type { Explorer, ExplorerFactory } from "./explorer"; 3 | 4 | // Define the StarkscanExplorer class that extends Explorer 5 | export class CartridgeExplorer implements Explorer { 6 | public name = "Cartridge Explorer"; 7 | private link: string; 8 | 9 | constructor(chain: Chain) { 10 | this.link = chain.explorers?.["cartridge"]?.toString() ?? ""; 11 | } 12 | 13 | block(hashOrNumber: { hash?: string; number?: number }): string { 14 | return `${this.link}/block/${hashOrNumber.hash ?? hashOrNumber.number}`; 15 | } 16 | 17 | transaction(hash: string): string { 18 | return `${this.link}/tx/${hash}`; 19 | } 20 | 21 | contract(address: string): string { 22 | return `${this.link}/contract/${address}`; 23 | } 24 | 25 | class(hash: string): string { 26 | return `${this.link}/class/${hash}`; 27 | } 28 | } 29 | 30 | // Define the starkscan factory function 31 | export const cartridge: ExplorerFactory = (chain: Chain) => { 32 | return new CartridgeExplorer(chain); 33 | }; 34 | -------------------------------------------------------------------------------- /packages/core/src/explorers/explorer.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "@starknet-react/chains"; 2 | 3 | export interface Explorer { 4 | // link to a block 5 | block(hashOrNumber: { hash?: string; number?: number }): string; 6 | // link to a transaction 7 | transaction(hash: string): string; 8 | // link to a contract/account 9 | contract(address: string): string; 10 | // link to class hash 11 | class(hash: string): string; 12 | // the name of the explorer 13 | name: string; 14 | } 15 | 16 | export type ExplorerFactory = ( 17 | chain: Chain, 18 | ) => T | null; 19 | -------------------------------------------------------------------------------- /packages/core/src/explorers/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./cartridge"; 2 | export * from "./explorer"; 3 | export * from "./starkscan"; 4 | export * from "./viewblock"; 5 | export * from "./voyager"; 6 | -------------------------------------------------------------------------------- /packages/core/src/explorers/starkscan.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "@starknet-react/chains"; 2 | import type { Explorer, ExplorerFactory } from "./explorer"; 3 | 4 | // Define the StarkscanExplorer class that extends Explorer 5 | export class StarkscanExplorer implements Explorer { 6 | public name = "Starkscan"; 7 | private link: string; 8 | 9 | constructor(chain: Chain) { 10 | this.link = chain.explorers?.["starkscan"]?.toString() ?? ""; 11 | } 12 | 13 | block(hashOrNumber: { hash?: string; number?: number }): string { 14 | return `${this.link}/block/${hashOrNumber.hash ?? hashOrNumber.number}`; 15 | } 16 | 17 | transaction(hash: string): string { 18 | return `${this.link}/tx/${hash}`; 19 | } 20 | 21 | contract(address: string): string { 22 | return `${this.link}/contract/${address}`; 23 | } 24 | 25 | class(hash: string): string { 26 | return `${this.link}/class/${hash}`; 27 | } 28 | } 29 | 30 | // Define the starkscan factory function 31 | export const starkscan: ExplorerFactory = (chain: Chain) => { 32 | return new StarkscanExplorer(chain); 33 | }; 34 | -------------------------------------------------------------------------------- /packages/core/src/explorers/viewblock.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "@starknet-react/chains"; 2 | import type { Explorer, ExplorerFactory } from "./explorer"; 3 | 4 | // Define the ViewblockExplorer class that extends Explorer 5 | export class ViewblockExplorer implements Explorer { 6 | public name = "Viewblock"; 7 | private link: string; 8 | 9 | constructor(chain: Chain) { 10 | this.link = chain.explorers?.["viewblock"]?.toString() ?? ""; 11 | } 12 | 13 | block(hashOrNumber: { hash?: string; number?: number }): string { 14 | if (hashOrNumber.hash && hashOrNumber.number === undefined) { 15 | throw new Error( 16 | "The viewblock explorer doesnt support hashes for blocks. Please provide a hash.", 17 | ); 18 | } 19 | return `${this.link}/block/${hashOrNumber.number}`; 20 | } 21 | 22 | transaction(hash: string): string { 23 | return `${this.link}/tx/${hash}`; 24 | } 25 | 26 | contract(address: string): string { 27 | return `${this.link}/contract/${address}`; 28 | } 29 | 30 | class(hash: string): string { 31 | return `${this.link}/class/${hash}`; 32 | } 33 | } 34 | 35 | // Define the viewblock factory function 36 | export const viewblock: ExplorerFactory = (chain: Chain) => { 37 | return new ViewblockExplorer(chain); 38 | }; 39 | -------------------------------------------------------------------------------- /packages/core/src/explorers/voyager.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "@starknet-react/chains"; 2 | import type { Explorer, ExplorerFactory } from "./explorer"; 3 | 4 | // Define the VoyagerExplorer class that extends Explorer 5 | export class VoyagerExplorer implements Explorer { 6 | public name = "Voyager"; 7 | private link: string; 8 | 9 | constructor(chain: Chain) { 10 | this.link = chain.explorers?.["voyager"]?.toString() ?? ""; 11 | } 12 | 13 | block(hashOrNumber: { hash?: string; number?: number }): string { 14 | if (hashOrNumber.number !== undefined && hashOrNumber.hash === undefined) { 15 | throw new Error( 16 | "The voyager explorer doesn't support numbers for blocks. Please provide a hash.", 17 | ); 18 | } 19 | return `${this.link}/block/${hashOrNumber.hash}`; 20 | } 21 | 22 | transaction(hash: string): string { 23 | return `${this.link}/tx/${hash}`; 24 | } 25 | 26 | contract(address: string): string { 27 | return `${this.link}/contract/${address}`; 28 | } 29 | 30 | class(hash: string): string { 31 | return `${this.link}/class/${hash}`; 32 | } 33 | } 34 | 35 | // Define the voyager factory function 36 | export const voyager: ExplorerFactory = (chain: Chain) => { 37 | return new VoyagerExplorer(chain); 38 | }; 39 | -------------------------------------------------------------------------------- /packages/core/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./use-account"; 2 | export * from "./use-add-chain"; 3 | export * from "./use-balance"; 4 | export * from "./use-block"; 5 | export * from "./use-block-number"; 6 | export * from "./use-call"; 7 | export * from "./use-connect"; 8 | export * from "./use-contract"; 9 | export * from "./use-contract-factory"; 10 | export * from "./use-declare-contract"; 11 | export * from "./use-deploy-account"; 12 | export * from "./use-disconnect"; 13 | export * from "./use-estimate-fees"; 14 | export * from "./use-explorer"; 15 | export * from "./use-invalidate-on-block"; 16 | export * from "./use-network"; 17 | export * from "./use-nonce-for-address"; 18 | export * from "./use-provider"; 19 | export * from "./use-read-contract"; 20 | export * from "./use-send-transaction"; 21 | export * from "./use-sign"; 22 | export * from "./use-stark-address"; 23 | export * from "./use-stark-name"; 24 | export * from "./use-stark-profile"; 25 | export * from "./use-switch-chain"; 26 | export * from "./use-transaction-receipt"; 27 | export * from "./use-wallet-request"; 28 | export * from "./use-watch-asset"; 29 | export * from "./use-universal-deployer-contract"; 30 | export * from "./use-events"; 31 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-add-chain.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { act, renderHook, waitFor } from "../../test/react"; 3 | 4 | import { shortString } from "starknet"; 5 | import { defaultConnector } from "../../test/devnet"; 6 | import { type UseAddChainArgs, useAddChain } from "./use-add-chain"; 7 | import { useConnect } from "./use-connect"; 8 | import { useDisconnect } from "./use-disconnect"; 9 | 10 | // Reference: https://github.com/PhilippeR26/Starknet-WalletAccount/blob/main/doc/walletAPIspec.md#example--3 11 | const chainData: UseAddChainArgs = { 12 | id: "ZORG", 13 | chain_id: shortString.encodeShortString("ZORG"), 14 | chain_name: "ZORG", 15 | rpc_urls: ["http://192.168.1.44:6060"], 16 | native_currency: { 17 | type: "ERC20", 18 | options: { 19 | address: 20 | "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", 21 | name: "ETHER", 22 | symbol: "ETH", 23 | decimals: 18, 24 | }, 25 | }, 26 | }; 27 | 28 | function useAddChainWithConnect() { 29 | return { 30 | addChain: useAddChain({ params: chainData }), 31 | connect: useConnect(), 32 | disconnect: useDisconnect(), 33 | }; 34 | } 35 | 36 | describe("useAddChain", () => { 37 | it("adds a new chain to the connector", async () => { 38 | const { result } = renderHook(() => useAddChainWithConnect()); 39 | 40 | await act(async () => { 41 | result.current.connect.connect({ 42 | connector: defaultConnector, 43 | }); 44 | }); 45 | 46 | await act(async () => { 47 | result.current.addChain.addChain(); 48 | }); 49 | 50 | await waitFor(() => { 51 | expect(result.current.addChain.isSuccess).toBeTruthy(); 52 | }); 53 | }); 54 | 55 | it("throws error if user doesn't approve the new chain", async () => { 56 | const { result } = renderHook(() => useAddChainWithConnect(), { 57 | connectorOptions: { rejectRequest: true }, 58 | }); 59 | await act(async () => { 60 | result.current.connect.connect({ 61 | connector: defaultConnector, 62 | }); 63 | }); 64 | await act(async () => { 65 | result.current.addChain.addChain(); 66 | }); 67 | await waitFor(() => { 68 | expect(result.current.addChain.isError).toBeTruthy(); 69 | }); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-add-chain.ts: -------------------------------------------------------------------------------- 1 | import type { AddStarknetChainParameters } from "@starknet-io/types-js"; 2 | 3 | import { 4 | type RequestArgs, 5 | type RequestResult, 6 | type UseWalletRequestProps, 7 | type UseWalletRequestResult, 8 | useWalletRequest, 9 | } from "./use-wallet-request"; 10 | 11 | export type UseAddChainArgs = AddStarknetChainParameters; 12 | 13 | export type UseAddChainProps = Omit< 14 | UseWalletRequestProps<"wallet_addStarknetChain">, 15 | keyof RequestArgs<"wallet_addStarknetChain"> 16 | > & { 17 | params?: UseAddChainArgs; 18 | }; 19 | 20 | export type UseAddChainResult = Omit< 21 | UseWalletRequestResult<"wallet_addStarknetChain">, 22 | "request" | "requestAsync" 23 | > & { 24 | addChain: (args?: UseAddChainArgs) => void; 25 | addChainAsync: ( 26 | args?: UseAddChainArgs, 27 | ) => Promise>; 28 | }; 29 | 30 | /** 31 | * Hook to add a new network in the list of networks of the wallet. 32 | */ 33 | export function useAddChain(props: UseAddChainProps): UseAddChainResult { 34 | const { params, ...rest } = props; 35 | 36 | const { request, requestAsync, ...result } = useWalletRequest({ 37 | type: "wallet_addStarknetChain", 38 | params, 39 | ...rest, 40 | }); 41 | 42 | const addChain = (args?: UseAddChainArgs) => { 43 | return request( 44 | args 45 | ? { 46 | params: args, 47 | type: "wallet_addStarknetChain", 48 | } 49 | : undefined, 50 | ); 51 | }; 52 | 53 | const addChainAsync = (args?: UseAddChainArgs) => { 54 | return requestAsync( 55 | args 56 | ? { 57 | params: args, 58 | type: "wallet_addStarknetChain", 59 | } 60 | : undefined, 61 | ); 62 | }; 63 | 64 | return { 65 | addChain, 66 | addChainAsync, 67 | ...result, 68 | }; 69 | } 70 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-balance.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { accounts } from "../../test/devnet"; 3 | import { renderHook, waitFor } from "../../test/react"; 4 | 5 | import { useBalance } from "./use-balance"; 6 | 7 | describe("useBalance", () => { 8 | describe("when address is undefined", () => { 9 | it("returns no balance", async () => { 10 | const { result } = renderHook(() => useBalance({})); 11 | 12 | await waitFor(() => { 13 | expect(result.current.fetchStatus).toEqual("idle"); 14 | }); 15 | 16 | expect(result.current).toMatchInlineSnapshot(` 17 | { 18 | "data": undefined, 19 | "error": null, 20 | "fetchStatus": "idle", 21 | "isError": false, 22 | "isFetching": false, 23 | "isLoading": false, 24 | "isPending": true, 25 | "isSuccess": false, 26 | "refetch": [Function], 27 | "status": "pending", 28 | } 29 | `); 30 | }); 31 | }); 32 | 33 | describe("when address is defined", () => { 34 | it("returns the balance", async () => { 35 | const { result } = renderHook(() => 36 | useBalance({ 37 | address: accounts.sepolia[0].address as `0x${string}`, 38 | }), 39 | ); 40 | 41 | await waitFor(() => { 42 | const { data, ...rest } = result.current; 43 | expect(data).toBeDefined(); 44 | expect(rest).toMatchInlineSnapshot(` 45 | { 46 | "error": null, 47 | "fetchStatus": "idle", 48 | "isError": false, 49 | "isFetching": false, 50 | "isLoading": false, 51 | "isPending": false, 52 | "isSuccess": true, 53 | "refetch": [Function], 54 | "status": "success", 55 | } 56 | `); 57 | }); 58 | }); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-block-number.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { renderHook, waitFor } from "../../test/react"; 3 | 4 | import { useBlockNumber } from "./use-block-number"; 5 | 6 | describe("useBlockNumber", () => { 7 | it("returns the current block number", async () => { 8 | const { result } = renderHook(() => useBlockNumber()); 9 | 10 | await waitFor(() => { 11 | expect(result.current.status).toEqual("success"); 12 | }); 13 | 14 | const { data, ...rest } = result.current; 15 | expect(data).toBeDefined(); 16 | expect(rest).toMatchInlineSnapshot(` 17 | { 18 | "error": null, 19 | "fetchStatus": "idle", 20 | "isError": false, 21 | "isFetching": false, 22 | "isLoading": false, 23 | "isPending": false, 24 | "isSuccess": true, 25 | "refetch": [Function], 26 | "status": "success", 27 | } 28 | `); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-block-number.ts: -------------------------------------------------------------------------------- 1 | import { type BlockNumber, BlockTag, type ProviderInterface } from "starknet"; 2 | 3 | import { useStarknet } from "../context/starknet"; 4 | import { type UseQueryProps, type UseQueryResult, useQuery } from "../query"; 5 | 6 | /** Arguments for `useBlockNumber`. */ 7 | export type UseBlockNumberProps = UseQueryProps< 8 | number | undefined, 9 | Error, 10 | number, 11 | ReturnType 12 | > & { 13 | /** Identifier for the block to fetch. */ 14 | blockIdentifier?: BlockNumber; 15 | }; 16 | 17 | /** Value returned from `useBlockNumber`. */ 18 | export type UseBlockNumberResult = UseQueryResult; 19 | 20 | /** 21 | * Hook for fetching the current block number. 22 | * 23 | * @remarks 24 | * 25 | * Control if and how often data is refreshed with `refetchInterval`. 26 | */ 27 | export function useBlockNumber({ 28 | blockIdentifier = BlockTag.LATEST, 29 | ...props 30 | }: UseBlockNumberProps = {}): UseBlockNumberResult { 31 | const { provider } = useStarknet(); 32 | 33 | return useQuery({ 34 | queryKey: queryKey({ blockIdentifier }), 35 | queryFn: queryFn({ provider, blockIdentifier }), 36 | ...props, 37 | }); 38 | } 39 | 40 | function queryKey({ blockIdentifier }: { blockIdentifier: BlockNumber }) { 41 | return [{ entity: "blockNumber", blockIdentifier }] as const; 42 | } 43 | 44 | function queryFn({ 45 | provider, 46 | blockIdentifier, 47 | }: { 48 | provider: ProviderInterface; 49 | blockIdentifier: BlockNumber; 50 | }) { 51 | return async () => { 52 | const block = await provider.getBlock(blockIdentifier); 53 | if (block.status !== "PENDING") { 54 | return block.block_number; 55 | } 56 | return undefined; 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-block.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { renderHook, waitFor } from "../../test/react"; 3 | 4 | import { useBlock } from "./use-block"; 5 | 6 | describe("useBlock", () => { 7 | it("returns the latest block", async () => { 8 | const { result } = renderHook(() => useBlock()); 9 | 10 | await waitFor(() => { 11 | expect(result.current.status).toEqual("success"); 12 | }); 13 | 14 | const { data, ...rest } = result.current; 15 | expect(data).toBeDefined(); 16 | expect(rest).toMatchInlineSnapshot(` 17 | { 18 | "error": null, 19 | "fetchStatus": "idle", 20 | "isError": false, 21 | "isFetching": false, 22 | "isLoading": false, 23 | "isPending": false, 24 | "isSuccess": true, 25 | "refetch": [Function], 26 | "status": "success", 27 | } 28 | `); 29 | }); 30 | 31 | it("returns an error if the block doesn't exist", async () => { 32 | const { result } = renderHook(() => useBlock({ blockIdentifier: 999999 })); 33 | 34 | await waitFor(() => { 35 | expect(result.current.isError).toBeTruthy(); 36 | }); 37 | 38 | const { data } = result.current; 39 | expect(data).toBeUndefined(); 40 | expect(result.current).toMatchInlineSnapshot(` 41 | { 42 | "data": undefined, 43 | "error": [RpcError: RPC: starknet_getBlockWithTxHashes with params { 44 | "block_id": { 45 | "block_number": 999999 46 | } 47 | } 48 | 49 | 24: Block not found: undefined], 50 | "fetchStatus": "idle", 51 | "isError": true, 52 | "isFetching": false, 53 | "isLoading": false, 54 | "isPending": false, 55 | "isSuccess": false, 56 | "refetch": [Function], 57 | "status": "error", 58 | } 59 | `); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-block.ts: -------------------------------------------------------------------------------- 1 | import { 2 | type BlockNumber, 3 | BlockTag, 4 | type GetBlockResponse, 5 | type ProviderInterface, 6 | } from "starknet"; 7 | 8 | import { useStarknet } from "../context/starknet"; 9 | import { type UseQueryProps, type UseQueryResult, useQuery } from "../query"; 10 | 11 | /** Arguments for `useBlock`. */ 12 | export type UseBlockProps = UseQueryProps< 13 | GetBlockResponse, 14 | Error, 15 | GetBlockResponse, 16 | ReturnType 17 | > & { 18 | /** Identifier for the block to fetch. */ 19 | blockIdentifier?: BlockNumber; 20 | }; 21 | 22 | /** Value returned from `useBlock`. */ 23 | export type UseBlockResult = UseQueryResult; 24 | 25 | /** 26 | * Hook for fetching a block. 27 | * 28 | * @remarks 29 | * 30 | * Specify which block to fetch with the `blockIdentifier` argument. 31 | * Control if and how often data is refreshed with `refetchInterval`. 32 | */ 33 | export function useBlock({ 34 | blockIdentifier = BlockTag.LATEST, 35 | ...props 36 | }: UseBlockProps = {}): UseBlockResult { 37 | const { provider } = useStarknet(); 38 | return useQuery({ 39 | queryKey: queryKey({ blockIdentifier }), 40 | queryFn: queryFn({ provider, blockIdentifier }), 41 | ...props, 42 | }); 43 | } 44 | 45 | function queryKey({ blockIdentifier }: { blockIdentifier: BlockNumber }) { 46 | return [{ entity: "block", blockIdentifier }] as const; 47 | } 48 | 49 | function queryFn({ 50 | provider, 51 | blockIdentifier, 52 | }: { 53 | provider: ProviderInterface; 54 | blockIdentifier: BlockNumber; 55 | }) { 56 | return async () => await provider.getBlock(blockIdentifier); 57 | } 58 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-call.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { accounts, tokenAddress } from "../../test/devnet"; 3 | import { renderHook, waitFor } from "../../test/react"; 4 | import { useCall } from "./use-call"; 5 | 6 | const abi = [ 7 | { 8 | name: "core::integer::u256", 9 | type: "struct", 10 | members: [ 11 | { 12 | name: "low", 13 | type: "core::integer::u128", 14 | }, 15 | { 16 | name: "high", 17 | type: "core::integer::u128", 18 | }, 19 | ], 20 | }, 21 | { 22 | name: "balanceOf", 23 | type: "function", 24 | inputs: [ 25 | { 26 | name: "account", 27 | type: "core::starknet::contract_address::ContractAddress", 28 | }, 29 | ], 30 | outputs: [ 31 | { 32 | type: "core::integer::u256", 33 | }, 34 | ], 35 | state_mutability: "view", 36 | }, 37 | ] as const; 38 | 39 | describe("useCall", () => { 40 | it("returns the call result", async () => { 41 | const { result } = renderHook(() => 42 | useCall({ 43 | functionName: "balanceOf", 44 | args: [accounts.sepolia[0].address], 45 | abi, 46 | address: tokenAddress, 47 | watch: true, 48 | }), 49 | ); 50 | 51 | await waitFor(() => { 52 | expect(result.current.isSuccess).toBeTruthy(); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-connect.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { act, renderHook, waitFor } from "../../test/react"; 3 | 4 | import { useConnect } from "./use-connect"; 5 | 6 | describe("useConnect", () => { 7 | it("connects the specified connector", async () => { 8 | const { result } = renderHook(() => useConnect()); 9 | 10 | await waitFor(() => { 11 | expect(result.current.connector).toBeUndefined(); 12 | expect(result.current.connectors).toHaveLength(1); 13 | }); 14 | 15 | await act(async () => { 16 | const connector = result.current.connectors[0]; 17 | await result.current.connectAsync({ connector }); 18 | }); 19 | 20 | await waitFor(() => { 21 | expect(result.current.connector).toBeDefined(); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-connect.ts: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react"; 2 | 3 | import type { Connector } from "../connectors/base"; 4 | import { useStarknet } from "../context/starknet"; 5 | import { 6 | type UseMutationProps, 7 | type UseMutationResult, 8 | useMutation, 9 | } from "../query"; 10 | 11 | export type ConnectVariables = { connector?: Connector }; 12 | 13 | type MutationResult = UseMutationResult; 14 | 15 | export type UseConnectProps = UseMutationProps; 16 | 17 | /** Value returned from `useConnect`. */ 18 | export type UseConnectResult = Omit< 19 | MutationResult, 20 | "mutate" | "mutateAsync" 21 | > & { 22 | /** Current connector. */ 23 | connector?: Connector; 24 | /** Connectors available for the current chain. */ 25 | connectors: Connector[]; 26 | /** Connector waiting approval for connection. */ 27 | pendingConnector?: Connector; 28 | /** Connect to a new connector. */ 29 | connect: (args?: ConnectVariables) => void; 30 | /** Connect to a new connector. */ 31 | connectAsync: (args?: ConnectVariables) => Promise; 32 | }; 33 | 34 | /** 35 | * Hook for connecting to a StarkNet wallet. 36 | * 37 | * @remarks 38 | * 39 | * Use this to implement a "connect wallet" component. 40 | * 41 | * ``` 42 | */ 43 | export function useConnect(props: UseConnectProps = {}): UseConnectResult { 44 | const { connector, connectors, connect: connect_, chain } = useStarknet(); 45 | 46 | const { mutate, mutateAsync, variables, ...result } = useMutation({ 47 | mutationKey: [{ entity: "connect", chainId: chain.name }], 48 | mutationFn: connect_, 49 | ...props, 50 | }); 51 | 52 | const connect = useCallback( 53 | (args?: ConnectVariables) => mutate(args ?? { connector }), 54 | [mutate, connector], 55 | ); 56 | 57 | const connectAsync = useCallback( 58 | (args?: ConnectVariables) => mutateAsync(args ?? { connector }), 59 | [mutateAsync, connector], 60 | ); 61 | 62 | return { 63 | connector, 64 | connectors, 65 | pendingConnector: variables?.connector, 66 | connect, 67 | connectAsync, 68 | variables, 69 | ...result, 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-contract-factory.ts: -------------------------------------------------------------------------------- 1 | import { useMemo } from "react"; 2 | import { type Abi, type CompiledContract, ContractFactory } from "starknet"; 3 | 4 | import { useAccount } from "./use-account"; 5 | 6 | /** Arguments for `useContractFactory`. */ 7 | export interface UseContractFactoryProps { 8 | /** The compiled contract. */ 9 | compiledContract?: CompiledContract; 10 | /** The class hash */ 11 | classHash: string; 12 | /** The contract abi. */ 13 | abi?: Abi; 14 | } 15 | 16 | /** Value returned from `useContractFactory`. */ 17 | export interface UseContractFactoryResult { 18 | /** The contract factory. */ 19 | contractFactory?: ContractFactory; 20 | } 21 | 22 | /** 23 | * Hook to create a `ContractFactory`. 24 | * 25 | * @remarks 26 | * 27 | * The returned contract factory is a starknet.js `ContractFactory` object. 28 | * 29 | * This hook works well with `useDeploy`. 30 | */ 31 | export function useContractFactory({ 32 | compiledContract, 33 | classHash, 34 | abi, 35 | }: UseContractFactoryProps): UseContractFactoryResult { 36 | const { account } = useAccount(); 37 | 38 | const contractFactory = useMemo(() => { 39 | if (compiledContract && account && classHash) { 40 | return new ContractFactory({ 41 | compiledContract, 42 | classHash, 43 | account, 44 | abi, 45 | }); 46 | } 47 | return undefined; 48 | }, [compiledContract, classHash, account, abi]); 49 | 50 | return { contractFactory }; 51 | } 52 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-declare-contract.ts: -------------------------------------------------------------------------------- 1 | import type { AddDeclareTransactionParameters } from "@starknet-io/types-js"; 2 | 3 | import { 4 | type RequestArgs, 5 | type RequestResult, 6 | type UseWalletRequestProps, 7 | type UseWalletRequestResult, 8 | useWalletRequest, 9 | } from "./use-wallet-request"; 10 | 11 | export type UseDeclareContractArgs = AddDeclareTransactionParameters; 12 | 13 | export type UseDeclareContractProps = Omit< 14 | UseWalletRequestProps<"wallet_addDeclareTransaction">, 15 | keyof RequestArgs<"wallet_addDeclareTransaction"> 16 | > & { 17 | params?: UseDeclareContractArgs; 18 | }; 19 | 20 | export type UseDeclareContractResult = Omit< 21 | UseWalletRequestResult<"wallet_addDeclareTransaction">, 22 | "request" | "requestAsync" 23 | > & { 24 | declare: (args?: UseDeclareContractArgs) => void; 25 | declareAsync: ( 26 | args?: UseDeclareContractArgs, 27 | ) => Promise>; 28 | }; 29 | 30 | /** 31 | * Hook to declare a new class in the current network. 32 | * 33 | */ 34 | export function useDeclareContract( 35 | props: UseDeclareContractProps, 36 | ): UseDeclareContractResult { 37 | const { params, ...rest } = props; 38 | 39 | const { request, requestAsync, ...result } = useWalletRequest({ 40 | type: "wallet_addDeclareTransaction", 41 | params, 42 | ...rest, 43 | }); 44 | 45 | const declare = (args?: UseDeclareContractArgs) => { 46 | return request( 47 | args 48 | ? { 49 | params: args, 50 | type: "wallet_addDeclareTransaction", 51 | } 52 | : undefined, 53 | ); 54 | }; 55 | 56 | const declareAsync = (args?: UseDeclareContractArgs) => { 57 | return requestAsync( 58 | args 59 | ? { 60 | params: args, 61 | type: "wallet_addDeclareTransaction", 62 | } 63 | : undefined, 64 | ); 65 | }; 66 | 67 | return { 68 | declare, 69 | declareAsync, 70 | ...result, 71 | }; 72 | } 73 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-disconnect.ts: -------------------------------------------------------------------------------- 1 | import { useStarknet } from "../context/starknet"; 2 | import { 3 | type UseMutationProps, 4 | type UseMutationResult, 5 | useMutation, 6 | } from "../query"; 7 | 8 | type MutationResult = UseMutationResult; 9 | 10 | export type UseDisconnectProps = UseMutationProps; 11 | 12 | /** Value returned from `useDisconnect`. */ 13 | export type UseDisconnectResult = Omit< 14 | MutationResult, 15 | "mutate" | "mutateAsync" 16 | > & { 17 | /** Disconnect wallet. */ 18 | disconnect: MutationResult["mutate"]; 19 | /** Disconnect wallet. */ 20 | disconnectAsync: MutationResult["mutateAsync"]; 21 | }; 22 | 23 | /** 24 | * 25 | * Hook for disconnecting connected wallet. 26 | */ 27 | export function useDisconnect( 28 | props: UseDisconnectProps = {}, 29 | ): UseDisconnectResult { 30 | const { disconnect, chain } = useStarknet(); 31 | 32 | const { mutate, mutateAsync, ...result } = useMutation({ 33 | mutationKey: [{ entity: "disconnect", chainId: chain.name }], 34 | mutationFn: disconnect, 35 | ...props, 36 | }); 37 | 38 | return { 39 | disconnect: mutate, 40 | disconnectAsync: mutateAsync, 41 | ...result, 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-estimate-fees.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { act, renderHook, waitFor } from "../../test/react"; 3 | 4 | import type { Abi } from "abi-wan-kanabi"; 5 | import { defaultConnector } from "../../test/devnet"; 6 | import { useAccount } from "./use-account"; 7 | import { useConnect } from "./use-connect"; 8 | import { useContract } from "./use-contract"; 9 | import { useDisconnect } from "./use-disconnect"; 10 | import { useEstimateFees } from "./use-estimate-fees"; 11 | import { useNetwork } from "./use-network"; 12 | 13 | function useEstimateFeesWithConnect() { 14 | const { chain } = useNetwork(); 15 | 16 | const { contract } = useContract({ 17 | abi, 18 | address: chain.nativeCurrency.address, 19 | }); 20 | 21 | const { address } = useAccount(); 22 | 23 | const calls = 24 | contract && address 25 | ? [contract.populate("transfer", [address, 1n])] 26 | : undefined; 27 | 28 | return { 29 | estimateFees: useEstimateFees({ calls }), 30 | connect: useConnect(), 31 | disconnect: useDisconnect(), 32 | }; 33 | } 34 | 35 | describe.skip("useEstimateFees", () => { 36 | it("estimate sucessfull if account is connected", async () => { 37 | const { result } = renderHook(() => useEstimateFeesWithConnect()); 38 | 39 | await act(async () => { 40 | result.current.connect.connect({ 41 | connector: defaultConnector, 42 | }); 43 | }); 44 | 45 | await waitFor(() => { 46 | expect(result.current.estimateFees.isSuccess).toBeTruthy(); 47 | }); 48 | }); 49 | 50 | it("estimate fails if account is not connected", async () => { 51 | const { result } = renderHook(() => useEstimateFeesWithConnect()); 52 | 53 | await waitFor(() => { 54 | expect(result.current.estimateFees.isError).toBeTruthy(); 55 | }); 56 | }); 57 | }); 58 | 59 | const abi = [ 60 | { 61 | type: "function", 62 | name: "transfer", 63 | state_mutability: "external", 64 | inputs: [ 65 | { 66 | name: "recipient", 67 | type: "core::starknet::contract_address::ContractAddress", 68 | }, 69 | { 70 | name: "amount", 71 | type: "core::integer::u256", 72 | }, 73 | ], 74 | outputs: [], 75 | }, 76 | ] as const satisfies Abi; 77 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-explorer.ts: -------------------------------------------------------------------------------- 1 | import { useStarknet } from "../context/starknet"; 2 | import type { Explorer } from "../explorers"; 3 | 4 | /** Access the current explorer, should be inside a StarknetConfig. */ 5 | export function useExplorer(): Explorer { 6 | const { explorer, chain } = useStarknet(); 7 | if (!explorer) 8 | throw Error("Explorer is undefined. Try adding it to StarknetConfig."); 9 | const explorerInstance = explorer(chain); 10 | if (!explorerInstance) throw Error("Explorer Instance is undefined"); 11 | return explorerInstance; 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-invalidate-on-block.ts: -------------------------------------------------------------------------------- 1 | import { type QueryKey, useQueryClient } from "@tanstack/react-query"; 2 | import { useEffect, useState } from "react"; 3 | 4 | import { useBlockNumber } from "./use-block-number"; 5 | 6 | /** 7 | * Invalidate the given query on every new block. 8 | */ 9 | export function useInvalidateOnBlock({ 10 | enabled = true, 11 | queryKey, 12 | }: { 13 | enabled?: boolean; 14 | queryKey: QueryKey; 15 | }) { 16 | const queryClient = useQueryClient(); 17 | 18 | const [prevBlockNumber, setPrevBlockNumber] = useState(); 19 | 20 | const { data: blockNumber } = useBlockNumber({ 21 | enabled, 22 | }); 23 | 24 | useEffect(() => { 25 | if (!prevBlockNumber) { 26 | return setPrevBlockNumber(blockNumber); 27 | } 28 | 29 | if (blockNumber !== prevBlockNumber) { 30 | queryClient.invalidateQueries({ queryKey }, { cancelRefetch: false }); 31 | return setPrevBlockNumber(blockNumber); 32 | } 33 | }, [blockNumber, prevBlockNumber, queryKey, queryClient]); 34 | } 35 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-network.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "@starknet-react/chains"; 2 | 3 | import { useStarknet } from "../context/starknet"; 4 | 5 | /** Value returned from `useNetwork`. */ 6 | export type UseNetworkResult = { 7 | /** The current chain. */ 8 | chain: Chain; 9 | /** List of supported chains. */ 10 | chains: Chain[]; 11 | }; 12 | 13 | /** 14 | * Hook for accessing the current connected chain. 15 | * 16 | * @remarks 17 | * 18 | * The network object contains information about the 19 | * network. 20 | * 21 | */ 22 | export function useNetwork(): UseNetworkResult { 23 | const { chain, chains } = useStarknet(); 24 | return { chain, chains }; 25 | } 26 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-nonce-for-address.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { renderHook, waitFor } from "../../test/react"; 3 | 4 | import { useNonceForAddress } from "./use-nonce-for-address"; 5 | 6 | describe("useNonceForAddress", () => { 7 | it("returns nonce for the given address", async () => { 8 | const { result } = renderHook(() => 9 | useNonceForAddress({ 10 | address: 11 | "0x64b48806902a367c8598f4f95c305e8c1a1acba5f082d294a43793113115691", 12 | }), 13 | ); 14 | 15 | await waitFor(() => { 16 | expect(result.current.status).toEqual("success"); 17 | }); 18 | 19 | const { data, ...rest } = result.current; 20 | expect(data).toEqual("0x0"); 21 | expect(rest).toMatchInlineSnapshot(` 22 | { 23 | "error": null, 24 | "fetchStatus": "idle", 25 | "isError": false, 26 | "isFetching": false, 27 | "isLoading": false, 28 | "isPending": false, 29 | "isSuccess": true, 30 | "refetch": [Function], 31 | "status": "success", 32 | } 33 | `); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-nonce-for-address.ts: -------------------------------------------------------------------------------- 1 | import type { Address } from "@starknet-react/chains"; 2 | 3 | import { 4 | type BlockNumber, 5 | BlockTag, 6 | type Nonce, 7 | type ProviderInterface, 8 | } from "starknet"; 9 | 10 | import { useStarknet } from "../context/starknet"; 11 | import { type UseQueryProps, type UseQueryResult, useQuery } from "../query"; 12 | 13 | /** Arguments for `useNonceForAddress`. */ 14 | export type UseNonceForAddressProps = UseQueryProps< 15 | Nonce, 16 | Error, 17 | Nonce, 18 | ReturnType 19 | > & { 20 | /** Address to fetch nonce for. */ 21 | address: Address; 22 | /** Identifier for the block to fetch. */ 23 | blockIdentifier?: BlockNumber; 24 | }; 25 | 26 | /** Value returned from `useNonceForAddress`. */ 27 | export type UseNonceForAddressResult = UseQueryResult; 28 | 29 | /** 30 | * Hook for fetching the nonce for the given address. 31 | */ 32 | export function useNonceForAddress({ 33 | address, 34 | blockIdentifier = BlockTag.LATEST, 35 | ...props 36 | }: UseNonceForAddressProps): UseNonceForAddressResult { 37 | const { provider } = useStarknet(); 38 | 39 | return useQuery({ 40 | queryKey: queryKey({ address, blockIdentifier }), 41 | queryFn: queryFn({ address, provider, blockIdentifier }), 42 | ...props, 43 | }); 44 | } 45 | 46 | function queryKey({ 47 | address, 48 | blockIdentifier, 49 | }: { address: Address; blockIdentifier: BlockNumber }) { 50 | return [{ entity: "nonce", blockIdentifier, address }] as const; 51 | } 52 | 53 | function queryFn({ 54 | provider, 55 | blockIdentifier, 56 | address, 57 | }: { 58 | provider: ProviderInterface; 59 | address: Address; 60 | blockIdentifier: BlockNumber; 61 | }) { 62 | return async () => { 63 | const nonce = await provider.getNonceForAddress(address, blockIdentifier); 64 | return nonce; 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-provider.ts: -------------------------------------------------------------------------------- 1 | import type { ProviderInterface } from "starknet"; 2 | 3 | import { useStarknet } from "../context/starknet"; 4 | 5 | /** Value returned from `useProvider`. */ 6 | export interface UseProviderResult { 7 | /** The current provider. */ 8 | provider: ProviderInterface; 9 | } 10 | 11 | /** 12 | * Hook for accessing the current provider. 13 | * 14 | * @remarks 15 | * 16 | * Use this hook to access the current provider object 17 | * implementing starknet.js `ProviderInterface`. 18 | */ 19 | export function useProvider(): UseProviderResult { 20 | const { provider } = useStarknet(); 21 | return { provider }; 22 | } 23 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-read-contract.test-d.ts: -------------------------------------------------------------------------------- 1 | import type { FunctionRet } from "abi-wan-kanabi/kanabi"; 2 | import { assertType, describe, it } from "vitest"; 3 | import { tokenAddress } from "../../test/devnet"; 4 | import { testAbi } from "../../test/test-abi"; 5 | import { 6 | type UseReadContractProps, 7 | useReadContract, 8 | } from "./use-read-contract"; 9 | 10 | type TAbi = typeof testAbi; 11 | 12 | const commonProps = { 13 | abi: testAbi, 14 | address: tokenAddress, 15 | } as const; 16 | 17 | describe("Types test for useReadContract.ts", () => { 18 | it("correct function name for given abi", () => { 19 | const props = { 20 | ...commonProps, 21 | functionName: "fn_felt", 22 | args: [1234], 23 | } as const; 24 | assertType>(props); 25 | }); 26 | 27 | it("wrong function name for given abi", () => { 28 | const props = { 29 | ...commonProps, 30 | functionName: "some_random_function", 31 | args: [1234], 32 | } as const; 33 | 34 | // @ts-expect-error 35 | assertType>(props); 36 | }); 37 | 38 | it("correct arguments of function for given abi", () => { 39 | const props = { 40 | ...commonProps, 41 | functionName: "fn_felt", 42 | args: ["some_bignumberish_value"], 43 | } as const; 44 | 45 | assertType>(props); 46 | }); 47 | 48 | it("wrong arguments of function for given abi", () => { 49 | const props = { 50 | ...commonProps, 51 | functionName: "fn_felt", 52 | args: [false], 53 | } as const; 54 | 55 | // @ts-expect-error 56 | assertType>(props); 57 | }); 58 | 59 | it("correct data with correct arguments & function for given abi", () => { 60 | const props = { 61 | ...commonProps, 62 | functionName: "fn_out_simple_array", 63 | args: [], 64 | } as const; 65 | 66 | const { data } = useReadContract(props); 67 | assertType | undefined>(data); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-read-contract.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { accounts, tokenAddress } from "../../test/devnet"; 3 | import { renderHook, waitFor } from "../../test/react"; 4 | 5 | import { useReadContract } from "./use-read-contract"; 6 | 7 | const abi = [ 8 | { 9 | name: "core::integer::u256", 10 | type: "struct", 11 | members: [ 12 | { 13 | name: "low", 14 | type: "core::integer::u128", 15 | }, 16 | { 17 | name: "high", 18 | type: "core::integer::u128", 19 | }, 20 | ], 21 | }, 22 | { 23 | name: "balanceOf", 24 | type: "function", 25 | inputs: [ 26 | { 27 | name: "account", 28 | type: "core::starknet::contract_address::ContractAddress", 29 | }, 30 | ], 31 | outputs: [ 32 | { 33 | type: "core::integer::u256", 34 | }, 35 | ], 36 | state_mutability: "view", 37 | }, 38 | ] as const; 39 | 40 | describe("useReadContract", () => { 41 | it("returns the contract read result", async () => { 42 | const { result } = renderHook(() => 43 | useReadContract({ 44 | functionName: "balanceOf", 45 | args: [accounts.sepolia[0].address], 46 | abi, 47 | address: tokenAddress, 48 | watch: true, 49 | }), 50 | ); 51 | 52 | await waitFor(() => { 53 | expect(result.current.isSuccess).toBeTruthy(); 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-send-transaction.ts: -------------------------------------------------------------------------------- 1 | import type { Call as RequestCall } from "@starknet-io/types-js"; 2 | import type { Call } from "starknet"; 3 | import { 4 | type RequestArgs, 5 | type RequestResult, 6 | type UseWalletRequestProps, 7 | type UseWalletRequestResult, 8 | useWalletRequest, 9 | } from "./use-wallet-request"; 10 | 11 | export type UseSendTransactionArgs = { 12 | /** List of smart contract calls to execute. */ 13 | calls?: Call[]; 14 | }; 15 | 16 | export type UseSendTransactionProps = UseSendTransactionArgs & 17 | Omit< 18 | UseWalletRequestProps<"wallet_addInvokeTransaction">, 19 | keyof RequestArgs<"wallet_addInvokeTransaction"> 20 | >; 21 | 22 | export type UseSendTransactionResult = Omit< 23 | UseWalletRequestResult<"wallet_addInvokeTransaction">, 24 | "request" | "requestAsync" 25 | > & { 26 | send: (args?: Call[]) => void; 27 | sendAsync: ( 28 | args?: Call[], 29 | ) => Promise>; 30 | }; 31 | 32 | /** Hook to send one or several transaction(s) to the network. */ 33 | export function useSendTransaction( 34 | props: UseSendTransactionProps, 35 | ): UseSendTransactionResult { 36 | const { calls, ...rest } = props; 37 | 38 | const params = calls ? { calls: transformCalls(calls) } : undefined; 39 | 40 | const { request, requestAsync, ...result } = useWalletRequest({ 41 | type: "wallet_addInvokeTransaction", 42 | params, 43 | ...rest, 44 | }); 45 | 46 | const send = (args?: Call[]) => { 47 | return request( 48 | args 49 | ? { 50 | params: { calls: transformCalls(args) }, 51 | type: "wallet_addInvokeTransaction", 52 | } 53 | : undefined, 54 | ); 55 | }; 56 | 57 | const sendAsync = (args?: Call[]) => { 58 | return requestAsync( 59 | args 60 | ? { 61 | params: { calls: transformCalls(args) }, 62 | type: "wallet_addInvokeTransaction", 63 | } 64 | : undefined, 65 | ); 66 | }; 67 | 68 | return { 69 | send, 70 | sendAsync, 71 | ...result, 72 | }; 73 | } 74 | 75 | function transformCalls(calls: Call[]) { 76 | return calls.map( 77 | (call) => 78 | ({ 79 | contract_address: call.contractAddress, 80 | entry_point: call.entrypoint, 81 | calldata: call.calldata, 82 | }) as RequestCall, 83 | ); 84 | } 85 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-sign.ts: -------------------------------------------------------------------------------- 1 | import type { TypedData } from "@starknet-io/types-js"; 2 | 3 | import { 4 | type RequestArgs, 5 | type RequestResult, 6 | type UseWalletRequestProps, 7 | type UseWalletRequestResult, 8 | useWalletRequest, 9 | } from "./use-wallet-request"; 10 | 11 | export type UseSignTypedDataArgs = TypedData; 12 | 13 | export type UseSignTypedDataProps = Omit< 14 | UseWalletRequestProps<"wallet_signTypedData">, 15 | keyof RequestArgs<"wallet_signTypedData"> 16 | > & { 17 | params?: UseSignTypedDataArgs; 18 | }; 19 | 20 | export type UseSignTypedDataResult = Omit< 21 | UseWalletRequestResult<"wallet_signTypedData">, 22 | "request" | "requestAsync" 23 | > & { 24 | signTypedData: (args?: UseSignTypedDataArgs) => void; 25 | signTypedDataAsync: ( 26 | args?: UseSignTypedDataArgs, 27 | ) => Promise>; 28 | }; 29 | 30 | export function useSignTypedData( 31 | props: UseSignTypedDataProps, 32 | ): UseSignTypedDataResult { 33 | const { params, ...rest } = props; 34 | 35 | const { request, requestAsync, ...result } = useWalletRequest({ 36 | type: "wallet_signTypedData", 37 | params, 38 | ...rest, 39 | }); 40 | 41 | const signTypedData = (args?: UseSignTypedDataArgs) => { 42 | return request( 43 | args 44 | ? { 45 | params: args, 46 | type: "wallet_signTypedData", 47 | } 48 | : undefined, 49 | ); 50 | }; 51 | 52 | const signTypedDataAsync = (args?: UseSignTypedDataArgs) => { 53 | return requestAsync( 54 | args 55 | ? { 56 | params: args, 57 | type: "wallet_signTypedData", 58 | } 59 | : undefined, 60 | ); 61 | }; 62 | 63 | return { 64 | signTypedData, 65 | signTypedDataAsync, 66 | ...result, 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-switch-chain.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { act, renderHook, waitFor } from "../../test/react"; 3 | 4 | import { constants } from "starknet"; 5 | import { defaultConnector } from "../../test/devnet"; 6 | import { useConnect } from "./use-connect"; 7 | import { useDisconnect } from "./use-disconnect"; 8 | import { useSwitchChain } from "./use-switch-chain"; 9 | 10 | function useSwitchChainWithConnect() { 11 | return { 12 | switchChain: useSwitchChain({ 13 | params: { chainId: constants.StarknetChainId.SN_MAIN }, 14 | }), 15 | connect: useConnect(), 16 | disconnect: useDisconnect(), 17 | }; 18 | } 19 | 20 | describe("useSwitchChain", () => { 21 | it("switch chain to mainnet", async () => { 22 | const { result } = renderHook(() => useSwitchChainWithConnect()); 23 | 24 | await act(async () => { 25 | result.current.connect.connect({ 26 | connector: defaultConnector, 27 | }); 28 | }); 29 | 30 | await act(async () => { 31 | result.current.switchChain.switchChain(); 32 | }); 33 | 34 | await waitFor(() => { 35 | expect(result.current.switchChain.isSuccess).toBeTruthy(); 36 | }); 37 | }); 38 | 39 | it("throws error if user cancels to switch to mainnet", async () => { 40 | const { result } = renderHook(() => useSwitchChainWithConnect(), { 41 | connectorOptions: { rejectRequest: true }, 42 | }); 43 | await act(async () => { 44 | result.current.connect.connect({ 45 | connector: defaultConnector, 46 | }); 47 | }); 48 | await act(async () => { 49 | result.current.switchChain.switchChain(); 50 | }); 51 | await waitFor(() => { 52 | expect(result.current.switchChain.isError).toBeTruthy(); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-switch-chain.ts: -------------------------------------------------------------------------------- 1 | import type { SwitchStarknetChainParameters } from "@starknet-io/types-js"; 2 | 3 | import { 4 | type RequestArgs, 5 | type RequestResult, 6 | type UseWalletRequestProps, 7 | type UseWalletRequestResult, 8 | useWalletRequest, 9 | } from "./use-wallet-request"; 10 | 11 | export type UseSwitchChainArgs = SwitchStarknetChainParameters; 12 | 13 | export type UseSwitchChainProps = Omit< 14 | UseWalletRequestProps<"wallet_switchStarknetChain">, 15 | keyof RequestArgs<"wallet_switchStarknetChain"> 16 | > & { 17 | params?: UseSwitchChainArgs; 18 | }; 19 | 20 | export type UseSwitchChainResult = Omit< 21 | UseWalletRequestResult<"wallet_switchStarknetChain">, 22 | "request" | "requestAsync" 23 | > & { 24 | switchChain: (args?: UseSwitchChainArgs) => void; 25 | switchChainAsync: ( 26 | args?: UseSwitchChainArgs, 27 | ) => Promise>; 28 | }; 29 | 30 | /** 31 | * Hook to change the current network of the wallet. 32 | * 33 | */ 34 | export function useSwitchChain( 35 | props: UseSwitchChainProps, 36 | ): UseSwitchChainResult { 37 | const { params, ...rest } = props; 38 | 39 | const { request, requestAsync, ...result } = useWalletRequest({ 40 | type: "wallet_switchStarknetChain", 41 | params, 42 | ...rest, 43 | }); 44 | 45 | const switchChain = (args?: UseSwitchChainArgs) => { 46 | return request( 47 | args 48 | ? { 49 | params: args, 50 | type: "wallet_switchStarknetChain", 51 | } 52 | : undefined, 53 | ); 54 | }; 55 | 56 | const switchChainAsync = (args?: UseSwitchChainArgs) => { 57 | return requestAsync( 58 | args 59 | ? { 60 | params: args, 61 | type: "wallet_switchStarknetChain", 62 | } 63 | : undefined, 64 | ); 65 | }; 66 | 67 | return { 68 | switchChain, 69 | switchChainAsync, 70 | ...result, 71 | }; 72 | } 73 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-wallet-request.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { act, renderHook, waitFor } from "../../test/react"; 3 | 4 | import { defaultConnector } from "../../test/devnet"; 5 | import { useConnect } from "./use-connect"; 6 | import { useDisconnect } from "./use-disconnect"; 7 | import { useWalletRequest } from "./use-wallet-request"; 8 | 9 | function useWalletRequestWithConnect() { 10 | return { 11 | walletRequest: useWalletRequest({ type: "wallet_getPermissions" }), 12 | connect: useConnect(), 13 | disconnect: useDisconnect(), 14 | }; 15 | } 16 | 17 | describe("useWalletRequest", () => { 18 | it("get permissions when connector is connected", async () => { 19 | const { result } = renderHook(() => useWalletRequestWithConnect()); 20 | 21 | await act(async () => { 22 | result.current.connect.connect({ 23 | connector: defaultConnector, 24 | }); 25 | }); 26 | 27 | await act(async () => { 28 | result.current.walletRequest.request(); 29 | }); 30 | 31 | await waitFor(() => { 32 | expect(result.current.walletRequest.data).toHaveLength(1); 33 | }); 34 | }); 35 | 36 | it("throw error if connector is not connected", async () => { 37 | const { result } = renderHook(() => useWalletRequestWithConnect()); 38 | 39 | await act(async () => { 40 | result.current.walletRequest.request(); 41 | }); 42 | 43 | await waitFor(() => { 44 | expect(result.current.walletRequest.isError).toBeTruthy(); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-watch-asset.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { defaultConnector } from "../../test/devnet"; 3 | import { act, renderHook, waitFor } from "../../test/react"; 4 | import { useConnect } from "./use-connect"; 5 | import { useDisconnect } from "./use-disconnect"; 6 | import { type UseWatchAssetArgs, useWatchAsset } from "./use-watch-asset"; 7 | 8 | const addrxASTR = 9 | "0x005EF67D8c38B82ba699F206Bf0dB59f1828087A710Bad48Cc4d51A2B0dA4C29"; 10 | const myAsset: UseWatchAssetArgs = { 11 | type: "ERC20", 12 | options: { 13 | address: addrxASTR, 14 | name: "ETHER", 15 | symbol: "ETH", 16 | decimals: 18, 17 | }, 18 | }; 19 | 20 | function useWatchAssetWithConnect() { 21 | return { 22 | watchAsset: useWatchAsset({ params: myAsset }), 23 | connect: useConnect(), 24 | disconnect: useDisconnect(), 25 | }; 26 | } 27 | 28 | describe("useWatchAsset", () => { 29 | it("add a token to the connected wallet", async () => { 30 | const { result } = renderHook(() => useWatchAssetWithConnect()); 31 | 32 | await act(async () => { 33 | result.current.connect.connect({ 34 | connector: defaultConnector, 35 | }); 36 | }); 37 | await act(async () => { 38 | result.current.watchAsset.watchAsset(); 39 | }); 40 | 41 | await waitFor(() => { 42 | expect(result.current.watchAsset.isSuccess).toBeTruthy(); 43 | }); 44 | }); 45 | 46 | it("throws error if user cancels the watch asset request", async () => { 47 | const { result } = renderHook(() => useWatchAssetWithConnect(), { 48 | connectorOptions: { rejectRequest: true }, 49 | }); 50 | 51 | await act(async () => { 52 | result.current.connect.connect({ 53 | connector: defaultConnector, 54 | }); 55 | }); 56 | 57 | await act(async () => { 58 | result.current.watchAsset.watchAsset(); 59 | }); 60 | 61 | await waitFor(() => { 62 | expect(result.current.watchAsset.isError).toBeTruthy(); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /packages/core/src/hooks/use-watch-asset.ts: -------------------------------------------------------------------------------- 1 | import type { WatchAssetParameters } from "@starknet-io/types-js"; 2 | import { 3 | type RequestArgs, 4 | type RequestResult, 5 | type UseWalletRequestProps, 6 | type UseWalletRequestResult, 7 | useWalletRequest, 8 | } from "./use-wallet-request"; 9 | 10 | export type UseWatchAssetArgs = WatchAssetParameters; 11 | 12 | export type UseWatchAssetProps = Omit< 13 | UseWalletRequestProps<"wallet_watchAsset">, 14 | keyof RequestArgs<"wallet_watchAsset"> 15 | > & { 16 | params?: UseWatchAssetArgs; 17 | }; 18 | 19 | export type UseWatchAssetResult = Omit< 20 | UseWalletRequestResult<"wallet_watchAsset">, 21 | "request" | "requestAsync" 22 | > & { 23 | watchAsset: (args?: UseWatchAssetArgs) => void; 24 | watchAssetAsync: ( 25 | args?: UseWatchAssetArgs, 26 | ) => Promise>; 27 | }; 28 | 29 | /** 30 | * Hook to watch an asset in the wallet. 31 | * 32 | */ 33 | 34 | export function useWatchAsset(props: UseWatchAssetProps): UseWatchAssetResult { 35 | const { params, ...rest } = props; 36 | 37 | const { request, requestAsync, ...result } = useWalletRequest({ 38 | type: "wallet_watchAsset", 39 | params, 40 | ...rest, 41 | }); 42 | 43 | const watchAsset = (args?: UseWatchAssetArgs) => { 44 | return request( 45 | args 46 | ? { 47 | params: args, 48 | type: "wallet_watchAsset", 49 | } 50 | : undefined, 51 | ); 52 | }; 53 | 54 | const watchAssetAsync = (args?: UseWatchAssetArgs) => { 55 | return requestAsync( 56 | args 57 | ? { 58 | params: args, 59 | type: "wallet_watchAsset", 60 | } 61 | : undefined, 62 | ); 63 | }; 64 | 65 | return { 66 | watchAsset, 67 | watchAssetAsync, 68 | ...result, 69 | }; 70 | } 71 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./connectors"; 2 | export * from "./context"; 3 | export * from "./errors"; 4 | export * from "./explorers"; 5 | export * from "./hooks"; 6 | export * from "./providers"; 7 | export * from "./utils"; 8 | 9 | export type { Abi } from "abi-wan-kanabi"; 10 | export type { Address } from "@starknet-react/chains"; 11 | -------------------------------------------------------------------------------- /packages/core/src/providers/alchemy.ts: -------------------------------------------------------------------------------- 1 | import { jsonRpcProvider } from "./jsonrpc"; 2 | 3 | /** Arguments for `alchemyProvider`. */ 4 | export type AlchemyProviderArgs = { 5 | /** Alchemy API key. */ 6 | apiKey: string; 7 | }; 8 | 9 | /** Configure the Alchemy provider using the provided API key. */ 10 | export function alchemyProvider({ apiKey }: AlchemyProviderArgs) { 11 | return jsonRpcProvider({ 12 | rpc: (chain) => { 13 | const baseHttpUrl = chain.rpcUrls["alchemy"]?.http[0]; 14 | if (!baseHttpUrl) return null; 15 | const nodeUrl = `${baseHttpUrl}/${apiKey}`; 16 | return { nodeUrl }; 17 | }, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/providers/blast.ts: -------------------------------------------------------------------------------- 1 | import { jsonRpcProvider } from "./jsonrpc"; 2 | 3 | /** Arguments for `blastProvider`. */ 4 | export type BlastProviderArgs = { 5 | /** Blast API key. */ 6 | apiKey: string; 7 | }; 8 | 9 | /** Configure the Blast provider using the provided API key. */ 10 | export function blastProvider({ apiKey }: BlastProviderArgs) { 11 | return jsonRpcProvider({ 12 | rpc: (chain) => { 13 | const baseHttpUrl = chain.rpcUrls["blast"]?.http[0]; 14 | if (!baseHttpUrl) return null; 15 | const nodeUrl = `${baseHttpUrl}/${apiKey}`; 16 | return { nodeUrl }; 17 | }, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/providers/cartridge.ts: -------------------------------------------------------------------------------- 1 | import { jsonRpcProvider } from "./jsonrpc"; 2 | 3 | /** Configure the Cartridge provider. */ 4 | export function cartridgeProvider() { 5 | return jsonRpcProvider({ 6 | rpc: (chain) => { 7 | const nodeUrl = chain.rpcUrls["cartridge"]?.http[0]; 8 | if (!nodeUrl) return null; 9 | return { nodeUrl }; 10 | }, 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/src/providers/factory.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "@starknet-react/chains"; 2 | import type { ProviderInterface } from "starknet"; 3 | 4 | export type ChainProviderFactory< 5 | T extends ProviderInterface = ProviderInterface, 6 | > = (chain: Chain) => T | null; 7 | -------------------------------------------------------------------------------- /packages/core/src/providers/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./factory"; 2 | 3 | export * from "./jsonrpc"; 4 | export * from "./public"; 5 | 6 | export * from "./alchemy"; 7 | export * from "./blast"; 8 | export * from "./cartridge"; 9 | export * from "./infura"; 10 | export * from "./lava"; 11 | export * from "./reddio"; 12 | export * from "./slot"; 13 | -------------------------------------------------------------------------------- /packages/core/src/providers/infura.ts: -------------------------------------------------------------------------------- 1 | import { jsonRpcProvider } from "./jsonrpc"; 2 | 3 | /** Arguments for `infuraProvider`. */ 4 | export type InfuraProviderArgs = { 5 | /** Infura API key. */ 6 | apiKey: string; 7 | }; 8 | 9 | /** Configure the Infura provider using the provided API key. */ 10 | export function infuraProvider({ apiKey }: InfuraProviderArgs) { 11 | return jsonRpcProvider({ 12 | rpc: (chain) => { 13 | const baseHttpUrl = chain.rpcUrls["infura"]?.http[0]; 14 | if (!baseHttpUrl) return null; 15 | const nodeUrl = `${baseHttpUrl}/${apiKey}`; 16 | return { nodeUrl }; 17 | }, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/providers/jsonrpc.test.ts: -------------------------------------------------------------------------------- 1 | import { type Chain, mainnet } from "@starknet-react/chains"; 2 | 3 | import { describe, expect, it } from "vitest"; 4 | import { jsonRpcProvider } from "./jsonrpc"; 5 | 6 | function rpc(chain: Chain) { 7 | return { 8 | nodeUrl: `https://${chain.network}.example.com`, 9 | }; 10 | } 11 | 12 | describe("jsonRpcProvider", () => { 13 | it("returns a public rpc endpoint", () => { 14 | expect( 15 | jsonRpcProvider({ rpc })(mainnet)?.channel.nodeUrl, 16 | ).toMatchInlineSnapshot('"https://mainnet.example.com"'); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/core/src/providers/jsonrpc.ts: -------------------------------------------------------------------------------- 1 | import type { Chain } from "@starknet-react/chains"; 2 | import { RpcProvider, type RpcProviderOptions } from "starknet"; 3 | 4 | import { starknetChainId } from "../context"; 5 | import type { ChainProviderFactory } from "./factory"; 6 | 7 | /** Arguments for `jsonRpcProvider`. */ 8 | export type JsonRpcProviderArgs = { 9 | rpc: (chain: Chain) => RpcProviderOptions | null; 10 | }; 11 | 12 | /** Configure the JSON-RPC provider using the provided function. */ 13 | export function jsonRpcProvider({ 14 | rpc, 15 | }: JsonRpcProviderArgs): ChainProviderFactory { 16 | return (chain) => { 17 | const config = rpc(chain); 18 | if (!config) return null; 19 | const chainId = starknetChainId(chain.id); 20 | 21 | const provider = new RpcProvider({ ...config, chainId }); 22 | return provider; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/src/providers/lava.ts: -------------------------------------------------------------------------------- 1 | import { jsonRpcProvider } from "./jsonrpc"; 2 | 3 | /** Arguments for `lavaProvider`. */ 4 | export type LavaProviderArgs = { 5 | /** Lava API key. */ 6 | apiKey: string; 7 | }; 8 | 9 | /** Configure the Lava provider using the provided API key. */ 10 | export function lavaProvider({ apiKey }: LavaProviderArgs) { 11 | return jsonRpcProvider({ 12 | rpc: (chain) => { 13 | const baseHttpUrl = chain.rpcUrls["lava"]?.http[0]; 14 | if (!baseHttpUrl) return null; 15 | const nodeUrl = `${baseHttpUrl}/${apiKey}`; 16 | return { nodeUrl }; 17 | }, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/providers/public.test.ts: -------------------------------------------------------------------------------- 1 | import { devnet } from "@starknet-react/chains"; 2 | 3 | import { describe, expect, it } from "vitest"; 4 | import { publicProvider } from "./public"; 5 | 6 | describe("publicProvider", () => { 7 | it("returns a public rpc endpoint", () => { 8 | expect(publicProvider()(devnet)?.channel.nodeUrl).toMatchInlineSnapshot( 9 | '"http://localhost:5050/rpc"', 10 | ); 11 | }); 12 | 13 | it("returns the chain", () => { 14 | expect(publicProvider()(devnet)?.getChainId()).resolves.toMatch( 15 | "0x534e5f5345504f4c4941", 16 | ); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/core/src/providers/public.ts: -------------------------------------------------------------------------------- 1 | import { jsonRpcProvider } from "./jsonrpc"; 2 | 3 | /** Configure the provider to use the public RPC endpoint. */ 4 | export function publicProvider() { 5 | return jsonRpcProvider({ 6 | rpc: (chain) => { 7 | // Pick random node from the list of public nodes. 8 | const rpcs = chain.rpcUrls.public.http; 9 | const nodeUrl = rpcs[Math.floor(Math.random() * rpcs.length)]; 10 | if (!nodeUrl) return null; 11 | return { nodeUrl, specVersion: "0.8" }; 12 | }, 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/src/providers/reddio.ts: -------------------------------------------------------------------------------- 1 | import { jsonRpcProvider } from "./jsonrpc"; 2 | 3 | /** Arguments for `reddioProvider`. */ 4 | export type ReddioProviderArgs = { 5 | /** Reddio API key. */ 6 | apiKey: string; 7 | }; 8 | 9 | /** Configure the Reddio provider using the provided API key. */ 10 | export function reddioProvider({ apiKey }: ReddioProviderArgs) { 11 | return jsonRpcProvider({ 12 | rpc: (chain) => { 13 | const baseHttpUrl = chain.rpcUrls["reddio"]?.http[0]; 14 | if (!baseHttpUrl) return null; 15 | const nodeUrl = `${baseHttpUrl}/${apiKey}`; 16 | return { nodeUrl }; 17 | }, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/providers/slot.ts: -------------------------------------------------------------------------------- 1 | import { getSlotChain } from "@starknet-react/chains"; 2 | import { jsonRpcProvider } from "./jsonrpc"; 3 | 4 | /** Arguments for `slotProvider`. */ 5 | export type SlotProviderArgs = { 6 | /** The name of your slot instance. */ 7 | projectId: string; 8 | }; 9 | 10 | /** Configure the Slot provider using the provided Project ID. */ 11 | export function slotProvider({ projectId }: SlotProviderArgs) { 12 | return jsonRpcProvider({ 13 | rpc: () => { 14 | const chain = getSlotChain(projectId); 15 | const nodeUrl = chain.rpcUrls.public.http[0]; 16 | return { nodeUrl }; 17 | }, 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/utils.ts: -------------------------------------------------------------------------------- 1 | import type { Address } from "@starknet-react/chains"; 2 | import { validateAndParseAddress } from "starknet"; 3 | 4 | /** 5 | * Validate and format the address. 6 | * 7 | * @param address - The address string to validate. 8 | * @returns The validated and formatted address as Address type. 9 | */ 10 | export function getAddress(address: string): Address { 11 | return validateAndParseAddress(address) as Address; 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/test/devnet.ts: -------------------------------------------------------------------------------- 1 | import { devnet } from "@starknet-react/chains"; 2 | import { Account, type AccountInterface, RpcProvider } from "starknet"; 3 | import { MockConnector } from "../src/connectors"; 4 | 5 | const provider = new RpcProvider({ nodeUrl: devnet.rpcUrls.public.http[0] }); 6 | 7 | export const tokenAddress = 8 | "0x49D36570D4E46F48E99674BD3FCC84644DDD6B96F7C741B1562B82F9E004DC7"; 9 | 10 | const devnetAccounts = [ 11 | { 12 | address: 13 | "0x64b48806902a367c8598f4f95c305e8c1a1acba5f082d294a43793113115691", 14 | privateKey: "0x71d7bb07b9a64f6f78ac4c816aff4da9", 15 | }, 16 | { 17 | address: 18 | "0x078662e7352d062084b0010068b99288486c2d8b914f6e2a55ce945f8792c8b1", 19 | privateKey: "0xe1406455b7d66b1690803be066cbe5e", 20 | }, 21 | { 22 | address: 23 | "0x49dfb8ce986e21d354ac93ea65e6a11f639c1934ea253e5ff14ca62eca0f38e", 24 | privateKey: "0xa20a02f0ac53692d144b20cb371a60d7", 25 | }, 26 | { 27 | address: 28 | "0x4f348398f859a55a0c80b1446c5fdc37edb3a8478a32f10764659fc241027d3", 29 | privateKey: "0xa641611c17d4d92bd0790074e34beeb7", 30 | }, 31 | { 32 | address: "0xd513de92c16aa42418cf7e5b60f8022dbee1b4dfd81bcf03ebee079cfb5cb5", 33 | privateKey: "0x5b4ac23628a5749277bcabbf4726b025", 34 | }, 35 | ]; 36 | 37 | function makeAccount({ 38 | address, 39 | privateKey, 40 | }: { 41 | address: string; 42 | privateKey: string; 43 | }): AccountInterface { 44 | return new Account(provider, address, privateKey); 45 | } 46 | 47 | export const accounts = { 48 | sepolia: [makeAccount(devnetAccounts[1]), makeAccount(devnetAccounts[3])], 49 | mainnet: [makeAccount(devnetAccounts[0]), makeAccount(devnetAccounts[2])], 50 | }; 51 | 52 | export const defaultConnector = new MockConnector({ 53 | accounts, 54 | options: { 55 | id: "mock", 56 | name: "Mock Connector", 57 | }, 58 | }); 59 | -------------------------------------------------------------------------------- /packages/core/test/setup.ts: -------------------------------------------------------------------------------- 1 | import "@testing-library/jest-dom/vitest"; 2 | 3 | import { cleanup } from "@testing-library/react"; 4 | import { afterEach } from "vitest"; 5 | 6 | afterEach(() => { 7 | cleanup(); 8 | }); 9 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@starknet-react/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "rootDir": ".", 6 | "outDir": "dist" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/core/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.ts", "src/providers/index.ts", "src/hooks/index.ts"], 5 | splitting: false, 6 | sourcemap: true, 7 | dts: true, 8 | clean: true, 9 | format: ["esm"], 10 | }); 11 | -------------------------------------------------------------------------------- /packages/core/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react"; 2 | import tsconfigPaths from "vite-tsconfig-paths"; 3 | import { defineConfig } from "vitest/config"; 4 | 5 | export default defineConfig({ 6 | plugins: [react(), tsconfigPaths({ ignoreConfigErrors: true })], 7 | test: { 8 | globals: true, 9 | environment: "jsdom", 10 | setupFiles: "./test/setup.ts", 11 | typecheck: { 12 | enabled: true, 13 | ignoreSourceErrors: true, 14 | }, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /packages/create-starknet/README.md: -------------------------------------------------------------------------------- 1 | # `create-starknet` 2 | 3 | Create starknet apps with one command 4 | 5 | ## Interactive 6 | 7 | You can create a new project interactively by running: 8 | 9 | ```bash 10 | npx create-starknet 11 | # or 12 | npm init starknet 13 | ``` 14 | 15 | You will be asked for the name of your project before it can be created for you. 16 | 17 | ## Non-interactive 18 | 19 | You can also pass command line arguments to set up a new project 20 | non-interactively. See `create-starknet-app --help`: 21 | 22 | ``` 23 | create-starknet [project-directory] [options] 24 | 25 | Options: 26 | -V, --version output the version number 27 | -t, --template Explicitly tell the CLI to bootstrap the app using the specified template (choices: "next", "vite") 28 | --use-npm Explicitly tell the CLI to bootstrap the app using npm 29 | --use-yarn Explicitly tell the CLI to bootstrap the app using yarn 30 | --use-pnpm Explicitly tell the CLI to bootstrap the app using pnpm 31 | -h, --help display help for command 32 | ``` -------------------------------------------------------------------------------- /packages/create-starknet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-starknet", 3 | "version": "4.0.1-beta.1", 4 | "description": "Create starknet apps with one command", 5 | "main": "./dist/index.js", 6 | "type": "module", 7 | "scripts": { 8 | "build": "tsup", 9 | "clean": "rimraf dist", 10 | "start": "pnpm run build && node dist/index.js", 11 | "lint": "biome check .", 12 | "lint:fix": "pnpm lint --write", 13 | "format:check": "biome format .", 14 | "format": "biome format . --write" 15 | }, 16 | "bin": { 17 | "create-starknet": "dist/index.js" 18 | }, 19 | "keywords": [ 20 | "starknet", 21 | "ethereum", 22 | "l2" 23 | ], 24 | "author": "Yohan Tancrez", 25 | "license": "MIT", 26 | "devDependencies": { 27 | "@types/fs-extra": "^11.0.1", 28 | "@types/node": "^18.11.18", 29 | "@types/prompts": "2.0.1", 30 | "@types/validate-npm-package-name": "^4.0.0", 31 | "tsup": "^8.0.2", 32 | "typescript": "^5.5.4" 33 | }, 34 | "files": [ 35 | "dist", 36 | "src", 37 | "README.md" 38 | ], 39 | "dependencies": { 40 | "@starknet-react/typescript-config": "workspace:*", 41 | "@types/cross-spawn": "^6.0.2", 42 | "chalk": "4.1.2", 43 | "commander": "^10.0.0", 44 | "cross-spawn": "^7.0.3", 45 | "fs-extra": "^11.1.0", 46 | "prompts": "2.1.0", 47 | "validate-npm-package-name": "^5.0.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/create-starknet/src/helpers/packageManager.ts: -------------------------------------------------------------------------------- 1 | export type PackageManager = "npm" | "yarn" | "pnpm"; 2 | 3 | export function getPackageManager(): PackageManager { 4 | const userAgent = process.env.npm_config_user_agent; 5 | 6 | if (userAgent?.includes("yarn")) { 7 | return "yarn"; 8 | } 9 | if (userAgent?.includes("pnpm")) { 10 | return "pnpm"; 11 | } 12 | 13 | return "npm"; 14 | } 15 | -------------------------------------------------------------------------------- /packages/create-starknet/src/helpers/validate.ts: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import fs from "fs-extra"; 3 | import validateNpmPackageName from "validate-npm-package-name"; 4 | 5 | export function getPackageNameValidation(projectPath: string) { 6 | const projectNameValidation = validateNpmPackageName( 7 | path.basename(path.resolve(projectPath)), 8 | ); 9 | 10 | if (!projectNameValidation.validForNewPackages) { 11 | return [ 12 | ...(projectNameValidation.warnings || []), 13 | ...(projectNameValidation.errors || []), 14 | ].join("\n"); 15 | } 16 | 17 | if (fs.existsSync(path.resolve(projectPath))) { 18 | return "A file with this name already exists"; 19 | } 20 | 21 | return true; 22 | } 23 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-starknet`](https://github.com/apibara/starknet-react/tree/main/packages/create-starknet). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@starknet-react/chains": "^3.0.0", 13 | "@starknet-react/core": "^3.0.0", 14 | "get-starknet-core": "^3.3.3", 15 | "react": "^18", 16 | "react-dom": "^18", 17 | "next": "14.2.6", 18 | "starknet": "^7.1.0" 19 | }, 20 | "devDependencies": { 21 | "typescript": "^5", 22 | "@types/node": "^20", 23 | "@types/react": "^18", 24 | "@types/react-dom": "^18", 25 | "postcss": "^8", 26 | "tailwindcss": "^3.4.1", 27 | "eslint": "^8", 28 | "eslint-config-next": "14.2.6" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | }, 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apibara/starknet-react/298912b61b3404cdbfbaf3e45a35e4dc899f42f6/packages/create-starknet/src/templates/next/src/app/favicon.ico -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 214, 219, 220; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | @media (prefers-color-scheme: dark) { 12 | :root { 13 | --foreground-rgb: 255, 255, 255; 14 | --background-start-rgb: 0, 0, 0; 15 | --background-end-rgb: 0, 0, 0; 16 | } 17 | } 18 | 19 | body { 20 | color: rgb(var(--foreground-rgb)); 21 | background: linear-gradient( 22 | to bottom, 23 | transparent, 24 | rgb(var(--background-end-rgb)) 25 | ) 26 | rgb(var(--background-start-rgb)); 27 | } 28 | 29 | @layer utilities { 30 | .text-balance { 31 | text-wrap: balance; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/src/app/layout.tsx: -------------------------------------------------------------------------------- 1 | import { StarknetProvider } from "@/components/starknet-provider"; 2 | import type { Metadata } from "next"; 3 | import { Inter } from "next/font/google"; 4 | import "./globals.css"; 5 | 6 | const inter = Inter({ subsets: ["latin"] }); 7 | 8 | export const metadata: Metadata = { 9 | title: "Create Next App", 10 | description: "Generated by create next app", 11 | }; 12 | 13 | export default function RootLayout({ 14 | children, 15 | }: { 16 | children: React.ReactNode; 17 | }) { 18 | return ( 19 | 20 | 21 | {children} 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/src/app/page.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import WalletBar from "@/components/wallet-bar.tsx"; 3 | 4 | export default function Home() { 5 | return ( 6 |
7 | 8 |

9 | Get started by editing  10 | pages/index.tsx 11 |

12 | 50 |
51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/src/components/starknet-provider.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import type { ReactNode } from "react"; 3 | 4 | import { mainnet } from "@starknet-react/chains"; 5 | import { 6 | StarknetConfig, 7 | argent, 8 | braavos, 9 | publicProvider, 10 | useInjectedConnectors, 11 | voyager, 12 | } from "@starknet-react/core"; 13 | 14 | export function StarknetProvider({ children }: { children: ReactNode }) { 15 | const { connectors } = useInjectedConnectors({ 16 | // Show these connectors if the user has no connector installed. 17 | recommended: [argent(), braavos()], 18 | // Hide recommended connectors if the user has any connector installed. 19 | includeRecommended: "onlyIfNoConnectors", 20 | // Randomize the order of the connectors. 21 | order: "random", 22 | }); 23 | 24 | return ( 25 | 31 | {children} 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/src/components/ui/Button.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react"; 2 | 3 | interface ButtonProps extends React.ButtonHTMLAttributes { 4 | children: React.ReactNode; 5 | } 6 | 7 | export const Button = ({ children, ...props }: ButtonProps) => { 8 | return ( 9 | 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/src/components/wallet-bar.tsx.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { useAccount, useConnect, useDisconnect } from "@starknet-react/core"; 3 | import { useMemo } from "react"; 4 | import { Button } from "./ui/Button"; 5 | 6 | function WalletConnected() { 7 | const { address } = useAccount(); 8 | const { disconnect } = useDisconnect(); 9 | 10 | const shortenedAddress = useMemo(() => { 11 | if (!address) return ""; 12 | return `${address.slice(0, 6)}...${address.slice(-4)}`; 13 | }, [address]); 14 | 15 | return ( 16 |
17 | Connected: {shortenedAddress} 18 | 19 |
20 | ); 21 | } 22 | 23 | function ConnectWallet() { 24 | const { connectors, connect } = useConnect(); 25 | 26 | return ( 27 |
28 | Choose a wallet: 29 | {connectors.map((connector) => { 30 | return ( 31 | 38 | ); 39 | })} 40 |
41 | ); 42 | } 43 | 44 | export default function WalletBar() { 45 | const { address } = useAccount(); 46 | 47 | return address ? : ; 48 | } 49 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | const config: Config = { 4 | content: [ 5 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 7 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 8 | ], 9 | theme: { 10 | extend: { 11 | backgroundImage: { 12 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 13 | "gradient-conic": 14 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 15 | }, 16 | }, 17 | }, 18 | plugins: [], 19 | }; 20 | export default config; 21 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/next/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["dom", "dom.iterable", "esnext"], 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "strict": true, 7 | "noEmit": true, 8 | "esModuleInterop": true, 9 | "module": "esnext", 10 | "moduleResolution": "bundler", 11 | "resolveJsonModule": true, 12 | "isolatedModules": true, 13 | "jsx": "preserve", 14 | "incremental": true, 15 | "plugins": [ 16 | { 17 | "name": "next" 18 | } 19 | ], 20 | "paths": { 21 | "@/*": ["./src/*"] 22 | } 23 | }, 24 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 13 | 14 | - Configure the top-level `parserOptions` property like this: 15 | 16 | ```js 17 | export default tseslint.config({ 18 | languageOptions: { 19 | // other options... 20 | parserOptions: { 21 | project: ['./tsconfig.node.json', './tsconfig.app.json'], 22 | tsconfigRootDir: import.meta.dirname, 23 | }, 24 | }, 25 | }) 26 | ``` 27 | 28 | - Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` 29 | - Optionally add `...tseslint.configs.stylisticTypeChecked` 30 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: 31 | 32 | ```js 33 | // eslint.config.js 34 | import react from 'eslint-plugin-react' 35 | 36 | export default tseslint.config({ 37 | // Set the react version 38 | settings: { react: { version: '18.3' } }, 39 | plugins: { 40 | // Add the react plugin 41 | react, 42 | }, 43 | rules: { 44 | // other rules... 45 | // Enable its recommended rules 46 | ...react.configs.recommended.rules, 47 | ...react.configs['jsx-runtime'].rules, 48 | }, 49 | }) 50 | ``` 51 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from "@eslint/js"; 2 | import reactHooks from "eslint-plugin-react-hooks"; 3 | import reactRefresh from "eslint-plugin-react-refresh"; 4 | import globals from "globals"; 5 | import tseslint from "typescript-eslint"; 6 | 7 | export default tseslint.config( 8 | { ignores: ["dist"] }, 9 | { 10 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 11 | files: ["**/*.{ts,tsx}"], 12 | languageOptions: { 13 | ecmaVersion: 2020, 14 | globals: globals.browser, 15 | }, 16 | plugins: { 17 | "react-hooks": reactHooks, 18 | "react-refresh": reactRefresh, 19 | }, 20 | rules: { 21 | ...reactHooks.configs.recommended.rules, 22 | "react-refresh/only-export-components": [ 23 | "warn", 24 | { allowConstantExport: true }, 25 | ], 26 | }, 27 | }, 28 | ); 29 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Create Starknet 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@starknet-react/chains": "^3.0.0", 14 | "@starknet-react/core": "^3.0.0", 15 | "get-starknet-core": "^4.0.0", 16 | "starknet": "^7.1.0", 17 | "react": "^18.3.1", 18 | "react-dom": "^18.3.1" 19 | }, 20 | "devDependencies": { 21 | "@eslint/js": "^9.9.0", 22 | "@types/react": "^18.3.3", 23 | "@types/react-dom": "^18.3.0", 24 | "@vitejs/plugin-react": "^4.3.1", 25 | "autoprefixer": "^10.4.20", 26 | "eslint": "^9.9.0", 27 | "eslint-plugin-react-hooks": "^5.1.0-rc.0", 28 | "eslint-plugin-react-refresh": "^0.4.9", 29 | "globals": "^15.9.0", 30 | "postcss": "^8.4.41", 31 | "tailwindcss": "^3.4.10", 32 | "typescript": "^5.5.3", 33 | "typescript-eslint": "^8.0.1", 34 | "vite": "^5.4.1" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/src/App.tsx: -------------------------------------------------------------------------------- 1 | // import { useBlock } from "@starknet-react/core"; 2 | import Header from "./components/Header"; 3 | 4 | function App() { 5 | return ( 6 |
7 |
8 |

9 | Get started by editing  10 | src/App.tsx 11 |

12 | 50 |
51 | ); 52 | } 53 | 54 | export default App; 55 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import { useAccount, useDisconnect } from "@starknet-react/core"; 2 | import ConnectModal from "./starknet/ConnectModal"; 3 | 4 | export default function Header() { 5 | const { address } = useAccount(); 6 | const { disconnect } = useDisconnect(); 7 | 8 | return ( 9 |
10 | {address ? ( 11 |
12 |

{`${address.slice( 13 | 0, 14 | 6, 15 | )}...${address.slice(-4)}`}

16 |

disconnect()} 18 | className="cursor-pointer text-black/50" 19 | > 20 | Disconnect 21 |

22 |
23 | ) : ( 24 | 25 | )} 26 |
27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/src/components/starknet/ConnectModal.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { type Connector, useConnect } from "@starknet-react/core"; 3 | import { Button } from "../ui/Button"; 4 | import Dialog from "../ui/Dialog"; 5 | 6 | export default function ConnectModal() { 7 | const { connect, connectors } = useConnect(); 8 | 9 | return ( 10 | 11 |
12 | {connectors.map((connector: Connector) => { 13 | return ( 14 | 27 | ); 28 | })} 29 |
30 |
31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/src/components/ui/Button.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react"; 2 | 3 | interface ButtonProps extends React.ButtonHTMLAttributes { 4 | children: React.ReactNode; 5 | } 6 | 7 | export const Button = ({ children, ...props }: ButtonProps) => { 8 | return ( 9 | 15 | ); 16 | }; 17 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/src/components/ui/Dialog.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Button } from "./Button"; 3 | 4 | export default function Dialog({ 5 | children, 6 | title, 7 | }: { children: React.ReactNode; title: string }) { 8 | const [isOpen, setIsOpen] = React.useState(false); 9 | 10 | return ( 11 |
12 | 13 | {isOpen && ( 14 |
15 |
16 |
17 |

{title}

18 | 25 |
26 | {children} 27 |
28 |
29 | )} 30 |
31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/src/global.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --foreground-rgb: 0, 0, 0; 7 | --background-start-rgb: 255, 255, 255; 8 | --background-end-rgb: 255, 255, 255; 9 | } 10 | 11 | body { 12 | color: rgb(var(--foreground-rgb)); 13 | background: linear-gradient( 14 | to bottom, 15 | transparent, 16 | rgb(var(--background-end-rgb)) 17 | ) 18 | rgb(var(--background-start-rgb)); 19 | } 20 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { mainnet } from "@starknet-react/chains"; 2 | import { 3 | StarknetConfig, 4 | argent, 5 | braavos, 6 | publicProvider, 7 | useInjectedConnectors, 8 | } from "@starknet-react/core"; 9 | import React from "react"; 10 | import ReactDOM from "react-dom/client"; 11 | import App from "./App"; 12 | import "./global.css"; 13 | 14 | export default function Root({ children }: { children: React.ReactNode }) { 15 | const chains = [mainnet]; 16 | const provider = publicProvider(); 17 | const { connectors } = useInjectedConnectors({ 18 | // Show these connectors if the user has no connector installed. 19 | recommended: [argent(), braavos()], 20 | // Randomize the order of the connectors. 21 | order: "random", 22 | }); 23 | 24 | return ( 25 | 31 | {children} 32 | 33 | ); 34 | } 35 | 36 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( 37 | 38 | 39 | 40 | 41 | , 42 | ); 43 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | "moduleResolution": "bundler", 9 | "allowImportingTsExtensions": true, 10 | "isolatedModules": true, 11 | "moduleDetection": "force", 12 | "noEmit": true, 13 | "jsx": "react-jsx", 14 | "strict": true, 15 | "noUnusedLocals": true, 16 | "noUnusedParameters": true, 17 | "noFallthroughCasesInSwitch": true 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | "allowImportingTsExtensions": true, 8 | "isolatedModules": true, 9 | "moduleDetection": "force", 10 | "noEmit": true, 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "moduleResolution": "bundler" 16 | }, 17 | "include": ["vite.config.ts"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/create-starknet/src/templates/vite/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react"; 2 | import { defineConfig } from "vite"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /packages/create-starknet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@starknet-react/typescript-config/react-library.json", 3 | "compilerOptions": { 4 | "outDir": "dist", 5 | "resolveJsonModule": true 6 | }, 7 | "include": ["src"], 8 | "exclude": ["node_modules", "dist", "src/templates"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/create-starknet/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.ts"], 5 | format: ["esm"], 6 | splitting: false, 7 | sourcemap: true, 8 | dts: false, 9 | clean: true, 10 | esbuildOptions: (options, context) => { 11 | if (context.format === "esm") { 12 | options.packages = "external"; 13 | } 14 | }, 15 | outExtension() { 16 | return { 17 | js: ".js", 18 | }; 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /packages/typescript-config/CHANGELOG.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@starknet-react/typescript-config", 3 | "entries": [ 4 | { 5 | "date": "Thu, 09 Jan 2025 09:48:12 GMT", 6 | "version": "0.0.2", 7 | "tag": "@starknet-react/typescript-config_v0.0.2", 8 | "comments": { 9 | "patch": [ 10 | { 11 | "author": "jadejajaipal5@gmail.com", 12 | "package": "@starknet-react/typescript-config", 13 | "commit": "e23757d4dc52217dcdf169ff742bfc46387e0459", 14 | "comment": "remove not needed configs" 15 | } 16 | ] 17 | } 18 | }, 19 | { 20 | "date": "Sat, 14 Dec 2024 16:19:53 GMT", 21 | "version": "0.0.1", 22 | "tag": "@starknet-react/typescript-config_v0.0.1", 23 | "comments": { 24 | "patch": [ 25 | { 26 | "author": "francesco@ceccon.me", 27 | "package": "@starknet-react/typescript-config", 28 | "commit": "b123755fd0b04c6b2462714382129f87527be33c", 29 | "comment": "core: update abi-wan-kanabi" 30 | } 31 | ] 32 | } 33 | }, 34 | { 35 | "date": "Thu, 31 Oct 2024 12:36:27 GMT", 36 | "version": "0.0.0", 37 | "tag": "@starknet-react/typescript-config_v0.0.0", 38 | "comments": { 39 | "none": [ 40 | { 41 | "author": "ponderingdemocritus@protonmail.com", 42 | "package": "@starknet-react/typescript-config", 43 | "commit": "f1001608f38fc656a888033fc3bf7adef843bccf", 44 | "comment": "none" 45 | } 46 | ] 47 | } 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /packages/typescript-config/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log - @starknet-react/typescript-config 2 | 3 | 4 | 5 | 6 | 7 | ## 0.0.2 8 | 9 | Thu, 09 Jan 2025 09:48:12 GMT 10 | 11 | ### Patches 12 | 13 | - remove not needed configs (jadejajaipal5@gmail.com) 14 | 15 | ## 0.0.1 16 | 17 | Sat, 14 Dec 2024 16:19:53 GMT 18 | 19 | ### Patches 20 | 21 | - core: update abi-wan-kanabi (francesco@ceccon.me) 22 | -------------------------------------------------------------------------------- /packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "target": "ES2022", 8 | "lib": ["ES2023"], 9 | "module": "ESNext", 10 | "moduleResolution": "bundler", 11 | "strict": true, 12 | "esModuleInterop": true, 13 | "skipLibCheck": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "isolatedModules": true 16 | }, 17 | "exclude": ["node_modules", "dist"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@starknet-react/typescript-config", 3 | "version": "0.0.2", 4 | "license": "MIT", 5 | "publishConfig": { 6 | "access": "public" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/typescript-config/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | "moduleResolution": "bundler", 9 | "allowImportingTsExtensions": true, 10 | "isolatedModules": true, 11 | "moduleDetection": "force", 12 | "noEmit": true, 13 | "jsx": "react-jsx", 14 | "strict": true, 15 | "allowJs": true, 16 | "esModuleInterop": true, 17 | "allowSyntheticDefaultImports": true, 18 | "forceConsistentCasingInFileNames": true, 19 | "resolveJsonModule": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - "packages/chains" 3 | - "packages/core" 4 | - "packages/create-starknet" 5 | - "packages/typescript-config" 6 | - "docs" 7 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turborepo.org/schema.json", 3 | "globalDependencies": [ 4 | "**/.env.*local" 5 | ], 6 | "tasks": { 7 | "build": { 8 | "dependsOn": [ 9 | "^build" 10 | ], 11 | "inputs": [ 12 | "src/**/*.ts", 13 | "src/**/*.tsx", 14 | "components/**/*.tsx", 15 | "pages/**/*.mdx", 16 | "package.json", 17 | "tsconfig.json" 18 | ], 19 | "outputs": [ 20 | "dist/**" 21 | ] 22 | }, 23 | "dev": { 24 | "dependsOn": [ 25 | "^build" 26 | ] 27 | }, 28 | "test": { 29 | "dependsOn": [ 30 | "^build" 31 | ] 32 | }, 33 | "test:ci": { 34 | "dependsOn": [ 35 | "^build" 36 | ] 37 | }, 38 | "test:typecheck": { 39 | "dependsOn": [ 40 | "^build" 41 | ] 42 | }, 43 | "lint": {}, 44 | "lint:fix": {}, 45 | "format:check": {}, 46 | "format": {}, 47 | "clean": { 48 | "dependsOn": [] 49 | } 50 | } 51 | } --------------------------------------------------------------------------------