-
Notifications
You must be signed in to change notification settings - Fork 13
feat(streaming): implement superfluid sdk and react hooks #31
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
Open
HushLuxe
wants to merge
25
commits into
GoodDollar:main
Choose a base branch
from
HushLuxe:feat/streaming-sdk
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
8b8ca73
feat(streaming): implement consolidated superfluid sdk and react hooks
HushLuxe deeda20
refactor(streaming): optimize sdk initialization and hook logic
HushLuxe 23ae225
refactor(streaming): optimize hook logic and fix type safety
HushLuxe 42091d2
chore: revert frontend and config changes to match main scope
HushLuxe ead6715
chore: remove accidental files and clean up package.json
HushLuxe 4ef249b
chore: remove all demo-identity-app changes from PR
HushLuxe aa82b15
chore: include updated yarn.lock for new packages
HushLuxe 5df9d13
chore: use * for internal dependency as requested
HushLuxe 4a09487
refactor(streaming): make token parameter optional with auto-resolution
HushLuxe 0791279
feat(demo): add streaming SDK demo app
HushLuxe a441adc
edit readme file
HushLuxe 168af8c
chore: update demo readme
HushLuxe 389bc15
chore: remove hardcoded addresses from readme
HushLuxe bc12016
fix: update security config
HushLuxe e14148d
docs: simplify readme and cleanup address placeholders
HushLuxe 72427d3
docs: update demo readme
HushLuxe 8ff61e7
docs: use bracketed placeholders for addresses
HushLuxe f1f3bd4
added gitiLgnore
HushLuxe 76e4bc6
feat: implement multi-token support and update demo app
HushLuxe 9670b4a
feat: implement safe batching and pagination for subgraph queries
HushLuxe f24af64
feat: sdk polish and defensive guards
HushLuxe fe10910
Merge remote-tracking branch 'upstream/main' into feat/streaming-sdk
HushLuxe 75d6e37
fix: correct setFlowrate args, align hook params, sync docs
HushLuxe 2165ec9
fix(streaming): align docs/hooks, remove unsupported chain refs
HushLuxe 0f508b5
fix(streaming): align CFA calls, hooks, and demo
HushLuxe 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
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
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 +1,2 @@ | ||
| export * from "./citizen-sdk" | ||
| export * from "./streaming" |
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,306 @@ | ||
| import { useMemo } from "react" | ||
| import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query" | ||
| import { type Address, type Hash } from "viem" | ||
| import { usePublicClient, useWalletClient } from "wagmi" | ||
| import { | ||
| StreamingSDK, | ||
| GdaSDK, | ||
| SubgraphClient, | ||
| SupportedChains, | ||
| type StreamInfo, | ||
| type GDAPool, | ||
| type PoolMembership, | ||
| type SUPReserveLocker, | ||
| type Environment, | ||
| } from "@goodsdks/streaming-sdk" | ||
|
|
||
| /** | ||
| * Hook parameter interfaces | ||
| */ | ||
| export interface UseCreateStreamParams { | ||
| receiver: Address | ||
| token: Address | ||
| flowRate: bigint | ||
| userData?: `0x${string}` | ||
| environment?: Environment | ||
| } | ||
|
|
||
| export interface UseUpdateStreamParams { | ||
| receiver: Address | ||
| token: Address | ||
| newFlowRate: bigint | ||
| userData?: `0x${string}` | ||
| environment?: Environment | ||
| } | ||
|
|
||
| export interface UseDeleteStreamParams { | ||
| receiver: Address | ||
| token: Address | ||
| environment?: Environment | ||
| } | ||
|
|
||
| export interface UseStreamListParams { | ||
| account: Address | ||
| direction?: "incoming" | "outgoing" | "all" | ||
| environment?: Environment | ||
| enabled?: boolean | ||
| } | ||
|
|
||
| export interface UseGDAPoolsParams { | ||
| enabled?: boolean | ||
| } | ||
|
|
||
| export interface UsePoolMembershipsParams { | ||
| account: Address | ||
| enabled?: boolean | ||
| } | ||
|
|
||
| export interface UseConnectToPoolParams { | ||
| poolAddress: Address | ||
| userData?: `0x${string}` | ||
| } | ||
|
|
||
| export interface UseDisconnectFromPoolParams { | ||
| poolAddress: Address | ||
| userData?: `0x${string}` | ||
| } | ||
|
|
||
| export interface UseSupReservesParams { | ||
| environment?: Environment | ||
| apiKey?: string | ||
| enabled?: boolean | ||
| } | ||
|
|
||
| /** | ||
| * React Hooks for Superfluid operations | ||
| */ | ||
| export function useCreateStream() { | ||
| const publicClient = usePublicClient() | ||
| const { data: walletClient } = useWalletClient() | ||
| const queryClient = useQueryClient() | ||
|
|
||
| const sdks = useMemo(() => { | ||
sourcery-ai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (!publicClient) return new Map<string, StreamingSDK>() | ||
| const envs = ["production", "staging", "development"] as const | ||
| const m = new Map<string, StreamingSDK>() | ||
| for (const e of envs) { | ||
| try { | ||
| m.set(e, new StreamingSDK(publicClient, walletClient ? walletClient : undefined, { environment: e })) | ||
| } catch (err) { | ||
| // ignore | ||
| } | ||
| } | ||
| return m | ||
| }, [publicClient, walletClient]) | ||
|
|
||
| return useMutation({ | ||
| mutationFn: async ({ | ||
| receiver, | ||
| token, | ||
| flowRate, | ||
| userData = "0x", | ||
| environment = "production", | ||
| }: UseCreateStreamParams): Promise<Hash> => { | ||
| if (!publicClient) throw new Error("Public client not available") | ||
| if (!walletClient) throw new Error("Wallet client not available") | ||
| const sdk = sdks.get(environment) | ||
| if (!sdk) throw new Error("SDK not available for selected environment") | ||
| return sdk.createStream({ receiver, token, flowRate, userData }) | ||
| }, | ||
| onSuccess: () => { | ||
| queryClient.invalidateQueries({ queryKey: ["streams"] }) | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| export function useUpdateStream() { | ||
| const publicClient = usePublicClient() | ||
| const { data: walletClient } = useWalletClient() | ||
| const queryClient = useQueryClient() | ||
|
|
||
| const sdks = useMemo(() => { | ||
| if (!publicClient) return new Map<string, StreamingSDK>() | ||
| const envs = ["production", "staging", "development"] as const | ||
| const m = new Map<string, StreamingSDK>() | ||
| for (const e of envs) { | ||
| try { | ||
| m.set(e, new StreamingSDK(publicClient, walletClient as any, { environment: e })) | ||
| } catch (err) { | ||
| // ignore | ||
| } | ||
| } | ||
| return m | ||
| }, [publicClient, walletClient]) | ||
|
|
||
| return useMutation({ | ||
| mutationFn: async ({ | ||
| receiver, | ||
| token, | ||
| newFlowRate, | ||
| userData = "0x", | ||
| environment = "production", | ||
| }: UseUpdateStreamParams): Promise<Hash> => { | ||
| if (!publicClient) throw new Error("Public client not available") | ||
| if (!walletClient) throw new Error("Wallet client not available") | ||
| const sdk = sdks.get(environment) | ||
| if (!sdk) throw new Error("SDK not available for selected environment") | ||
| return sdk.updateStream({ receiver, token, newFlowRate, userData }) | ||
| }, | ||
| onSuccess: () => { | ||
| queryClient.invalidateQueries({ queryKey: ["streams"] }) | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| export function useDeleteStream() { | ||
| const publicClient = usePublicClient() | ||
| const { data: walletClient } = useWalletClient() | ||
| const queryClient = useQueryClient() | ||
|
|
||
| const sdks = useMemo(() => { | ||
| if (!publicClient) return new Map<string, StreamingSDK>() | ||
| const envs = ["production", "staging", "development"] as const | ||
| const m = new Map<string, StreamingSDK>() | ||
| for (const e of envs) { | ||
| try { | ||
| m.set(e, new StreamingSDK(publicClient, walletClient as any, { environment: e })) | ||
| } catch (err) { | ||
| // ignore | ||
| } | ||
| } | ||
| return m | ||
| }, [publicClient, walletClient]) | ||
|
|
||
| return useMutation({ | ||
| mutationFn: async ({ | ||
| receiver, | ||
| token, | ||
| environment = "production", | ||
| }: UseDeleteStreamParams): Promise<Hash> => { | ||
| if (!publicClient) throw new Error("Public client not available") | ||
| if (!walletClient) throw new Error("Wallet client not available") | ||
| const sdk = sdks.get(environment) | ||
| if (!sdk) throw new Error("SDK not available for selected environment") | ||
| return sdk.deleteStream({ receiver, token }) | ||
| }, | ||
| onSuccess: () => { | ||
| queryClient.invalidateQueries({ queryKey: ["streams"] }) | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| export function useStreamList({ | ||
| account, | ||
| direction = "all", | ||
| environment = "production", | ||
| enabled = true, | ||
| }: UseStreamListParams) { | ||
| const publicClient = usePublicClient() | ||
|
|
||
| return useQuery<StreamInfo[]>({ | ||
| queryKey: ["streams", account, direction, environment, publicClient?.chain?.id], | ||
| queryFn: async () => { | ||
| if (!publicClient) throw new Error("Public client not available") | ||
| const sdk = new StreamingSDK(publicClient, undefined, { environment }) | ||
| return sdk.getActiveStreams(account, direction) | ||
| }, | ||
| enabled: enabled && !!account && !!publicClient, | ||
| }) | ||
| } | ||
|
|
||
| export function useGDAPools({ | ||
| enabled = true | ||
| }: UseGDAPoolsParams = {}) { | ||
| const publicClient = usePublicClient() | ||
| const sdk = useMemo(() => { | ||
| if (!publicClient) return null | ||
| return new GdaSDK(publicClient, undefined, { chainId: publicClient.chain?.id }) | ||
| }, [publicClient]) | ||
|
|
||
| return useQuery<GDAPool[]>({ | ||
| queryKey: ["gda-pools", publicClient?.chain?.id], | ||
| queryFn: async () => { | ||
| if (!sdk) throw new Error("Public client not available") | ||
| return sdk.getDistributionPools() | ||
| }, | ||
| enabled: enabled && !!publicClient, | ||
| }) | ||
| } | ||
|
|
||
| export function usePoolMemberships({ | ||
| account, | ||
| enabled = true, | ||
| }: UsePoolMembershipsParams) { | ||
| const publicClient = usePublicClient() | ||
| const sdk = useMemo(() => { | ||
| if (!publicClient) return null | ||
| return new GdaSDK(publicClient) | ||
| }, [publicClient]) | ||
|
|
||
| return useQuery<PoolMembership[]>({ | ||
| queryKey: ["gda-memberships", account, publicClient?.chain?.id], | ||
| queryFn: async () => { | ||
| if (!sdk) throw new Error("Public client not available") | ||
| return sdk.getPoolMemberships(account) | ||
| }, | ||
| enabled: enabled && !!publicClient && !!account, | ||
| }) | ||
| } | ||
|
|
||
| export function useConnectToPool() { | ||
| const publicClient = usePublicClient() | ||
| const { data: walletClient } = useWalletClient() | ||
| const queryClient = useQueryClient() | ||
|
|
||
| return useMutation({ | ||
| mutationFn: async ({ | ||
| poolAddress, | ||
| userData = "0x", | ||
| }: UseConnectToPoolParams): Promise<Hash> => { | ||
| if (!publicClient) throw new Error("Public client not available") | ||
| if (!walletClient) throw new Error("Wallet client not available") | ||
| const sdk = new GdaSDK(publicClient, walletClient as any) | ||
| return sdk.connectToPool({ poolAddress, userData }) | ||
| }, | ||
| onSuccess: () => { | ||
| queryClient.invalidateQueries({ queryKey: ["gda-pools"] }) | ||
| queryClient.invalidateQueries({ queryKey: ["gda-memberships"] }) | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| export function useDisconnectFromPool() { | ||
| const publicClient = usePublicClient() | ||
| const { data: walletClient } = useWalletClient() | ||
| const queryClient = useQueryClient() | ||
|
|
||
| return useMutation({ | ||
| mutationFn: async ({ | ||
| poolAddress, | ||
| userData = "0x", | ||
| }: UseDisconnectFromPoolParams): Promise<Hash> => { | ||
| if (!publicClient) throw new Error("Public client not available") | ||
| if (!walletClient) throw new Error("Wallet client not available") | ||
| const sdk = new GdaSDK(publicClient, walletClient as any) | ||
| return sdk.disconnectFromPool({ poolAddress, userData }) | ||
| }, | ||
| onSuccess: () => { | ||
| queryClient.invalidateQueries({ queryKey: ["gda-pools"] }) | ||
| queryClient.invalidateQueries({ queryKey: ["gda-memberships"] }) | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| export function useSupReserves({ | ||
| apiKey, | ||
| enabled = true | ||
| }: UseSupReservesParams = {}) { | ||
| return useQuery<SUPReserveLocker[]>({ | ||
| queryKey: ["sup-reserves", SupportedChains.BASE, apiKey], | ||
| queryFn: async () => { | ||
| const client = new SubgraphClient(SupportedChains.BASE, { apiKey }) | ||
| return client.querySUPReserves() | ||
| }, | ||
| enabled, | ||
| }) | ||
| } | ||
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.
Uh oh!
There was an error while loading. Please reload this page.