-
Notifications
You must be signed in to change notification settings - Fork 54
chore: add sdk token balance example #421
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
pnpm-debug.log* | ||
lerna-debug.log* | ||
|
||
node_modules | ||
dist | ||
dist-ssr | ||
*.local | ||
|
||
# Editor directories and files | ||
.vscode/* | ||
!.vscode/extensions.json | ||
.idea | ||
.DS_Store | ||
*.suo | ||
*.ntvs* | ||
*.njsproj | ||
*.sln | ||
*.sw? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# React + TypeScript + Vite | ||
|
||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. | ||
|
||
Currently, two official plugins are available: | ||
|
||
- [@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 | ||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh | ||
|
||
## Expanding the ESLint configuration | ||
|
||
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: | ||
|
||
```js | ||
export default tseslint.config({ | ||
extends: [ | ||
// Remove ...tseslint.configs.recommended and replace with this | ||
...tseslint.configs.recommendedTypeChecked, | ||
// Alternatively, use this for stricter rules | ||
...tseslint.configs.strictTypeChecked, | ||
// Optionally, add this for stylistic rules | ||
...tseslint.configs.stylisticTypeChecked, | ||
], | ||
languageOptions: { | ||
// other options... | ||
parserOptions: { | ||
project: ['./tsconfig.node.json', './tsconfig.app.json'], | ||
tsconfigRootDir: import.meta.dirname, | ||
}, | ||
}, | ||
}) | ||
``` | ||
|
||
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: | ||
|
||
```js | ||
// eslint.config.js | ||
import reactX from 'eslint-plugin-react-x' | ||
import reactDom from 'eslint-plugin-react-dom' | ||
|
||
export default tseslint.config({ | ||
plugins: { | ||
// Add the react-x and react-dom plugins | ||
'react-x': reactX, | ||
'react-dom': reactDom, | ||
}, | ||
rules: { | ||
// other rules... | ||
// Enable its recommended typescript rules | ||
...reactX.configs['recommended-typescript'].rules, | ||
...reactDom.configs.recommended.rules, | ||
}, | ||
}) | ||
``` | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { createDojoConfig } from "@dojoengine/core"; | ||
|
||
import manifest from "../../worlds/dojo-starter/manifest_dev.json"; | ||
|
||
export const dojoConfig = createDojoConfig({ | ||
manifest, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import js from '@eslint/js' | ||
import globals from 'globals' | ||
import reactHooks from 'eslint-plugin-react-hooks' | ||
import reactRefresh from 'eslint-plugin-react-refresh' | ||
import tseslint from 'typescript-eslint' | ||
|
||
export default tseslint.config( | ||
{ ignores: ['dist'] }, | ||
{ | ||
extends: [js.configs.recommended, ...tseslint.configs.recommended], | ||
files: ['**/*.{ts,tsx}'], | ||
languageOptions: { | ||
ecmaVersion: 2020, | ||
globals: globals.browser, | ||
}, | ||
plugins: { | ||
'react-hooks': reactHooks, | ||
'react-refresh': reactRefresh, | ||
}, | ||
rules: { | ||
...reactHooks.configs.recommended.rules, | ||
'react-refresh/only-export-components': [ | ||
'warn', | ||
{ allowConstantExport: true }, | ||
], | ||
}, | ||
}, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Example SDK Tokens</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<script type="module" src="/src/main.tsx"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,43 @@ | ||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||
"name": "example-vite-token-balance", | ||||||||||||||||||||||||||||||||||||||||||
"private": true, | ||||||||||||||||||||||||||||||||||||||||||
"version": "0.0.0", | ||||||||||||||||||||||||||||||||||||||||||
"type": "module", | ||||||||||||||||||||||||||||||||||||||||||
"scripts": { | ||||||||||||||||||||||||||||||||||||||||||
"dev": "vite", | ||||||||||||||||||||||||||||||||||||||||||
"build": "tsc -b && vite build", | ||||||||||||||||||||||||||||||||||||||||||
"lint": "eslint .", | ||||||||||||||||||||||||||||||||||||||||||
"preview": "vite preview" | ||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||
"dependencies": { | ||||||||||||||||||||||||||||||||||||||||||
"@cartridge/connector": "^0.7.6", | ||||||||||||||||||||||||||||||||||||||||||
"@cartridge/controller": "^0.7.6", | ||||||||||||||||||||||||||||||||||||||||||
"@dojoengine/core": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||
"@dojoengine/predeployed-connector": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||
"@dojoengine/sdk": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||
"@dojoengine/torii-client": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||
"@dojoengine/utils": "workspace:*", | ||||||||||||||||||||||||||||||||||||||||||
"@starknet-react/chains": "catalog:", | ||||||||||||||||||||||||||||||||||||||||||
"@starknet-react/core": "catalog:", | ||||||||||||||||||||||||||||||||||||||||||
"@tailwindcss/vite": "^4.0.1", | ||||||||||||||||||||||||||||||||||||||||||
"react": "^19.0.0", | ||||||||||||||||||||||||||||||||||||||||||
"react-dom": "^19.0.0", | ||||||||||||||||||||||||||||||||||||||||||
"starknet": "catalog:", | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+20
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainSpecify exact versions instead of using "catalog:" references. Using "catalog:" for version references may lead to unpredictable behavior if the catalog version changes. It's generally better to pin specific versions for production code. "@dojoengine/sdk": "workspace:*",
"@dojoengine/torii-client": "workspace:*",
"@dojoengine/utils": "workspace:*",
- "@starknet-react/chains": "catalog:",
- "@starknet-react/core": "catalog:",
+ "@starknet-react/chains": "^0.2.2",
+ "@starknet-react/core": "^2.1.0",
"@tailwindcss/vite": "^4.0.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
- "starknet": "catalog:",
+ "starknet": "^5.24.3",
"tailwindcss": "^4.0.14" 🌐 Web query:
💡 Result: As of March 2025, the latest versions are: @starknet-react/chains: 3.1.2 Key details from sources:
These versions support Starknet network upgrades up to v0.13.3[3][5], including new features like optimistic parallelization and applicative recursion[3]. When installing, ensure compatibility between package versions as shown in the Starknet React documentation[19]. Citations:
Update the version references to the latest stable releases in package.json Please change the version references for the @starknet-react and starknet dependencies from
Below is the updated diff snippet for the file "@dojoengine/sdk": "workspace:*",
"@dojoengine/torii-client": "workspace:*",
"@dojoengine/utils": "workspace:*",
- "@starknet-react/chains": "catalog:",
- "@starknet-react/core": "catalog:",
+ "@starknet-react/chains": "^3.1.2",
+ "@starknet-react/core": "^3.7.2",
"@tailwindcss/vite": "^4.0.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
- "starknet": "catalog:",
+ "starknet": "^6.24.1",
"tailwindcss": "^4.0.14" Using specific version numbers will help avoid unpredictable behavior if the catalog versions change. Please update accordingly. 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
"tailwindcss": "^4.0.14" | ||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||
"devDependencies": { | ||||||||||||||||||||||||||||||||||||||||||
"@eslint/js": "^9.21.0", | ||||||||||||||||||||||||||||||||||||||||||
"@types/react": "^19.0.10", | ||||||||||||||||||||||||||||||||||||||||||
"@types/react-dom": "^19.0.4", | ||||||||||||||||||||||||||||||||||||||||||
"@vitejs/plugin-react": "^4.3.4", | ||||||||||||||||||||||||||||||||||||||||||
"eslint": "^9.21.0", | ||||||||||||||||||||||||||||||||||||||||||
"eslint-plugin-react-hooks": "^5.1.0", | ||||||||||||||||||||||||||||||||||||||||||
"eslint-plugin-react-refresh": "^0.4.19", | ||||||||||||||||||||||||||||||||||||||||||
"globals": "^15.15.0", | ||||||||||||||||||||||||||||||||||||||||||
"typescript": "~5.7.2", | ||||||||||||||||||||||||||||||||||||||||||
"typescript-eslint": "^8.24.1", | ||||||||||||||||||||||||||||||||||||||||||
"vite": "^6.2.0", | ||||||||||||||||||||||||||||||||||||||||||
"vite-plugin-top-level-await": "^1.5.0", | ||||||||||||||||||||||||||||||||||||||||||
"vite-plugin-wasm": "^3.4.1" | ||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#root { | ||
max-width: 1280px; | ||
margin: 0 auto; | ||
padding: 2rem; | ||
text-align: center; | ||
} | ||
|
||
.logo { | ||
height: 6em; | ||
padding: 1.5em; | ||
will-change: filter; | ||
transition: filter 300ms; | ||
} | ||
.logo:hover { | ||
filter: drop-shadow(0 0 2em #646cffaa); | ||
} | ||
.logo.react:hover { | ||
filter: drop-shadow(0 0 2em #61dafbaa); | ||
} | ||
|
||
@keyframes logo-spin { | ||
from { | ||
transform: rotate(0deg); | ||
} | ||
to { | ||
transform: rotate(360deg); | ||
} | ||
} | ||
|
||
@media (prefers-reduced-motion: no-preference) { | ||
a:nth-of-type(2) .logo { | ||
animation: logo-spin infinite 20s linear; | ||
} | ||
} | ||
|
||
.card { | ||
padding: 2em; | ||
} | ||
|
||
.read-the-docs { | ||
color: #888; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import "./App.css"; | ||
import { Wallet } from "./components/wallet"; | ||
import TokenBalance from "./components/token-balance"; | ||
|
||
function App() { | ||
return ( | ||
<> | ||
<h1>Connect your wallet</h1> | ||
<Wallet /> | ||
<TokenBalance /> | ||
</> | ||
); | ||
} | ||
|
||
export default App; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,41 @@ | ||||||||||||||||||||||||||||||||||
import type { PropsWithChildren } from "react"; | ||||||||||||||||||||||||||||||||||
import { mainnet } from "@starknet-react/chains"; | ||||||||||||||||||||||||||||||||||
import { jsonRpcProvider, StarknetConfig, voyager } from "@starknet-react/core"; | ||||||||||||||||||||||||||||||||||
import { dojoConfig } from "../../dojoConfig"; | ||||||||||||||||||||||||||||||||||
import { usePredeployedAccounts } from "@dojoengine/predeployed-connector/react"; | ||||||||||||||||||||||||||||||||||
import { ControllerConnector } from "@cartridge/connector"; | ||||||||||||||||||||||||||||||||||
import { shortString } from "starknet"; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const controller = new ControllerConnector({ | ||||||||||||||||||||||||||||||||||
chains: [ | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
rpcUrl: "http://localhost:5050", | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||||
defaultChainId: shortString.encodeShortString("KATANA"), | ||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||
Comment on lines
+9
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid hardcoding RPC URL in the controller configuration The RPC URL is hardcoded to "http://localhost:5050". Consider using the URL from const controller = new ControllerConnector({
chains: [
{
- rpcUrl: "http://localhost:5050",
+ rpcUrl: dojoConfig.rpcUrl as string,
},
],
defaultChainId: shortString.encodeShortString("KATANA"),
}); 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
export default function StarknetProvider({ children }: PropsWithChildren) { | ||||||||||||||||||||||||||||||||||
const { connectors } = usePredeployedAccounts({ | ||||||||||||||||||||||||||||||||||
rpc: dojoConfig.rpcUrl as string, | ||||||||||||||||||||||||||||||||||
id: "katana", | ||||||||||||||||||||||||||||||||||
name: "Katana", | ||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const provider = jsonRpcProvider({ | ||||||||||||||||||||||||||||||||||
rpc: () => ({ nodeUrl: dojoConfig.rpcUrl as string }), | ||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||
<StarknetConfig | ||||||||||||||||||||||||||||||||||
chains={[mainnet]} | ||||||||||||||||||||||||||||||||||
provider={provider} | ||||||||||||||||||||||||||||||||||
connectors={[...connectors, controller]} | ||||||||||||||||||||||||||||||||||
explorer={voyager} | ||||||||||||||||||||||||||||||||||
autoConnect | ||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||
{/* @ts-ignore react version mismatch */} | ||||||||||||||||||||||||||||||||||
{children} | ||||||||||||||||||||||||||||||||||
Comment on lines
+37
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainRemove TypeScript ignore comment and fix type issue properly The code uses a TypeScript ignore comment to suppress a React version mismatch error. Instead of ignoring the error, consider addressing the underlying issue by ensuring compatible versions of dependencies. - {/* @ts-ignore react version mismatch */}
{children} Then update your package.json to ensure compatible versions of React dependencies. 🏁 Script executed: #!/bin/bash
# Check React versions in package.json
grep -r "\"react\":" examples/example-vite-token-balance/package.json
grep -r "\"@starknet-react" examples/example-vite-token-balance/package.json Length of output: 265 Fix dependency mismatches and remove the TS ignore directive
📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||
</StarknetConfig> | ||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { useTokens, WithAccount } from "@dojoengine/sdk/react"; | ||
|
||
function TokenBalance({ address }: { address: `0x${string}` }) { | ||
const { tokens, getBalance, toDecimal } = useTokens({ | ||
accountAddresses: [address], | ||
}); | ||
|
||
return ( | ||
<div> | ||
Token Balance: {address} | ||
<div> | ||
{tokens.map((token, idx) => ( | ||
<div key={idx}> | ||
Comment on lines
+12
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using array index as key in React lists Using array indices as keys can lead to rendering issues if the order of items changes. Consider using a more stable unique identifier like -{tokens.map((token, idx) => (
- <div key={idx}>
+{tokens.map((token) => (
+ <div key={token.contract_address}>
🧰 Tools🪛 Biome (1.9.4)[error] 13-13: Avoid using the index of an array as key property in an element. This is the source of the key value. The order of the items may change, and this also affects performances and component state. (lint/suspicious/noArrayIndexKey) |
||
{token.symbol} | ||
| ||
{toDecimal(token, getBalance(token))} | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default WithAccount(TokenBalance); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { | ||
Connector, | ||
useAccount, | ||
useConnect, | ||
useDisconnect, | ||
} from "@starknet-react/core"; | ||
import { useCallback, useState } from "react"; | ||
|
||
export function Wallet() { | ||
const { connectAsync, connectors } = useConnect(); | ||
const { address } = useAccount(); | ||
const { disconnect } = useDisconnect(); | ||
const [pendingConnectorId, setPendingConnectorId] = useState< | ||
string | undefined | ||
>(undefined); | ||
|
||
const connect = useCallback( | ||
async (connector: Connector) => { | ||
setPendingConnectorId(connector.id); | ||
try { | ||
await connectAsync({ connector }); | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
setPendingConnectorId(undefined); | ||
}, | ||
[connectAsync] | ||
); | ||
|
||
function isWalletConnecting(connectorId: string) { | ||
return pendingConnectorId === connectorId; | ||
} | ||
|
||
if (address) { | ||
return ( | ||
<div className="mb-6 flex justify-center"> | ||
<div style={{ display: "flex", gap: "1rem" }}> | ||
<button | ||
onClick={() => disconnect()} | ||
className="text-white border border-white p-3" | ||
> | ||
Disconnect | ||
</button> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<div className="mb-6"> | ||
<h2 className="text-white">Connect Wallet</h2> | ||
<div style={{ display: "flex", gap: "1rem" }}> | ||
{} | ||
{connectors.map((connector) => ( | ||
<button | ||
key={connector.id} | ||
onClick={() => connect(connector)} | ||
disabled={!connector.available()} | ||
className="text-white border border-white p-3" | ||
> | ||
{connector.name} | ||
{isWalletConnecting(connector.id) && "Connecting"} | ||
</button> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add installation and usage instructions
The README lacks instructions on how to install dependencies and run the example. Consider adding sections for: