UNPKG

@brahmafi/cards-sdk

Version:

Official SDK for integrating Swype payment and credit services

443 lines (363 loc) 14.6 kB
# Brahma SDK A React SDK for seamless KYC, card activation, and credit management flows. Integrate Brahma SDK's widgets, hooks, and utilities into your app with minimal setup. --- ## Setting Up ## 1. SDK Initialization & Authentication To use the SDK, you must initialize it **after authenticating the user** with an EIP-712 signature. The authentication is valid for 1 hour; after that, a new signature is required. **Requirements:** - User's EOA address (wallet) - EIP-712 signature (generated via wallet) - API key (from Swype) - Deadline (timestamp, 1 hour in the future) **Example (React, using wagmi):** ```tsx // 1. Generate signature const { signature, timestamp } = await generateAuthSign( process.env.NEXT_PUBLIC_SWYPE_TENANT_ID ?? "", signTypedDataAsync, ) // 2. Exchange for JWT const newJwt: JWT = await initializeAuth(signature, timestamp, { eoaAddress: address, tenantId: process.env.NEXT_PUBLIC_SWYPE_TENANT_ID ?? "", apiKey: process.env.NEXT_PUBLIC_SWYPE_API_KEY || "", baseUrl, apiPath: "/v1/vendor", }) // 3. Initialize SDK await initializeSwypeSDK({ apiKey: process.env.NEXT_PUBLIC_SWYPE_API_KEY || "", tenantId: process.env.NEXT_PUBLIC_SWYPE_TENANT_ID ?? "", baseUrl, apiPath: "/v1/vendor", eoaAddress: address, jwt: newJwt, }) ``` > **Note:** After 1 hour, you must prompt the user to sign again and re-initialize the SDK. --- ## 2. Widgets The SDK provides ready-to-use React components for KYC and card management. > ### **Prerequisites** > > `@import "@brahmafi/cards-sdk/dist/styles.css";` > > Import styles in global.css ### **KycModal** - **Props:** - `eoaAddress: string` (required) - `onClose?: () => void` - `onComplete?: () => void` - **Description:** Handles the full KYC flow, including SumSub integration, consent, and pending/approved states. Callbacks are triggered on close or completion. **Behavior by User Status:** - **'userNotExisting':** Shows the SumSub widget for users to start their KYC verification process. - **'pending':** Shows pending screen. KYC verification is in process and may take up to 2 days to complete. Can be pending from SumSub or Rain. - **'rejected':** Shows rejected screen with option to contact support to resolve the issue. - **'resubmit':** Shows resubmission screen. Verification was rejected, user needs to contact support to resubmit. - **'submitted':** KYC verification has been successfully submitted. Modal doesn't show anything for this status (returns null). - **'approved':** The KYC is complete. User can proceed with other actions that comes after kyc. ### **ManageCardModal** - **Props:** - `title: string` - `onClose: () => void` - `callbacks: CardDetailsCallbacks` - `address: string` - **Description:** Lets users view card details, reveal secrets, freeze/unfreeze, and change PIN. Integrates with SDK hooks for state and actions. --- ## 3. Hooks The SDK exposes hooks for accessing user/card/credit/transaction data: ### **useCardData** Returns: ```ts { status: CardStatus | null, userCard: UserCard | null, isUserCardDelegated: boolean, isLoading: boolean, error: string | null, refreshCardStatus: () => Promise<void> } ``` ### **useCreditData** Returns: ```ts { creditInfo: Record<StoreCreditType, CreditInformationResponse | null>, isLoading: boolean, error: string | null, userConfig: UserConfig["config"] | null, refreshPositions: (creditTypes: StoreCreditType[]) => Promise<void>, isRefreshingPositions: boolean } ``` ### **useGetTransactions** Returns: ```ts { transactions: Transaction[], isLoading: boolean, loadingNextPage: boolean, error: string | null, hasNext: boolean, pendingTxnAmount: number, loadMore: () => Promise<void>, refetch: () => Promise<void>, resetError: () => void } ``` ### **useGetHookTransactions** Returns: ```ts { transactions: HookTransaction[], isLoading: boolean, loadingNextPage: boolean, error: string | null, hasNext: boolean, loadMore: () => Promise<void>, refetch: () => Promise<void>, resetError: () => void } ``` ## 4. Utility Functions ### **delegateAmount** ```ts async function delegateAmount(params: { creditType: CreditProviderId; creditLimit: number; sendTransactionAsync: (params: { to: string; value: bigint; data: string; }) => Promise<string>; userParams?: UserParams; chainID: number; }): Promise<{ success: boolean; message: string; transactionHash?: string }>; ``` - **Description:** Handles the process of delegating a credit limit to a user's card. It fetches the required transaction data, sends the delegation transaction, and updates the credit store with the latest information. Also handles user configuration initialization for spend mode providers. - **Params:** - `creditType`: CreditProviderId The credit protocol to use for delegation. - `creditLimit`: number The amount of credit to delegate (must be >= 0). - `sendTransactionAsync`: (params) => Promise<string> Callback to send the delegation transaction. - `userParams?`: UserParams Optional additional user parameters (e.g., vault addresses). - `chainID`: number The chain ID for the operation. - **Returns:** - `{ success: boolean; message: string; transactionHash?: string }` Indicates if delegation succeeded, provides a message, and optionally returns the transaction hash. - **Notes:** - Validates credit limit is >= 0 before proceeding. - Updates user configuration for spend mode providers when no card exists. - Updates credit store with latest credit information after delegation. --- ### **createCardAction** ```ts async function createCardAction(params: { creditType: CreditProviderId; }): Promise<{ success: boolean; message: string }>; ``` - **Description:** Creates a new user card if one does not already exist and updates the card status store. The function fetches existing cards, creates a new card if needed, and verifies the creation was successful by ensuring the card belongs to the user's EOA address. - **Params:** - `creditType`: CreditProviderId The type of credit to associate with the card. - **Returns:** - `{ success: boolean; message: string }` Indicates if card creation succeeded and provides a message. - **Notes:** - Will not create a new card if one already exists for the user. - Automatically determines the appropriate solver configuration based on credit type and user config. - Verifies that the created card's credit provider address matches the user's EOA address. - Updates the card status store with the newly created card information. ### **updateCardProvider** ```ts async function updateCardProvider(params: { creditType: CreditProviderId; chainId: number; config?: { aTokenAddress?: string; vaultTokenAddress?: string; purchaseBaseTokenAddress: string; }; }): Promise<{ success: boolean; message: string }>; ``` - **Description:** Updates an existing card's credit provider configuration. This function allows switching between different credit providers or updating the configuration for the current provider. After updating, it refetches the card data to ensure the changes are reflected. - **Params:** - `creditType`: CreditProviderId The new credit provider type to switch to. - `chainId`: number The chain ID for the operation. - `config?`: Optional configuration object containing: - `aTokenAddress?`: string Address of the aToken (for Aave-based providers). - `vaultTokenAddress?`: string Address of the vault token (for vault-based providers). - `purchaseBaseTokenAddress`: string Address of the base token used for purchases. - **Returns:** - `{ success: boolean; message: string }` Indicates if the update succeeded and provides a message. - **Notes:** - Requires an existing card to be present before updating. - Updates the card status store with the latest card information after the update. - Validates that the EOA address and card ID are available before proceeding. --- ### **showCardDetails** ```ts /** * Retrieves and decrypts a user's sensitive credit card details (16-digit number, CVC, expiry month, and expiry year). * This function initiates a secure key exchange with the backend and utilizes the Rain SDK for local decryption. */ export async function showCardDetails( signTypedData: (params: any) => Promise<string>, address: string, ): Promise<{ cardNumber: string; cvc: string; expiryMonth: string; expiryYear: string; }>; ``` - **Description:** Retrieves and securely decrypts a user's sensitive credit card details, including the 16-digit card number (PAN), Card Verification Value (CVC), expiry month, and expiry year. This process involves fetching a public key from the backend, generating a secure session using the Rain SDK, and then decrypting the encrypted card data received from the backend. The entire flow is designed to ensure sensitive information remains protected. - **Params:** - `signTypedData`: `(params: any) => Promise<string>` A function provided by the dApp's wallet integration (e.g., from a Wagmi hook like useSignTypedData). This function is used to sign EIP-712 typed data, which is essential for authorizing the secure fetching of encrypted card secrets. - `address: string`: number The Ethereum wallet address of the user who owns the card. This address is used for authentication and to associate the request with the correct user's card. - **Returns:** - `Promise<{ cardNumber: string; cvc: string; expiryMonth: string; expiryYear: string }>` A promise that resolves to an object containing the decrypted card details: - cardNumber: string The 16-digit Primary Account Number (PAN) of the card. - cvc: string The Card Verification Value (typically 3 or 4 digits). - expiryMonth: string The two-digit expiry month (e.g., "01" for January). - expiryYear: string The four-digit expiry year (e.g., "2027"). - **Notes:** - This function requires the Rain SDK to be available in the global window.rain object. It is expected that the SDK's bundle will have executed the rain.js content to define this object before showCardDetails is called. - Error handling is built-in; the function will throw an error if any step (e.g., key fetching, session generation, decryption, or underlying SDK calls) fails, or if required parameters are missing/invalid. - It is the responsibility of the calling application to handle the display and security of the decrypted card details. These details should be displayed cautiously and ideally for a limited time to mitigate security risks. ```ts import { useSignTypedData, useAccount } from 'wagmi'; // Example with wagmi import { showCardDetails, ensureRainScriptLoaded } from './path/to/your/sdk-functions'; // ... in your component const { signTypedData } = useSignTypedData(); const { address } = useAccount(); const handleRevealCard = async () => { if (!address || !signTypedData) { alert("Wallet not connected or signTypedData not available."); return; } try { // Ensure Rain SDK is loaded const isRainReady = await ensureRainScriptLoaded(); if (!isRainReady) { alert("Rain SDK is not ready. Cannot reveal card."); return; } const details = await showCardDetails(signTypedData, address); console.log("Card Number:", details.cardNumber); console.log("CVC:", details.cvc); console.log("Expiry:", `${details.expiryMonth}/${details.expiryYear}`); // Now you can display these details in your UI } catch (error) { console.error("Failed to reveal card details:", error); alert(error.message); } }; ``` ### **updateCardPin** ```ts import { updateCardPin, ensureRainScriptLoaded } from './path/to/your/sdk-functions'; import { useSignTypedData, useAccount } from 'wagmi'; // Example with wagmi import { useState } from 'react'; // ... in your component const { signTypedData } = useSignTypedData(); const { address } = useAccount(); const [newPin, setNewPin] = useState(''); const handleChangePin = async () => { if (!address || !signTypedData) { alert("Wallet not connected or signTypedData not available."); return; } if (!newPin) { alert("Please enter a new PIN."); return; } try { const isRainReady = await ensureRainScriptLoaded(); if (!isRainReady) { alert("Rain SDK is not ready. Cannot update PIN."); return; } const success = await updateCardPin(newPin, signTypedData, address); if (success) { alert("PIN updated successfully!"); setNewPin(''); // Clear input } } catch (error) { console.error("Failed to update PIN:", error); alert(error.message); } }; // ... in your JSX // <input type="password" value={newPin} onChange={(e) => setNewPin(e.target.value)} /> // <button onClick={handleChangePin}>Update PIN</button> ``` ## 5. Types The SDK exports the following types for type safety and integration: - `CardStatus`: Status of the user's card/KYC ```js | "userNotExisting" | "initiated" | "review" | "pending" | "approved" | "rejected" | "feePending"; ``` - `UserCard`: Structure representing a user's card (cardID, status, type, last4, etc.) ```js interface UserCard { cardID: string; creditProviderAddress: string; type: "virtual" | "physical"; status: "active" | "inactive" | "pending" | "locked"; last4: string; solverType: "aave-v3" | "euler" | "hypurrFi"; expirationMonth: string; expirationYear: string; } ``` - `Transaction` ```js interface Transaction { id: string; type: TransactionType; status: TransactionStatus; amount: number; currency: string; local_amount?: number; local_currency: string; merchant: Merchant; declined_reason?: string; created_at: string; authorized_at?: string; posted_at?: string | null; onchain_transactions?: OnchainTransaction[]; } ``` - `OnchainTransactionDetail` ```js interface OnchainTransactionDetail { id: string; transaction_id: string; direction: OnchainDirection; chain_id: string; from_address: string; to_address: string; transaction_hash: string; amount: number; amount_raw: string; fee_raw: string; token: string; status: OnchainStatus; purpose: OnchainPurpose; error_details?: string; created_at: string; completed_at?: string; } ``` - ...and more (see `src/api/types.ts` for full list). --- **For more details, see the code comments and type definitions in the SDK.**