Conversation
📝 WalkthroughWalkthroughIntroduces the Changes
Sequence DiagramsequenceDiagram
participant User
participant App as React App
participant FastAuth as FastAuth Hook
participant Relayer as FastAuth Relayer
participant NEAR as NEAR Network
User->>App: Initiate Login
App->>FastAuth: useFastAuth()
FastAuth->>Relayer: init()
Relayer->>NEAR: Connect & Load Account
Relayer-->>FastAuth: Initialized
User->>App: Click Create Account
App->>Relayer: createAccount(action)
Relayer->>NEAR: Sign & Send Transaction
NEAR-->>Relayer: Account Created
User->>App: Request Transaction Signature
App->>Relayer: createTransfer(...)
Relayer->>NEAR: Fetch Block Hash & Nonce
NEAR-->>Relayer: Transaction Object
User->>App: Sign Transaction
App->>Relayer: relaySignAction(action)
Relayer->>NEAR: Call sign() on Contract
NEAR-->>Relayer: Signature
User->>App: Broadcast Transaction
App->>Relayer: send(signature, tx)
Relayer->>NEAR: Submit Signed Tx
NEAR-->>App: txHash & Confirmation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Actionable comments posted: 12
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
examples/spa/src/hooks/use-fast-auth-workflow.ts (2)
115-115: Unsafe non-null assertion onparseNearAmount.The non-null assertion operator (
!) is used onparseNearAmount("0.01"), butparseNearAmountcan returnnullif parsing fails. This could cause a runtime error.Apply this diff to add proper null handling:
-const action = await signer?.createSignAction(signatureRequest, { deposit: BigInt(parseNearAmount("0.01")!) }); +const amount = parseNearAmount("0.01"); +if (!amount) { + throw new Error("Failed to parse NEAR amount"); +} +const action = await signer?.createSignAction(signatureRequest, { deposit: BigInt(amount) });
135-137: Remove@ts-ignoreand fix type incompatibility.The
@ts-ignorecomment suppresses TypeScript errors, which indicates a type incompatibility withFastAuthSignature.fromBase64(). Instead of suppressing the error, the underlying type issue should be resolved.Please investigate why TypeScript is flagging this line and either:
- Fix the type incompatibility (e.g., by properly typing
result.status.SuccessValue)- Use a proper type assertion if the types are known to be correct
- Add a more specific
@ts-expect-errorwith a comment explaining why it's necessary
🟡 Minor comments (9)
apps/account-verifier/src/utils/history.ts-1-2 (1)
1-2: Remove unused history instance.This file is not imported or used anywhere in the codebase. The app correctly uses
<BrowserRouter>from react-router-dom (in App.tsx), which is the proper approach for React Router v7. Deleteapps/account-verifier/src/utils/history.tsas dead code.apps/account-verifier/index.html-7-7 (1)
7-7: Customize the page title.The title still uses the default Vite template value. Update it to reflect the account-verifier app's purpose.
Apply this diff:
- <title>Vite + React + TS</title> + <title>Account Verifier</title>apps/account-verifier/src/components/steps/RequestTransactionStep.tsx-89-89 (1)
89-89: Misleading status message.The message "Requesting transaction approval..." displays when
transferRequestedis true, but at that point the request has already been initiated (not currently in progress). Consider rewording to "Transaction approval requested" or removing it if not needed.- {transferRequested && <p>Requesting transaction approval...</p>} + {transferRequested && <p>Transaction approval requested ✓</p>}apps/account-verifier/src/pages/Home.tsx-250-256 (1)
250-256: Duplicate error display foraccessKeysError.
accessKeysErroris rendered at lines 150-154 within the Access Keys section and again here at line 254. This could confuse users by showing the same error twice.Consider removing the
accessKeysErrorfrom this bottom section since it's already displayed contextually within the Access Keys section.- {(fastAuthError || accessKeysError) && ( + {fastAuthError && ( <section style={{ borderColor: "#f87171" }}> <h2 style={{ color: "#f87171" }}>Error</h2> {fastAuthError && <p>FastAuth Error: {fastAuthError.message}</p>} - {accessKeysError && <p>Access Keys Error: {accessKeysError.message}</p>} </section> )}apps/account-verifier/src/hooks/use-fast-auth-workflow.ts-103-115 (1)
103-115: Guard against nullpublicKeybefore using non-null assertion.Line 104 uses
publicKey!which will throw ifpublicKeyis null. Add an explicit check to provide a meaningful error.const requestTransactionSignature = async (accountId: string, receiverId: string, amount: string) => { + if (!publicKey) { + throw new Error("Public key not available"); + } - const tx = await relayer?.createTransfer(accountId, PublicKey.fromString(publicKey!), receiverId, amount); + const tx = await relayer?.createTransfer(accountId, PublicKey.fromString(publicKey), receiverId, amount); if (!tx) { throw new Error("Transaction not created"); }apps/account-verifier/src/hooks/use-fast-auth-workflow.ts-141-147 (1)
141-147: Remove the@ts-ignoreand properly type the signature payload.The
@ts-ignorebypasses a valid type error. Instead, add a type guard to verifyresult.statusandSuccessValueexist before accessing them, similar to the pattern inpackages/sdks/react/src/core/signers/signer.ts:if (typeof result.status !== "object" || !("SuccessValue" in result.status)) { throw new Error("Failed to sign delegate action"); } const signature = FastAuthSignature.fromBase64(result.status.SuccessValue!);Alternatively, use a type assertion:
FastAuthSignature.fromBase64(result.status.SuccessValue as string).apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx-135-141 (1)
135-141: Error message references incorrect provider name.The error message says "useFastAuthRelayer must be used within a FastAuthRelayerProvider" but the actual provider is named
FastAuthProviderand the hook isuseFastAuth.export function useFastAuth(): FastAuthContextType { const context = useContext(FastAuthContext); if (context === null) { - throw new Error("useFastAuthRelayer must be used within a FastAuthRelayerProvider"); + throw new Error("useFastAuth must be used within a FastAuthProvider"); } return context; }apps/account-verifier/src/services/fast-auth-relayer.ts-145-164 (1)
145-164: Null assertion onparseNearAmountresult.
parseNearAmount(amount)!uses a non-null assertion, butparseNearAmountcan returnnullfor invalid inputs. This could cause a runtime error.+ const parsedAmount = parseNearAmount(amount); + if (!parsedAmount) { + throw new Error(`Invalid NEAR amount: ${amount}`); + } + const tx = createTransaction( signerId, signerPublicKey, receiverId, nonce, - [transfer(BigInt(parseNearAmount(amount)!))], + [transfer(BigInt(parsedAmount))], base_decode(accessKey.block_hash), );apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx-114-118 (1)
114-118: Mutating relayer state may cause stale reference issues.After
relayer.switchNetwork(newNetwork), callingsetRelayer(relayer)with the same object reference won't trigger React re-renders in consumers that depend on referential equality. Consider creating a new relayer instance or using a different state update pattern.if (relayer) { await relayer.switchNetwork(newNetwork); - setRelayer(relayer); + // Force state update with a new reference pattern or reinitialize + await initializeRelayer(newNetwork); - setIsRelayerInitialized(true); - await initializeClient(relayer.getConnection().connection, newNetwork);Alternatively, if performance is a concern, ensure consumers use the relayer's methods rather than relying on referential equality.
Committable suggestion skipped: line range outside the PR's diff.
🧹 Nitpick comments (15)
apps/account-verifier/.gitignore (1)
1-24: Comprehensive .gitignore for Vite + React project.The file covers all essential patterns: logs, build outputs, dependencies, and editor artifacts. The preservation of
.vscode/extensions.json(line 17) is a good practice for team configuration.Optional enhancement for future consideration: If the project uses environment variables in
.envfiles (without.localsuffix) as checked-in templates, the current setup is fine. However, if bare.envfiles should be ignored, consider adding a pattern for/.env(with leading slash to match the root only).apps/account-verifier/src/components/steps/BroadcastStep.tsx (1)
6-6: Use specific typing instead ofany.The
resultprop usesany, which defeats TypeScript's type safety. Consider defining a specific type or interface for the result data.+interface TransactionResult { + // Define the expected shape of result + transaction: unknown; + // Add other relevant fields +} + interface BroadcastStepProps { - result: any; + result: TransactionResult | null; txHash: string | null;apps/account-verifier/src/components/steps/CreateAccountStep.tsx (1)
58-58: Use consistent naming convention for input name.The input name
"accountid"(all lowercase) is inconsistent with typical JavaScript/HTML naming conventions.Apply this diff for better consistency:
- name="accountid" + name="accountId"And update line 28 accordingly:
- const accountId = formData.get("accountid") as string; + const accountId = formData.get("accountId") as string;apps/account-verifier/src/components/Accordion.tsx (1)
10-33: Add ARIA attributes for better accessibility.The accordion lacks proper ARIA attributes, making it harder for screen readers to convey the expand/collapse state.
Apply this diff to improve accessibility:
const Accordion: React.FC<AccordionProps> = ({ title, expanded, onClick, children }) => { + const contentId = React.useId(); + return ( <div style={{ border: "1px solid #333", borderRadius: 8, marginBottom: 16, background: "#23272f" }}> <button type="button" onClick={onClick} + aria-expanded={expanded} + aria-controls={contentId} style={{ width: "100%", textAlign: "left", padding: "1rem", background: "#181a20", border: "none", borderRadius: "8px 8px 0 0", fontWeight: 600, cursor: "pointer", outline: "none", color: "#f1f1f1", }} > {title} </button> - {expanded && <div style={{ padding: "1rem", color: "#e0e0e0" }}>{children}</div>} + {expanded && ( + <div id={contentId} role="region" style={{ padding: "1rem", color: "#e0e0e0" }}> + {children} + </div> + )} </div> ); };apps/account-verifier/src/config.ts (2)
24-32: CachegetConfig()result to avoid repeated object creation.The current implementation calls
getConfig()four times, creating four separate objects. This is inefficient and can be optimized by caching the result.Apply this diff:
+const config = getConfig(); + export const providerConfig = { - domain: getConfig().domain, - clientId: getConfig().clientId, + domain: config.domain, + clientId: config.clientId, onRedirectCallback, authorizationParams: { redirect_uri: window.location.origin, - ...(getConfig().audience ? { audience: getConfig().audience } : null), + ...(config.audience ? { audience: config.audience } : {}), scope: "transaction:send-transaction transaction:read-transaction test:send-test", }, };
20-20: Use empty object instead ofnullin spread operator.Spreading
nullworks but is unconventional. Using an empty object is more idiomatic and clearer.Apply this diff:
return { domain: configJson.domain, clientId: configJson.clientId, - ...(audience ? { audience } : null), + ...(audience ? { audience } : {}), };apps/account-verifier/src/components/steps/LoginStep.tsx (1)
39-45: Clarify the button's intent or rename the callback.When logged in, the "Create Account" button triggers
onLogin, which is semantically confusing. If this is intentional (e.g.,onLoginadvances the workflow step), consider renamingonLoginto something likeonProceedoronNextStepinLoginStepPropsto better reflect its purpose.apps/account-verifier/src/hooks/use-fast-auth-workflow.ts (2)
14-14: Consider typingresultproperly instead ofany.Using
anyloses type safety. Based on usage at line 145, this appears to be a transaction result withstatus.SuccessValue. Define a proper type for the relayer response.
83-83: Unnecessary dependencies inuseCallback.
relayerandnetworkare included in the dependency array but are not used withinfetchPublicKey. This can cause unnecessary re-computation. Consider removing them, or if the intent is to refetch when network changes, add an explicit reset of workflow state whennetworkchanges.- }, [isClientInitialized, client, relayer, network]); + }, [isClientInitialized, client]);apps/account-verifier/src/hooks/use-access-keys.ts (3)
22-34: Add timeout and abort signal to external API fetch.The
fetchcall to FastNear API lacks a timeout mechanism. If the API is slow or unresponsive, this could leave the hook in a loading state indefinitely.-async function getAccountIdsByPublicKey(publicKey: string, network: "testnet" | "mainnet"): Promise<string[]> { +async function getAccountIdsByPublicKey(publicKey: string, network: "testnet" | "mainnet", signal?: AbortSignal): Promise<string[]> { const apiBase = network === "mainnet" ? MAINNET_FASTNEAR_API_BASE : TESTNET_FASTNEAR_API_BASE; try { - const response = await fetch(`${apiBase}/public_key/${encodeURIComponent(publicKey)}/all`); + const response = await fetch(`${apiBase}/public_key/${encodeURIComponent(publicKey)}/all`, { signal }); if (!response.ok) { throw new Error(`Failed to fetch account IDs: ${response.statusText}`); }
82-102: Sequential account fetching may be slow for many accounts.The loop fetches access keys sequentially. For accounts with many linked IDs, consider using
Promise.allSettledfor parallel fetching to improve performance.- for (const accountId of accountIdsList) { - try { - const result = await connection.connection.provider.query({ - request_type: "view_access_key_list", - finality: "final", - account_id: accountId, - }); - - // The result contains an array of access keys with public_key and access_key - const keys: AccessKeyInfo[] = (result as any).keys.map((item: any) => ({ - publicKey: item.public_key, - accessKey: item.access_key, - accountId: accountId, - })); - - allAccessKeys.push(...keys); - } catch (err) { - console.error(`Failed to fetch access keys for account ${accountId}:`, err); - // Continue with other accounts even if one fails - } - } + const results = await Promise.allSettled( + accountIdsList.map(async (accountId) => { + const result = await connection.connection.provider.query({ + request_type: "view_access_key_list", + finality: "final", + account_id: accountId, + }); + return (result as any).keys.map((item: any) => ({ + publicKey: item.public_key, + accessKey: item.access_key, + accountId, + })); + }), + ); + + for (const result of results) { + if (result.status === "fulfilled") { + allAccessKeys.push(...result.value); + } else { + console.error("Failed to fetch access keys for an account:", result.reason); + } + }
91-95: Avoid usinganytype for API response mapping.The
(result as any).keyscast loses type safety. Consider defining a typed response interface for the query result.+interface AccessKeyListResult { + keys: Array<{ + public_key: string; + access_key: AccessKeyView; + }>; +} - const keys: AccessKeyInfo[] = (result as any).keys.map((item: any) => ({ + const keys: AccessKeyInfo[] = (result as AccessKeyListResult).keys.map((item) => ({ publicKey: item.public_key, accessKey: item.access_key, accountId: accountId, }));apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
95-100: Disabled exhaustive-deps rule may hide bugs.The
useEffectdepends onnetworkbut callsinitializeRelayer(network). IfinitializeRelayerchanges (unlikely but possible), this could cause stale closures. Consider includinginitializeRelayerin the dependency array or extracting stable initialization logic.apps/account-verifier/src/services/fast-auth-relayer.ts (2)
31-38: Class name conflicts with existingFastAuthRelayerin the SDK package.There's already a
FastAuthRelayerclass inpackages/sdks/react/src/core/relayer/relayer.tswith different functionality. This naming collision could cause confusion. Consider renaming to something more specific likeNearRelayerServiceorAccountVerifierRelayer.
36-38: Use proper types instead ofanyfor NEAR connection and account.Using
anyforconfig,near, andaccountloses type safety. Import and use proper types from near-api-js.+import { Near, NearConfig } from "near-api-js"; class FastAuthRelayer { private keyStore: keyStores.InMemoryKeyStore; private keyPair: KeyPair; private accountId: string; private networkId: NetworkId; - private config: any; - private near: any; - private account: any; + private config: NearConfig; + private near: Near | null; + private account: Account | null;
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (3)
apps/account-verifier/public/vite.svgis excluded by!**/*.svgapps/account-verifier/src/assets/react.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (37)
apps/account-verifier/.env.example(1 hunks)apps/account-verifier/.gitignore(1 hunks)apps/account-verifier/README.md(1 hunks)apps/account-verifier/eslint.config.js(1 hunks)apps/account-verifier/index.html(1 hunks)apps/account-verifier/package.json(1 hunks)apps/account-verifier/src/App.css(1 hunks)apps/account-verifier/src/App.tsx(1 hunks)apps/account-verifier/src/auth_config.json(1 hunks)apps/account-verifier/src/components/Accordion.tsx(1 hunks)apps/account-verifier/src/components/LoginButton.tsx(1 hunks)apps/account-verifier/src/components/LogoutButton.tsx(1 hunks)apps/account-verifier/src/components/Spinner.tsx(1 hunks)apps/account-verifier/src/components/steps/BroadcastStep.tsx(1 hunks)apps/account-verifier/src/components/steps/CreateAccountStep.tsx(1 hunks)apps/account-verifier/src/components/steps/LoginStep.tsx(1 hunks)apps/account-verifier/src/components/steps/RequestTransactionStep.tsx(1 hunks)apps/account-verifier/src/components/steps/SignTransactionStep.tsx(1 hunks)apps/account-verifier/src/components/steps/index.ts(1 hunks)apps/account-verifier/src/config.ts(1 hunks)apps/account-verifier/src/hooks/use-access-keys.ts(1 hunks)apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx(1 hunks)apps/account-verifier/src/hooks/use-fast-auth-workflow.ts(1 hunks)apps/account-verifier/src/index.css(1 hunks)apps/account-verifier/src/main.tsx(1 hunks)apps/account-verifier/src/pages/Home.css(1 hunks)apps/account-verifier/src/pages/Home.tsx(1 hunks)apps/account-verifier/src/polyfills/buffer/index.ts(1 hunks)apps/account-verifier/src/polyfills/index.ts(1 hunks)apps/account-verifier/src/services/fast-auth-relayer.ts(1 hunks)apps/account-verifier/src/utils/history.ts(1 hunks)apps/account-verifier/src/vite-env.d.ts(1 hunks)apps/account-verifier/tsconfig.app.json(1 hunks)apps/account-verifier/tsconfig.json(1 hunks)apps/account-verifier/tsconfig.node.json(1 hunks)apps/account-verifier/vite.config.ts(1 hunks)examples/spa/src/hooks/use-fast-auth-workflow.ts(1 hunks)
🧰 Additional context used
🧠 Learnings (12)
📚 Learning: 2025-04-07T12:08:24.795Z
Learnt from: obnol
Repo: Peersyst/near-mobile PR: 154
File: packages/frontend/auth/package.json:0-0
Timestamp: 2025-04-07T12:08:24.795Z
Learning: The BiometricsService is correctly re-exported in /packages/frontend/auth/src/data-access/services/index.ts with the line `export * from "./biometrics.service";`, validating the export path in package.json.
Applied to files:
apps/account-verifier/src/components/steps/index.tsapps/account-verifier/src/main.tsxapps/account-verifier/package.jsonapps/account-verifier/src/polyfills/index.tsexamples/spa/src/hooks/use-fast-auth-workflow.tsapps/account-verifier/src/services/fast-auth-relayer.ts
📚 Learning: 2025-09-10T13:23:58.048Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 571
File: packages/shared/api/src/index.ts:33-33
Timestamp: 2025-09-10T13:23:58.048Z
Learning: The packages/shared/api package exports source files directly (./src/index.ts) rather than compiled output because it's auto-generated by openapi-typescript-codegen and this export strategy is intentional for this shared package.
Applied to files:
apps/account-verifier/src/components/steps/index.tsapps/account-verifier/tsconfig.jsonapps/account-verifier/package.json
📚 Learning: 2025-06-06T15:08:15.340Z
Learnt from: JordiParraCrespo
Repo: Peersyst/near-mobile PR: 331
File: packages/shared/utils/src/index.ts:1-1
Timestamp: 2025-06-06T15:08:15.340Z
Learning: The packages/shared/utils package has a properly structured error module with an index.ts file that exports from ./decorator. The export * from "./error" statement in the main index works correctly and allows importing createErrorHandlerDecorator from shared/utils.
Applied to files:
apps/account-verifier/src/components/steps/index.ts
📚 Learning: 2025-08-14T14:53:11.507Z
Learnt from: AdriaCarrera
Repo: Peersyst/near-mobile PR: 520
File: turbo.json:0-0
Timestamp: 2025-08-14T14:53:11.507Z
Learning: In turbo.json, package.json files can be legitimate outputs when build tasks modify them during execution (e.g., version updates, metadata injection). In such cases, including package.json in the outputs array ensures proper cache restoration of the modified files.
Applied to files:
apps/account-verifier/tsconfig.json
📚 Learning: 2025-08-29T16:22:11.387Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 553
File: apps/mobile/src/modules/token/screens/npro-pre-staking-token-details/screens/npro-pre-staking-token-details-general/containers/npro-pre-staking-token-details-actions/npro-pre-staking-token-details-item/npro-pre-staking-token-details-item.tsx:3-3
Timestamp: 2025-08-29T16:22:11.387Z
Learning: In the NEAR mobile app codebase, the team prefers to use the React namespace (e.g., React.ReactNode) instead of standalone imports (e.g., ReactNode) from the react package.
Applied to files:
apps/account-verifier/src/main.tsxapps/account-verifier/src/hooks/use-fast-auth-relayer.tsxexamples/spa/src/hooks/use-fast-auth-workflow.ts
📚 Learning: 2025-04-30T08:57:52.130Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 228
File: packages/frontend/price/src/ui/queries/use-convert-amount-to-fiat.ts:1-8
Timestamp: 2025-04-30T08:57:52.130Z
Learning: In this codebase, BigNumber is set up as a global variable (likely through polyfills) and should be used without explicit imports.
Applied to files:
apps/account-verifier/src/polyfills/buffer/index.ts
📚 Learning: 2025-04-30T08:57:52.130Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 228
File: packages/frontend/price/src/ui/queries/use-convert-amount-to-fiat.ts:1-8
Timestamp: 2025-04-30T08:57:52.130Z
Learning: In this codebase, developers expect BigNumber to be available globally without explicit imports, though the pattern is inconsistent across files.
Applied to files:
apps/account-verifier/src/polyfills/buffer/index.ts
📚 Learning: 2025-09-18T13:10:13.778Z
Learnt from: JordiParraCrespo
Repo: Peersyst/bitcoin-light PR: 85
File: packages/shared/blockchain/src/wci/chains/nervos/providers/dao/nervos-dao.provider.ts:1-1
Timestamp: 2025-09-18T13:10:13.778Z
Learning: In the nervos-dao.provider.ts file in the Bitcoin Light codebase, BigNumber is used on line 117 but needs to be explicitly imported, even though it may be available globally elsewhere in the codebase.
Applied to files:
apps/account-verifier/src/polyfills/buffer/index.tsapps/account-verifier/src/polyfills/index.ts
📚 Learning: 2025-06-09T09:14:11.981Z
Learnt from: JordiParraCrespo
Repo: Peersyst/near-mobile PR: 342
File: apps/mobile/src/modules/wallet/hooks/use-get-wallet-account-total-balance/use-get-wallet-account-total-balance.ts:26-28
Timestamp: 2025-06-09T09:14:11.981Z
Learning: In the near-mobile project, when calculating derived values from query results in React hooks, use useMemo with proper dependencies (like queryResult.data and fiatPrice.data) to avoid unnecessary re-renders and reference changes. This pattern is established in files like use-get-wallet-amounts-in-chain.ts and should be followed consistently across wallet-related hooks.
Applied to files:
apps/account-verifier/src/hooks/use-access-keys.tsexamples/spa/src/hooks/use-fast-auth-workflow.ts
📚 Learning: 2025-05-30T13:25:36.454Z
Learnt from: JordiParraCrespo
Repo: Peersyst/near-mobile PR: 305
File: apps/mobile/src/modules/wallet-selector/containers/sign-request/sign-request-form/sign-request-form.tsx:32-32
Timestamp: 2025-05-30T13:25:36.454Z
Learning: In wallet selector sign request forms, useRef is intentionally used to capture the initial account ID for comparison with the signer ID, rather than tracking account changes reactively. The goal is to detect account mismatches without triggering re-renders when the account changes.
Applied to files:
examples/spa/src/hooks/use-fast-auth-workflow.ts
📚 Learning: 2025-06-09T09:14:11.981Z
Learnt from: JordiParraCrespo
Repo: Peersyst/near-mobile PR: 342
File: apps/mobile/src/modules/wallet/hooks/use-get-wallet-account-total-balance/use-get-wallet-account-total-balance.ts:26-28
Timestamp: 2025-06-09T09:14:11.981Z
Learning: In the near-mobile project, when calculating derived values from query results in React hooks, use useMemo with proper dependencies (like queryResult.data and fiatPrice.data) to avoid unnecessary re-renders and reference changes. This pattern should be followed consistently across wallet-related hooks to optimize performance.
Applied to files:
examples/spa/src/hooks/use-fast-auth-workflow.ts
📚 Learning: 2025-02-27T10:24:14.276Z
Learnt from: AgustinMJ
Repo: Peersyst/near-mobile PR: 58
File: packages/shared/blockchain/core/src/signers/signer.ts:26-27
Timestamp: 2025-02-27T10:24:14.276Z
Learning: The Signer interface uses `Record<string, any>` for the transaction parameter in `signTransaction` method to allow implementing classes to add their own specific types extending this base type, providing flexibility for different blockchain implementations.
Applied to files:
apps/account-verifier/src/components/steps/SignTransactionStep.tsx
🧬 Code graph analysis (10)
apps/account-verifier/src/components/LoginButton.tsx (1)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
useFastAuth(135-141)
apps/account-verifier/src/components/steps/CreateAccountStep.tsx (1)
packages/shared/cli/src/utils/get-packages-paths.mjs (1)
p(12-12)
apps/account-verifier/src/main.tsx (1)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
FastAuthProvider(53-133)
apps/account-verifier/src/pages/Home.tsx (3)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
useFastAuth(135-141)apps/account-verifier/src/hooks/use-fast-auth-workflow.ts (1)
useFastAuthWorkflow(33-175)apps/account-verifier/src/hooks/use-access-keys.ts (1)
useAccessKeys(36-127)
apps/account-verifier/src/components/LogoutButton.tsx (1)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
useFastAuth(135-141)
apps/account-verifier/src/components/steps/LoginStep.tsx (2)
apps/account-verifier/src/components/LogoutButton.tsx (1)
LogoutButton(5-23)apps/account-verifier/src/components/LoginButton.tsx (1)
LoginButton(5-23)
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (4)
packages/sdks/react/src/core/relayer/relayer.ts (1)
FastAuthRelayer(10-102)packages/providers/javascript/src/provider.ts (1)
JavascriptProvider(13-130)apps/account-verifier/src/services/fast-auth-relayer.ts (1)
NetworkId(16-16)packages/sdks/react/src/providers/utils/contracts.ts (1)
getContractsFromNetwork(8-21)
apps/account-verifier/src/components/steps/SignTransactionStep.tsx (1)
packages/shared/cli/src/utils/get-packages-paths.mjs (1)
p(12-12)
apps/account-verifier/src/hooks/use-fast-auth-workflow.ts (3)
examples/spa/src/hooks/use-fast-auth-workflow.ts (3)
WorkflowState(9-22)WorkflowActions(24-31)useFastAuthWorkflow(33-167)packages/providers/javascript/src/provider.ts (1)
JavascriptProvider(13-130)apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
useFastAuth(135-141)
apps/account-verifier/src/services/fast-auth-relayer.ts (1)
packages/sdks/react/src/core/relayer/relayer.ts (1)
FastAuthRelayer(10-102)
🪛 dotenv-linter (4.0.0)
apps/account-verifier/.env.example
[warning] 1-1: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 2-2: [UnorderedKey] The VITE_RELAYER_ACCOUNT_ID key should go before the VITE_RELAYER_PRIVATE_KEY key
(UnorderedKey)
[warning] 3-3: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 3-3: [UnorderedKey] The VITE_APP_ORIGIN key should go before the VITE_RELAYER_ACCOUNT_ID key
(UnorderedKey)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build-base / Build
- GitHub Check: integration-packages / Build
🔇 Additional comments (20)
apps/account-verifier/tsconfig.app.json (1)
1-26: LGTM! Well-configured TypeScript setup for React + Vite.The configuration follows modern best practices:
- ES2020 target with DOM libraries is appropriate for browser environments
- Bundler mode resolution aligns with Vite's build system
- react-jsx uses the modern JSX transform (React 17+)
- Comprehensive strict type-checking with additional linting rules
apps/account-verifier/tsconfig.json (1)
1-7: LGTM! Correct TypeScript project references setup.The configuration properly uses TypeScript's project references pattern, separating app code (tsconfig.app.json) from build tooling (tsconfig.node.json). This enables incremental builds and better IDE support.
apps/account-verifier/tsconfig.node.json (1)
1-24: LGTM! Appropriate Node.js/build tooling configuration.The configuration correctly targets ES2022/ES2023 for Node.js runtime (where Vite executes), which is intentionally newer than the app configuration's ES2020 target. This allows build tooling to leverage modern Node.js features while maintaining broader browser compatibility for the app code.
apps/account-verifier/.env.example (1)
1-3: Static analysis warnings are false positives.The dotenv-linter warnings about quote characters and key ordering can be safely ignored:
- Quotes around empty strings in
.env.examplefiles are conventional and harmless.- Key ordering is a stylistic preference with no functional impact.
apps/account-verifier/src/App.css (1)
30-34: Good accessibility practice.The reduced-motion media query respects user preferences, which is excellent for accessibility.
apps/account-verifier/src/polyfills/index.ts (1)
1-1: LGTM!The Buffer polyfill import is appropriate for browser environments that lack Node.js Buffer API.
examples/spa/src/hooks/use-fast-auth-workflow.ts (1)
3-4: Verify the package renames and API compatibility.The imports have been updated from
@fast-auth/browserand@fast-auth/javascriptto@fast-auth/browser-sdkand@fast-auth/javascript-provider. These new packages exist in the monorepo workspace and maintain full API compatibility with all required exports present.apps/account-verifier/vite.config.ts (1)
1-11: LGTM!The Vite configuration is appropriate for a React + NEAR app, with node polyfills correctly included to support browser-based NEAR SDK usage.
apps/account-verifier/src/polyfills/buffer/index.ts (1)
1-3: LGTM!The Buffer polyfill correctly exposes Node.js Buffer globally for browser environments, following the established pattern for global variable setup in this codebase.
apps/account-verifier/src/App.tsx (1)
1-17: LGTM!The App component provides a clean router setup with appropriate structure.
apps/account-verifier/src/main.tsx (1)
1-14: LGTM!The bootstrap code correctly follows React 19 patterns, with proper import order (polyfills first), StrictMode wrapping, and FastAuthProvider context setup.
apps/account-verifier/package.json (1)
22-22: React 19.2.0 does not include breaking changes—the breaking changes were in React 19.0.React 19.2 is not a breaking release; it was released on October 1, 2025 and focuses on performance and new APIs like
<Activity>anduseEffectEvent. The breaking changes you mentioned (propTypes removal and string refs removal) occurred in React 19.0, not 19.2. React 19.1 also introduced no breaking changes.For React 19.2.0 specifically, you'll need to upgrade to eslint-plugin-react-hooks@latest so that the linter doesn't try to insert useEffectEvent functions as dependencies. No verification of deprecated patterns is necessary for this version.
Likely an incorrect or invalid review comment.
apps/account-verifier/src/components/steps/index.ts (1)
1-5: LGTM!Clean barrel export pattern that provides a unified import surface for all step components.
apps/account-verifier/src/components/steps/LoginStep.tsx (1)
15-31: LGTM!Loading state management follows the established pattern used by
LoginButtonandLogoutButton, with proper try/finally to ensure state is reset.apps/account-verifier/src/pages/Home.tsx (1)
7-46: LGTM!Good structure with proper state management and handler guards. The early returns in
handleNetworkChangeprevent unnecessary operations when already switching or selecting the same network.apps/account-verifier/src/components/steps/RequestTransactionStep.tsx (1)
23-45: LGTM!Clean form submission handling with proper validation, loading state management, and error handling using try/catch/finally.
apps/account-verifier/src/hooks/use-fast-auth-workflow.ts (1)
33-47: LGTM on the hook structure.The state management and workflow coordination follow the established pattern from the SPA example. The separation of state and actions provides a clean interface for consuming components.
apps/account-verifier/src/hooks/use-access-keys.ts (1)
119-127: LGTM!The return object cleanly exposes all necessary state and the fetch function for consumers.
apps/account-verifier/src/services/fast-auth-relayer.ts (1)
166-201: LGTM -relaySignActionimplementation.The method correctly constructs a transaction, signs it locally, and sends it via the provider. The SHA-256 hashing and base58 encoding align with NEAR's signing conventions.
apps/account-verifier/src/hooks/use-fast-auth-relayer.tsx (1)
38-51: Duplicated contract mapping logic needs resolution.The
getContractsFromNetworkfunction duplicates logic frompackages/sdks/react/src/providers/utils/contracts.ts, but this function is not currently exported from@fast-auth/browser-sdk, making it inaccessible for import. To eliminate the duplication, either export this utility function from the shared package and import it here, or document why the local implementation is necessary.
| "domain": "auth0.aws.peersyst.tech", | ||
| "clientId": "qOfA3FaWedmD9LjFS9uRvQVJ0U3XhsgA", | ||
| "audience": "fast-auth-api-test-0.com", | ||
| "appOrigin": "http://localhost:3000", |
There was a problem hiding this comment.
Make appOrigin environment-specific.
The hardcoded localhost:3000 value will break when deployed to staging or production environments.
Consider using environment variables:
{
"domain": "auth0.aws.peersyst.tech",
"clientId": "qOfA3FaWedmD9LjFS9uRvQVJ0U3XhsgA",
"audience": "fast-auth-api-test-0.com",
- "appOrigin": "http://localhost:3000",
+ "appOrigin": "${APP_ORIGIN}",
"mpcContractId": "v1.signer-prod.testnet",
"fastAuthContractId": "fast-auth-beta-001.testnet"
}Then in your config loader, replace the placeholder with import.meta.env.VITE_APP_ORIGIN or use Vite's environment variable substitution.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/account-verifier/src/auth_config.json around line 5, appOrigin is
hardcoded to "http://localhost:3000"; change it to be environment-specific by
replacing the literal with a placeholder and update the config loader to read
the runtime env (e.g. use import.meta.env.VITE_APP_ORIGIN when using Vite or
process.env.VITE_APP_ORIGIN in Node builds), provide a sensible fallback (e.g.
empty string or default origin) and validate the value before use so
staging/production origins are injected from environment variables.
| <button | ||
| onClick={onClick} | ||
| style={{ | ||
| width: "100%", | ||
| textAlign: "left", | ||
| padding: "1rem", | ||
| background: "#181a20", | ||
| border: "none", | ||
| borderRadius: "8px 8px 0 0", | ||
| fontWeight: 600, | ||
| cursor: "pointer", | ||
| outline: "none", | ||
| color: "#f1f1f1", | ||
| }} | ||
| > | ||
| {title} | ||
| </button> |
There was a problem hiding this comment.
Add type="button" to prevent unintended form submission.
The button lacks an explicit type attribute, which defaults to "submit" in HTML forms. This can cause unintended form submissions if the Accordion is used inside a form context.
Apply this diff:
<button
+ type="button"
onClick={onClick}
style={{📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button | |
| onClick={onClick} | |
| style={{ | |
| width: "100%", | |
| textAlign: "left", | |
| padding: "1rem", | |
| background: "#181a20", | |
| border: "none", | |
| borderRadius: "8px 8px 0 0", | |
| fontWeight: 600, | |
| cursor: "pointer", | |
| outline: "none", | |
| color: "#f1f1f1", | |
| }} | |
| > | |
| {title} | |
| </button> | |
| <button | |
| type="button" | |
| onClick={onClick} | |
| style={{ | |
| width: "100%", | |
| textAlign: "left", | |
| padding: "1rem", | |
| background: "#181a20", | |
| border: "none", | |
| borderRadius: "8px 8px 0 0", | |
| fontWeight: 600, | |
| cursor: "pointer", | |
| outline: "none", | |
| color: "#f1f1f1", | |
| }} | |
| > | |
| {title} | |
| </button> |
🤖 Prompt for AI Agents
In apps/account-verifier/src/components/Accordion.tsx around lines 13 to 29, the
clickable button element lacks an explicit type and will default to
type="submit" when placed inside a form; update the button to include
type="button" to prevent unintended form submissions, keeping the existing props
(onClick, style, children) unchanged.
| const handleLogin = async () => { | ||
| setIsLoading(true); | ||
| try { | ||
| await client?.login(); | ||
| } finally { | ||
| setIsLoading(false); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Add error handling and user feedback for login failures.
The login flow has two reliability gaps:
- If
clientis null, the login silently does nothing due to optional chaining - Login errors are caught but not displayed to the user
Apply this diff to add error feedback:
const LoginButton = () => {
const { client } = useFastAuth();
const [isLoading, setIsLoading] = useState(false);
+ const [error, setError] = useState<string | null>(null);
const handleLogin = async () => {
+ if (!client) {
+ setError("Authentication client not initialized");
+ return;
+ }
setIsLoading(true);
+ setError(null);
try {
- await client?.login();
+ await client.login();
+ } catch (err) {
+ setError(err instanceof Error ? err.message : "Login failed");
} finally {
setIsLoading(false);
}
};
return (
- <button onClick={handleLogin} disabled={isLoading}>
- {isLoading ? <Spinner size={18} /> : "Log in"}
- </button>
+ <div>
+ <button onClick={handleLogin} disabled={isLoading}>
+ {isLoading ? <Spinner size={18} /> : "Log in"}
+ </button>
+ {error && <p style={{ color: "red" }}>Error: {error}</p>}
+ </div>
);
}Committable suggestion skipped: line range outside the PR's diff.
| const handleLogout = async () => { | ||
| setIsLoading(true); | ||
| try { | ||
| await client?.logout(); | ||
| } finally { | ||
| setIsLoading(false); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Add error handling for logout failures.
The logout call has no error handling. If client.logout() throws an error, it will be unhandled and the user won't receive feedback about the failure.
Apply this diff to handle errors appropriately:
const handleLogout = async () => {
setIsLoading(true);
try {
await client?.logout();
+ } catch (error) {
+ console.error("Logout failed:", error);
+ // Consider showing a user-facing error message
+ // e.g., toast notification or alert
} finally {
setIsLoading(false);
}
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const handleLogout = async () => { | |
| setIsLoading(true); | |
| try { | |
| await client?.logout(); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }; | |
| const handleLogout = async () => { | |
| setIsLoading(true); | |
| try { | |
| await client?.logout(); | |
| } catch (error) { | |
| console.error("Logout failed:", error); | |
| // Consider showing a user-facing error message | |
| // e.g., toast notification or alert | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In apps/account-verifier/src/components/LogoutButton.tsx around lines 9 to 16,
the logout call lacks error handling so exceptions from client.logout() are
unhandled; wrap the await client?.logout() in a try/catch/finally, in the catch
capture the error, log it (console.error or a logger) and surface user feedback
(set an error state or call the existing toast/notification API) so the user
knows logout failed, and keep setIsLoading(false) in the finally block to ensure
loading state is cleared.
| // Add keyframes for spin animation | ||
| const style = document.createElement("style"); | ||
| style.innerHTML = `@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`; | ||
| document.head.appendChild(style); |
There was a problem hiding this comment.
Move animation injection inside component or to a CSS file.
The module-level DOM mutation creates side effects at import time, which can cause duplicate <style> elements if the module is imported multiple times or fails in SSR contexts.
Consider one of these approaches:
Option 1: Use useEffect to inject once
+import React, { useEffect } from "react";
+
+let animationInjected = false;
+
const Spinner: React.FC<{ size?: number }> = ({ size = 18 }) => {
+ useEffect(() => {
+ if (!animationInjected && !document.querySelector('style[data-spinner-animation]')) {
+ const style = document.createElement("style");
+ style.setAttribute('data-spinner-animation', 'true');
+ style.innerHTML = `@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`;
+ document.head.appendChild(style);
+ animationInjected = true;
+ }
+ }, []);
+
<span
style={{Option 2: Move to a CSS file
Create Spinner.css:
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}Then import it:
import React from "react";
+import "./Spinner.css";-
-// Add keyframes for spin animation
-const style = document.createElement("style");
-style.innerHTML = `@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`;
-document.head.appendChild(style);🤖 Prompt for AI Agents
In apps/account-verifier/src/components/Spinner.tsx around lines 20-23, the
module-level DOM mutation injects a <style> tag at import time which causes
duplicate styles and breaks SSR; move this logic into the component (inject once
inside a useEffect with a guard to avoid duplicate insertion) or, preferably,
create a Spinner.css with the @keyframes spin and import that CSS from the
component, then remove the
document.createElement/style.innerHTML/document.head.appendChild code from the
module scope.
| span { | ||
| color: #000; | ||
| } | ||
|
|
||
| li { | ||
| color: #000; | ||
| } |
There was a problem hiding this comment.
Fix dark mode text color for span and li elements.
Hardcoding color: #000 (black) on span and li elements will make them nearly invisible against the dark background (#242424) in dark mode, severely impacting readability.
Apply this diff to make these elements respect the color scheme:
span {
- color: #000;
+ color: inherit;
}
li {
- color: #000;
+ color: inherit;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
+ span,
+ li {
+ color: #000;
+ }
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In apps/account-verifier/src/index.css around lines 57 to 63, the span and li
rules currently hardcode color: #000 which breaks readability in dark mode;
change these rules so they don't force black — use a theme-aware value such as
color: inherit or color: var(--text-color, currentColor) (or currentColor) so
they follow the page/root text color or CSS variable used for light/dark themes;
update the CSS to remove the hardcoded #000 and reference the appropriate
variable/inherit behavior.
| .info-label { | ||
| font-weight: 500; | ||
| color: #bbb; | ||
| } | ||
|
|
||
| input { | ||
| background-color: #181a20; | ||
| color: #e0e0e0; | ||
| border: 1px solid #222; | ||
| border-radius: 4px; | ||
| padding: 0.5rem; | ||
| width: 100%; | ||
| max-width: 300px; | ||
| } | ||
|
|
||
| .info-label { | ||
| display: flex; | ||
| flex-direction: column; | ||
| gap: 0.5rem; | ||
| margin: 0.5rem 0; | ||
| } |
There was a problem hiding this comment.
Duplicate .info-label selector causing style override.
The .info-label class is defined twice (lines 34-37 and 49-54). The second definition will completely override the first, losing the font-weight and color properties. Merge these into a single definition.
Apply this diff to merge the definitions:
.info-label {
font-weight: 500;
color: #bbb;
-}
-
-input {
- background-color: #181a20;
- color: #e0e0e0;
- border: 1px solid #222;
- border-radius: 4px;
- padding: 0.5rem;
- width: 100%;
- max-width: 300px;
-}
-
-.info-label {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin: 0.5rem 0;
}
+
+input {
+ background-color: #181a20;
+ color: #e0e0e0;
+ border: 1px solid #222;
+ border-radius: 4px;
+ padding: 0.5rem;
+ width: 100%;
+ max-width: 300px;
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .info-label { | |
| font-weight: 500; | |
| color: #bbb; | |
| } | |
| input { | |
| background-color: #181a20; | |
| color: #e0e0e0; | |
| border: 1px solid #222; | |
| border-radius: 4px; | |
| padding: 0.5rem; | |
| width: 100%; | |
| max-width: 300px; | |
| } | |
| .info-label { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| margin: 0.5rem 0; | |
| } | |
| .info-label { | |
| font-weight: 500; | |
| color: #bbb; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| margin: 0.5rem 0; | |
| } | |
| input { | |
| background-color: #181a20; | |
| color: #e0e0e0; | |
| border: 1px solid #222; | |
| border-radius: 4px; | |
| padding: 0.5rem; | |
| width: 100%; | |
| max-width: 300px; | |
| } |
🤖 Prompt for AI Agents
In apps/account-verifier/src/pages/Home.css around lines 34 to 54, the
.info-label selector is declared twice so the second block overrides the first
and drops font-weight and color; merge the two blocks into a single .info-label
rule that includes font-weight: 500, color: #bbb, display: flex, flex-direction:
column, gap: 0.5rem, and margin: 0.5rem 0, then remove the duplicate
declaration.
| // Environment variables for relayer configuration | ||
| const RELAYER_PRIVATE_KEY = import.meta.env.VITE_RELAYER_PRIVATE_KEY; | ||
| const RELAYER_ACCOUNT_ID = import.meta.env.VITE_RELAYER_ACCOUNT_ID; | ||
| // Contract IDs will be determined by network | ||
| export type NetworkId = "testnet" | "mainnet"; | ||
|
|
||
| const getFastAuthContractId = (networkId: NetworkId): string => { | ||
| return networkId === "mainnet" ? "fast-auth.near" : "fast-auth-beta-001.testnet"; | ||
| }; | ||
|
|
||
| // Validate required environment variables | ||
| if (!RELAYER_PRIVATE_KEY) { | ||
| throw new Error("VITE_RELAYER_PRIVATE_KEY environment variable is required. Please create a .env file with your relayer credentials."); | ||
| } | ||
|
|
||
| if (!RELAYER_ACCOUNT_ID) { | ||
| throw new Error("VITE_RELAYER_ACCOUNT_ID environment variable is required. Please create a .env file with your relayer credentials."); | ||
| } |
There was a problem hiding this comment.
Module-level throw blocks application startup.
Throwing at module load time will crash the entire application if environment variables are missing, even for routes/components that don't use this service. Consider lazy validation in init() or constructor.
// Environment variables for relayer configuration
const RELAYER_PRIVATE_KEY = import.meta.env.VITE_RELAYER_PRIVATE_KEY;
const RELAYER_ACCOUNT_ID = import.meta.env.VITE_RELAYER_ACCOUNT_ID;
// Contract IDs will be determined by network
export type NetworkId = "testnet" | "mainnet";
const getFastAuthContractId = (networkId: NetworkId): string => {
return networkId === "mainnet" ? "fast-auth.near" : "fast-auth-beta-001.testnet";
};
-// Validate required environment variables
-if (!RELAYER_PRIVATE_KEY) {
- throw new Error("VITE_RELAYER_PRIVATE_KEY environment variable is required. Please create a .env file with your relayer credentials.");
-}
-
-if (!RELAYER_ACCOUNT_ID) {
- throw new Error("VITE_RELAYER_ACCOUNT_ID environment variable is required. Please create a .env file with your relayer credentials.");
-}Then validate in init():
async init() {
if (!RELAYER_PRIVATE_KEY) {
throw new Error("VITE_RELAYER_PRIVATE_KEY environment variable is required.");
}
if (!RELAYER_ACCOUNT_ID) {
throw new Error("VITE_RELAYER_ACCOUNT_ID environment variable is required.");
}
// ... rest of init
}🤖 Prompt for AI Agents
In apps/account-verifier/src/services/fast-auth-relayer.ts around lines 12 to
29, the module currently throws errors during import when RELAYER_PRIVATE_KEY or
RELAYER_ACCOUNT_ID are missing which crashes the whole app; remove these
top-level throws and instead perform the same validations inside an async init()
(or the service constructor) so missing env variables are detected only when the
relayer is actually initialized—move the error messages into init(), throw there
if values are falsy, and keep the RELAYER_* constants available for lazy checks;
ensure no other code relies on the module to throw at load time.
| async createAccount(action: Action) { | ||
| try { | ||
| const signerPublicKey = this.keyPair.getPublicKey(); | ||
| const accessKey = (await this.getConnection().connection.provider.query( | ||
| `access_key/${this.accountId}/${signerPublicKey}`, | ||
| "", | ||
| )) as AccessKeyView; | ||
| const nonce = ++accessKey.nonce; | ||
|
|
||
| const tx = createTransaction(this.accountId, signerPublicKey, this.networkId, nonce, [action], base_decode(accessKey.block_hash)); | ||
| await this.account.signAndSendTransaction(tx); | ||
| } catch (error) { | ||
| console.error("Error creating account:", error); | ||
| throw error; | ||
| } | ||
| } |
There was a problem hiding this comment.
Fix signAndSendTransaction call to pass options object instead of Transaction object.
The signAndSendTransaction method expects { receiverId, actions } but is being called with a Transaction object. Change to:
await this.account.signAndSendTransaction({ receiverId: this.accountId, actions: [action] });
🤖 Prompt for AI Agents
In apps/account-verifier/src/services/fast-auth-relayer.ts around lines 128 to
143, the code builds a Transaction and calls
this.account.signAndSendTransaction(tx) but signAndSendTransaction expects an
options object ({ receiverId, actions }) not a Transaction; remove the manual
Transaction creation and related access_key query/nonce logic and replace the
call with await this.account.signAndSendTransaction({ receiverId:
this.accountId, actions: [action] }) so the account API handles signing and
sending correctly.
| async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction) { | ||
| const signedTransaction = new SignedTransaction({ | ||
| transaction: tx, | ||
| signature: new Signature({ | ||
| keyType: KeyType.SECP256K1, | ||
| data: signature, | ||
| }), | ||
| }); | ||
|
|
||
| return await this.getConnection().connection.provider.sendTransaction(signedTransaction); | ||
| } |
There was a problem hiding this comment.
Hardcoded SECP256K1 key type may not match all signatures.
The send method hardcodes KeyType.SECP256K1, but the signature type should match the key type used to create it. If the transaction was signed with an ED25519 key (common for NEAR), this will fail verification.
Consider passing the key type as a parameter or inferring it from the transaction's signer public key:
- async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction) {
+ async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction, keyType: KeyType = KeyType.SECP256K1) {
const signedTransaction = new SignedTransaction({
transaction: tx,
signature: new Signature({
- keyType: KeyType.SECP256K1,
+ keyType,
data: signature,
}),
});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction) { | |
| const signedTransaction = new SignedTransaction({ | |
| transaction: tx, | |
| signature: new Signature({ | |
| keyType: KeyType.SECP256K1, | |
| data: signature, | |
| }), | |
| }); | |
| return await this.getConnection().connection.provider.sendTransaction(signedTransaction); | |
| } | |
| async send(signature: Uint8Array<ArrayBufferLike>, tx: Transaction, keyType: KeyType = KeyType.SECP256K1) { | |
| const signedTransaction = new SignedTransaction({ | |
| transaction: tx, | |
| signature: new Signature({ | |
| keyType, | |
| data: signature, | |
| }), | |
| }); | |
| return await this.getConnection().connection.provider.sendTransaction(signedTransaction); | |
| } |
🤖 Prompt for AI Agents
In apps/account-verifier/src/services/fast-auth-relayer.ts around lines 203-213
the Signature is hardcoded to KeyType.SECP256K1 which can break verification for
transactions signed with other key types (e.g. ED25519); change the method to
accept a keyType parameter (or infer it from the transaction signer public key)
and use that value when constructing new Signature, or map/infer the correct
KeyType enum before creating SignedTransaction, and add a small validation/error
if the keyType is unsupported.
[[account-verifier] feat: setup
Changes 🛠️
app/package
account-verifierapp.Summary by CodeRabbit
New Features
Updates
✏️ Tip: You can customize this high-level summary in your review settings.