├── .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 |
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 |
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 | (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 |
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 | }
--------------------------------------------------------------------------------