Skip to content
Open
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
25ee077
Feat: Installed farcaster package
vortex-hue Aug 13, 2025
42fc37e
fix: build errors
vortex-hue Aug 14, 2025
9557dce
feat: Add Farcaster miniapp support for identity flow with build fixes
vortex-hue Aug 14, 2025
42e08a9
rm eslintrc
vortex-hue Aug 14, 2025
64d56a8
refactor: Address code review feedback with improved architecture acr…
vortex-hue Aug 14, 2025
3323d82
fix: Address code review complaints
vortex-hue Aug 16, 2025
8bff2fe
fix: working on resolving the reviews made
vortex-hue Aug 18, 2025
f3940b2
fix: removed dynamic import, and reverted some configs to the default…
vortex-hue Aug 19, 2025
53564da
pulled update
vortex-hue Aug 28, 2025
60eb1cb
fix: Addressed all outstanding code review feedback.
vortex-hue Sep 2, 2025
c105e1b
fix: resolved all code changes requested
vortex-hue Sep 2, 2025
e10b584
feat: implement shared build config utility for Node.js built-ins and…
vortex-hue Sep 2, 2025
8edaca1
revert: removed the shared build config changes and other changes
vortex-hue Sep 3, 2025
c34de25
fc:frame meta tag
vortex-hue Sep 5, 2025
f6889fd
fix: refined the codebase
vortex-hue Sep 5, 2025
8616d89
fix:patching up the codebase
vortex-hue Sep 8, 2025
36dfa32
Revert "fix:patching up the codebase"
vortex-hue Sep 8, 2025
5ed0e06
revert: reverted all changes requested
vortex-hue Sep 8, 2025
5bdab21
revert: reverted all changes requested
vortex-hue Sep 8, 2025
cd6d40f
revert: reverted all changes requested
vortex-hue Sep 8, 2025
f1e9b8d
fix: revert changes requested
vortex-hue Sep 13, 2025
b7de6cb
fix: revert changes requested
vortex-hue Sep 13, 2025
304c15a
fix: revert changes affecting mobile
vortex-hue Sep 18, 2025
9841794
feat: implemented the universal link using farcaster docs
vortex-hue Sep 22, 2025
d19d211
fix: resolving previous issues
vortex-hue Oct 4, 2025
158465a
fix: resolved redirection concerns and fixed bugs
vortex-hue Oct 4, 2025
4060809
Merge remote-tracking branch 'origin/main' into add-farcaster-support…
vortex-hue Oct 9, 2025
e6ba4d0
fix: build id working well now
vortex-hue Oct 25, 2025
8cf55a7
fix: remove the unused interface of VerifyButtonProps
vortex-hue Oct 25, 2025
c1486dc
fix: removed the used import { createUniversalLinkCallback } from ../…
vortex-hue Oct 25, 2025
04ff59c
fix: revert apps/demo-identity-app/src/App.tsx and verifybutton.tsx t…
vortex-hue Oct 25, 2025
3dd1832
Merge upstream/main into add-farcaster-support-for-the-identity-flow
vortex-hue Nov 10, 2025
59484bc
fix: update auth.ts to use chainConfigs instead of contractAddresses
vortex-hue Nov 10, 2025
f620a1c
Merge remote-tracking branch 'upstream/main' into add-farcaster-suppo…
vortex-hue Dec 16, 2025
c38476f
refactor: apply engineering principles to Farcaster implementation
vortex-hue Dec 16, 2025
20d0905
refactor: clean up demo app following engineering principles
vortex-hue Dec 16, 2025
9a9dbbc
fix: address code review feedback
vortex-hue Dec 28, 2025
7a7a921
fix: address round 3 code review comments (restore comments, fix fvRe…
vortex-hue Dec 28, 2025
994b4f3
fix: address PR review feedback from L03TJ3
vortex-hue Feb 10, 2026
75a9b45
fix: address round 2 PR review feedback from sirpy
vortex-hue Feb 16, 2026
6377bf0
chore: merge upstream/main and regenerate yarn.lock
vortex-hue Feb 16, 2026
359e2c2
feat: add navigateToFaceVerification with Farcaster-aware redirect
vortex-hue Feb 16, 2026
4ad2886
refactor: remove Farcaster config coupling from SDK internals
vortex-hue Feb 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/demo-identity-app/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
</html>
12 changes: 3 additions & 9 deletions apps/demo-identity-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ const App: React.FC = () => {
(await identitySDK?.getWhitelistedRoot(address)) ?? {}
setIsWhitelisted(isWhitelisted)
setIsVerified(isWhitelisted ?? false)
} catch (error) {
console.error("Error checking whitelist:", error)
} catch {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe the setIsWhitelisted should have been added in the catch but there is no reason to remove the error log

setIsWhitelisted(false)
} finally {
setLoadingWhitelist(false)
}
Expand All @@ -87,10 +87,6 @@ const App: React.FC = () => {
}
}, [address, identitySDK, isWhitelisted, connectedAccount])

const handleVerificationSuccess = () => {
setIsVerified(true)
}

return (
<TamaguiProvider config={tamaguiConfig}>
<ScrollView
Expand Down Expand Up @@ -180,9 +176,7 @@ const App: React.FC = () => {
!isWhitelisted &&
!error ? (
<YStack alignItems="center" gap={12}>
<VerifyButton
onVerificationSuccess={handleVerificationSuccess}
/>
<VerifyButton />
<Text fontSize={14} color="$gray10">
You need to verify your identity via GoodDollar to continue.
</Text>
Expand Down
10 changes: 3 additions & 7 deletions apps/demo-identity-app/src/components/ClaimButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,25 +72,21 @@ export const ClaimButton: React.FC = () => {
setError("ClaimSDK is not initialized.")
return
}
console.log("handleClaim called")

setIsClaiming(true)
setError(null)
setTxHash(null)

try {
const callBackExample = async () => {
console.log("waiting for claim for 2 seconds...")
await new Promise((resolve) => setTimeout(resolve, 2000)) // wait 2 seconds
console.log("tx start")
const txConfirm = async () => {
await new Promise((resolve) => setTimeout(resolve, 2000))
}

const tx = await sdk.claim(callBackExample)
const tx = await sdk.claim(txConfirm)
if (!tx) return

setTxHash(tx.transactionHash)
} catch (err: any) {
console.error("Claim failed:", err)
setError(err.message || "An unexpected error occurred.")
} finally {
setIsClaiming(false)
Expand Down
13 changes: 3 additions & 10 deletions apps/demo-identity-app/src/components/VerifyButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,7 @@ import { Button } from "tamagui"
import { useIdentitySDK } from "@goodsdks/react-hooks"
import { useAccount } from "wagmi"

interface VerifyButtonProps {
onVerificationSuccess: () => void
}

export const VerifyButton: React.FC<VerifyButtonProps> = ({
onVerificationSuccess,
}) => {
export const VerifyButton: React.FC = () => {
const { address } = useAccount()
const { sdk: identitySDK } = useIdentitySDK("development")

Expand All @@ -24,9 +18,8 @@ export const VerifyButton: React.FC<VerifyButtonProps> = ({
)

window.location.href = fvLink
} catch (error) {
console.error("Verification failed:", error)
// Handle error (e.g., show toast)
} catch {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refactor is both not needed or in any way related to your fixes for farcaster + its not true.
generateFVLink throws an error and is not handled there

// Silent fail - error will be caught by the identity SDK
}
}

Expand Down
10 changes: 7 additions & 3 deletions apps/demo-identity-app/src/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ import React, { ReactNode } from "react"

const queryClient = new QueryClient()

const projectId = "71dd03d057d89d0af68a4c627ec59694"

const projectId = "71dd03d057d89d0af68a4c627ec59694"
const metadata = {
name: "AppKit",
description: "AppKit Example",
url: "https://example.com", // origin must match your domain & subdomain
url: "http://localhost:3000",
icons: ["https://avatars.githubusercontent.com/u/179229932"],
}

Expand Down Expand Up @@ -43,6 +42,11 @@ createAppKit({
"--w3m-color-mix-strength": 40,
"--w3m-accent": "#00BB7F",
},
allowUnsupportedChain: false,
enableWalletConnect: true,
enableInjected: true,
enableEIP6963: true,
enableCoinbase: true,
})

type ComponentProps = {
Expand Down
2 changes: 2 additions & 0 deletions apps/demo-identity-app/src/globals.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import React from "react"

declare namespace JSX {
interface IntrinsicElements {
"claim-button": React.DetailedHTMLProps<
Expand Down
2 changes: 1 addition & 1 deletion apps/demo-identity-app/vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ export default defineConfig({
"process.browser": true,
"process.env": process.env,
},
});
});
2 changes: 1 addition & 1 deletion apps/demo-webcomponents/vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ export default defineConfig({
"process.browser": true,
"process.env": process.env,
},
})
})
1 change: 1 addition & 0 deletions packages/citizen-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"wagmi": "*"
},
"dependencies": {
"@farcaster/miniapp-sdk": "^0.1.8",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dev?peer? @L03TJ3

"lz-string": "^1.5.0",
"tsup": "^8.4.0"
},
Expand Down
19 changes: 19 additions & 0 deletions packages/citizen-sdk/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ export const Envs: Record<string, Record<string, string>> = {
},
}

/**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are just placeholders and not working this should be clarified in a readme and should be configurable options for developers to pass down
(we are not hosting a farcaster app, developers integrating the identitysdk/claim-sdk might)

* Farcaster Mini App configurations for different environments
* You need to replace these with your actual Farcaster app IDs and slugs from the Farcaster Developer Portal
*/
export const FarcasterAppConfigs: Record<string, { appId: string; appSlug: string }> = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apps dont have envs in farcaster

production: {
appId: "your-production-app-id", // Replace with actual app ID from Farcaster Developer Portal
appSlug: "gooddollar-identity", // Replace with actual app slug
},
staging: {
appId: "your-staging-app-id", // Replace with actual app ID from Farcaster Developer Portal
appSlug: "gooddollar-identity-staging", // Replace with actual app slug
},
development: {
appId: "your-development-app-id", // Replace with actual app ID from Farcaster Developer Portal
appSlug: "gooddollar-identity-dev", // Replace with actual app slug
},
}

export interface ContractAddresses {
identityContract: `0x${string}`
ubiContract: `0x${string}`
Expand Down
2 changes: 2 additions & 0 deletions packages/citizen-sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from "./sdks"
export * from "./constants"
export * from "./utils/auth"

1 change: 0 additions & 1 deletion packages/citizen-sdk/src/sdks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from "./viem-identity-sdk"
export * from "./viem-claim-sdk"
export * from "./viem-custodial-claim-sdk"
export * from "./viem-custodial-identity-sdk"
72 changes: 49 additions & 23 deletions packages/citizen-sdk/src/sdks/viem-claim-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type WalletClient,
ContractFunctionExecutionError,
TransactionReceipt,
zeroAddress,
} from "viem"

import { waitForTransactionReceipt } from "viem/actions"
Expand All @@ -20,9 +21,15 @@ import {
faucetABI,
isSupportedChain,
ubiSchemeV2ABI,
FarcasterAppConfigs,
} from "../constants"
import type { ContractAddresses } from "../constants"
import { resolveChainAndContract } from "../utils/chains"
import {
createVerificationCallbackUrl,
createFarcasterCallbackUniversalLink,
isInFarcasterMiniApp
} from "../utils/auth"
import { triggerFaucet as triggerFaucetUtil } from "../utils/triggerFaucet"
import {
createRpcIteratorRegistry,
Expand Down Expand Up @@ -82,7 +89,7 @@ export class ClaimSDK {
private readonly faucetAddress: Address
private readonly account: Address
private readonly env: contractEnv
public readonly rdu: string
public rdu: string

constructor({
account,
Expand All @@ -99,9 +106,11 @@ export class ClaimSDK {
this.walletClient = walletClient
this.identitySDK = identitySDK
this.account = account ?? walletClient.account.address
this.env = env

// Initialize callback URL - will be set properly in initializeCallbackUrl
this.rdu = rdu
this.env = env
this.initializeCallbackUrl(rdu);

const { chainId, contractEnvAddresses } = resolveChainAndContract(
walletClient,
Expand Down Expand Up @@ -142,6 +151,37 @@ export class ClaimSDK {
this.faucetAddress = contractEnvAddresses.faucetContract as Address
}

/**
* Initialize the callback URL with proper Farcaster Universal Link support
* @param rdu - The redirect URL after claim
*/
private async initializeCallbackUrl(rdu?: string): Promise<void> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is duplicate. it should be in the identity sdk

if (!rdu) return;

try {
// Check if we're in a Farcaster context and should use Universal Links
const isFarcaster = await isInFarcasterMiniApp();

if (isFarcaster && FarcasterAppConfigs[this.env]) {
// Create proper Farcaster Universal Link
const farcasterConfig = FarcasterAppConfigs[this.env];
this.rdu = createFarcasterCallbackUniversalLink(
farcasterConfig,
'claim',
{ source: "gooddollar_claim_verification" }
);
} else {
// Fallback to direct callback URL for non-Farcaster environments
this.rdu = await createVerificationCallbackUrl(rdu, {
source: "gooddollar_claim_verification"
});
}
} catch (error) {
// Fallback to original URL on error
this.rdu = rdu;
}
}

private getContractsForChain(chainId: SupportedChains): ContractAddresses {
const contracts = this.chainContracts.get(chainId)

Expand Down Expand Up @@ -417,7 +457,13 @@ export class ClaimSDK {
const { isWhitelisted } =
await this.identitySDK.getWhitelistedRoot(userAddress)
if (!isWhitelisted) {
await this.fvRedirect()
// Use IdentitySDK's navigation method to eliminate code duplication
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Use IdentitySDK's navigation method to eliminate code duplication

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments should not describe changes done for a commit.
it should explain current behavior, possibly edge-cases or why something has been done in a particular way.

Thats why my suggestion

await this.identitySDK.navigateToFaceVerification(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. what duplication is being handled here exactly?
  2. if you choose to do a refactor, always make sure functionality does not change along the way

You introduce: hardcoded chain-id, different behavior of reloading page etc.
Its not necessarily a bad idea to move handling of face-verification to the identity-sdk.

but it should always be trippled checked against exisiting flows.
how would this affect dapps that already have this flow?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. chainid should not be hardcoded to celo
  2. Flow should stay the same as it was, changes needed for your flow should only affect your intended flow

And include a demo that this change works as expected, as I am not sure this is the way to handle pop-up window (fallbackToNewTab? should it not just close the pop-up window?)

false, // popupMode
this.rdu, // callbackUrl
42220 // chainId
);

throw new Error("User requires identity verification.")
}

Expand Down Expand Up @@ -449,26 +495,6 @@ export class ClaimSDK {
}
}

/**
* Redirects the user through the face-verification flow.
* @throws If face verification redirect fails.
*/
private async fvRedirect(): Promise<void> {
const fvChainId = this.fvDefaultChain ?? this.chainId
const fvLink = await this.identitySDK.generateFVLink(
false,
this.rdu,
fvChainId,
)
if (typeof window !== "undefined") {
window.location.href = fvLink
} else {
throw new Error(
"Face verification redirect is only supported in browser environments.",
)
}
}

/**
* Retrieves the next available claim time for the connected user.
* Returns epoch time (0) if the user can claim now (entitlement > 0).
Expand Down
Loading