generated from ChainSafe/yarn-workspaces-typescript-template
-
Notifications
You must be signed in to change notification settings - Fork 4
feat: react sdk context #48
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
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
7188214
react lib
BeroBurny c91c1f9
improve sdk typings
BeroBurny 759bb9b
save!
BeroBurny 255e7de
first release
BeroBurny d61c599
small fixes and hooks
BeroBurny 3dff7f9
did i optimize it?
BeroBurny 9d2d0a7
implement deferredRequest inside SDK
BeroBurny 8b88c0f
refactor
BeroBurny abaf660
purge my past mistakes
BeroBurny 094e2e2
readme! updated
BeroBurny 0e8b06d
Merge branch 'master' into beroburny/react-context
BeroBurny 63244c7
release please stuff
BeroBurny e559963
fix code styling
BeroBurny 090bf54
fix README.md
BeroBurny File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| { | ||
| "packages/sdk": "0.1.0" | ||
| "packages/sdk": "0.1.0", | ||
| "packages/react": "0.0.0" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # Logs | ||
| logs | ||
| *.log | ||
| npm-debug.log* | ||
| yarn-debug.log* | ||
| yarn-error.log* | ||
| pnpm-debug.log* | ||
| lerna-debug.log* | ||
|
|
||
| node_modules | ||
| dist | ||
| dist-ssr | ||
| *.local | ||
|
|
||
| *.tsbuildinfo | ||
|
|
||
| # Editor directories and files | ||
| .vscode/* | ||
| !.vscode/extensions.json | ||
| .idea | ||
| .DS_Store | ||
| *.suo | ||
| *.ntvs* | ||
| *.njsproj | ||
| *.sln | ||
| *.sw? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| # Sprinter React SDK | ||
|
|
||
| The Sprinter React SDK is a React wrapper for the [Sprinter SDK](https://github.com/ChainSafe/sprinter-sdk), enabling easy interaction with blockchain networks through React components and hooks. It provides context management and custom hooks for retrieving balances, tokens, supported chains, and solutions for asset transfers. | ||
|
|
||
| ## Installation | ||
|
|
||
| To install the package, use npm or yarn: | ||
|
|
||
| ```bash | ||
| npm install @chainsafe/sprinter-react | ||
| # or | ||
| yarn add @chainsafe/sprinter-react | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| Wrap your application in the `SprinterContext` to gain access to blockchain-related data within your component tree. | ||
|
|
||
| ### Example | ||
|
|
||
| ```tsx | ||
| import React from 'react'; | ||
| import { SprinterContext } from '@chainsafe/sprinter-react'; | ||
|
|
||
| const App = () => ( | ||
| <SprinterContext> | ||
| <YourComponent /> | ||
| </SprinterContext> | ||
| ); | ||
|
|
||
| export default App; | ||
| ``` | ||
|
|
||
| Inside your components, you can use the provided hooks to interact with blockchain data: | ||
|
|
||
| ```tsx | ||
| import React, { useEffect } from 'react'; | ||
| import { useSprinterBalances, useSprinterTokens } from '@chainsafe/sprinter-react'; | ||
|
|
||
| const YourComponent = () => { | ||
| const ownerAddress = "0xYourAddressHere"; | ||
| const { balances, getUserBalances } = useSprinterBalances(ownerAddress); | ||
|
|
||
| useEffect(() => { | ||
| getUserBalances(); | ||
| }, [getUserBalances]); | ||
|
|
||
| return ( | ||
| <div> | ||
| <h1>Balances:</h1> | ||
| <pre>{JSON.stringify(balances, null, 2)}</pre> | ||
| <h1>Available Tokens:</h1> | ||
| <pre>{JSON.stringify(tokens, null, 2)}</pre> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default YourComponent; | ||
| ``` | ||
|
|
||
| ### Available Hooks | ||
|
|
||
| The following hooks are provided by the SDK: | ||
|
|
||
| - **`useSprinter()`**: Access everything from the Sprinter context. | ||
| - **`useSprinterBalances(account: Address)`**: Retrieve user balances for a given account. | ||
| - **`useSprinterTokens()`**: Retrieve available tokens. | ||
| - **`useSprinterChains()`**: Retrieve available blockchain chains. | ||
| - **`useSprinterSolution()`**: Retrieve solutions for asset transfers. | ||
| - **`useSprinterCallSolution()`**: Call solutions for transferring assets. | ||
|
|
||
| ### Custom Fetch Options | ||
|
|
||
| You can pass custom fetch options when initializing the context: | ||
|
|
||
| ```tsx | ||
| <SprinterContext fetchOptions={{ baseUrl: "https://api.test.sprinter.buildwithsygma.com/" }}> | ||
| <YourComponent /> | ||
| </SprinterContext> | ||
| ``` | ||
|
|
||
| ## Contributing | ||
|
|
||
| Contributions are welcome! Feel free to open issues or submit pull requests for new features or bug fixes. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 }, | ||
| ], | ||
| }, | ||
| }, | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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>Vite + React + TS</title> | ||
| </head> | ||
| <body> | ||
| <div id="root"></div> | ||
| <script type="module" src="/src/main.tsx"></script> | ||
| </body> | ||
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import {createContext, ReactNode, useEffect, useState} from "react"; | ||
| import {type FetchOptions, Sprinter} from "@chainsafe/sprinter-sdk"; | ||
| import {useTokens} from "./internal/useTokens.ts"; | ||
| import {useChains} from "./internal/useChains.ts"; | ||
| import {useSolution} from "./internal/useSolution.ts"; | ||
| import {useCallSolution} from "./internal/useCallSolution.ts"; | ||
| import {useBalances} from "./internal/useBalances.ts"; | ||
|
|
||
| type SprinterContext = ReturnType<typeof useBalances> & ReturnType<typeof useTokens> & ReturnType<typeof useChains> & ReturnType<typeof useSolution> & ReturnType<typeof useCallSolution>; | ||
|
|
||
| export const Context = createContext<SprinterContext | null>(null); | ||
|
|
||
| interface SprinterContextProps { | ||
| children?: ReactNode | undefined; | ||
| fetchOptions?: Omit<FetchOptions, "signal">; | ||
| } | ||
|
|
||
| export function SprinterContext({ children, fetchOptions }: SprinterContextProps) { | ||
| const [sprinter] = useState(new Sprinter(fetchOptions)); | ||
|
|
||
| /** Balances */ | ||
| const { balances, getUserBalances } = useBalances(sprinter); | ||
|
|
||
| /** Tokens */ | ||
| const { tokens, getAvailableTokens } = useTokens(sprinter); | ||
|
|
||
| /** Chains */ | ||
| const { chains, getAvailableChains } = useChains(sprinter); | ||
|
|
||
| /** Solutions */ | ||
| const { solution, getSolution } = useSolution(sprinter); | ||
|
|
||
| /** Call Solution */ | ||
| const { callSolution, getCallSolution } = useCallSolution(sprinter); | ||
|
|
||
| /** Initialization */ | ||
| useEffect(() => { | ||
| getAvailableTokens(); | ||
| getAvailableChains(); | ||
| }, [sprinter]); | ||
|
|
||
| return <Context.Provider value={{ | ||
| balances, getUserBalances, | ||
| tokens, getAvailableTokens, | ||
| chains, getAvailableChains, | ||
| solution, getSolution, | ||
| callSolution, getCallSolution | ||
| }}>{children}</Context.Provider>; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| import {useCallback, useContext} from "react"; | ||
| import {Context} from "./context.tsx"; | ||
| import {Address} from "@chainsafe/sprinter-sdk"; | ||
| import {BalancesEntry} from "./internal/useBalances.ts"; | ||
|
|
||
| /** Everything from context */ | ||
| export function useSprinter() { | ||
| const context = useContext(Context); | ||
|
|
||
| if (!context) throw new Error('Sprinter Context is not defined'); | ||
|
|
||
| return context; | ||
| } | ||
|
|
||
| /** Balances */ | ||
| const balancesEmptyState = { | ||
| data: null, | ||
| loading: false, | ||
| error: null, | ||
| }; | ||
|
|
||
| export function useSprinterBalances(account: Address) { | ||
| const { balances: _balances, getUserBalances: _getUserBalances } = useSprinter(); | ||
|
|
||
| const balances: BalancesEntry = _balances[account] || balancesEmptyState; | ||
| const getUserBalances = useCallback(() => _getUserBalances(account), [account]); | ||
|
|
||
| return { balances, getUserBalances }; | ||
| } | ||
|
|
||
| /** Tokens */ | ||
| export function useSprinterTokens() { | ||
| const { tokens, getAvailableTokens } = useSprinter(); | ||
| return { tokens, getAvailableTokens }; | ||
| } | ||
|
|
||
| /** Chains */ | ||
| export function useSprinterChains() { | ||
| const { chains, getAvailableChains } = useSprinter(); | ||
| return { chains, getAvailableChains }; | ||
| } | ||
|
|
||
| /** Solutions */ | ||
| export function useSprinterSolution() { | ||
| const { solution, getSolution } = useSprinter(); | ||
| return { solution, getSolution }; | ||
| } | ||
|
|
||
| /** Call Solution */ | ||
| export function useSprinterCallSolution() { | ||
| const { callSolution, getCallSolution } = useSprinter(); | ||
| return { callSolution, getCallSolution }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| import {useCallback, useReducer} from "react"; | ||
|
|
||
| const initialState = { | ||
| data: null, | ||
| loading: false, | ||
| error: null, | ||
| }; | ||
|
|
||
| export function useAsyncRequest<T>() { | ||
| const [state, dispatch] = useReducer(fetchReducer<T>, initialState as AsyncRequestState<T>); | ||
|
|
||
| const makeRequest = useCallback((request: Promise<T>) => { | ||
| dispatch({ type: RequestAction.INIT }); | ||
|
|
||
| request.then(result => { | ||
| dispatch({ type: RequestAction.SUCCESS, payload: result }); | ||
| }).catch((error: Error) => { | ||
| dispatch({ type: RequestAction.FAILURE, error: error.message }); | ||
| }); | ||
| }, [dispatch]); | ||
|
|
||
| return { state, makeRequest }; | ||
| } | ||
|
|
||
| enum RequestAction { | ||
| INIT = 'REQUEST_INIT', | ||
| SUCCESS = 'REQUEST_SUCCESS', | ||
| FAILURE = "REQUEST_FAILURE", | ||
| } | ||
|
|
||
| export interface AsyncRequestState<T> { | ||
| data: T | null; | ||
| loading: boolean; | ||
| error: string | null; | ||
| } | ||
|
|
||
| type AsyncRequestActions<T> = | ||
| | { type: RequestAction.INIT } | ||
| | { type: RequestAction.SUCCESS; payload: T } | ||
| | { type: RequestAction.FAILURE; error: string }; | ||
|
|
||
| const fetchReducer = <T>(state: AsyncRequestState<T>, action: AsyncRequestActions<T>): AsyncRequestState<T> => { | ||
| switch (action.type) { | ||
| case RequestAction.INIT: | ||
| return { | ||
| ...state, | ||
| loading: true, | ||
| error: null, | ||
| }; | ||
| case RequestAction.SUCCESS: | ||
| return { | ||
| ...state, | ||
| loading: false, | ||
| data: action.payload, | ||
| }; | ||
| case RequestAction.FAILURE: | ||
| return { | ||
| ...state, | ||
| loading: false, | ||
| error: action.error, | ||
| }; | ||
| default: | ||
| throw new Error('Unknown action type'); | ||
| } | ||
| }; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Seems like a centralized service, doesn't it make sense to choose from selectable environments rather than a connection string? Like
SprinterEnvironment.TestorSprinterEnvironment.MainThere 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.
It defaults to
mainnetand with that approach, we eliminate the need for updates for client's custom deployments or proxies