@chipi-stack/backend 14.3.1 → 14.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1536 -7
- package/dist/index.d.ts +1536 -7
- package/dist/index.js +2445 -318
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2379 -333
- package/dist/index.mjs.map +1 -1
- package/dist/skuPurchases.js +406 -19
- package/dist/skuPurchases.js.map +1 -1
- package/dist/skuPurchases.mjs +406 -19
- package/dist/skuPurchases.mjs.map +1 -1
- package/dist/transactions.js +406 -19
- package/dist/transactions.js.map +1 -1
- package/dist/transactions.mjs +406 -19
- package/dist/transactions.mjs.map +1 -1
- package/dist/wallets-CYCLyyXY.d.mts +221 -0
- package/dist/wallets-DxKnh21Q.d.ts +221 -0
- package/dist/wallets.d.mts +3 -56
- package/dist/wallets.d.ts +3 -56
- package/dist/wallets.js +901 -32
- package/dist/wallets.js.map +1 -1
- package/dist/wallets.mjs +901 -32
- package/dist/wallets.mjs.map +1 -1
- package/package.json +9 -4
package/dist/skuPurchases.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/encryption.ts","../src/paymaster-adapter.ts","../src/execute-paymaster-transaction.ts","../src/transactions.ts","../src/exchanges.ts","../src/sku-purchases.ts"],"names":["CryptoES","WALLET_RPC_ENDPOINTS","WALLET_CLASS_HASHES","RpcProvider","Account","typedData","apiMessage","STARKNET_CONTRACTS","formatAmount","API_ENDPOINTS","hash","Chain","CallData","SKU_CONTRACTS","cairo","CARRIER_IDS","SERVICE_TYPES"],"mappings":"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","file":"skuPurchases.js","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (privateKey: string, password: string): string => {\n if (!privateKey || !password) {\n throw new Error(\"Private key and password are required\");\n }\n\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (encryptedPrivateKey: string, password: string): string => {\n if (!encryptedPrivateKey || !password) {\n throw new Error(\"Encrypted private key and password are required\");\n }\n\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n if (!decrypted) {\n throw new Error(\"Decryption resulted in empty string\");\n }\n return decrypted;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Decryption failed: ${error}`);\n }\n};\n","import type {\n PaymasterAdapter,\n PaymasterAccount,\n PrepareTypedDataResponse,\n ExecuteSponsoredTransactionResponse,\n WalletType,\n} from \"@chipi-stack/types\";\nimport type { Call, TypedData } from \"starknet\";\nimport { WALLET_CLASS_HASHES, getWalletTypeFromClassHash } from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\n\n/**\n * Unwrap the /prepare-typed-data response.\n * Supports both current shape ({ typedData, walletType }) and legacy (raw TypedData).\n */\nfunction unwrapPrepareResponse(response: unknown): {\n typedData: TypedData;\n walletType?: WalletType;\n} {\n if (!response || typeof response !== \"object\") {\n throw new Error(\n \"Invalid response from /transactions/prepare-typed-data: response is not an object\"\n );\n }\n\n // Current shape: { typedData: TypedData, walletType: WalletType }\n if (\"typedData\" in response) {\n const resp = response as PrepareTypedDataResponse;\n if (\n !resp.typedData ||\n typeof resp.typedData !== \"object\" ||\n !(\"types\" in resp.typedData) ||\n !(\"message\" in resp.typedData)\n ) {\n throw new Error(\n \"Invalid response from /transactions/prepare-typed-data: typedData structure is invalid\"\n );\n }\n return { typedData: resp.typedData, walletType: resp.walletType };\n }\n\n // Legacy shape: the response itself is the TypedData\n if (\"types\" in response && \"message\" in response) {\n return { typedData: response as TypedData };\n }\n\n // Possibly an API error shape\n const apiMessage =\n typeof (response as any).message === \"string\" ? (response as any).message : undefined;\n\n throw new Error(\n apiMessage ?? \"Invalid response from /transactions/prepare-typed-data: typedData is missing\"\n );\n}\n\n/**\n * Normalize signature to { r: string, s: string } format.\n * Handles WeierstrassSignatureType ({r, s} as bigint) and ArraySignatureType ([r, s]).\n */\nexport function normalizeSignature(signature: unknown): { r: string; s: string } {\n // ArraySignatureType: string[]\n if (Array.isArray(signature)) {\n if (signature.length < 2) {\n throw new Error(`Array signature must have at least 2 elements, got ${signature.length}`);\n }\n const r = signature[0];\n const s = signature[1];\n if (r == null || s == null) {\n throw new Error(`Signature elements must not be null/undefined. Got r=${r}, s=${s}`);\n }\n return { r: String(r), s: String(s) };\n }\n\n // WeierstrassSignatureType: { r: bigint, s: bigint }\n if (signature && typeof signature === \"object\" && \"r\" in signature && \"s\" in signature) {\n const sig = signature as { r: unknown; s: unknown; recovery?: unknown };\n if (sig.r == null || sig.s == null) {\n throw new Error(`Object signature has null/undefined fields. Got r=${sig.r}, s=${sig.s}`);\n }\n return {\n r: String(sig.r),\n s: String(sig.s),\n };\n }\n\n throw new Error(\"Unrecognized signature format from account.signMessage()\");\n}\n\n/**\n * PaymasterAdapter implementation that uses Chipi's backend API for gasless transactions.\n *\n * Flow:\n * 1. Detect wallet type from on-chain class hash\n * 2. Call /transactions/prepare-typed-data to get TypedData\n * 3. Call account.signMessage(typedData) — triggers wallet popup for external wallets\n * 4. Call /transactions/execute-sponsored-transaction with signature\n * 5. Return transaction hash\n */\nexport class ChipiPaymasterAdapter implements PaymasterAdapter {\n private readonly client: ChipiClient;\n private readonly bearerToken: string;\n\n constructor(client: ChipiClient, bearerToken: string) {\n this.client = client;\n this.bearerToken = bearerToken;\n }\n\n async execute({ account, calls }: { account: PaymasterAccount; calls: Call[] }): Promise<string> {\n // 1. Detect wallet type from on-chain class hash\n const classHash = await account.getClassHashAt(account.address);\n const walletType = getWalletTypeFromClassHash(classHash);\n\n // Use mapped class hash for known types, on-chain hash for custom accounts.\n // The Rust paymaster auto-detects the interface version (V1/V2) from the class,\n // so custom SNIP-9 accounts work without an allowlist.\n const accountClassHash = walletType ? WALLET_CLASS_HASHES[walletType] : classHash;\n\n // 2. Prepare typed data via Chipi's backend\n const prepareResponse = await this.client.post<PrepareTypedDataResponse>({\n endpoint: \"/transactions/prepare-typed-data\",\n bearerToken: this.bearerToken,\n body: {\n publicKey: account.address,\n calls,\n accountClassHash,\n },\n });\n\n // 3. Unwrap response\n const { typedData, walletType: resolvedWalletType } = unwrapPrepareResponse(prepareResponse);\n\n // 4. Sign — triggers wallet popup for Argent X / Braavos\n const signature = await account.signMessage(typedData);\n\n // 5. Normalize signature format\n const normalizedSig = normalizeSignature(signature);\n\n // 6. Execute sponsored transaction\n const result = await this.client.post<ExecuteSponsoredTransactionResponse>({\n endpoint: \"/transactions/execute-sponsored-transaction\",\n bearerToken: this.bearerToken,\n body: {\n publicKey: account.address,\n typedData,\n userSignature: normalizedSig,\n walletType: resolvedWalletType ?? walletType,\n saveToDatabase: true,\n },\n });\n\n if (!result || typeof result !== \"object\") {\n throw new Error(\n \"Invalid response from /transactions/execute-sponsored-transaction: response is not an object\"\n );\n }\n\n const apiMessage =\n typeof (result as any).message === \"string\" ? (result as any).message : undefined;\n\n if (!result.transactionHash) {\n throw new Error(apiMessage ?? \"Response does not contain transaction hash\");\n }\n\n return result.transactionHash;\n }\n}\n","import type {\n ExecuteSponsoredTransactionResponse,\n WalletData,\n WalletType,\n SessionKeyData,\n PrepareTypedDataResponse,\n} from \"@chipi-stack/types\";\nimport type { Call } from \"starknet\";\nimport { Account, RpcProvider, TypedData, ec, typedData, num } from \"starknet\";\nimport { decryptPrivateKey } from \"./encryption\";\nimport {\n WALLET_CLASS_HASHES,\n WALLET_RPC_ENDPOINTS,\n SESSION_ERRORS,\n ChipiSessionError,\n} from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\nimport { normalizeSignature } from \"./paymaster-adapter\";\n\n// Extended WalletData with optional wallet type for transactions\n\n// Internal type - not exported to users\ninterface ExecutePaymasterTransactionParams {\n encryptKey?: string;\n wallet: WalletData;\n calls: Call[];\n saveToDatabase: boolean; // Internal only - always set by SDK, users cannot control this\n usePasskey?: boolean;\n}\n\n/**\n * Execute a paymaster transaction (gasless) via Chipi's paymaster\n * Supports both CHIPI and ARGENT wallet types\n */\nexport const executePaymasterTransaction = async ({\n params,\n bearerToken,\n client,\n}: {\n params: ExecutePaymasterTransactionParams;\n bearerToken: string;\n client: ChipiClient;\n}): Promise<string> => {\n try {\n const { encryptKey, wallet, calls, saveToDatabase, usePasskey } = params;\n\n // Validate encryptKey is provided\n if (!encryptKey) {\n throw new Error(\n usePasskey\n ? \"encryptKey is required when using passkey. The passkey authentication should have provided the encryptKey.\"\n : \"encryptKey is required for transaction execution\"\n );\n }\n\n const walletType = wallet.walletType ?? \"READY\";\n\n // For known types, use mapped RPC and class hash.\n // For custom types, fall back to default CHIPI RPC (all StarkNet accounts use the same RPC)\n // and use the wallet's classHash if available.\n const isKnownType =\n Object.prototype.hasOwnProperty.call(WALLET_RPC_ENDPOINTS, walletType) &&\n Object.prototype.hasOwnProperty.call(WALLET_CLASS_HASHES, walletType);\n\n const rpcUrl = isKnownType ? WALLET_RPC_ENDPOINTS[walletType] : WALLET_RPC_ENDPOINTS[\"CHIPI\"];\n const accountClassHash = isKnownType\n ? WALLET_CLASS_HASHES[walletType]\n : WALLET_CLASS_HASHES[\"CHIPI\"];\n\n // Decrypt the private key\n let privateKeyDecrypted: string;\n try {\n privateKeyDecrypted = decryptPrivateKey(wallet.encryptedPrivateKey, encryptKey);\n } catch {\n throw new Error(\"Failed to decrypt private key. Verify the encryptKey is correct.\");\n }\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n const account = new Account({\n provider,\n address: wallet.publicKey,\n signer: privateKeyDecrypted,\n });\n\n // Build the type data via Chipi's backend\n const prepareResponse = await client.post<PrepareTypedDataResponse>({\n endpoint: \"/transactions/prepare-typed-data\",\n bearerToken,\n body: {\n publicKey: wallet.publicKey,\n calls: calls,\n accountClassHash,\n },\n });\n\n // Validate response structure\n if (!prepareResponse || typeof prepareResponse !== \"object\") {\n throw new Error(\n \"Invalid response from /transactions/prepare-typed-data: response is not an object\"\n );\n }\n\n // Support both current and legacy API response shapes:\n // - Current: { typedData: TypedData, walletType: WalletType }\n // - Legacy: TypedData directly (domain/types/primaryType/message)\n let typedData: TypedData | undefined;\n let resolvedWalletType: WalletType | undefined;\n\n if (\"typedData\" in prepareResponse) {\n const resp = prepareResponse as PrepareTypedDataResponse;\n typedData = resp.typedData;\n // Only accept known wallet types from the backend\n if (\n resp.walletType &&\n Object.prototype.hasOwnProperty.call(WALLET_CLASS_HASHES, resp.walletType)\n ) {\n resolvedWalletType = resp.walletType;\n }\n } else if (prepareResponse && \"types\" in prepareResponse && \"message\" in prepareResponse) {\n // Legacy shape: the response itself is the TypedData\n typedData = prepareResponse as TypedData;\n } else {\n // Likely an API error shape like { message: string }\n const apiMessage =\n prepareResponse && typeof (prepareResponse as any).message === \"string\"\n ? (prepareResponse as any).message\n : undefined;\n\n throw new Error(\n apiMessage ??\n \"Invalid response from /transactions/prepare-typed-data: typedData is missing. \" +\n \"This may occur for older STARKNET wallets that don't support paymaster transactions. \" +\n \"Please ensure the wallet is a CHIPI wallet type.\"\n );\n }\n\n // Validate typedData structure before signing\n if (\n !typedData ||\n typeof typedData !== \"object\" ||\n !(\"types\" in typedData) ||\n !(\"message\" in typedData)\n ) {\n throw new Error(\n \"Invalid typedData received from backend: missing 'types' or 'message' field. \" +\n \"This may occur for older STARKNET wallets that don't support paymaster transactions.\"\n );\n }\n\n // Sign the message\n const userSignature = await account.signMessage(typedData);\n\n // Normalize signature format (handles both Weierstrass and Array types)\n const normalizedSig = normalizeSignature(userSignature);\n\n // Execute the sponsored transaction via Chipi's paymaster\n const result = await client.post<ExecuteSponsoredTransactionResponse>({\n endpoint: \"/transactions/execute-sponsored-transaction\",\n bearerToken,\n body: {\n publicKey: wallet.publicKey,\n typedData,\n userSignature: normalizedSig,\n saveToDatabase,\n walletType: resolvedWalletType ?? walletType,\n },\n });\n\n if (!result || typeof result !== \"object\") {\n throw new Error(\n \"Invalid response from /transactions/execute-sponsored-transaction: response is not an object\"\n );\n }\n\n const apiMessage =\n typeof (result as any).message === \"string\" ? (result as any).message : undefined;\n\n if (typeof result.transactionHash !== \"string\" || result.transactionHash.trim().length === 0) {\n throw new Error(apiMessage ?? \"Response does not contain transaction hash\");\n }\n\n return result.transactionHash;\n } catch (error) {\n console.error(\"Error sending transaction with paymaster\", error);\n throw error;\n }\n};\n\n// Internal type for session-based paymaster transactions\ninterface ExecutePaymasterTransactionWithSessionParams {\n encryptKey: string;\n wallet: WalletData;\n session: SessionKeyData;\n calls: Call[];\n saveToDatabase: boolean;\n}\n\n/**\n * Execute a paymaster transaction (gasless) using a session key.\n *\n * This function uses the 4-element session signature format:\n * [sessionPubKey, r, s, validUntil]\n *\n * The session key must be registered on the contract before use via\n * `addSessionKeyToContract()`.\n *\n * CHIPI wallets only - will throw if wallet type is not CHIPI.\n *\n * @internal\n */\nexport const executePaymasterTransactionWithSession = async ({\n params,\n bearerToken,\n client,\n}: {\n params: ExecutePaymasterTransactionWithSessionParams;\n bearerToken: string;\n client: ChipiClient;\n}): Promise<string> => {\n const { encryptKey, wallet, session, calls, saveToDatabase } = params;\n\n // Validate CHIPI wallet - session keys only work with CHIPI wallets\n if (wallet.walletType !== \"CHIPI\") {\n console.error(\"[ChipiSDK:Session:Execute] Invalid wallet type for session execution\", {\n provided: wallet.walletType,\n required: \"CHIPI\",\n expectedClassHash: WALLET_CLASS_HASHES.CHIPI,\n walletAddress: wallet.publicKey?.slice(0, 15) + \"...\",\n hint: \"Session keys only work with CHIPI wallets (SNIP-9 compatible)\",\n });\n throw new ChipiSessionError(\n `Session execution requires CHIPI wallet type. Got: \"${wallet.walletType || \"undefined\"}\"`,\n SESSION_ERRORS.INVALID_WALLET_TYPE_FOR_SESSION\n );\n }\n\n // Check if session has expired\n const nowSeconds = Math.floor(Date.now() / 1000);\n if (session.validUntil < nowSeconds) {\n console.error(\"[ChipiSDK:Session:Execute] Session has expired\", {\n sessionExpiry: new Date(session.validUntil * 1000).toISOString(),\n currentTime: new Date(nowSeconds * 1000).toISOString(),\n expiredAgo: `${nowSeconds - session.validUntil} seconds`,\n });\n throw new ChipiSessionError(\n `Session expired at ${new Date(session.validUntil * 1000).toISOString()}. ` +\n `Create a new session key.`,\n SESSION_ERRORS.SESSION_EXPIRED\n );\n }\n\n try {\n // console.log(\"[ChipiSDK:Session:Execute] Starting session transaction\", {\n // walletAddress: wallet.publicKey.slice(0, 15) + \"...\",\n // sessionPubKey: session.publicKey.slice(0, 15) + \"...\",\n // sessionExpiry: new Date(session.validUntil * 1000).toISOString(),\n // callCount: calls.length,\n // });\n\n // Decrypt the session private key\n let sessionPrivateKey: string;\n try {\n sessionPrivateKey = decryptPrivateKey(session.encryptedPrivateKey, encryptKey);\n } catch {\n console.error(\"[ChipiSDK:Session:Execute] Failed to decrypt session private key\", {\n sessionPubKey: session.publicKey?.slice(0, 15) + \"...\",\n hint: \"Ensure the encryptKey matches the one used when creating the session\",\n });\n throw new ChipiSessionError(\n \"Failed to decrypt session private key. Verify the encryptKey is correct.\",\n SESSION_ERRORS.SESSION_DECRYPTION_FAILED\n );\n }\n\n // Verify the session private key matches the public key\n const derivedPubKey = ec.starkCurve.getStarkKey(sessionPrivateKey);\n if (derivedPubKey.toLowerCase() !== session.publicKey.toLowerCase()) {\n console.error(\"[ChipiSDK:Session:Execute] Session key mismatch\", {\n expected: session.publicKey.slice(0, 15) + \"...\",\n derived: derivedPubKey.slice(0, 15) + \"...\",\n hint: \"The encrypted private key does not match the stored public key\",\n });\n throw new ChipiSessionError(\n \"Session key mismatch: decrypted private key does not match the public key\",\n SESSION_ERRORS.SESSION_DECRYPTION_FAILED\n );\n }\n\n const accountClassHash = WALLET_CLASS_HASHES.CHIPI;\n\n // Build the type data via Chipi's backend\n const prepareResponse = await client.post<PrepareTypedDataResponse>({\n endpoint: \"/transactions/prepare-typed-data\",\n bearerToken,\n body: {\n publicKey: wallet.publicKey,\n calls: calls,\n accountClassHash,\n walletType: \"CHIPI\",\n },\n });\n\n // Unwrap the response — backend returns { typedData, walletType } for CHIPI wallets\n if (!prepareResponse || typeof prepareResponse !== \"object\") {\n throw new ChipiSessionError(\n \"Invalid response from /transactions/prepare-typed-data: response is not an object\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n\n let sessionTypedData: TypedData;\n if (\"typedData\" in prepareResponse && (prepareResponse as PrepareTypedDataResponse).typedData) {\n const candidate = (prepareResponse as PrepareTypedDataResponse).typedData;\n if (\n !candidate ||\n typeof candidate !== \"object\" ||\n !(\"types\" in candidate) ||\n !(\"message\" in candidate)\n ) {\n throw new ChipiSessionError(\n \"Invalid response from /transactions/prepare-typed-data: typedData structure is invalid\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n sessionTypedData = candidate;\n } else if (\"types\" in prepareResponse && \"message\" in prepareResponse) {\n sessionTypedData = prepareResponse as unknown as TypedData;\n } else {\n throw new ChipiSessionError(\n \"Invalid response from /transactions/prepare-typed-data: typedData is missing\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n\n // Compute the message hash from typed data\n const msgHash = typedData.getMessageHash(sessionTypedData, wallet.publicKey);\n\n // Sign with session private key using ECDSA\n const { r, s } = ec.starkCurve.sign(msgHash, sessionPrivateKey);\n\n // Build 4-element session signature: [sessionPubKey, r, s, validUntil]\n const sessionSignature = [\n session.publicKey,\n num.toHex(r),\n num.toHex(s),\n num.toHex(session.validUntil),\n ];\n\n // Execute the sponsored transaction via Chipi's paymaster\n const result = await client.post<ExecuteSponsoredTransactionResponse>({\n endpoint: \"/transactions/execute-sponsored-transaction\",\n bearerToken,\n body: {\n publicKey: wallet.publicKey,\n typedData: sessionTypedData,\n // Session signature format - array of 4 hex strings\n userSignature: sessionSignature,\n saveToDatabase: saveToDatabase,\n walletType: \"CHIPI\",\n isSessionSignature: true, // Flag to indicate session signature format\n },\n });\n\n if (!result || typeof result !== \"object\") {\n throw new ChipiSessionError(\n \"Invalid response from /transactions/execute-sponsored-transaction: response is not an object\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n\n if (typeof result.transactionHash !== \"string\" || result.transactionHash.trim().length === 0) {\n const apiMessage =\n typeof (result as any).message === \"string\" ? (result as any).message : undefined;\n console.error(\"[ChipiSDK:Session:Execute] No transaction hash in response\", {\n result,\n });\n throw new ChipiSessionError(\n apiMessage ?? \"Response does not contain transaction hash\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n\n return result.transactionHash;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n // Re-throw ChipiSessionError as-is\n if (error instanceof ChipiSessionError) {\n throw error;\n }\n\n console.error(\"[ChipiSDK:Session:Execute] Unexpected error\", {\n error: err.message,\n walletAddress: wallet.publicKey?.slice(0, 15) + \"...\",\n sessionPubKey: session.publicKey?.slice(0, 15) + \"...\",\n });\n throw error;\n }\n};\n","import {\n CallAnyContractParams,\n STARKNET_CONTRACTS,\n WalletData,\n type ExecuteTransactionParams,\n type RecordSendTransactionParams,\n type Transaction,\n type TransferParams,\n type GetTransactionListQuery,\n type PaginatedResponse,\n type TransactionStatusResponse,\n type SyncOnChainTransfersParams,\n type SyncOnChainTransfersResponse,\n} from \"@chipi-stack/types\";\nimport { API_ENDPOINTS, formatAmount } from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\nimport { executePaymasterTransaction } from \"./execute-paymaster-transaction\";\n\n/**\n * Transaction management utilities\n */\nexport class ChipiTransactions {\n constructor(private client: ChipiClient) {}\n /**\n * Execute a gasless transaction using paymaster\n * @internal saveToDatabase - Internal only, not exposed to clients\n */\n async executeTransaction({\n params,\n bearerToken,\n saveToDatabase = true, // Internal only - defaults to true, can be overridden internally\n }: {\n params: ExecuteTransactionParams;\n bearerToken: string;\n saveToDatabase?: boolean; // Internal only - not part of public API\n }): Promise<string> {\n return executePaymasterTransaction({\n params: {\n ...params,\n saveToDatabase,\n },\n bearerToken,\n client: this.client,\n });\n }\n\n /**\n * Transfer tokens\n */\n async transfer({\n params,\n bearerToken,\n }: {\n params: TransferParams;\n bearerToken: string;\n }): Promise<string> {\n const { encryptKey, wallet, token, otherToken, recipient, amount } = params;\n const contract = STARKNET_CONTRACTS[token];\n let contractAddress = contract.contractAddress;\n let decimals = contract.decimals;\n if (token === \"OTHER\") {\n if (!otherToken) {\n throw new Error(\"Other token is required when token is OTHER\");\n }\n contractAddress = otherToken.contractAddress;\n decimals = otherToken.decimals;\n }\n const formattedAmount = formatAmount(amount, decimals);\n return this.executeTransaction({\n params: {\n encryptKey,\n wallet,\n calls: [\n {\n contractAddress,\n entrypoint: \"transfer\",\n calldata: [recipient, formattedAmount, \"0x0\"],\n },\n ],\n },\n bearerToken,\n });\n }\n\n /**\n * Approve token spending\n */\n async approve(params: {\n encryptKey: string;\n wallet: WalletData;\n contractAddress: string;\n spender: string;\n amount: string;\n decimals?: number;\n bearerToken: string;\n }): Promise<string> {\n const formattedAmount = formatAmount(params.amount, params.decimals);\n\n return this.executeTransaction({\n params: {\n encryptKey: params.encryptKey,\n wallet: params.wallet,\n calls: [\n {\n contractAddress: params.contractAddress,\n entrypoint: \"approve\",\n calldata: [params.spender, formattedAmount, \"0x0\"],\n },\n ],\n },\n bearerToken: params.bearerToken,\n });\n }\n\n /**\n * Call any contract method\n */\n // {\n // encryptKey: string;\n // wallet: any;\n // calls: any[];\n // bearerToken: string;\n // }\n\n async callAnyContract({\n params,\n bearerToken,\n }: {\n params: CallAnyContractParams;\n bearerToken: string;\n }): Promise<string> {\n return this.executeTransaction({\n params,\n bearerToken,\n });\n }\n\n /**\n * Record a send transaction\n */\n async recordSendTransaction({\n params,\n bearerToken,\n }: {\n params: RecordSendTransactionParams;\n bearerToken: string;\n }): Promise<Transaction> {\n const response = await this.client.post<Transaction>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/record-send`,\n bearerToken,\n body: params,\n });\n return response;\n }\n\n /**\n * Get paginated transaction history\n */\n async getTransactionList(\n query: GetTransactionListQuery,\n bearerToken: string\n ): Promise<PaginatedResponse<Transaction>> {\n const response = await this.client.get<PaginatedResponse<Transaction>>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/transaction-list`,\n params: query,\n bearerToken,\n });\n return response;\n }\n\n /**\n * Get a single transaction by hash or internal ID\n */\n async getTransaction(hashOrId: string, bearerToken: string): Promise<Transaction> {\n return this.client.get<Transaction>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${hashOrId}`,\n bearerToken,\n });\n }\n\n /**\n * Get on-chain transaction status\n */\n async getTransactionStatus(hash: string, bearerToken: string): Promise<TransactionStatusResponse> {\n return this.client.get<TransactionStatusResponse>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${hash}/status`,\n bearerToken,\n });\n }\n\n /**\n * Sync on-chain transfers from Voyager into the DB (read-through cache).\n * Discovers transactions not made through the SDK (e.g., external USDC receives).\n * After sync, getTransactionList returns the newly discovered transactions.\n */\n async syncOnChainTransfers(\n params: SyncOnChainTransfersParams,\n bearerToken: string,\n ): Promise<SyncOnChainTransfersResponse> {\n return this.client.post<SyncOnChainTransfersResponse>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/sync-on-chain`,\n bearerToken,\n body: params,\n });\n }\n}\n","import { Currency } from \"@chipi-stack/types\";\nimport { ChipiClient } from \"./client\";\nimport { API_ENDPOINTS } from \"@chipi-stack/shared\";\n\nexport class ChipiExchanges {\n constructor(private client: ChipiClient) {}\n\n async getUsdAmount(\n currencyAmount: number,\n currency: Currency,\n bearerToken: string\n ): Promise<number> {\n return this.client.get<number>({\n endpoint: `${API_ENDPOINTS.EXCHANGES}/usd-amount`,\n bearerToken,\n params: { currencyAmount, currency },\n });\n }\n}\n","import {\n CreateSkuPurchaseParams,\n Transaction,\n STARKNET_CONTRACTS,\n Chain,\n ChainToken,\n CreateSkuPurchaseBody,\n} from \"@chipi-stack/types\";\nimport { ChipiClient } from \"./client\";\nimport { ChipiTransactions } from \"./transactions\";\n\nimport {\n CARRIER_IDS,\n CHAIN_TOKEN_TYPES,\n CHAIN_TYPES,\n SERVICE_TYPES,\n SKU_CONTRACTS,\n formatAmount,\n} from \"@chipi-stack/shared\";\nimport { Call, CallData, cairo, hash } from \"starknet\";\nimport { API_ENDPOINTS } from \"@chipi-stack/shared\";\nimport CryptoES from \"crypto-es\";\nimport { ChipiExchanges } from \"./exchanges\";\n\nexport class ChipiSkuPurchases {\n private transactions: ChipiTransactions;\n private exchanges: ChipiExchanges;\n\n constructor(private client: ChipiClient) {\n this.transactions = new ChipiTransactions(client);\n this.exchanges = new ChipiExchanges(client);\n }\n\n /**\n * Purchase a SKU with gasless execution\n * @param params - Purchase parameters including transaction hash, SKU ID, wallet, etc.\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuPurchaseResponse> - The purchase response with transaction details\n */\n async purchaseSku(params: CreateSkuPurchaseParams, bearerToken: string): Promise<Transaction> {\n const { skuId, skuReference, currencyAmount, currency, chain, token, encryptKey, wallet } =\n params;\n\n if (chain !== Chain.STARKNET) {\n throw new Error(`Unsupported chain for SKU purchases: ${chain}`);\n }\n\n const tokenConfig = STARKNET_CONTRACTS[token];\n if (!tokenConfig?.contractAddress) {\n throw new Error(`Unsupported token for Starknet SKU purchases: ${token}`);\n }\n\n const usdAmount = await this.exchanges.getUsdAmount(currencyAmount, currency, bearerToken);\n const tokenAddress = tokenConfig.contractAddress as `0x${string}`;\n\n if (!Number.isFinite(usdAmount) || usdAmount <= 0) {\n throw new Error(`Invalid USD amount: ${usdAmount}. Amount must be positive.`);\n }\n\n const minUsdAmount = Math.max(usdAmount, 0.000001);\n const parsedAmount = formatAmount(minUsdAmount.toString(), tokenConfig.decimals);\n\n const calls: Call[] = [\n {\n contractAddress: tokenAddress,\n entrypoint: \"approve\",\n calldata: CallData.compile({\n spender: SKU_CONTRACTS.RECHARGER_WITH_STRK_MAINNET,\n amount: cairo.uint256(parsedAmount),\n }),\n },\n {\n contractAddress: SKU_CONTRACTS.RECHARGER_WITH_STRK_MAINNET,\n entrypoint: \"process_recharge\",\n calldata: CallData.compile({\n token: tokenAddress,\n amount: cairo.uint256(parsedAmount),\n recharge_id: CryptoES.SHA256(\n CryptoES.lib.WordArray.random(32) // 32 bytes = 256 bits entropy\n )\n .toString()\n .slice(0, 20),\n product_code: skuId,\n merchant_slug: CARRIER_IDS.CHIPI_PAY,\n }),\n },\n {\n contractAddress: SKU_CONTRACTS.CHIPI_BILL_SERVICE,\n entrypoint: \"mint_item\",\n calldata: CallData.compile({\n recipient: wallet.publicKey,\n metadata: {\n service_type: SERVICE_TYPES.BUY_SERVICE,\n timestamp: Date.now(),\n chipi_user_id: hash.starknetKeccak(wallet.publicKey || \"0x0\").toString(),\n kyc: true,\n amount: cairo.uint256(parsedAmount),\n },\n }),\n },\n ];\n\n const txHash = await this.transactions.executeTransaction({\n params: {\n encryptKey: encryptKey,\n wallet: wallet,\n calls: calls,\n },\n bearerToken: bearerToken,\n saveToDatabase: false,\n });\n\n const body: CreateSkuPurchaseBody = {\n transactionHash: txHash,\n walletAddress: wallet.publicKey,\n skuId: skuId,\n skuReference: skuReference,\n chain: chain,\n token: token,\n currencyAmount: currencyAmount,\n };\n\n // Record the SKU purchase and fetch the purchase result\n const response = await this.client.post<Transaction>({\n endpoint: `${API_ENDPOINTS.SKU_PURCHASES}`,\n bearerToken,\n body,\n });\n\n return response;\n }\n\n /**\n * Get a SKU purchase by id\n * @param id - The SKU purchase id\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuPurchaseResponse> - Single SKU purchase\n */\n async getSkuPurchase(id: string, bearerToken: string): Promise<Transaction> {\n const response = await this.client.get<Transaction>({\n endpoint: `${API_ENDPOINTS.SKU_PURCHASES}/${id}`,\n bearerToken,\n });\n return response;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/encryption.ts","../src/encryption.ts","../src/shhh/snip12-hash.ts","../src/shhh/threshold.ts","../src/shhh/oe.ts","../src/shhh/compute-wallet-address.ts","../src/shhh/signers/stark.ts","../src/shhh/signers/ed25519.ts","../src/shhh/execute-paymaster-raw.ts","../src/execute-paymaster-transaction.ts","../src/paymaster-adapter.ts","../src/transactions.ts","../src/exchanges.ts","../src/sku-purchases.ts"],"names":["CryptoES","init_encryption","hash","CallData","shortString","ec","executeShhhSponsoredRaw","WALLET_RPC_ENDPOINTS","WALLET_CLASS_HASHES","RpcProvider","Account","typedData","apiMessage","STARKNET_CONTRACTS","formatAmount","API_ENDPOINTS","Chain","SKU_CONTRACTS","cairo","CARRIER_IDS","SERVICE_TYPES"],"mappings":"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","file":"skuPurchases.js","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (privateKey: string, password: string): string => {\n if (!privateKey || !password) {\n throw new Error(\"Private key and password are required\");\n }\n\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (encryptedPrivateKey: string, password: string): string => {\n if (!encryptedPrivateKey || !password) {\n throw new Error(\"Encrypted private key and password are required\");\n }\n\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n if (!decrypted) {\n throw new Error(\"Decryption resulted in empty string\");\n }\n return decrypted;\n } catch (error) {\n if (error instanceof Error) {\n throw error;\n }\n throw new Error(`Decryption failed: ${error}`);\n }\n};\n","export { encryptPrivateKey, decryptPrivateKey } from \"./lib/encryption\";\n","/**\n * SNIP-12 typed-data hash for `OutsideExecution` — TypeScript reference.\n *\n * Vendored from haycarlitos/shhh-wallet-cairo @ v8.4 commit 3975532\n * source: scripts/ts/snip12-hash.ts\n * license: MIT (Copyright (c) 2026 Carlos Castillo and contributors)\n *\n * MUST produce byte-identical output to `compute_snip12_hash` in\n * `src/outside_execution.cairo` at the same commit. If the canonical\n * Cairo source ships a breaking change, the upstream Shhh maintainer\n * will open a PR against this file (per Q3 of SHHH_INTEGRATION_ANSWERS.md).\n */\n\nimport { hash, shortString, CallData, type Call, type RawArgs } from \"starknet\";\n\n// ================================================================\n// Constants — MUST match src/outside_execution.cairo exactly.\n// ================================================================\n\nexport const OUTSIDE_EXECUTION_TYPE_HASH_REV1 =\n 0x5a4b49e17039355cd95d1f0981d75901191d1319b1f4b05a9a791d218d7e0cn;\n\nexport const CALL_TYPE_HASH_REV1 =\n 0x3635c7f2a7ba93844c0d064e18e487f35ab90f7c39d00f186a781fc3f0c2ca9n;\n\nexport const STARKNET_DOMAIN_TYPE_HASH_REV1 =\n 0x1ff2f602e42168014d405a94f75e8a93d640751d71d16311266e140d8b0a210n;\n\nexport const STARKNET_MESSAGE_PREFIX = shortString.encodeShortString(\"StarkNet Message\");\n\nexport const OE_DOMAIN_NAME = shortString.encodeShortString(\"Account.execute_from_outside\");\nexport const OE_DOMAIN_VERSION = 2n;\nexport const OE_DOMAIN_REVISION = 1n;\n\nexport const SIG_VERSION_V1_HEX_ASCII = shortString.encodeShortString(\"V1_HEX_ASCII\");\nexport const SIG_VERSION_V2_SNIP12 = shortString.encodeShortString(\"V2_SNIP12\");\nexport const SIG_VERSION_V2_THRESHOLD = shortString.encodeShortString(\"V2_THRESHOLD\");\n\n// SRC-5 interface IDs — see Cairo `src/signer/interface.cairo::ISIGNER_ID`.\nexport const ISRC9_V2_ID = BigInt(\n \"0x1d1144bb2138366ff28d8e9ab57456b1d332ac42196230c3a602003c89872\"\n);\nexport const ISIGNER_ID = BigInt(\n \"0x94c5a761f34b25a4e603c651ac0e1fc4fad9cdb5517f7fa1bb54044c7e5ef8\"\n);\n\nexport const ISIGNER_CANONICAL_LABEL = \"ISigner_V1\";\n\n/** Recomputes the canonical `ISIGNER_ID` at runtime. */\nexport function computeISignerId(): bigint {\n return BigInt(hash.starknetKeccak(ISIGNER_CANONICAL_LABEL));\n}\n\n// ================================================================\n// Types\n// ================================================================\n\nexport type OutsideExecution = {\n caller: bigint | string; // ContractAddress (hex or bigint)\n nonce: bigint | string;\n execute_after: bigint; // u64\n execute_before: bigint; // u64\n calls: Call[];\n};\n\n// ================================================================\n// Hash functions\n// ================================================================\n\nfunction toBigInt(x: bigint | string | number): bigint {\n if (typeof x === \"bigint\") return x;\n if (typeof x === \"number\") return BigInt(x);\n return BigInt(x); // accepts \"0x...\" or decimal strings\n}\n\nfunction poseidonSpan(values: Array<bigint | string>): bigint {\n const felts = values.map((v) => (typeof v === \"bigint\" ? \"0x\" + v.toString(16) : v));\n return BigInt(hash.computePoseidonHashOnElements(felts));\n}\n\nexport function hashCall(call: Call): bigint {\n const calldataFelts: string[] = CallData.toHex(\n (Array.isArray(call.calldata) ? call.calldata : [call.calldata]) as RawArgs\n );\n const calldataItems = calldataFelts.map((x) => BigInt(x));\n const calldataHash = poseidonSpan(calldataItems);\n return poseidonSpan([\n CALL_TYPE_HASH_REV1,\n toBigInt(call.contractAddress),\n toBigInt(hash.getSelectorFromName(call.entrypoint)),\n calldataHash,\n ]);\n}\n\nexport function hashCalls(calls: Call[]): bigint {\n const callHashes = calls.map(hashCall);\n return poseidonSpan(callHashes);\n}\n\nexport function hashStarknetDomain(chainIdFelt: bigint | string): bigint {\n return poseidonSpan([\n STARKNET_DOMAIN_TYPE_HASH_REV1,\n BigInt(OE_DOMAIN_NAME),\n OE_DOMAIN_VERSION,\n toBigInt(chainIdFelt),\n OE_DOMAIN_REVISION,\n ]);\n}\n\nexport function hashOutsideExecutionStruct(oe: OutsideExecution): bigint {\n const callsArrayHash = hashCalls(oe.calls);\n return poseidonSpan([\n OUTSIDE_EXECUTION_TYPE_HASH_REV1,\n toBigInt(oe.caller),\n toBigInt(oe.nonce),\n oe.execute_after,\n oe.execute_before,\n callsArrayHash,\n ]);\n}\n\n/**\n * The authoritative SNIP-12 message hash for an OutsideExecution.\n * Signers sign over this felt252 (or its hex-ASCII re-encoding for\n * Phantom UX compatibility — see snip12HashToHexAsciiBytes).\n */\nexport function computeSnip12Hash(\n oe: OutsideExecution,\n contractAddress: bigint | string,\n chainIdFelt: bigint | string\n): bigint {\n const domainHash = hashStarknetDomain(chainIdFelt);\n const structHash = hashOutsideExecutionStruct(oe);\n return poseidonSpan([\n BigInt(STARKNET_MESSAGE_PREFIX),\n domainHash,\n toBigInt(contractAddress),\n structHash,\n ]);\n}\n\n/**\n * Phantom hex-ASCII envelope helper. Phantom signs a string; we give it\n * a 64-byte hex-ASCII representation of the SNIP-12 hash, and the Cairo\n * verifier re-computes the hash and compares byte-by-byte.\n */\nexport function snip12HashToHexAsciiBytes(h: bigint): Uint8Array {\n const hex = h.toString(16).padStart(64, \"0\"); // 32 bytes -> 64 ASCII chars\n return new TextEncoder().encode(hex);\n}\n","/**\n * SHHH V8.4 threshold envelope assembly + gas estimation.\n *\n * Wave B PR B2. The single-owner OE flow already ships via\n * `wrap_v2_snip12_envelope` in `oe.ts`. This module adds the\n * multi-owner threshold flow: N owners (possibly with mixed signer\n * kinds) co-sign a single OE, and the wallet's\n * `execute_from_outside_v2` walks the envelope to verify each owner\n * independently before checking total weight against the configured\n * threshold.\n *\n * Cairo dispatch shape (`src/account.cairo:418-460`):\n *\n * signature = [\n * V2_THRESHOLD, // tag\n * n, // u32, MUST be >= 2 and <= owner_count\n * env_1_len, // u32\n * ...env_1 (env_1_len felts),\n * env_2_len,\n * ...env_2,\n * ...\n * env_n_len,\n * ...env_n,\n * ]\n *\n * Each inner envelope is a V2_SNIP12 single-owner envelope\n * (`wrap_v2_snip12_envelope` output) from a different owner. Nested\n * threshold envelopes are NOT permitted — the Cairo `_verify_sub_envelope`\n * recursively checks the inner tag and rejects anything except\n * V2_SNIP12.\n *\n * Cairo-enforced invariants this module replicates client-side so\n * mis-shaped envelopes fail at the SDK boundary with a clear message\n * instead of with an opaque \"THRESH: …\" Starknet revert:\n *\n * - signature.len() >= 2\n * - n >= 2 (n=1 is invalid — use V2_SNIP12 directly for single-owner)\n * - each inner env_len >= 2\n * - no buffer overflow / truncation\n * - no trailing bytes after the last inner envelope\n * - no duplicate owner_id across inner envelopes (extracted from\n * envelope[1] of each inner)\n *\n * Total-weight vs threshold is enforced ON-CHAIN (the SDK can't know\n * the configured threshold without reading on-chain state). Use\n * `estimateThresholdGasOverhead` to predict paymaster fees.\n */\n\nimport { SHHH_KIND_GAS_OVERHEAD } from \"@chipi-stack/shared\";\nimport type { ShhhSignerKind } from \"@chipi-stack/types\";\nimport { shortString } from \"starknet\";\n\nimport { SIG_VERSION_V2_SNIP12, SIG_VERSION_V2_THRESHOLD } from \"./snip12-hash\";\n\n// ================================================================\n// Constants — encode-shortstring values matched against snip12-hash.ts\n// ================================================================\n\nconst V2_SNIP12_TAG = BigInt(SIG_VERSION_V2_SNIP12);\nconst V2_THRESHOLD_TAG = BigInt(SIG_VERSION_V2_THRESHOLD);\n\n/** Minimum number of inner envelopes in a threshold (Cairo enforces >= 2). */\nexport const MIN_THRESHOLD_OWNERS = 2;\n\n// ================================================================\n// Validation\n// ================================================================\n\n/**\n * Validate that an envelope is a well-formed V2_SNIP12 single-owner\n * envelope suitable for inclusion in a threshold envelope. Returns\n * the extracted `owner_id` (envelope[1]) so the caller can dedupe.\n *\n * Rejects nested threshold envelopes (`signature[0] == V2_THRESHOLD`)\n * — V8.4 does not allow nesting; the Cairo `_verify_sub_envelope`\n * would revert with `'SRC9: bad tag'`.\n */\nexport function assertValidV2Snip12Envelope(envelope: bigint[]): bigint {\n if (envelope.length < 2) {\n throw new Error(\n `THRESH: inner envelope must have at least 2 felts (tag + owner_id); got ${envelope.length}`\n );\n }\n const tag = envelope[0];\n if (tag !== V2_SNIP12_TAG) {\n if (tag === V2_THRESHOLD_TAG) {\n throw new Error(\n \"THRESH: nested threshold envelopes are not allowed; \" + \"inner envelopes must be V2_SNIP12\"\n );\n }\n const decoded = _tryDecodeShortString(tag);\n throw new Error(\n `THRESH: inner envelope tag must be V2_SNIP12; got ${decoded ?? \"0x\" + tag.toString(16)}`\n );\n }\n return envelope[1];\n}\n\nfunction _tryDecodeShortString(felt: bigint): string | null {\n try {\n return shortString.decodeShortString(\"0x\" + felt.toString(16));\n } catch {\n return null;\n }\n}\n\n// ================================================================\n// Assembly\n// ================================================================\n\n/**\n * Build a V2_THRESHOLD envelope from a list of pre-signed V2_SNIP12\n * inner envelopes. Each inner envelope must come from a DIFFERENT\n * owner — duplicates fail loudly here instead of on-chain.\n *\n * The typical UI flow:\n * 1. Compute the OE message hash once (computeOeHash from oe.ts)\n * 2. Distribute the hash to N owners (push notification, QR, etc.)\n * 3. Each owner signs with their kind's envelope builder and\n * returns the resulting `bigint[]`\n * 4. UI collects the envelopes and calls this function\n * 5. UI submits the resulting threshold envelope as the\n * `signature` field of `paymaster_executeSponsoredRaw.calldata`\n *\n * `buildThresholdEnvelope` does NOT submit anything. It returns the\n * felt span that goes into the OE calldata.\n */\nexport function buildThresholdEnvelope(args: { innerEnvelopes: bigint[][] }): bigint[] {\n const { innerEnvelopes } = args;\n\n if (innerEnvelopes.length < MIN_THRESHOLD_OWNERS) {\n throw new Error(\n `THRESH: need at least ${MIN_THRESHOLD_OWNERS} inner envelopes; ` +\n `got ${innerEnvelopes.length}. Use wrap_v2_snip12_envelope ` +\n `for single-owner OEs.`\n );\n }\n\n // Single pass: validate, dedup owner_id, append interleaved\n // [env_len, ...env_data] per inner envelope. Layout matches Cairo\n // `src/account.cairo:418-454` (cursor reads env_len, then env_data,\n // then advances) — NOT the grouped [...lens, ...flat] shape an\n // earlier latent `wrapV2ThresholdEnvelope` produced. That function\n // was never called in production; removed in this PR.\n const seenOwners = new Set<string>();\n const out: bigint[] = [V2_THRESHOLD_TAG, BigInt(innerEnvelopes.length)];\n\n for (let i = 0; i < innerEnvelopes.length; i++) {\n const env = innerEnvelopes[i];\n const ownerId = assertValidV2Snip12Envelope(env);\n const key = ownerId.toString();\n if (seenOwners.has(key)) {\n throw new Error(\n `THRESH: duplicate owner_id ${\"0x\" + ownerId.toString(16)} at inner envelope ${i}`\n );\n }\n seenOwners.add(key);\n out.push(BigInt(env.length));\n for (const felt of env) {\n if (felt < 0n) {\n throw new RangeError(\n `THRESH: envelope ${i} contains negative felt (cannot serialize as felt252)`\n );\n }\n out.push(felt);\n }\n }\n\n return out;\n}\n\n// ================================================================\n// Parsing\n// ================================================================\n\n/**\n * Split a V2_THRESHOLD envelope back into its constituent inner\n * V2_SNIP12 envelopes. Inverse of `buildThresholdEnvelope`.\n *\n * Useful for UI flows that need to display \"N of M signers signed\n * so far\" status without re-deriving from individual envelopes. Also\n * useful in tests for round-trip validation.\n *\n * Throws if the envelope is malformed (tag mismatch, n < 2, length\n * mismatch, trailing bytes). Mirrors the Cairo dispatch's structural\n * checks (`src/account.cairo:418-456`) so the same envelope that\n * would parse-fail here would also revert on-chain.\n */\nexport function parseThresholdEnvelope(envelope: bigint[]): {\n innerEnvelopes: bigint[][];\n} {\n if (envelope.length < 2) {\n throw new Error(`THRESH: envelope too short (need at least [tag, n]); got ${envelope.length}`);\n }\n if (envelope[0] !== V2_THRESHOLD_TAG) {\n throw new Error(`THRESH: envelope tag must be V2_THRESHOLD; got 0x${envelope[0].toString(16)}`);\n }\n const n = Number(envelope[1]);\n if (!Number.isInteger(n) || n < MIN_THRESHOLD_OWNERS) {\n throw new Error(`THRESH: n must be an integer >= ${MIN_THRESHOLD_OWNERS}; got ${envelope[1]}`);\n }\n\n // Re-validate each inner envelope while parsing so a framed-but-\n // malformed envelope (nested V2_THRESHOLD, duplicate owner_id,\n // negative felts) fails here with the same error as the builder\n // would have raised. Keeps parse / build symmetric.\n const seenOwners = new Set<string>();\n const innerEnvelopes: bigint[][] = [];\n let cursor = 2;\n for (let i = 0; i < n; i++) {\n if (cursor >= envelope.length) {\n throw new Error(`THRESH: envelope truncated at inner ${i} (no length felt)`);\n }\n const envLen = Number(envelope[cursor]);\n cursor += 1;\n if (!Number.isInteger(envLen) || envLen < 2) {\n throw new Error(`THRESH: inner ${i} env_len must be >= 2; got ${envLen}`);\n }\n if (cursor + envLen > envelope.length) {\n throw new Error(\n `THRESH: inner ${i} would overflow envelope (env_len ${envLen}, ` +\n `cursor ${cursor}, total ${envelope.length})`\n );\n }\n const inner = envelope.slice(cursor, cursor + envLen);\n for (const felt of inner) {\n if (felt < 0n) {\n throw new RangeError(\n `THRESH: inner ${i} contains negative felt (cannot serialize as felt252)`\n );\n }\n }\n const ownerId = assertValidV2Snip12Envelope(inner);\n const key = ownerId.toString();\n if (seenOwners.has(key)) {\n throw new Error(\n `THRESH: duplicate owner_id ${\"0x\" + ownerId.toString(16)} at inner envelope ${i}`\n );\n }\n seenOwners.add(key);\n innerEnvelopes.push(inner);\n cursor += envLen;\n }\n if (cursor !== envelope.length) {\n throw new Error(\n `THRESH: trailing bytes after inner ${n - 1} (cursor ${cursor}, ` +\n `length ${envelope.length})`\n );\n }\n return { innerEnvelopes };\n}\n\n// ================================================================\n// Gas estimation\n// ================================================================\n\n/**\n * Predict the on-chain L2 gas overhead a threshold envelope will\n * consume. Each inner envelope dispatches to its kind's verifier\n * class via `library_call`, so total overhead is the sum of\n * per-kind overheads.\n *\n * Returned value is the same unit as `SHHH_KIND_GAS_OVERHEAD` in\n * `@chipi-stack/shared` (raw L2 gas units). Use to predict paymaster\n * fees:\n * estimatedFee = baselineOEGas + estimateThresholdGasOverhead(owners)\n *\n * Does NOT include the wallet's threshold-validation loop overhead\n * (the deduplication walk and weight summation) — that's a constant\n * ~50K L2 gas regardless of N, and the paymaster's fee predictor\n * already accounts for it.\n */\nexport function estimateThresholdGasOverhead(\n owners: Array<{ signerKind: ShhhSignerKind }>\n): number {\n if (owners.length < MIN_THRESHOLD_OWNERS) {\n throw new Error(\n `THRESH: need at least ${MIN_THRESHOLD_OWNERS} owners to estimate ` +\n `threshold gas; got ${owners.length}`\n );\n }\n let total = 0;\n for (const { signerKind } of owners) {\n const overhead = SHHH_KIND_GAS_OVERHEAD[signerKind];\n if (overhead === undefined) {\n throw new Error(\n `THRESH: unknown signer kind ${signerKind} — missing from ` + `SHHH_KIND_GAS_OVERHEAD`\n );\n }\n total += overhead;\n }\n return total;\n}\n","/**\n * Outside-Execution construction for SHHH V8.4 ShhhAccount.\n *\n * Wraps the canonical SNIP-12 hash + envelope assembly so SDK callers\n * never touch the underlying felt-array shapes directly. Implements\n * the envelope routing per V8.4 handover §5:\n *\n * [ signature[0] ]\n * ├─ 'V2_SNIP12' → [owner_id, kind_tag, ...payload] (single-owner)\n * ├─ 'V2_THRESHOLD' → [n, env_1_len, ..., env_n_len, ...] (multisig)\n * └─ (else, len==4) → SNIP-163 session-key envelope\n *\n * Source of truth: `src/account.cairo::execute_from_outside_v2` at\n * shhh-wallet-cairo v8.4 commit 3975532.\n */\n\nimport { shortString, type Call } from \"starknet\";\nimport {\n computeSnip12Hash,\n SIG_VERSION_V2_SNIP12,\n SIG_VERSION_V2_THRESHOLD,\n type OutsideExecution,\n} from \"./snip12-hash\";\n\n/**\n * The `caller` sentinel used for paymaster-sponsored OE flows. Any\n * forwarder may submit the OE; binding `caller = ANY_CALLER` lifts the\n * usual caller-equality check inside the account.\n */\nexport const ANY_CALLER_FELT = BigInt(shortString.encodeShortString(\"ANY_CALLER\"));\n\n/**\n * Per audit M-2, OE validity windows must not exceed 2 hours. The\n * V8.4 account enforces this on-chain; we expose the constant so SDK\n * callers can default sensibly.\n */\nexport const MAX_OE_VALIDITY_WINDOW_SECONDS = 2 * 60 * 60;\n\n/**\n * Clock-skew buffer (seconds) subtracted from `now` when defaulting\n * the OE's `execute_after`. The wallet's check at\n * `sessions-smart-contract/src/account.cairo:377` (and the matching\n * V8.4 line in `shhh-wallet-cairo/src/account.cairo`) is strict\n * `assert(execute_after < now, 'SRC9: now <= execute_after')`. If\n * the OE is built and submitted within the same second the\n * sequencer mints the next block, `execute_after == now` and the\n * wallet panics with `'SRC9: too early'`, which CHIPI v29's\n * `_execute_calls` then swallows silently. 60s is well within the\n * audit-M-2 window (2h max) and well above any realistic SDK ↔\n * sequencer clock drift.\n */\nexport const OE_EXECUTE_AFTER_CLOCK_SKEW_BUFFER = 60;\n\n/**\n * Build a standard paymaster-sponsored OutsideExecution with sensible\n * defaults. Callers can override any field; the typical happy path is\n * to pass only `nonce` + `calls`.\n */\nexport function buildOutsideExecution(params: {\n /** Unique per-account replay nonce. The account stores these in `oe_nonces`. */\n nonce: bigint | string;\n /** The calls the account should execute on success. */\n calls: Call[];\n /** Override `caller`; defaults to ANY_CALLER for paymaster flows. */\n caller?: bigint | string;\n /**\n * UNIX seconds. Defaults to `now - OE_EXECUTE_AFTER_CLOCK_SKEW_BUFFER`\n * (60s in the past) so the OE is valid by the time the next block is\n * minted regardless of small clock drifts between the SDK host and\n * the sequencer. The wallet's check is strict `<` (`account.cairo:377`\n * `'SRC9: now <= execute_after'`) — without the buffer, a fast\n * SDK→paymaster round trip can land in the SAME block as the OE\n * was built in and revert with `'SRC9: too early'`. PR sdks#289\n * (this builder fix) made the buffer the default after the first\n * session smoke run reproduced the race.\n */\n executeAfter?: bigint;\n /** UNIX seconds; defaults to now + 2h (the maximum window per audit M-2). */\n executeBefore?: bigint;\n}): OutsideExecution {\n const nowSec = BigInt(Math.floor(Date.now() / 1000));\n const after = params.executeAfter ?? nowSec - BigInt(OE_EXECUTE_AFTER_CLOCK_SKEW_BUFFER);\n // When defaulting both endpoints, keep `before - after` exactly at\n // the audit-M-2 cap. Pulling `after` back by the clock-skew buffer\n // without pulling `before` back by the same amount would push the\n // span over MAX_OE_VALIDITY_WINDOW_SECONDS and trip the validator\n // below. The explicit-override branches keep their independent\n // values (caller still gets the M-2 check).\n const before =\n params.executeBefore ??\n nowSec + BigInt(MAX_OE_VALIDITY_WINDOW_SECONDS) - BigInt(OE_EXECUTE_AFTER_CLOCK_SKEW_BUFFER);\n if (before <= after) {\n // An inverted or zero-length window passes the max-span check but produces\n // an OE that can never be valid on-chain. Reject up front.\n throw new Error(\n `executeBefore (${before}) must be strictly greater than executeAfter (${after}).`\n );\n }\n if (before - after > BigInt(MAX_OE_VALIDITY_WINDOW_SECONDS)) {\n throw new Error(\n `OE validity window ${before - after}s exceeds max ${MAX_OE_VALIDITY_WINDOW_SECONDS}s (audit M-2). Adjust executeBefore.`\n );\n }\n return {\n caller: params.caller ?? ANY_CALLER_FELT,\n nonce: params.nonce,\n execute_after: after,\n execute_before: before,\n calls: params.calls,\n };\n}\n\n/**\n * Compute the SNIP-12 hash for the given OutsideExecution against\n * a specific account address and chain. This is what the signer\n * (STARK / Ed25519 / EIP-191 / WebAuthn / etc.) commits to.\n *\n * For Phantom UX where the user signs a string, hex-encode the\n * resulting hash via `snip12HashToHexAsciiBytes` from snip12-hash.\n */\nexport function computeOeHash(\n oe: OutsideExecution,\n accountAddress: bigint | string,\n chainId: bigint | string\n): bigint {\n return computeSnip12Hash(oe, accountAddress, chainId);\n}\n\n// ================================================================\n// Envelope assembly\n// ================================================================\n\n/**\n * Single-owner V2_SNIP12 envelope.\n *\n * The account strips signature[0..2] = ['V2_SNIP12', owner_id, kind_tag]\n * and library_calls the matching verifier with `payload`. Chipi\n * paymaster passes the entire envelope verbatim to\n * `execute_from_outside_v2`; it does NOT need to know the kind.\n *\n * **`ownerId` is a u32 INDEX into the wallet's owner_set**, NOT the\n * poseidon `owner_commitment`. Primary owner = `0n`; subsequent owners\n * added via `propose_add_owner` get `1n`, `2n`, etc. The V8.4\n * dispatcher (`src/account.cairo:480`) panics with `'SHHH: bad\n * owner_id'` if signature[1] does not fit in u32 — which happens\n * silently at the wallet level (outer paymaster tx still reports\n * SUCCEEDED). Discovered 2026-05-27 in a production trace audit.\n *\n * Returns the `signature: felt252[]` span you pass to\n * `paymaster_executeSponsoredRaw.calldata`.\n */\nexport function wrapV2Snip12Envelope(params: {\n /** u32 INDEX into owner_set (0n for primary). NOT the commitment. */\n ownerId: bigint;\n kindTag: string | bigint;\n payload: Array<bigint | string>;\n}): bigint[] {\n const tag =\n typeof params.kindTag === \"bigint\"\n ? params.kindTag\n : BigInt(shortString.encodeShortString(params.kindTag));\n return [\n BigInt(SIG_VERSION_V2_SNIP12),\n params.ownerId,\n tag,\n ...params.payload.map((v) => (typeof v === \"bigint\" ? v : BigInt(v))),\n ];\n}\n\n// Threshold envelope (V2_THRESHOLD): see `./threshold.ts:buildThresholdEnvelope`\n// for the canonical builder with validation + deduplication + Cairo-\n// matching interleaved layout.\n//\n// `wrapV2ThresholdEnvelope` below is kept as a deprecated compat shim\n// for v13.x integrators who imported it directly. Wave A shipped this\n// function with the WRONG layout (grouped lens before data, instead\n// of interleaved per Cairo dispatch); it was never called in\n// production. The shim now delegates to the correct builder so any\n// existing call sites get the fixed shape with no SDK API break.\n\nimport { buildThresholdEnvelope } from \"./threshold\";\n\n/**\n * @deprecated since Wave B B2 — use `buildThresholdEnvelope` from\n * `@chipi-stack/backend/shhh/threshold` instead. This wrapper exists\n * for backward compat with v13.x and will be removed one minor\n * release after `chipi-stack@14.5.0` ships.\n *\n * Forwards to the validated builder. Note that callers passing\n * fewer than 2 envelopes (which the old version silently accepted\n * with a bogus layout) will now correctly throw — Cairo rejects\n * `n < 2` thresholds.\n */\nexport function wrapV2ThresholdEnvelope(innerEnvelopes: bigint[][]): bigint[] {\n return buildThresholdEnvelope({ innerEnvelopes });\n}\n","/**\n * Deterministic ShhhAccount (V8.4) address derivation.\n *\n * Vendored from haycarlitos/shhh-wallet-cairo @ v8.4 commit 3975532\n * source: scripts/ts/compute-wallet-address.ts\n * license: MIT (Copyright (c) 2026 Carlos Castillo and contributors)\n *\n * Given the primary owner (kind + raw pubkey bytes) and the\n * ShhhAccount class hash, returns the Starknet address the account\n * will deploy to.\n *\n * MUST match `src/account.cairo::constructor` at the same commit. If\n * the upstream constructor changes shape, the Shhh maintainer will\n * open a PR against this file.\n */\n\nimport { hash, shortString } from \"starknet\";\n\nexport type ComputeAddressInput = {\n /** SHHH ShhhAccount class hash — see WALLET_CLASS_HASHES.SHHH in @chipi-stack/shared. */\n classHash: bigint;\n /** Primary signer kind, e.g. 'STARK' / 'ED25519' / 'WEBAUTHN_P256'. */\n primaryKind: string;\n /** Raw pubkey bytes interpreted as felt252-sized halves (kind-specific layout). */\n pubkey: bigint[];\n /** Verifier class hash for primaryKind — see SHHH_VERIFIER_CLASS_HASHES. */\n verifierClassHash: bigint;\n /** Optional user-facing tag bound into the constructor (default 'primary'). */\n label?: string;\n /** Factory / UDC address; default 0 for self-deploy. */\n deployerAddress?: bigint;\n};\n\n// poseidon_hash_span matches core::poseidon::poseidon_hash_span on-chain.\nfunction poseidon(values: Array<bigint | string>): bigint {\n const felts = values.map((v) => (typeof v === \"bigint\" ? \"0x\" + v.toString(16) : v));\n return BigInt(hash.computePoseidonHashOnElements(felts));\n}\n\n/** Mirrors `src/signer/interface.cairo::owner_commitment` = poseidon(kind_tag, pubkey...). */\nexport function ownerCommitment(kindTag: bigint, pubkey: bigint[]): bigint {\n return poseidon([kindTag, ...pubkey]);\n}\n\n/**\n * Mirrors the V8.4 constructor's salt derivation:\n * salt = poseidon(primary_kind, primary_pubkey_hash)\n * where primary_pubkey_hash = owner_commitment(primary_kind, pubkey).\n * Binding kind into the salt ensures the same raw key under two\n * different kinds produces two distinct addresses.\n */\nexport function computeAddressSalt(primaryKind: string, pubkey: bigint[]): bigint {\n if (pubkey.length === 0) {\n // Fail-fast: an empty pubkey array would still produce a deterministic\n // (but unsignable) address. Reject up front so callers can't silently\n // ship a wallet that no signer can ever authorize.\n throw new Error(\n \"computeAddressSalt: pubkey must contain at least one felt — empty signer material is rejected to prevent silent address mismatch.\"\n );\n }\n const kindTag = BigInt(shortString.encodeShortString(primaryKind));\n const pubkeyHash = ownerCommitment(kindTag, pubkey);\n return poseidon([kindTag, pubkeyHash]);\n}\n\n/** Computes the deterministic deployment address for a SHHH ShhhAccount. */\nexport function computeShhhAddress(input: ComputeAddressInput): bigint {\n const {\n classHash,\n primaryKind,\n pubkey,\n verifierClassHash,\n label = \"primary\",\n deployerAddress = 0n,\n } = input;\n\n const salt = computeAddressSalt(primaryKind, pubkey);\n const kindTag = BigInt(shortString.encodeShortString(primaryKind));\n const labelFelt = BigInt(shortString.encodeShortString(label));\n\n // Constructor calldata: [primary_kind, primary_verifier, pubkey_len, pubkey..., label]\n const ctor: Array<bigint | string> = [\n kindTag,\n verifierClassHash,\n BigInt(pubkey.length),\n ...pubkey,\n labelFelt,\n ];\n\n const addressHex = hash.calculateContractAddressFromHash(\n \"0x\" + salt.toString(16),\n \"0x\" + classHash.toString(16),\n ctor.map((x) => (typeof x === \"bigint\" ? \"0x\" + x.toString(16) : x)),\n \"0x\" + deployerAddress.toString(16)\n );\n return BigInt(addressHex);\n}\n","/**\n * STARK ECDSA signer for SHHH V8.4 ShhhAccount.\n *\n * Cheapest verifier path (~2M l2_gas). Native Stark-curve ECDSA over\n * the SNIP-12 hash; the verifier class is a thin syscall wrapper.\n *\n * Reference: shhh-wallet-cairo/scripts/ts/gen-phase3-account-fixture.mjs\n * (same Stark signature shape, wrapped in V2_SNIP12).\n *\n * For non-STARK kinds (Ed25519, EIP-191, WebAuthn, JWT, BLS) the\n * envelope payload is per-kind — see sibling files in this directory.\n */\n\nimport { ec, shortString } from \"starknet\";\nimport { ownerCommitment } from \"../compute-wallet-address\";\nimport { wrapV2Snip12Envelope } from \"../oe\";\n\nconst STARK_KIND_TAG = \"STARK\";\nconst STARK_KIND_TAG_FELT = BigInt(shortString.encodeShortString(STARK_KIND_TAG));\n\n/**\n * Build a V2_SNIP12 envelope for the STARK kind from a private key +\n * the OE's SNIP-12 hash. The envelope is the `signature` span you\n * pass to `paymaster_executeSponsoredRaw.calldata`.\n *\n * Payload for STARK is exactly `[r, s]` — the verifier reads these\n * two felts and invokes the chain's `ec_op` syscall.\n *\n * **Envelope layout (V8.4):** `[V2_SNIP12, owner_id, kind_tag, ...payload]`\n *\n * `owner_id` at position [1] is a **u32 INDEX into the owner_set**,\n * NOT the poseidon `owner_commitment`. For the primary owner of a\n * fresh deploy that index is `0n`; for additional owners added via\n * `propose_add_owner` it's `1n`, `2n`, etc. The V8.4 dispatcher\n * (`src/account.cairo:480`) does `(*signature.at(1)).try_into::<u32>()`\n * and panics with `'SHHH: bad owner_id'` if the felt exceeds u32 MAX —\n * which is exactly what happens if a poseidon commitment is passed\n * here instead of the index. (Discovered 2026-05-27 trace audit on\n * tx 0x1d1ee02e0dd1ffdbc6f0dddb426098d0dc87800eee3d0d0201e74d97ddc0a55.)\n */\nexport function buildStarkEnvelope(params: {\n /** STARK private key as bigint or 0x-prefixed hex. */\n privateKey: bigint | string;\n /** SNIP-12 hash of the OutsideExecution — see oe.ts::computeOeHash. */\n messageHash: bigint;\n /**\n * Owner index in the wallet's owner_set. **Defaults to 0n (primary).**\n * Override for additional owners added via `propose_add_owner`.\n * MUST fit in u32 (i.e., < 2^32). Passing the poseidon\n * `owner_commitment` here will revert on chain with\n * `'SHHH: bad owner_id'`.\n */\n ownerIndex?: bigint;\n}): bigint[] {\n // starknet.js getStarkKey/sign accept hex strings, not raw bigints.\n // Normalize to 0x-prefixed 64-char hex regardless of input form.\n const pkHex =\n \"0x\" +\n (typeof params.privateKey === \"bigint\" ? params.privateKey : BigInt(params.privateKey))\n .toString(16)\n .padStart(64, \"0\");\n\n const sig = ec.starkCurve.sign(\"0x\" + params.messageHash.toString(16), pkHex);\n\n const r = BigInt(\"0x\" + sig.r.toString(16));\n const s = BigInt(\"0x\" + sig.s.toString(16));\n\n const ownerIndex = params.ownerIndex ?? 0n;\n if (ownerIndex < 0n || ownerIndex >= 0x100000000n) {\n // u32 range check matches the on-chain try_into bound; surface as\n // a loud SDK-side error instead of a silent on-chain revert.\n throw new Error(\n `buildStarkEnvelope: ownerIndex ${ownerIndex} is out of u32 range [0, 2^32). ` +\n \"owner_id is the u32 INDEX into the wallet's owner_set (0 for primary, \" +\n \"1 for second, etc.); do NOT pass an owner_commitment or pubkey here.\"\n );\n }\n\n return wrapV2Snip12Envelope({\n ownerId: ownerIndex,\n kindTag: STARK_KIND_TAG,\n payload: [r, s],\n });\n}\n\n/**\n * Compute the V8.4 owner_id for a STARK-kind owner from its public\n * key. owner_id = owner_commitment(kind_tag, [pubkey]) per\n * `src/signer/interface.cairo::owner_commitment`. The account uses\n * this to dedupe owners and select the verifier class.\n */\nexport function starkOwnerId(starkPubKey: bigint): bigint {\n return ownerCommitment(STARK_KIND_TAG_FELT, [starkPubKey]);\n}\n\n/**\n * STARK pubkey layout for the V8.4 constructor / propose_add_owner.\n * The Stark curve pubkey fits in one felt252, so this is a 1-element\n * array. Kept as a function for parity with kinds that split the\n * pubkey into multiple felts (Ed25519, secp256k1, P-256, BLS).\n */\nexport function starkPubkeyFelts(starkPubKey: bigint | string): bigint[] {\n return [typeof starkPubKey === \"bigint\" ? starkPubKey : BigInt(starkPubKey)];\n}\n","/**\n * Ed25519 signer for SHHH V8.4 ShhhAccount.\n *\n * Used by Phantom (Solana) flows and any generic Ed25519 signer. The\n * V8.4 verifier (class `0x030a7dfc…949f74`) consumes a Cairo-ready\n * calldata array produced by Garaga's `eddsaCalldataBuilder` — it\n * contains the signature halves plus elliptic-curve hints the Cairo\n * verifier needs to keep gas bounded.\n *\n * Reference: shhh-wallet-cairo/scripts/ts/regen-ed25519-fixtures.mjs\n *\n * Verifier overhead: ~33M l2_gas (per SHHH_KIND_GAS_OVERHEAD).\n *\n * IMPORTANT — dynamic imports\n *\n * Garaga ships a ~1.2MB WASM bundle. We dynamic-import it so callers\n * who never touch Ed25519 don't pay the bundle cost. The first call\n * to `buildEd25519Envelope` will lazy-load + initialize Garaga; this\n * is irreversible and cached for the process lifetime. Cold-start\n * cost is ~200-400ms on Android, ~80-150ms on iPhone 13+.\n *\n * `@noble/ed25519` is also dynamic-imported for symmetry, though it\n * tree-shakes cleanly as a static import too.\n */\n\nimport { shortString } from \"starknet\";\nimport { ownerCommitment } from \"../compute-wallet-address\";\nimport { wrapV2Snip12Envelope } from \"../oe\";\nimport { snip12HashToHexAsciiBytes } from \"../snip12-hash\";\n\nconst ED25519_KIND_TAG = \"ED25519\";\nconst ED25519_KIND_TAG_FELT = BigInt(shortString.encodeShortString(ED25519_KIND_TAG));\n\nlet garagaInitPromise: Promise<typeof import(\"garaga\")> | null = null;\n\n/**\n * Lazy + memoized Garaga WASM init. Safe to call repeatedly.\n *\n * On failure (e.g. transient WASM fetch error) we clear the memoized\n * promise so subsequent calls retry; otherwise a single bad init would\n * brick the SDK for the process lifetime.\n */\nasync function ensureGaragaInit(): Promise<typeof import(\"garaga\")> {\n if (garagaInitPromise) return garagaInitPromise;\n const attempt = (async () => {\n const garaga = await import(\"garaga\");\n await garaga.init();\n return garaga;\n })();\n garagaInitPromise = attempt;\n try {\n return await attempt;\n } catch (err) {\n // Reset so the next caller gets a fresh attempt instead of the\n // cached rejection.\n if (garagaInitPromise === attempt) garagaInitPromise = null;\n throw err;\n }\n}\n\n/**\n * Split a 32-byte little-endian Ed25519 value into two felt252-sized\n * halves matching Cairo's `u256` storage layout (low_u128, high_u128).\n * bytes[0] is the LSB of `low`.\n */\nfunction bytesToLeU256(bytes: Uint8Array): { low: bigint; high: bigint } {\n if (bytes.length !== 32) {\n throw new Error(`Ed25519 value must be exactly 32 bytes; got ${bytes.length}.`);\n }\n let low = 0n;\n let high = 0n;\n for (let i = 0; i < 16; i++) low += BigInt(bytes[i]) << BigInt(8 * i);\n for (let i = 0; i < 16; i++) high += BigInt(bytes[16 + i]) << BigInt(8 * i);\n return { low, high };\n}\n\nfunction bytesToLeBigInt(bytes: Uint8Array): bigint {\n let x = 0n;\n for (let i = bytes.length - 1; i >= 0; i--) x = (x << 8n) | BigInt(bytes[i]);\n return x;\n}\n\n/**\n * The Cairo Ed25519 verifier reads the SNIP-12 hash via its hex-ASCII\n * 64-byte encoding so the signature commits to a string that Phantom\n * (and any \"sign-this-string\" UX) can display. This helper is exposed\n * here for parity with the Cairo-side decoder; it's the same function\n * as `snip12HashToHexAsciiBytes` in snip12-hash.ts, re-exported under\n * a kind-specific name for discoverability.\n */\nexport function ed25519SignedBytes(messageHash: bigint): Uint8Array {\n return snip12HashToHexAsciiBytes(messageHash);\n}\n\n/**\n * Compute the V8.4 owner_id for an Ed25519-kind owner from its public\n * key. owner_id = owner_commitment(ED25519_tag, [pub_low, pub_high])\n * — the same shape as `src/signer/ed25519/verifier.cairo` expects in\n * `validate_pubkey`.\n */\nexport function ed25519OwnerId(publicKey: Uint8Array): bigint {\n const { low, high } = bytesToLeU256(publicKey);\n return ownerCommitment(ED25519_KIND_TAG_FELT, [low, high]);\n}\n\n/**\n * Ed25519 pubkey felt layout for the V8.4 constructor / propose_add_owner.\n * Returns the low/high u128 halves of the 32-byte public key in that\n * order — what the Cairo `kind == ED25519` branch reads.\n */\nexport function ed25519PubkeyFelts(publicKey: Uint8Array): bigint[] {\n const { low, high } = bytesToLeU256(publicKey);\n return [low, high];\n}\n\n/**\n * Build a V2_SNIP12 envelope for the Ed25519 kind. Async because the\n * underlying Garaga WASM must be initialized; subsequent calls reuse\n * the cached init.\n *\n * Inputs:\n * privateKey — 32-byte Ed25519 secret (Uint8Array, NOT hex/bigint:\n * the noble lib refuses anything else).\n * messageHash — the SNIP-12 hash of the OE (see oe.ts::computeOeHash).\n *\n * Output: the `signature` span you pass to\n * `paymaster_executeSponsoredRaw.calldata`.\n */\nexport async function buildEd25519Envelope(params: {\n privateKey: Uint8Array;\n messageHash: bigint;\n /**\n * Owner index in the wallet's owner_set. **Defaults to 0n (primary).**\n * Override for additional owners added via `propose_add_owner`.\n * MUST fit in u32 (i.e., < 2^32). Passing the poseidon\n * `owner_commitment` (e.g. via `ed25519OwnerId`) here will revert\n * on chain with `'SHHH: bad owner_id'` — the bug Shhh team caught\n * 2026-05-27 + audit-trail 2026-05-28.\n */\n ownerIndex?: bigint;\n}): Promise<bigint[]> {\n // Validate cheap params BEFORE Garaga init + signing. An out-of-range\n // ownerIndex should not pay for the ~80-400ms WASM warm-up or an ECDSA\n // sign that we will discard.\n const ownerIndex = params.ownerIndex ?? 0n;\n if (ownerIndex < 0n || ownerIndex >= 0x100000000n) {\n throw new Error(\n `buildEd25519Envelope: ownerIndex ${ownerIndex} is out of u32 range [0, 2^32). ` +\n \"owner_id is the u32 INDEX into the wallet's owner_set (0 for primary, \" +\n \"1 for second, etc.); do NOT pass an owner_commitment or pubkey here.\"\n );\n }\n if (params.privateKey.length !== 32) {\n throw new Error(\n `Ed25519 private key must be exactly 32 bytes; got ${params.privateKey.length}.`\n );\n }\n\n // @noble/ed25519 ≥ 3.x is async-by-default and ships as ESM.\n const ed = await import(\"@noble/ed25519\");\n\n const garaga = await ensureGaragaInit();\n\n const publicKey = await ed.getPublicKeyAsync(params.privateKey);\n const signedBytes = ed25519SignedBytes(params.messageHash);\n const signature = await ed.signAsync(signedBytes, params.privateKey);\n\n // Per RFC 8032: signature = R (32B) || s (32B).\n const R = signature.slice(0, 32);\n const s = signature.slice(32, 64);\n\n // Garaga's eddsaCalldataBuilder(Ry_le_bigint, s_le_bigint, Py_le_bigint, msg, prependPublickey=false)\n // returns the calldata array Cairo's Ed25519 verifier consumes:\n // [ Ry_low, Ry_high, s_low, s_high,\n // msg_len, msg_byte_0, ..., msg_byte_{msg_len-1},\n // ...msm_hint..., ...sqrt_Rx_hint..., ...sqrt_Px_hint... ]\n const payload = (garaga as any).eddsaCalldataBuilder(\n bytesToLeBigInt(R),\n bytesToLeBigInt(s),\n bytesToLeBigInt(publicKey),\n signedBytes,\n false\n );\n\n return wrapV2Snip12Envelope({\n ownerId: ownerIndex,\n kindTag: ED25519_KIND_TAG,\n payload: payload as Array<bigint | string>,\n });\n}\n","/**\n * High-level SHHH V8.4 OE execution path for the backend SDK.\n *\n * This module is the glue between the low-level OE builders in\n * `oe.ts` + `signers/*.ts` and chipi-back's\n * `POST /transactions/execute-sponsored-raw` endpoint.\n *\n * Why this exists separately from the legacy\n * `executePaymasterTransaction` flow:\n *\n * - The Chipi paymaster cannot synthesize SHHH envelopes server-side\n * (each of the 10 V8.4 signer kinds has a different envelope\n * shape; the paymaster's design — see chipi-pay/paymaster#16 — is\n * to pass the signature span verbatim to `execute_from_outside_v2`).\n * - Therefore SHHH clients MUST build + sign the OE locally and\n * submit it pre-signed to a forwarding endpoint\n * (`/transactions/execute-sponsored-raw`).\n * - The legacy flow (`prepare-typed-data` → sign → `execute-sponsored-\n * transaction`) is unchanged and continues to serve CHIPI / READY\n * wallets.\n *\n * Scope (Wave B, this PR): STARK + ED25519 signer kinds.\n * EIP-191 / WEBAUTHN_P256 / JWT_ES256_APPLE_SUB still throw the\n * deferred-feature error until the external-rooted wallet adapter\n * flow lands.\n */\n\nimport { hash, type Call } from \"starknet\";\nimport { decryptPrivateKey } from \"../encryption\";\nimport type { ChipiClient } from \"../client\";\nimport { buildOutsideExecution, computeOeHash, ANY_CALLER_FELT } from \"./oe\";\nimport { buildStarkEnvelope } from \"./signers/stark\";\nimport { buildEd25519Envelope } from \"./signers/ed25519\";\n\n// Default chain ID for SHHH OE signing. Chipi Pay operates exclusively\n// on Starknet mainnet per CLAUDE.md (\"ALWAYS mainnet — Chipi Pay\n// operates exclusively on Starknet mainnet. Staging, tests, and\n// production all use mainnet\"). Callers on non-mainnet environments\n// can override via the `chainId` param on `executeShhhSponsoredRaw`.\n// Drift here = SNIP-12 signature mismatch and on-chain rejection.\nconst SN_MAIN_CHAIN_ID = \"0x534e5f4d41494e\"; // shortString.encodeShortString(\"SN_MAIN\")\nconst SN_SEPOLIA_CHAIN_ID = \"0x534e5f5345504f4c4941\"; // shortString.encodeShortString(\"SN_SEPOLIA\")\n\n/**\n * Pick the chain ID for SNIP-12 hashing. If the caller did not provide\n * an explicit override, infer from the chipi-back base URL (sepolia\n * hostnames map to SN_SEPOLIA; everything else maps to SN_MAIN per\n * the project's mainnet-only invariant).\n *\n * Exported for unit-testing the resolver in isolation.\n */\nexport function resolveShhhChainId(params: {\n override?: bigint | string;\n baseUrl?: string;\n}): string {\n if (params.override !== undefined) {\n return typeof params.override === \"bigint\"\n ? \"0x\" + params.override.toString(16)\n : params.override;\n }\n const url = (params.baseUrl ?? \"\").toLowerCase();\n if (url.includes(\"sepolia\")) return SN_SEPOLIA_CHAIN_ID;\n return SN_MAIN_CHAIN_ID;\n}\n\n/**\n * Serialize an OutsideExecution struct + signature span into the\n * flat felt-array calldata that `execute_from_outside_v2` expects.\n *\n * Cairo's serde order (per shhh-wallet-cairo v8.4\n * `src/account.cairo::execute_from_outside_v2`):\n *\n * caller\n * nonce\n * execute_after (u64, 1 felt)\n * execute_before (u64, 1 felt)\n * calls.len()\n * for each Call:\n * to (felt)\n * selector (felt)\n * calldata.len()\n * ...calldata felts\n * signature.len()\n * ...signature felts\n *\n * Returns 0x-prefixed lowercase hex strings ready for direct\n * JSON-RPC submission via the chipi-back forwarder.\n */\nexport function serializeExecuteFromOutsideV2Calldata(params: {\n outsideExecution: {\n caller: bigint | string;\n nonce: bigint | string;\n execute_after: bigint;\n execute_before: bigint;\n calls: Call[];\n };\n signature: bigint[];\n}): string[] {\n const out: bigint[] = [];\n const oe = params.outsideExecution;\n\n const toBig = (v: bigint | string): bigint => (typeof v === \"bigint\" ? v : BigInt(v));\n\n out.push(toBig(oe.caller));\n out.push(toBig(oe.nonce));\n out.push(oe.execute_after);\n out.push(oe.execute_before);\n\n out.push(BigInt(oe.calls.length));\n for (const call of oe.calls) {\n out.push(BigInt(call.contractAddress));\n out.push(BigInt(hash.getSelectorFromName(call.entrypoint)));\n const callData = Array.isArray(call.calldata)\n ? (call.calldata as Array<string | number | bigint>)\n : [];\n out.push(BigInt(callData.length));\n for (const datum of callData) {\n out.push(typeof datum === \"bigint\" ? datum : BigInt(datum));\n }\n }\n\n out.push(BigInt(params.signature.length));\n for (const sigFelt of params.signature) {\n out.push(sigFelt);\n }\n\n return out.map((v) => \"0x\" + v.toString(16));\n}\n\n/**\n * Generate a unique OE nonce. The V8.4 account stores consumed nonces\n * in `oe_nonces` and rejects replays, so we need something with enough\n * entropy to avoid collisions across concurrent SDK calls. Combines\n * `Date.now()` (ms) with a 24-bit random suffix; both fit comfortably\n * in a felt252.\n */\nfunction newOeNonce(): bigint {\n const tsMs = BigInt(Date.now());\n const rand = BigInt(Math.floor(Math.random() * 0xffffff));\n // Shift the timestamp left by 24 bits and OR the random suffix to\n // produce a single felt-sized value. ~85 years of millisecond range\n // before the high bits push past 252 bits.\n return (tsMs << 24n) | rand;\n}\n\n/**\n * Decrypt the wallet's STARK private key from its\n * `encryptedPrivateKey` ciphertext + the per-wallet `encryptKey` (PIN\n * or passkey-derived secret), build a SHHH V8.4 OE around the given\n * inner calls, sign it with the wallet's STARK key, serialize the\n * calldata for `execute_from_outside_v2`, and forward to chipi-back's\n * `/transactions/execute-sponsored-raw` endpoint.\n *\n * Returns the on-chain transaction hash.\n *\n * Pre-conditions:\n * - `wallet.walletType === \"SHHH\"`.\n * - `wallet.publicKey` is the deployed account address (NOT the raw\n * STARK pubkey; V8.4 deployment derives address from kind-bound\n * salt + verifier).\n * - `wallet.encryptedPrivateKey` decrypts cleanly with `encryptKey`.\n * - The wallet is already deployed (no deploy_and_invoke variant\n * here; that flow stays inside `createWallet`).\n */\nexport async function executeShhhSponsoredRaw(params: {\n client: ChipiClient;\n bearerToken: string;\n wallet: {\n publicKey: string;\n encryptedPrivateKey: string;\n walletType?: string;\n };\n encryptKey: string;\n calls: Call[];\n /**\n * Defaults to `\"STARK\"`. Wave B ships STARK + ED25519. EIP-191 /\n * WEBAUTHN_P256 / JWT_ES256_APPLE_SUB are deferred to the\n * external-rooted wallet adapter PRs.\n */\n signerKind?: \"STARK\" | \"ED25519\";\n /** Override the OE nonce; default = `Date.now() << 24 | random24bit`. */\n nonce?: bigint;\n /** Optional externalUserId for the audit-log hint. */\n externalUserId?: string;\n /**\n * Override the chain ID used for SNIP-12 hashing. Defaults to\n * mainnet per CLAUDE.md's mainnet-only invariant; sepolia is auto-\n * inferred from the chipi-back base URL when present. Drift here\n * = the V8.4 account rejects the signature on chain.\n */\n chainId?: bigint | string;\n}): Promise<string> {\n const signerKind = params.signerKind ?? \"STARK\";\n const SDK_SHIPPED_OE_KINDS = [\"STARK\", \"ED25519\"] as const;\n if (!SDK_SHIPPED_OE_KINDS.includes(signerKind as (typeof SDK_SHIPPED_OE_KINDS)[number])) {\n throw new Error(\n `SHHH signerKind=\"${signerKind}\" is not yet shipped from the SDK ` +\n \"(Wave B ships STARK + ED25519). Wait for the follow-up PR that \" +\n \"adds external-rooted (MetaMask, Phantom, passkey, Apple) signing.\"\n );\n }\n\n const privateKeyHex = decryptPrivateKey(params.wallet.encryptedPrivateKey, params.encryptKey);\n if (!privateKeyHex) {\n throw new Error(\n \"Failed to decrypt private key for SHHH OE. Verify the encryptKey matches the one used at wallet creation.\"\n );\n }\n\n const oe = buildOutsideExecution({\n nonce: params.nonce ?? newOeNonce(),\n calls: params.calls,\n caller: ANY_CALLER_FELT,\n });\n\n const chainId = resolveShhhChainId({\n override: params.chainId,\n baseUrl: params.client.baseUrl,\n });\n const messageHash = computeOeHash(oe, params.wallet.publicKey, chainId);\n\n let signature: bigint[];\n if (signerKind === \"STARK\") {\n signature = buildStarkEnvelope({\n privateKey: privateKeyHex,\n messageHash,\n });\n } else {\n // ED25519 — decode the stored hex private key back to 32 raw bytes\n // and route through the Ed25519 envelope builder. The builder\n // generates RFC 8032 deterministic signatures + the Garaga\n // calldata hints the Cairo verifier requires.\n //\n // Defensive 0x prefix strip: today the wallet-creation path stores\n // bare hex (no prefix), but a future storage migration might add\n // one. Normalizing here keeps the validator's error message\n // accurate either way.\n const edKeyHex = privateKeyHex.startsWith(\"0x\") ? privateKeyHex.slice(2) : privateKeyHex;\n if (edKeyHex.length !== 64) {\n throw new Error(\n `SHHH ED25519 private key is ${edKeyHex.length} hex chars; expected 64 (32 raw bytes). ` +\n \"The stored ciphertext does not look like a Chipi-held Ed25519 key — check wallet provenance.\"\n );\n }\n const edPrivKey = Uint8Array.from(Buffer.from(edKeyHex, \"hex\"));\n signature = await buildEd25519Envelope({\n privateKey: edPrivKey,\n messageHash,\n });\n }\n\n const calldata = serializeExecuteFromOutsideV2Calldata({\n outsideExecution: oe,\n signature,\n });\n\n // Forward to chipi-back's /transactions/execute-sponsored-raw. The\n // endpoint owns the paymaster JSON-RPC call (paymaster cannot be\n // hit directly without the paymaster API key, which lives only on\n // chipi-back). chipi-back also records the resulting Transaction.\n const response = await params.client.post<{\n transactionHash?: string;\n id?: string;\n }>({\n endpoint: \"/transactions/execute-sponsored-raw\",\n bearerToken: params.bearerToken,\n body: {\n accountAddress: params.wallet.publicKey,\n calldata,\n signerKind,\n ...(params.externalUserId ? { externalUserId: params.externalUserId } : {}),\n },\n });\n\n // The endpoint returns either a saved Transaction row (with\n // `transactionHash`) or `{ transactionHash, trackingId }` when\n // saveToDatabase=false. Either way the hash is at the top level.\n if (!response || !response.transactionHash) {\n throw new Error(\n \"execute-sponsored-raw response missing transactionHash. Check the chipi-back logs for upstream paymaster errors.\"\n );\n }\n return response.transactionHash;\n}\n","import type {\n ExecuteSponsoredTransactionResponse,\n WalletData,\n WalletType,\n SessionKeyData,\n PrepareTypedDataResponse,\n} from \"@chipi-stack/types\";\nimport type { Call } from \"starknet\";\nimport { Account, RpcProvider, TypedData, ec, typedData, num } from \"starknet\";\nimport { decryptPrivateKey } from \"./encryption\";\nimport {\n WALLET_CLASS_HASHES,\n WALLET_RPC_ENDPOINTS,\n SESSION_ERRORS,\n ChipiSessionError,\n} from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\nimport { normalizeSignature } from \"./paymaster-adapter\";\n\n// Extended WalletData with optional wallet type for transactions\n\n// Internal type - not exported to users\ninterface ExecutePaymasterTransactionParams {\n encryptKey?: string;\n wallet: WalletData;\n calls: Call[];\n saveToDatabase: boolean; // Internal only - always set by SDK, users cannot control this\n usePasskey?: boolean;\n}\n\n/**\n * Execute a paymaster transaction (gasless) via Chipi's paymaster\n * Supports both CHIPI and ARGENT wallet types\n */\nexport const executePaymasterTransaction = async ({\n params,\n bearerToken,\n client,\n}: {\n params: ExecutePaymasterTransactionParams;\n bearerToken: string;\n client: ChipiClient;\n}): Promise<string> => {\n try {\n const { encryptKey, wallet, calls, saveToDatabase, usePasskey } = params;\n\n // Validate encryptKey is provided\n if (!encryptKey) {\n throw new Error(\n usePasskey\n ? \"encryptKey is required when using passkey. The passkey authentication should have provided the encryptKey.\"\n : \"encryptKey is required for transaction execution\"\n );\n }\n\n const walletType = wallet.walletType ?? \"READY\";\n\n // SHHH V8.4 ShhhAccount wallets cannot use the legacy\n // prepare-typed-data → sign → execute-sponsored-transaction flow\n // because the Chipi paymaster cannot synthesize SHHH envelopes\n // server-side (each V8.4 signer kind has a different envelope\n // shape — see chipi-pay/paymaster#16). Route SHHH OEs through the\n // execute-sponsored-raw forwarder which expects pre-signed\n // calldata. The legacy flow below is unchanged for CHIPI/READY.\n if (walletType === \"SHHH\") {\n const { executeShhhSponsoredRaw } = await import(\"./shhh/execute-paymaster-raw\");\n // Auto-route to the right envelope builder. Default to STARK to\n // preserve pre-Wave-B behavior when the caller's WalletData was\n // populated from an older response (or from a non-SHHH row where\n // chipi-back returns null for signerKind).\n const shhhSignerKind = ((wallet.signerKind ?? \"STARK\") || \"STARK\") as \"STARK\" | \"ED25519\";\n return await executeShhhSponsoredRaw({\n client,\n bearerToken,\n wallet: {\n publicKey: wallet.publicKey,\n encryptedPrivateKey: wallet.encryptedPrivateKey,\n walletType: wallet.walletType,\n },\n encryptKey,\n calls,\n signerKind: shhhSignerKind,\n });\n }\n\n // For known types, use mapped RPC and class hash.\n // For custom types, fall back to default CHIPI RPC (all StarkNet accounts use the same RPC)\n // and use the wallet's classHash if available.\n const isKnownType =\n Object.prototype.hasOwnProperty.call(WALLET_RPC_ENDPOINTS, walletType) &&\n Object.prototype.hasOwnProperty.call(WALLET_CLASS_HASHES, walletType);\n\n const rpcUrl = isKnownType ? WALLET_RPC_ENDPOINTS[walletType] : WALLET_RPC_ENDPOINTS[\"CHIPI\"];\n const accountClassHash = isKnownType\n ? WALLET_CLASS_HASHES[walletType]\n : WALLET_CLASS_HASHES[\"CHIPI\"];\n\n // Decrypt the private key\n let privateKeyDecrypted: string;\n try {\n privateKeyDecrypted = decryptPrivateKey(wallet.encryptedPrivateKey, encryptKey);\n } catch {\n throw new Error(\"Failed to decrypt private key. Verify the encryptKey is correct.\");\n }\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n const account = new Account({\n provider,\n address: wallet.publicKey,\n signer: privateKeyDecrypted,\n });\n\n // Build the type data via Chipi's backend\n const prepareResponse = await client.post<PrepareTypedDataResponse>({\n endpoint: \"/transactions/prepare-typed-data\",\n bearerToken,\n body: {\n publicKey: wallet.publicKey,\n calls: calls,\n accountClassHash,\n },\n });\n\n // Validate response structure\n if (!prepareResponse || typeof prepareResponse !== \"object\") {\n throw new Error(\n \"Invalid response from /transactions/prepare-typed-data: response is not an object\"\n );\n }\n\n // Support both current and legacy API response shapes:\n // - Current: { typedData: TypedData, walletType: WalletType }\n // - Legacy: TypedData directly (domain/types/primaryType/message)\n let typedData: TypedData | undefined;\n let resolvedWalletType: WalletType | undefined;\n\n if (\"typedData\" in prepareResponse) {\n const resp = prepareResponse as PrepareTypedDataResponse;\n typedData = resp.typedData;\n // Only accept known wallet types from the backend\n if (\n resp.walletType &&\n Object.prototype.hasOwnProperty.call(WALLET_CLASS_HASHES, resp.walletType)\n ) {\n resolvedWalletType = resp.walletType;\n }\n } else if (prepareResponse && \"types\" in prepareResponse && \"message\" in prepareResponse) {\n // Legacy shape: the response itself is the TypedData\n typedData = prepareResponse as TypedData;\n } else {\n // Likely an API error shape like { message: string }\n const apiMessage =\n prepareResponse && typeof (prepareResponse as any).message === \"string\"\n ? (prepareResponse as any).message\n : undefined;\n\n throw new Error(\n apiMessage ??\n \"Invalid response from /transactions/prepare-typed-data: typedData is missing. \" +\n \"This may occur for older STARKNET wallets that don't support paymaster transactions. \" +\n \"Please ensure the wallet is a CHIPI wallet type.\"\n );\n }\n\n // Validate typedData structure before signing\n if (\n !typedData ||\n typeof typedData !== \"object\" ||\n !(\"types\" in typedData) ||\n !(\"message\" in typedData)\n ) {\n throw new Error(\n \"Invalid typedData received from backend: missing 'types' or 'message' field. \" +\n \"This may occur for older STARKNET wallets that don't support paymaster transactions.\"\n );\n }\n\n // Sign the message\n const userSignature = await account.signMessage(typedData);\n\n // Normalize signature format (handles both Weierstrass and Array types)\n const normalizedSig = normalizeSignature(userSignature);\n\n // Execute the sponsored transaction via Chipi's paymaster\n const result = await client.post<ExecuteSponsoredTransactionResponse>({\n endpoint: \"/transactions/execute-sponsored-transaction\",\n bearerToken,\n body: {\n publicKey: wallet.publicKey,\n typedData,\n userSignature: normalizedSig,\n saveToDatabase,\n walletType: resolvedWalletType ?? walletType,\n },\n });\n\n if (!result || typeof result !== \"object\") {\n throw new Error(\n \"Invalid response from /transactions/execute-sponsored-transaction: response is not an object\"\n );\n }\n\n const apiMessage =\n typeof (result as any).message === \"string\" ? (result as any).message : undefined;\n\n if (typeof result.transactionHash !== \"string\" || result.transactionHash.trim().length === 0) {\n throw new Error(apiMessage ?? \"Response does not contain transaction hash\");\n }\n\n return result.transactionHash;\n } catch (error) {\n console.error(\"Error sending transaction with paymaster\", error);\n throw error;\n }\n};\n\n// Internal type for session-based paymaster transactions\ninterface ExecutePaymasterTransactionWithSessionParams {\n encryptKey: string;\n wallet: WalletData;\n session: SessionKeyData;\n calls: Call[];\n saveToDatabase: boolean;\n}\n\n/**\n * Execute a paymaster transaction (gasless) using a session key.\n *\n * This function uses the 4-element session signature format:\n * [sessionPubKey, r, s, validUntil]\n *\n * The session key must be registered on the contract before use via\n * `addSessionKeyToContract()`.\n *\n * CHIPI wallets only - will throw if wallet type is not CHIPI.\n *\n * @internal\n */\nexport const executePaymasterTransactionWithSession = async ({\n params,\n bearerToken,\n client,\n}: {\n params: ExecutePaymasterTransactionWithSessionParams;\n bearerToken: string;\n client: ChipiClient;\n}): Promise<string> => {\n const { encryptKey, wallet, session, calls, saveToDatabase } = params;\n\n // Accept CHIPI v29 + SHHH V8.4 (both embed SNIP-163 sessions; the\n // 4-felt session sig fast path at account.cairo:389 runs the same\n // on either class).\n if (wallet.walletType !== \"CHIPI\" && wallet.walletType !== \"SHHH\") {\n console.error(\"[ChipiSDK:Session:Execute] Invalid wallet type for session execution\", {\n provided: wallet.walletType,\n required: \"CHIPI or SHHH\",\n walletAddress: wallet.publicKey?.slice(0, 15) + \"...\",\n hint: \"Session keys require a SNIP-163 sessions component (CHIPI v29 or SHHH V8.4).\",\n });\n throw new ChipiSessionError(\n `Session execution requires CHIPI or SHHH wallet type. Got: \"${wallet.walletType || \"undefined\"}\"`,\n SESSION_ERRORS.INVALID_WALLET_TYPE_FOR_SESSION\n );\n }\n\n // Check if session has expired\n const nowSeconds = Math.floor(Date.now() / 1000);\n if (session.validUntil < nowSeconds) {\n console.error(\"[ChipiSDK:Session:Execute] Session has expired\", {\n sessionExpiry: new Date(session.validUntil * 1000).toISOString(),\n currentTime: new Date(nowSeconds * 1000).toISOString(),\n expiredAgo: `${nowSeconds - session.validUntil} seconds`,\n });\n throw new ChipiSessionError(\n `Session expired at ${new Date(session.validUntil * 1000).toISOString()}. ` +\n `Create a new session key.`,\n SESSION_ERRORS.SESSION_EXPIRED\n );\n }\n\n try {\n // console.log(\"[ChipiSDK:Session:Execute] Starting session transaction\", {\n // walletAddress: wallet.publicKey.slice(0, 15) + \"...\",\n // sessionPubKey: session.publicKey.slice(0, 15) + \"...\",\n // sessionExpiry: new Date(session.validUntil * 1000).toISOString(),\n // callCount: calls.length,\n // });\n\n // Decrypt the session private key\n let sessionPrivateKey: string;\n try {\n sessionPrivateKey = decryptPrivateKey(session.encryptedPrivateKey, encryptKey);\n } catch {\n console.error(\"[ChipiSDK:Session:Execute] Failed to decrypt session private key\", {\n sessionPubKey: session.publicKey?.slice(0, 15) + \"...\",\n hint: \"Ensure the encryptKey matches the one used when creating the session\",\n });\n throw new ChipiSessionError(\n \"Failed to decrypt session private key. Verify the encryptKey is correct.\",\n SESSION_ERRORS.SESSION_DECRYPTION_FAILED\n );\n }\n\n // Verify the session private key matches the public key\n const derivedPubKey = ec.starkCurve.getStarkKey(sessionPrivateKey);\n if (derivedPubKey.toLowerCase() !== session.publicKey.toLowerCase()) {\n console.error(\"[ChipiSDK:Session:Execute] Session key mismatch\", {\n expected: session.publicKey.slice(0, 15) + \"...\",\n derived: derivedPubKey.slice(0, 15) + \"...\",\n hint: \"The encrypted private key does not match the stored public key\",\n });\n throw new ChipiSessionError(\n \"Session key mismatch: decrypted private key does not match the public key\",\n SESSION_ERRORS.SESSION_DECRYPTION_FAILED\n );\n }\n\n if (wallet.walletType === \"SHHH\") {\n // V8.4 session OE path. Bypass chipi-back's prepare-typed-data +\n // execute-sponsored-transaction (which are shaped for CHIPI v29\n // wallets — they hardcode the CHIPI typedData domain + the\n // `isSessionSignature` flag the CHIPI controller reads). Route\n // the session OE through `/transactions/execute-sponsored-raw`\n // with the 4-felt session sig as the signature span.\n //\n // V8.4's `execute_from_outside_v2` checks `signature.len() == 4`\n // at `account.cairo:389` BEFORE the V2_SNIP12 envelope dispatch,\n // so the session-sig path runs the same way as on CHIPI v29 —\n // session whitelist + spending-policy enforcement + signature\n // verification against the SESSION pubkey (NOT the primary\n // owner), all inside the SNIP-163 component.\n const { buildOutsideExecution, computeOeHash, ANY_CALLER_FELT } = await import(\"./shhh/oe\");\n const { resolveShhhChainId, serializeExecuteFromOutsideV2Calldata } = await import(\n \"./shhh/execute-paymaster-raw\"\n );\n\n const oe = buildOutsideExecution({\n nonce: (BigInt(Date.now()) << 24n) | BigInt(Math.floor(Math.random() * 0xffffff)),\n calls,\n caller: ANY_CALLER_FELT,\n });\n\n const chainId = resolveShhhChainId({ baseUrl: client.baseUrl });\n const messageHash = computeOeHash(oe, wallet.publicKey, chainId);\n\n // ec.starkCurve.sign expects a Hex string (0x-prefixed). The\n // V8.4 OE message hash from computeOeHash is a bigint; convert.\n const messageHashHex = \"0x\" + messageHash.toString(16);\n const { r, s } = ec.starkCurve.sign(messageHashHex, sessionPrivateKey);\n\n // 4-felt session signature span: [session_pubkey, r, s, valid_until].\n // The wallet reads sig[0] as session_pubkey, enforces the whitelist\n // + spending policy, and validates (r, s) against session_pubkey\n // via the SNIP-163 component (NOT the primary signer's verifier\n // class). See `sessions-smart-contract/src/account.cairo:387-433`\n // and `shhh-wallet-cairo/src/account.cairo:389-405`.\n const sessionSignature: bigint[] = [\n BigInt(session.publicKey),\n BigInt(r),\n BigInt(s),\n BigInt(session.validUntil),\n ];\n\n const calldata = serializeExecuteFromOutsideV2Calldata({\n outsideExecution: oe,\n signature: sessionSignature,\n });\n\n const response = await client.post<{\n transactionHash?: string;\n id?: string;\n }>({\n endpoint: \"/transactions/execute-sponsored-raw\",\n bearerToken,\n body: {\n accountAddress: wallet.publicKey,\n calldata,\n // Gas budget for the session-sig path is the same as STARK\n // primary (~2M l2_gas). The paymaster's kind-detection\n // branch reads signature[0] == 'V2_SNIP12' to look up the\n // per-kind gas overhead; signature[0] here is the\n // session_pubkey (not the V2_SNIP12 prefix), so the\n // detection falls through to the STARK default — which is\n // correct, since the session verifier is STARK ECDSA.\n signerKind: \"STARK\" as const,\n },\n });\n\n if (!response?.transactionHash) {\n throw new ChipiSessionError(\n \"execute-sponsored-raw response missing transactionHash. Check chipi-back logs for upstream paymaster errors.\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n return response.transactionHash;\n }\n\n // CHIPI v29 path (unchanged).\n const accountClassHash = WALLET_CLASS_HASHES.CHIPI;\n\n // Build the type data via Chipi's backend\n const prepareResponse = await client.post<PrepareTypedDataResponse>({\n endpoint: \"/transactions/prepare-typed-data\",\n bearerToken,\n body: {\n publicKey: wallet.publicKey,\n calls: calls,\n accountClassHash,\n walletType: \"CHIPI\",\n },\n });\n\n // Unwrap the response — backend returns { typedData, walletType } for CHIPI wallets\n if (!prepareResponse || typeof prepareResponse !== \"object\") {\n throw new ChipiSessionError(\n \"Invalid response from /transactions/prepare-typed-data: response is not an object\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n\n let sessionTypedData: TypedData;\n if (\"typedData\" in prepareResponse && (prepareResponse as PrepareTypedDataResponse).typedData) {\n const candidate = (prepareResponse as PrepareTypedDataResponse).typedData;\n if (\n !candidate ||\n typeof candidate !== \"object\" ||\n !(\"types\" in candidate) ||\n !(\"message\" in candidate)\n ) {\n throw new ChipiSessionError(\n \"Invalid response from /transactions/prepare-typed-data: typedData structure is invalid\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n sessionTypedData = candidate;\n } else if (\"types\" in prepareResponse && \"message\" in prepareResponse) {\n sessionTypedData = prepareResponse as unknown as TypedData;\n } else {\n throw new ChipiSessionError(\n \"Invalid response from /transactions/prepare-typed-data: typedData is missing\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n\n // Compute the message hash from typed data\n const msgHash = typedData.getMessageHash(sessionTypedData, wallet.publicKey);\n\n // Sign with session private key using ECDSA\n const { r, s } = ec.starkCurve.sign(msgHash, sessionPrivateKey);\n\n // Build 4-element session signature: [sessionPubKey, r, s, validUntil]\n const sessionSignature = [\n session.publicKey,\n num.toHex(r),\n num.toHex(s),\n num.toHex(session.validUntil),\n ];\n\n // Execute the sponsored transaction via Chipi's paymaster\n const result = await client.post<ExecuteSponsoredTransactionResponse>({\n endpoint: \"/transactions/execute-sponsored-transaction\",\n bearerToken,\n body: {\n publicKey: wallet.publicKey,\n typedData: sessionTypedData,\n // Session signature format - array of 4 hex strings\n userSignature: sessionSignature,\n saveToDatabase: saveToDatabase,\n walletType: \"CHIPI\",\n isSessionSignature: true, // Flag to indicate session signature format\n },\n });\n\n if (!result || typeof result !== \"object\") {\n throw new ChipiSessionError(\n \"Invalid response from /transactions/execute-sponsored-transaction: response is not an object\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n\n if (typeof result.transactionHash !== \"string\" || result.transactionHash.trim().length === 0) {\n const apiMessage =\n typeof (result as any).message === \"string\" ? (result as any).message : undefined;\n console.error(\"[ChipiSDK:Session:Execute] No transaction hash in response\", {\n result,\n });\n throw new ChipiSessionError(\n apiMessage ?? \"Response does not contain transaction hash\",\n SESSION_ERRORS.SESSION_INVALID_RESPONSE\n );\n }\n\n return result.transactionHash;\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n\n // Re-throw ChipiSessionError as-is\n if (error instanceof ChipiSessionError) {\n throw error;\n }\n\n console.error(\"[ChipiSDK:Session:Execute] Unexpected error\", {\n error: err.message,\n walletAddress: wallet.publicKey?.slice(0, 15) + \"...\",\n sessionPubKey: session.publicKey?.slice(0, 15) + \"...\",\n });\n throw error;\n }\n};\n","import type {\n PaymasterAdapter,\n PaymasterAccount,\n PrepareTypedDataResponse,\n ExecuteSponsoredTransactionResponse,\n WalletType,\n} from \"@chipi-stack/types\";\nimport type { Call, TypedData } from \"starknet\";\nimport { WALLET_CLASS_HASHES, getWalletTypeFromClassHash } from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\n\n/**\n * Unwrap the /prepare-typed-data response.\n * Supports both current shape ({ typedData, walletType }) and legacy (raw TypedData).\n */\nfunction unwrapPrepareResponse(response: unknown): {\n typedData: TypedData;\n walletType?: WalletType;\n} {\n if (!response || typeof response !== \"object\") {\n throw new Error(\n \"Invalid response from /transactions/prepare-typed-data: response is not an object\"\n );\n }\n\n // Current shape: { typedData: TypedData, walletType: WalletType }\n if (\"typedData\" in response) {\n const resp = response as PrepareTypedDataResponse;\n if (\n !resp.typedData ||\n typeof resp.typedData !== \"object\" ||\n !(\"types\" in resp.typedData) ||\n !(\"message\" in resp.typedData)\n ) {\n throw new Error(\n \"Invalid response from /transactions/prepare-typed-data: typedData structure is invalid\"\n );\n }\n return { typedData: resp.typedData, walletType: resp.walletType };\n }\n\n // Legacy shape: the response itself is the TypedData\n if (\"types\" in response && \"message\" in response) {\n return { typedData: response as TypedData };\n }\n\n // Possibly an API error shape\n const apiMessage =\n typeof (response as any).message === \"string\" ? (response as any).message : undefined;\n\n throw new Error(\n apiMessage ?? \"Invalid response from /transactions/prepare-typed-data: typedData is missing\"\n );\n}\n\n/**\n * Normalize signature to { r: string, s: string } format.\n * Handles WeierstrassSignatureType ({r, s} as bigint) and ArraySignatureType ([r, s]).\n */\nexport function normalizeSignature(signature: unknown): { r: string; s: string } {\n // ArraySignatureType: string[]\n if (Array.isArray(signature)) {\n if (signature.length < 2) {\n throw new Error(`Array signature must have at least 2 elements, got ${signature.length}`);\n }\n const r = signature[0];\n const s = signature[1];\n if (r == null || s == null) {\n throw new Error(`Signature elements must not be null/undefined. Got r=${r}, s=${s}`);\n }\n return { r: String(r), s: String(s) };\n }\n\n // WeierstrassSignatureType: { r: bigint, s: bigint }\n if (signature && typeof signature === \"object\" && \"r\" in signature && \"s\" in signature) {\n const sig = signature as { r: unknown; s: unknown; recovery?: unknown };\n if (sig.r == null || sig.s == null) {\n throw new Error(`Object signature has null/undefined fields. Got r=${sig.r}, s=${sig.s}`);\n }\n return {\n r: String(sig.r),\n s: String(sig.s),\n };\n }\n\n throw new Error(\"Unrecognized signature format from account.signMessage()\");\n}\n\n/**\n * PaymasterAdapter implementation that uses Chipi's backend API for gasless transactions.\n *\n * Flow:\n * 1. Detect wallet type from on-chain class hash\n * 2. Call /transactions/prepare-typed-data to get TypedData\n * 3. Call account.signMessage(typedData) — triggers wallet popup for external wallets\n * 4. Call /transactions/execute-sponsored-transaction with signature\n * 5. Return transaction hash\n */\nexport class ChipiPaymasterAdapter implements PaymasterAdapter {\n private readonly client: ChipiClient;\n private readonly bearerToken: string;\n\n constructor(client: ChipiClient, bearerToken: string) {\n this.client = client;\n this.bearerToken = bearerToken;\n }\n\n async execute({ account, calls }: { account: PaymasterAccount; calls: Call[] }): Promise<string> {\n // 1. Detect wallet type from on-chain class hash\n const classHash = await account.getClassHashAt(account.address);\n const walletType = getWalletTypeFromClassHash(classHash);\n\n // Use mapped class hash for known types, on-chain hash for custom accounts.\n // The Rust paymaster auto-detects the interface version (V1/V2) from the class,\n // so custom SNIP-9 accounts work without an allowlist.\n const accountClassHash = walletType ? WALLET_CLASS_HASHES[walletType] : classHash;\n\n // 2. Prepare typed data via Chipi's backend\n const prepareResponse = await this.client.post<PrepareTypedDataResponse>({\n endpoint: \"/transactions/prepare-typed-data\",\n bearerToken: this.bearerToken,\n body: {\n publicKey: account.address,\n calls,\n accountClassHash,\n },\n });\n\n // 3. Unwrap response\n const { typedData, walletType: resolvedWalletType } = unwrapPrepareResponse(prepareResponse);\n\n // 4. Sign — triggers wallet popup for Argent X / Braavos\n const signature = await account.signMessage(typedData);\n\n // 5. Normalize signature format\n const normalizedSig = normalizeSignature(signature);\n\n // 6. Execute sponsored transaction\n const result = await this.client.post<ExecuteSponsoredTransactionResponse>({\n endpoint: \"/transactions/execute-sponsored-transaction\",\n bearerToken: this.bearerToken,\n body: {\n publicKey: account.address,\n typedData,\n userSignature: normalizedSig,\n walletType: resolvedWalletType ?? walletType,\n saveToDatabase: true,\n },\n });\n\n if (!result || typeof result !== \"object\") {\n throw new Error(\n \"Invalid response from /transactions/execute-sponsored-transaction: response is not an object\"\n );\n }\n\n const apiMessage =\n typeof (result as any).message === \"string\" ? (result as any).message : undefined;\n\n if (!result.transactionHash) {\n throw new Error(apiMessage ?? \"Response does not contain transaction hash\");\n }\n\n return result.transactionHash;\n }\n}\n","import {\n CallAnyContractParams,\n STARKNET_CONTRACTS,\n WalletData,\n type ExecuteTransactionParams,\n type RecordSendTransactionParams,\n type Transaction,\n type TransferParams,\n type GetTransactionListQuery,\n type PaginatedResponse,\n type TransactionStatusResponse,\n type SyncOnChainTransfersParams,\n type SyncOnChainTransfersResponse,\n} from \"@chipi-stack/types\";\nimport { API_ENDPOINTS, formatAmount } from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\nimport { executePaymasterTransaction } from \"./execute-paymaster-transaction\";\n\n/**\n * Transaction management utilities\n */\nexport class ChipiTransactions {\n constructor(private client: ChipiClient) {}\n /**\n * Execute a gasless transaction using paymaster\n * @internal saveToDatabase - Internal only, not exposed to clients\n */\n async executeTransaction({\n params,\n bearerToken,\n saveToDatabase = true, // Internal only - defaults to true, can be overridden internally\n }: {\n params: ExecuteTransactionParams;\n bearerToken: string;\n saveToDatabase?: boolean; // Internal only - not part of public API\n }): Promise<string> {\n return executePaymasterTransaction({\n params: {\n ...params,\n saveToDatabase,\n },\n bearerToken,\n client: this.client,\n });\n }\n\n /**\n * Transfer tokens\n */\n async transfer({\n params,\n bearerToken,\n }: {\n params: TransferParams;\n bearerToken: string;\n }): Promise<string> {\n const { encryptKey, wallet, token, otherToken, recipient, amount } = params;\n const contract = STARKNET_CONTRACTS[token];\n let contractAddress = contract.contractAddress;\n let decimals = contract.decimals;\n if (token === \"OTHER\") {\n if (!otherToken) {\n throw new Error(\"Other token is required when token is OTHER\");\n }\n contractAddress = otherToken.contractAddress;\n decimals = otherToken.decimals;\n }\n const formattedAmount = formatAmount(amount, decimals);\n return this.executeTransaction({\n params: {\n encryptKey,\n wallet,\n calls: [\n {\n contractAddress,\n entrypoint: \"transfer\",\n calldata: [recipient, formattedAmount, \"0x0\"],\n },\n ],\n },\n bearerToken,\n });\n }\n\n /**\n * Approve token spending\n */\n async approve(params: {\n encryptKey: string;\n wallet: WalletData;\n contractAddress: string;\n spender: string;\n amount: string;\n decimals?: number;\n bearerToken: string;\n }): Promise<string> {\n const formattedAmount = formatAmount(params.amount, params.decimals);\n\n return this.executeTransaction({\n params: {\n encryptKey: params.encryptKey,\n wallet: params.wallet,\n calls: [\n {\n contractAddress: params.contractAddress,\n entrypoint: \"approve\",\n calldata: [params.spender, formattedAmount, \"0x0\"],\n },\n ],\n },\n bearerToken: params.bearerToken,\n });\n }\n\n /**\n * Call any contract method\n */\n // {\n // encryptKey: string;\n // wallet: any;\n // calls: any[];\n // bearerToken: string;\n // }\n\n async callAnyContract({\n params,\n bearerToken,\n }: {\n params: CallAnyContractParams;\n bearerToken: string;\n }): Promise<string> {\n return this.executeTransaction({\n params,\n bearerToken,\n });\n }\n\n /**\n * Record a send transaction\n */\n async recordSendTransaction({\n params,\n bearerToken,\n }: {\n params: RecordSendTransactionParams;\n bearerToken: string;\n }): Promise<Transaction> {\n const response = await this.client.post<Transaction>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/record-send`,\n bearerToken,\n body: params,\n });\n return response;\n }\n\n /**\n * Get paginated transaction history\n */\n async getTransactionList(\n query: GetTransactionListQuery,\n bearerToken: string\n ): Promise<PaginatedResponse<Transaction>> {\n const response = await this.client.get<PaginatedResponse<Transaction>>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/transaction-list`,\n params: query,\n bearerToken,\n });\n return response;\n }\n\n /**\n * Get a single transaction by hash or internal ID\n */\n async getTransaction(hashOrId: string, bearerToken: string): Promise<Transaction> {\n return this.client.get<Transaction>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${hashOrId}`,\n bearerToken,\n });\n }\n\n /**\n * Get on-chain transaction status\n */\n async getTransactionStatus(hash: string, bearerToken: string): Promise<TransactionStatusResponse> {\n return this.client.get<TransactionStatusResponse>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/${hash}/status`,\n bearerToken,\n });\n }\n\n /**\n * Sync on-chain transfers from Voyager into the DB (read-through cache).\n * Discovers transactions not made through the SDK (e.g., external USDC receives).\n * After sync, getTransactionList returns the newly discovered transactions.\n */\n async syncOnChainTransfers(\n params: SyncOnChainTransfersParams,\n bearerToken: string,\n ): Promise<SyncOnChainTransfersResponse> {\n return this.client.post<SyncOnChainTransfersResponse>({\n endpoint: `${API_ENDPOINTS.TRANSACTIONS}/sync-on-chain`,\n bearerToken,\n body: params,\n });\n }\n}\n","import { Currency } from \"@chipi-stack/types\";\nimport { ChipiClient } from \"./client\";\nimport { API_ENDPOINTS } from \"@chipi-stack/shared\";\n\nexport class ChipiExchanges {\n constructor(private client: ChipiClient) {}\n\n async getUsdAmount(\n currencyAmount: number,\n currency: Currency,\n bearerToken: string\n ): Promise<number> {\n return this.client.get<number>({\n endpoint: `${API_ENDPOINTS.EXCHANGES}/usd-amount`,\n bearerToken,\n params: { currencyAmount, currency },\n });\n }\n}\n","import {\n CreateSkuPurchaseParams,\n Transaction,\n STARKNET_CONTRACTS,\n Chain,\n ChainToken,\n CreateSkuPurchaseBody,\n} from \"@chipi-stack/types\";\nimport { ChipiClient } from \"./client\";\nimport { ChipiTransactions } from \"./transactions\";\n\nimport {\n CARRIER_IDS,\n CHAIN_TOKEN_TYPES,\n CHAIN_TYPES,\n SERVICE_TYPES,\n SKU_CONTRACTS,\n formatAmount,\n} from \"@chipi-stack/shared\";\nimport { Call, CallData, cairo, hash } from \"starknet\";\nimport { API_ENDPOINTS } from \"@chipi-stack/shared\";\nimport CryptoES from \"crypto-es\";\nimport { ChipiExchanges } from \"./exchanges\";\n\nexport class ChipiSkuPurchases {\n private transactions: ChipiTransactions;\n private exchanges: ChipiExchanges;\n\n constructor(private client: ChipiClient) {\n this.transactions = new ChipiTransactions(client);\n this.exchanges = new ChipiExchanges(client);\n }\n\n /**\n * Purchase a SKU with gasless execution\n * @param params - Purchase parameters including transaction hash, SKU ID, wallet, etc.\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuPurchaseResponse> - The purchase response with transaction details\n */\n async purchaseSku(params: CreateSkuPurchaseParams, bearerToken: string): Promise<Transaction> {\n const { skuId, skuReference, currencyAmount, currency, chain, token, encryptKey, wallet } =\n params;\n\n if (chain !== Chain.STARKNET) {\n throw new Error(`Unsupported chain for SKU purchases: ${chain}`);\n }\n\n const tokenConfig = STARKNET_CONTRACTS[token];\n if (!tokenConfig?.contractAddress) {\n throw new Error(`Unsupported token for Starknet SKU purchases: ${token}`);\n }\n\n const usdAmount = await this.exchanges.getUsdAmount(currencyAmount, currency, bearerToken);\n const tokenAddress = tokenConfig.contractAddress as `0x${string}`;\n\n if (!Number.isFinite(usdAmount) || usdAmount <= 0) {\n throw new Error(`Invalid USD amount: ${usdAmount}. Amount must be positive.`);\n }\n\n const minUsdAmount = Math.max(usdAmount, 0.000001);\n const parsedAmount = formatAmount(minUsdAmount.toString(), tokenConfig.decimals);\n\n const calls: Call[] = [\n {\n contractAddress: tokenAddress,\n entrypoint: \"approve\",\n calldata: CallData.compile({\n spender: SKU_CONTRACTS.RECHARGER_WITH_STRK_MAINNET,\n amount: cairo.uint256(parsedAmount),\n }),\n },\n {\n contractAddress: SKU_CONTRACTS.RECHARGER_WITH_STRK_MAINNET,\n entrypoint: \"process_recharge\",\n calldata: CallData.compile({\n token: tokenAddress,\n amount: cairo.uint256(parsedAmount),\n recharge_id: CryptoES.SHA256(\n CryptoES.lib.WordArray.random(32) // 32 bytes = 256 bits entropy\n )\n .toString()\n .slice(0, 20),\n product_code: skuId,\n merchant_slug: CARRIER_IDS.CHIPI_PAY,\n }),\n },\n {\n contractAddress: SKU_CONTRACTS.CHIPI_BILL_SERVICE,\n entrypoint: \"mint_item\",\n calldata: CallData.compile({\n recipient: wallet.publicKey,\n metadata: {\n service_type: SERVICE_TYPES.BUY_SERVICE,\n timestamp: Date.now(),\n chipi_user_id: hash.starknetKeccak(wallet.publicKey || \"0x0\").toString(),\n kyc: true,\n amount: cairo.uint256(parsedAmount),\n },\n }),\n },\n ];\n\n const txHash = await this.transactions.executeTransaction({\n params: {\n encryptKey: encryptKey,\n wallet: wallet,\n calls: calls,\n },\n bearerToken: bearerToken,\n saveToDatabase: false,\n });\n\n const body: CreateSkuPurchaseBody = {\n transactionHash: txHash,\n walletAddress: wallet.publicKey,\n skuId: skuId,\n skuReference: skuReference,\n chain: chain,\n token: token,\n currencyAmount: currencyAmount,\n };\n\n // Record the SKU purchase and fetch the purchase result\n const response = await this.client.post<Transaction>({\n endpoint: `${API_ENDPOINTS.SKU_PURCHASES}`,\n bearerToken,\n body,\n });\n\n return response;\n }\n\n /**\n * Get a SKU purchase by id\n * @param id - The SKU purchase id\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuPurchaseResponse> - Single SKU purchase\n */\n async getSkuPurchase(id: string, bearerToken: string): Promise<Transaction> {\n const response = await this.client.get<Transaction>({\n endpoint: `${API_ENDPOINTS.SKU_PURCHASES}/${id}`,\n bearerToken,\n });\n return response;\n }\n}\n"]}
|