@chipi-stack/backend 12.7.0 → 13.0.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 +20 -8
- package/dist/index.d.ts +20 -8
- package/dist/index.js +90 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +91 -57
- package/dist/index.mjs.map +1 -1
- package/dist/skuPurchases.d.mts +25 -0
- package/dist/skuPurchases.d.ts +25 -0
- package/dist/{skuTransactions.js → skuPurchases.js} +64 -44
- package/dist/skuPurchases.js.map +1 -0
- package/dist/{skuTransactions.mjs → skuPurchases.mjs} +65 -45
- package/dist/skuPurchases.mjs.map +1 -0
- package/dist/transactions.js +1 -11
- package/dist/transactions.js.map +1 -1
- package/dist/transactions.mjs +1 -11
- package/dist/transactions.mjs.map +1 -1
- package/dist/wallets.js +4 -1
- package/dist/wallets.js.map +1 -1
- package/dist/wallets.mjs +4 -1
- package/dist/wallets.mjs.map +1 -1
- package/package.json +9 -9
- package/dist/skuTransactions.d.mts +0 -24
- package/dist/skuTransactions.d.ts +0 -24
- package/dist/skuTransactions.js.map +0 -1
- package/dist/skuTransactions.mjs.map +0 -1
package/dist/transactions.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/encryption.ts","../src/execute-paymaster-transaction.ts","../src/transactions.ts"],"names":["CryptoES","WALLET_RPC_ENDPOINTS","WALLET_CLASS_HASHES","RpcProvider","Account","typedData","STARKNET_CONTRACTS","formatAmount","API_ENDPOINTS"],"mappings":"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","file":"transactions.js","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (\n privateKey: string,\n password: string\n): string => {\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (\n encryptedPrivateKey: string,\n password: string\n): string => {\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n\n // Check if the decrypted string is empty\n if (!decrypted) throw new Error(\"Decryption failed\");\n\n return decrypted;\n } catch (error) {\n console.error(\"Decryption failed:\", error);\n throw new Error(`Decryption failed: ${error}`);\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\";\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\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 // Select RPC endpoint based on wallet type\n // const rpcUrl =\n // walletType === \"READY\"\n // ? WALLET_RPC_ENDPOINTS.READY\n // : WALLET_RPC_ENDPOINTS.CHIPI;\n const rpcUrl = WALLET_RPC_ENDPOINTS.READY;\n\n // Select class hash based on wallet type\n // const accountClassHash =\n // walletType === \"READY\"\n // ? WALLET_CLASS_HASHES.READY\n // : WALLET_CLASS_HASHES.CHIPI;\n const accountClassHash = WALLET_CLASS_HASHES.READY;\n\n // Decrypt the private key\n const privateKeyDecrypted = decryptPrivateKey(\n wallet.encryptedPrivateKey,\n encryptKey\n );\n\n if (!privateKeyDecrypted) {\n throw new Error(\"Failed to decrypt private key\");\n }\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n const account = new Account(\n provider,\n wallet.publicKey,\n privateKeyDecrypted\n );\n\n // Build the type data via Chipi's backend\n const response = 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 let walletType \n let typedData\n \n if (response.walletType) {\n walletType = response.walletType;\n typedData = response.typedData;\n } else{\n typedData = response;\n walletType = \"READY\";\n }\n \n // Sign the message\n const userSignature = await account.signMessage(typedData as TypedData);\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: {\n r: (userSignature as any).r.toString(),\n s: (userSignature as any).s.toString(),\n recovery: (userSignature as any).recovery,\n },\n saveToDatabase: saveToDatabase,\n walletType:walletType,\n },\n });\n \n if (!result.transactionHash) {\n console.error(\"result\", result);\n throw new Error(\"The response does not contain the 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(\n \"[ChipiSDK:Session:Execute] Invalid wallet type for session execution\",\n {\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 );\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 const sessionPrivateKey = decryptPrivateKey(\n session.encryptedPrivateKey,\n encryptKey\n );\n\n if (!sessionPrivateKey) {\n console.error(\n \"[ChipiSDK:Session:Execute] Failed to decrypt session private key\",\n {\n sessionPubKey: session.publicKey?.slice(0, 15) + \"...\",\n hint: \"Ensure the encryptKey matches the one used when creating the session\",\n }\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 prepareResp = await client.post<TypedData>({\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 // Normalize shape: {typedData} | {typed_data} | flat\n const typeDataResult =\n (prepareResp as any)?.typedData ||\n (prepareResp as any)?.typed_data ||\n prepareResp;\n\n if (\n !typeDataResult ||\n !typeDataResult.message ||\n !typeDataResult.domain ||\n !typeDataResult.types\n ) {\n console.error(\"[ChipiSDK:Session:Execute] Invalid typed data response\", {\n prepareResp,\n });\n throw new Error(\"Invalid typed data response from prepare-typed-data\");\n }\n\n // Compute the message hash from typed data\n const msgHash = typedData.getMessageHash(typeDataResult, 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 typeData: typeDataResult,\n // Session signature format - array of 4 hex strings\n userSignature: sessionSignature,\n saveToDatabase: saveToDatabase,\n walletType: wallet.walletType,\n isSessionSignature: true, // Flag to indicate session signature format\n },\n });\n\n if (!result.transactionHash) {\n console.error(\n \"[ChipiSDK:Session:Execute] No transaction hash in response\",\n {\n result,\n }\n );\n throw new Error(\"Response does not contain transaction hash\");\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} 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/encryption.ts","../src/execute-paymaster-transaction.ts","../src/transactions.ts"],"names":["CryptoES","WALLET_RPC_ENDPOINTS","WALLET_CLASS_HASHES","RpcProvider","Account","typedData","STARKNET_CONTRACTS","formatAmount","API_ENDPOINTS"],"mappings":"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","file":"transactions.js","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (\n privateKey: string,\n password: string\n): string => {\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (\n encryptedPrivateKey: string,\n password: string\n): string => {\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n\n // Check if the decrypted string is empty\n if (!decrypted) throw new Error(\"Decryption failed\");\n\n return decrypted;\n } catch (error) {\n console.error(\"Decryption failed:\", error);\n throw new Error(`Decryption failed: ${error}`);\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\";\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 // Select RPC endpoint based on wallet type\n // const rpcUrl =\n // walletType === \"READY\"\n // ? WALLET_RPC_ENDPOINTS.READY\n // : WALLET_RPC_ENDPOINTS.CHIPI;\n const rpcUrl = WALLET_RPC_ENDPOINTS.READY;\n\n // Select class hash based on wallet type\n // const accountClassHash =\n // walletType === \"READY\"\n // ? WALLET_CLASS_HASHES.READY\n // : WALLET_CLASS_HASHES.CHIPI;\n const accountClassHash = WALLET_CLASS_HASHES.READY;\n\n // Decrypt the private key\n const privateKeyDecrypted = decryptPrivateKey(\n wallet.encryptedPrivateKey,\n encryptKey,\n );\n\n if (!privateKeyDecrypted) {\n throw new Error(\"Failed to decrypt private key\");\n }\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n const account = new Account(\n provider,\n wallet.publicKey,\n privateKeyDecrypted,\n );\n\n // Build the type data via Chipi's backend\n const { typedData, walletType } =\n 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 // Sign the message\n const userSignature = await account.signMessage(typedData);\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: {\n r: (userSignature as any).r.toString(),\n s: (userSignature as any).s.toString(),\n recovery: (userSignature as any).recovery,\n },\n saveToDatabase,\n walletType,\n },\n });\n\n if (!result.transactionHash) {\n throw new Error(\"The response does not contain the 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(\n \"[ChipiSDK:Session:Execute] Invalid wallet type for session execution\",\n {\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 );\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 const sessionPrivateKey = decryptPrivateKey(\n session.encryptedPrivateKey,\n encryptKey,\n );\n\n if (!sessionPrivateKey) {\n console.error(\n \"[ChipiSDK:Session:Execute] Failed to decrypt session private key\",\n {\n sessionPubKey: session.publicKey?.slice(0, 15) + \"...\",\n hint: \"Ensure the encryptKey matches the one used when creating the session\",\n },\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 typeDataResult = await client.post<TypedData>({\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 // Compute the message hash from typed data\n const msgHash = typedData.getMessageHash(typeDataResult, 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 typeData: typeDataResult,\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.transactionHash) {\n console.error(\n \"[ChipiSDK:Session:Execute] No transaction hash in response\",\n {\n result,\n },\n );\n throw new Error(\"Response does not contain transaction hash\");\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} 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"]}
|
package/dist/transactions.mjs
CHANGED
|
@@ -42,7 +42,7 @@ var executePaymasterTransaction = async ({
|
|
|
42
42
|
wallet.publicKey,
|
|
43
43
|
privateKeyDecrypted
|
|
44
44
|
);
|
|
45
|
-
const
|
|
45
|
+
const { typedData: typedData2, walletType } = await client.post({
|
|
46
46
|
endpoint: "/transactions/prepare-typed-data",
|
|
47
47
|
bearerToken,
|
|
48
48
|
body: {
|
|
@@ -51,15 +51,6 @@ var executePaymasterTransaction = async ({
|
|
|
51
51
|
accountClassHash
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
|
-
let walletType;
|
|
55
|
-
let typedData2;
|
|
56
|
-
if (response.walletType) {
|
|
57
|
-
walletType = response.walletType;
|
|
58
|
-
typedData2 = response.typedData;
|
|
59
|
-
} else {
|
|
60
|
-
typedData2 = response;
|
|
61
|
-
walletType = "READY";
|
|
62
|
-
}
|
|
63
54
|
const userSignature = await account.signMessage(typedData2);
|
|
64
55
|
const result = await client.post({
|
|
65
56
|
endpoint: "/transactions/execute-sponsored-transaction",
|
|
@@ -77,7 +68,6 @@ var executePaymasterTransaction = async ({
|
|
|
77
68
|
}
|
|
78
69
|
});
|
|
79
70
|
if (!result.transactionHash) {
|
|
80
|
-
console.error("result", result);
|
|
81
71
|
throw new Error("The response does not contain the transaction hash");
|
|
82
72
|
}
|
|
83
73
|
return result.transactionHash;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/encryption.ts","../src/execute-paymaster-transaction.ts","../src/transactions.ts"],"names":["typedData"],"mappings":"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","file":"transactions.mjs","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (\n privateKey: string,\n password: string\n): string => {\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (\n encryptedPrivateKey: string,\n password: string\n): string => {\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n\n // Check if the decrypted string is empty\n if (!decrypted) throw new Error(\"Decryption failed\");\n\n return decrypted;\n } catch (error) {\n console.error(\"Decryption failed:\", error);\n throw new Error(`Decryption failed: ${error}`);\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\";\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\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 // Select RPC endpoint based on wallet type\n // const rpcUrl =\n // walletType === \"READY\"\n // ? WALLET_RPC_ENDPOINTS.READY\n // : WALLET_RPC_ENDPOINTS.CHIPI;\n const rpcUrl = WALLET_RPC_ENDPOINTS.READY;\n\n // Select class hash based on wallet type\n // const accountClassHash =\n // walletType === \"READY\"\n // ? WALLET_CLASS_HASHES.READY\n // : WALLET_CLASS_HASHES.CHIPI;\n const accountClassHash = WALLET_CLASS_HASHES.READY;\n\n // Decrypt the private key\n const privateKeyDecrypted = decryptPrivateKey(\n wallet.encryptedPrivateKey,\n encryptKey\n );\n\n if (!privateKeyDecrypted) {\n throw new Error(\"Failed to decrypt private key\");\n }\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n const account = new Account(\n provider,\n wallet.publicKey,\n privateKeyDecrypted\n );\n\n // Build the type data via Chipi's backend\n const response = 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 let walletType \n let typedData\n \n if (response.walletType) {\n walletType = response.walletType;\n typedData = response.typedData;\n } else{\n typedData = response;\n walletType = \"READY\";\n }\n \n // Sign the message\n const userSignature = await account.signMessage(typedData as TypedData);\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: {\n r: (userSignature as any).r.toString(),\n s: (userSignature as any).s.toString(),\n recovery: (userSignature as any).recovery,\n },\n saveToDatabase: saveToDatabase,\n walletType:walletType,\n },\n });\n \n if (!result.transactionHash) {\n console.error(\"result\", result);\n throw new Error(\"The response does not contain the 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(\n \"[ChipiSDK:Session:Execute] Invalid wallet type for session execution\",\n {\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 );\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 const sessionPrivateKey = decryptPrivateKey(\n session.encryptedPrivateKey,\n encryptKey\n );\n\n if (!sessionPrivateKey) {\n console.error(\n \"[ChipiSDK:Session:Execute] Failed to decrypt session private key\",\n {\n sessionPubKey: session.publicKey?.slice(0, 15) + \"...\",\n hint: \"Ensure the encryptKey matches the one used when creating the session\",\n }\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 prepareResp = await client.post<TypedData>({\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 // Normalize shape: {typedData} | {typed_data} | flat\n const typeDataResult =\n (prepareResp as any)?.typedData ||\n (prepareResp as any)?.typed_data ||\n prepareResp;\n\n if (\n !typeDataResult ||\n !typeDataResult.message ||\n !typeDataResult.domain ||\n !typeDataResult.types\n ) {\n console.error(\"[ChipiSDK:Session:Execute] Invalid typed data response\", {\n prepareResp,\n });\n throw new Error(\"Invalid typed data response from prepare-typed-data\");\n }\n\n // Compute the message hash from typed data\n const msgHash = typedData.getMessageHash(typeDataResult, 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 typeData: typeDataResult,\n // Session signature format - array of 4 hex strings\n userSignature: sessionSignature,\n saveToDatabase: saveToDatabase,\n walletType: wallet.walletType,\n isSessionSignature: true, // Flag to indicate session signature format\n },\n });\n\n if (!result.transactionHash) {\n console.error(\n \"[ChipiSDK:Session:Execute] No transaction hash in response\",\n {\n result,\n }\n );\n throw new Error(\"Response does not contain transaction hash\");\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} 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"]}
|
|
1
|
+
{"version":3,"sources":["../src/encryption.ts","../src/execute-paymaster-transaction.ts","../src/transactions.ts"],"names":["typedData"],"mappings":"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","file":"transactions.mjs","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (\n privateKey: string,\n password: string\n): string => {\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (\n encryptedPrivateKey: string,\n password: string\n): string => {\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n\n // Check if the decrypted string is empty\n if (!decrypted) throw new Error(\"Decryption failed\");\n\n return decrypted;\n } catch (error) {\n console.error(\"Decryption failed:\", error);\n throw new Error(`Decryption failed: ${error}`);\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\";\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 // Select RPC endpoint based on wallet type\n // const rpcUrl =\n // walletType === \"READY\"\n // ? WALLET_RPC_ENDPOINTS.READY\n // : WALLET_RPC_ENDPOINTS.CHIPI;\n const rpcUrl = WALLET_RPC_ENDPOINTS.READY;\n\n // Select class hash based on wallet type\n // const accountClassHash =\n // walletType === \"READY\"\n // ? WALLET_CLASS_HASHES.READY\n // : WALLET_CLASS_HASHES.CHIPI;\n const accountClassHash = WALLET_CLASS_HASHES.READY;\n\n // Decrypt the private key\n const privateKeyDecrypted = decryptPrivateKey(\n wallet.encryptedPrivateKey,\n encryptKey,\n );\n\n if (!privateKeyDecrypted) {\n throw new Error(\"Failed to decrypt private key\");\n }\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n const account = new Account(\n provider,\n wallet.publicKey,\n privateKeyDecrypted,\n );\n\n // Build the type data via Chipi's backend\n const { typedData, walletType } =\n 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 // Sign the message\n const userSignature = await account.signMessage(typedData);\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: {\n r: (userSignature as any).r.toString(),\n s: (userSignature as any).s.toString(),\n recovery: (userSignature as any).recovery,\n },\n saveToDatabase,\n walletType,\n },\n });\n\n if (!result.transactionHash) {\n throw new Error(\"The response does not contain the 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(\n \"[ChipiSDK:Session:Execute] Invalid wallet type for session execution\",\n {\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 );\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 const sessionPrivateKey = decryptPrivateKey(\n session.encryptedPrivateKey,\n encryptKey,\n );\n\n if (!sessionPrivateKey) {\n console.error(\n \"[ChipiSDK:Session:Execute] Failed to decrypt session private key\",\n {\n sessionPubKey: session.publicKey?.slice(0, 15) + \"...\",\n hint: \"Ensure the encryptKey matches the one used when creating the session\",\n },\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 typeDataResult = await client.post<TypedData>({\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 // Compute the message hash from typed data\n const msgHash = typedData.getMessageHash(typeDataResult, 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 typeData: typeDataResult,\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.transactionHash) {\n console.error(\n \"[ChipiSDK:Session:Execute] No transaction hash in response\",\n {\n result,\n },\n );\n throw new Error(\"Response does not contain transaction hash\");\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} 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"]}
|
package/dist/wallets.js
CHANGED
|
@@ -37,7 +37,8 @@ var ChipiWallets = class {
|
|
|
37
37
|
userId,
|
|
38
38
|
walletType = "CHIPI",
|
|
39
39
|
// Default to CHIPI wallet
|
|
40
|
-
usePasskey
|
|
40
|
+
usePasskey,
|
|
41
|
+
chain
|
|
41
42
|
} = params;
|
|
42
43
|
if (!encryptKey) {
|
|
43
44
|
if (usePasskey) {
|
|
@@ -67,6 +68,7 @@ var ChipiWallets = class {
|
|
|
67
68
|
endpoint: `${shared.API_ENDPOINTS.CHIPI_WALLETS}/prepare-creation`,
|
|
68
69
|
bearerToken,
|
|
69
70
|
body: {
|
|
71
|
+
chain,
|
|
70
72
|
publicKey,
|
|
71
73
|
walletType,
|
|
72
74
|
starkKeyPubAX
|
|
@@ -90,6 +92,7 @@ var ChipiWallets = class {
|
|
|
90
92
|
userId,
|
|
91
93
|
publicKey,
|
|
92
94
|
walletType,
|
|
95
|
+
chain,
|
|
93
96
|
userSignature: {
|
|
94
97
|
r: userSignature.r.toString(),
|
|
95
98
|
s: userSignature.s.toString(),
|
package/dist/wallets.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/encryption.ts","../src/wallets.ts"],"names":["CryptoES","WALLET_RPC_ENDPOINTS","RpcProvider","ec","WALLET_CLASS_HASHES","hash","Account","API_ENDPOINTS","num","ChipiTransactionError","CairoCustomEnum","CairoOption","CairoOptionVariant","CallData","ChipiApiError"],"mappings":"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","file":"wallets.js","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (\n privateKey: string,\n password: string\n): string => {\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (\n encryptedPrivateKey: string,\n password: string\n): string => {\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n\n // Check if the decrypted string is empty\n if (!decrypted) throw new Error(\"Decryption failed\");\n\n return decrypted;\n } catch (error) {\n console.error(\"Decryption failed:\", error);\n throw new Error(`Decryption failed: ${error}`);\n }\n};\n","import type {\n CreateWalletParams,\n CreateWalletResponse,\n PrepareWalletCreationResponse,\n CreateCustodialWalletParams,\n GetWalletParams,\n WalletData,\n GetWalletResponse,\n GetTokenBalanceParams,\n GetTokenBalanceResponse,\n WalletType,\n DeploymentData,\n} from \"@chipi-stack/types\";\nimport {\n API_ENDPOINTS,\n WALLET_CLASS_HASHES,\n WALLET_RPC_ENDPOINTS,\n} from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\nimport CryptoES from \"crypto-es\";\n\nimport { ChipiTransactionError, ChipiApiError } from \"@chipi-stack/shared\";\nimport {\n Account,\n CairoCustomEnum,\n CairoOption,\n CairoOptionVariant,\n CallData,\n ec,\n hash,\n num,\n RpcProvider,\n stark,\n} from \"starknet\";\nimport { encryptPrivateKey } from \"./encryption\";\n\n// Local DeploymentData type (replacing @avnu/gasless-sdk dependency)\n/**\n * Wallet management utilities\n */\nexport class ChipiWallets {\n constructor(private client: ChipiClient) {}\n\n async createWallet(\n params: CreateWalletParams & { bearerToken: string }\n ): Promise<CreateWalletResponse> {\n try {\n const {\n encryptKey,\n externalUserId,\n bearerToken,\n userId,\n walletType = \"CHIPI\", // Default to CHIPI wallet\n usePasskey,\n } = params;\n\n if (!encryptKey) {\n if (usePasskey) {\n throw new Error(\n \"encryptKey is required when using passkey. The passkey authentication should have provided the encryptKey.\"\n );\n }\n throw new Error(\"encryptKey is required for wallet creation\");\n }\n\n // Select RPC endpoint based on wallet type\n const rpcUrl =\n walletType === \"READY\"\n ? WALLET_RPC_ENDPOINTS.READY\n : WALLET_RPC_ENDPOINTS.CHIPI;\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n // Generating the private key with Stark Curve\n const privateKeyAX = this.getPrivateKeyAX();\n const starkKeyPubAX = ec.starkCurve.getStarkKey(privateKeyAX);\n\n // Select class hash based on wallet type\n const accountClassHash =\n walletType === \"READY\"\n ? WALLET_CLASS_HASHES.READY\n : WALLET_CLASS_HASHES.CHIPI;\n\n // Build constructor calldata based on wallet type\n const constructorCallData = this.buildConstructorCallData(\n walletType,\n starkKeyPubAX\n );\n\n // Calculate future address of the account\n const publicKey = hash.calculateContractAddressFromHash(\n starkKeyPubAX,\n accountClassHash,\n constructorCallData,\n 0\n );\n\n // Initiating Account\n const account = new Account(provider, publicKey, privateKeyAX);\n\n const typedDataResponse =\n await this.client.post<PrepareWalletCreationResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/prepare-creation`,\n bearerToken,\n body: {\n publicKey,\n walletType,\n starkKeyPubAX, // Needed for backend to build deployment data\n },\n });\n\n const { typedData, accountClassHash: accountClassHashResponse } =\n typedDataResponse;\n\n const userSignature = await account.signMessage(typedData);\n\n const deploymentData: DeploymentData = {\n class_hash: accountClassHashResponse,\n salt: starkKeyPubAX,\n unique: `${num.toHex(0)}`,\n calldata: constructorCallData.map((value) => num.toHex(value)),\n };\n\n const encryptedPrivateKey = encryptPrivateKey(privateKeyAX, encryptKey);\n\n // Call the API to save the wallet in dashboard\n const executeTransactionResponse =\n await this.client.post<CreateWalletResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}`,\n bearerToken,\n body: {\n externalUserId,\n userId,\n publicKey,\n walletType,\n userSignature: {\n r: (userSignature as any).r.toString(),\n s: (userSignature as any).s.toString(),\n recovery: (userSignature as any).recovery,\n },\n typedData,\n encryptedPrivateKey,\n deploymentData: {\n ...deploymentData,\n salt: `${deploymentData.salt}`,\n calldata: deploymentData.calldata.map((data) => `${data}`),\n },\n },\n });\n\n return executeTransactionResponse;\n } catch (error: unknown) {\n console.error(\"Detailed error:\", error);\n\n if (error instanceof Error && error.message.includes(\"SSL\")) {\n throw new Error(\n \"SSL connection error. Try using NODE_TLS_REJECT_UNAUTHORIZED=0 or verify the RPC URL\"\n );\n }\n throw new ChipiTransactionError(\n `Failed to create wallet: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"WALLET_CREATION_FAILED\"\n );\n }\n }\n\n /**\n * Build constructor calldata based on wallet type\n * - CHIPI: Simple OpenZeppelin account with just public_key\n * - ARGENT: Argent X Account with owner/guardian structure\n */\n private buildConstructorCallData(\n walletType: WalletType,\n starkKeyPubAX: string\n ): string[] {\n if (walletType === \"READY\") {\n // Argent X Account: owner (CairoCustomEnum) + guardian (CairoOption None)\n const axSigner = new CairoCustomEnum({\n Starknet: { pubkey: starkKeyPubAX },\n });\n const axGuardian = new CairoOption<unknown>(CairoOptionVariant.None);\n\n return CallData.compile({\n owner: axSigner,\n guardian: axGuardian,\n });\n }\n\n // ChipiWallet (default): Simple OpenZeppelin account with just public_key\n return CallData.compile({\n public_key: starkKeyPubAX,\n });\n }\n\n /**\n * Create a custodial merchant wallet\n */\n async createCustodialWallet({\n params,\n bearerToken,\n }: {\n params: Omit<CreateCustodialWalletParams, \"orgId\">;\n bearerToken: string;\n }): Promise<WalletData> {\n const response = await this.client.post<WalletData>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/custodial`,\n bearerToken,\n body: params,\n });\n\n return response!;\n }\n\n async getWallet(\n params: GetWalletParams,\n bearerToken: string\n ): Promise<GetWalletResponse | null> {\n try {\n const { externalUserId } = params;\n const getWalletResponse = await this.client.get<GetWalletResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/by-user`,\n params: { externalUserId },\n bearerToken,\n });\n\n return getWalletResponse;\n } catch (err) {\n // Check if it's a 404 error (wallet not found)\n if (err instanceof ChipiApiError && err.status === 404) {\n return null;\n }\n throw new Error(`getWallet error: ${String(err)}`);\n }\n }\n\n getPrivateKeyAX = () => {\n // Generate 32 random bytes (256 bits)\n // const privateKeyBytes = Crypto.getRandomBytes(32); old implementation\n const privateKeyBytes = CryptoES.lib.WordArray.random(32);\n // Convert to hex string and ensure it's 64 characters (32 bytes)\n const privateKey = privateKeyBytes.toString(CryptoES.enc.Hex);\n\n // Add '0x' prefix\n const fullPrivateKey = `0x${privateKey}`;\n\n // Ensure the private key is within Starknet's valid range (0 to 2^251 - 1)\n // Convert to BigInt and take modulo 2^251\n const maxStarknetValue = BigInt(\n \"0x800000000000000000000000000000000000000000000000000000000000000\"\n );\n const privateKeyBigInt = BigInt(fullPrivateKey) % maxStarknetValue;\n\n // Convert back to hex string with '0x' prefix\n return `0x${privateKeyBigInt.toString(16)}`;\n };\n\n async getTokenBalance({\n params,\n bearerToken,\n }: {\n params: GetTokenBalanceParams;\n bearerToken: string;\n }): Promise<GetTokenBalanceResponse> {\n const getBalanceResponse = await this.client.get<GetTokenBalanceResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/token-balance`,\n params,\n bearerToken,\n });\n\n return getBalanceResponse;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/encryption.ts","../src/wallets.ts"],"names":["CryptoES","WALLET_RPC_ENDPOINTS","RpcProvider","ec","WALLET_CLASS_HASHES","hash","Account","API_ENDPOINTS","num","ChipiTransactionError","CairoCustomEnum","CairoOption","CairoOptionVariant","CallData","ChipiApiError"],"mappings":"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","file":"wallets.js","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (\n privateKey: string,\n password: string\n): string => {\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (\n encryptedPrivateKey: string,\n password: string\n): string => {\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n\n // Check if the decrypted string is empty\n if (!decrypted) throw new Error(\"Decryption failed\");\n\n return decrypted;\n } catch (error) {\n console.error(\"Decryption failed:\", error);\n throw new Error(`Decryption failed: ${error}`);\n }\n};\n","import type {\n CreateWalletParams,\n CreateWalletResponse,\n PrepareWalletCreationResponse,\n CreateCustodialWalletParams,\n GetWalletParams,\n WalletData,\n GetWalletResponse,\n GetTokenBalanceParams,\n GetTokenBalanceResponse,\n WalletType,\n DeploymentData,\n} from \"@chipi-stack/types\";\nimport {\n API_ENDPOINTS,\n WALLET_CLASS_HASHES,\n WALLET_RPC_ENDPOINTS,\n} from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\nimport CryptoES from \"crypto-es\";\n\nimport { ChipiTransactionError, ChipiApiError } from \"@chipi-stack/shared\";\nimport {\n Account,\n CairoCustomEnum,\n CairoOption,\n CairoOptionVariant,\n CallData,\n ec,\n hash,\n num,\n RpcProvider,\n stark,\n} from \"starknet\";\nimport { encryptPrivateKey } from \"./encryption\";\n\n// Local DeploymentData type (replacing @avnu/gasless-sdk dependency)\n/**\n * Wallet management utilities\n */\nexport class ChipiWallets {\n constructor(private client: ChipiClient) {}\n\n async createWallet(\n params: CreateWalletParams & { bearerToken: string }\n ): Promise<CreateWalletResponse> {\n try {\n const {\n encryptKey,\n externalUserId,\n bearerToken,\n userId,\n walletType = \"CHIPI\", // Default to CHIPI wallet\n usePasskey,\n chain,\n } = params;\n\n if (!encryptKey) {\n if (usePasskey) {\n throw new Error(\n \"encryptKey is required when using passkey. The passkey authentication should have provided the encryptKey.\"\n );\n }\n throw new Error(\"encryptKey is required for wallet creation\");\n }\n\n // Select RPC endpoint based on wallet type\n const rpcUrl =\n walletType === \"READY\"\n ? WALLET_RPC_ENDPOINTS.READY\n : WALLET_RPC_ENDPOINTS.CHIPI;\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n // Generating the private key with Stark Curve\n const privateKeyAX = this.getPrivateKeyAX();\n const starkKeyPubAX = ec.starkCurve.getStarkKey(privateKeyAX);\n\n // Select class hash based on wallet type\n const accountClassHash =\n walletType === \"READY\"\n ? WALLET_CLASS_HASHES.READY\n : WALLET_CLASS_HASHES.CHIPI;\n\n // Build constructor calldata based on wallet type\n const constructorCallData = this.buildConstructorCallData(\n walletType,\n starkKeyPubAX\n );\n\n // Calculate future address of the account\n const publicKey = hash.calculateContractAddressFromHash(\n starkKeyPubAX,\n accountClassHash,\n constructorCallData,\n 0\n );\n\n // Initiating Account\n const account = new Account(provider, publicKey, privateKeyAX);\n\n const typedDataResponse =\n await this.client.post<PrepareWalletCreationResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/prepare-creation`,\n bearerToken,\n body: {\n chain,\n publicKey,\n walletType,\n starkKeyPubAX, // Needed for backend to build deployment data\n },\n });\n\n const { typedData, accountClassHash: accountClassHashResponse } =\n typedDataResponse;\n\n const userSignature = await account.signMessage(typedData);\n\n const deploymentData: DeploymentData = {\n class_hash: accountClassHashResponse,\n salt: starkKeyPubAX,\n unique: `${num.toHex(0)}`,\n calldata: constructorCallData.map((value) => num.toHex(value)),\n };\n\n const encryptedPrivateKey = encryptPrivateKey(privateKeyAX, encryptKey);\n\n // Call the API to save the wallet in dashboard\n const executeTransactionResponse =\n await this.client.post<CreateWalletResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}`,\n bearerToken,\n body: {\n externalUserId,\n userId,\n publicKey,\n walletType,\n chain,\n userSignature: {\n r: (userSignature as any).r.toString(),\n s: (userSignature as any).s.toString(),\n recovery: (userSignature as any).recovery,\n },\n typedData,\n encryptedPrivateKey,\n deploymentData: {\n ...deploymentData,\n salt: `${deploymentData.salt}`,\n calldata: deploymentData.calldata.map((data) => `${data}`),\n },\n },\n });\n\n return executeTransactionResponse;\n } catch (error: unknown) {\n console.error(\"Detailed error:\", error);\n\n if (error instanceof Error && error.message.includes(\"SSL\")) {\n throw new Error(\n \"SSL connection error. Try using NODE_TLS_REJECT_UNAUTHORIZED=0 or verify the RPC URL\"\n );\n }\n throw new ChipiTransactionError(\n `Failed to create wallet: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"WALLET_CREATION_FAILED\"\n );\n }\n }\n\n /**\n * Build constructor calldata based on wallet type\n * - CHIPI: Simple OpenZeppelin account with just public_key\n * - ARGENT: Argent X Account with owner/guardian structure\n */\n private buildConstructorCallData(\n walletType: WalletType,\n starkKeyPubAX: string\n ): string[] {\n if (walletType === \"READY\") {\n // Argent X Account: owner (CairoCustomEnum) + guardian (CairoOption None)\n const axSigner = new CairoCustomEnum({\n Starknet: { pubkey: starkKeyPubAX },\n });\n const axGuardian = new CairoOption<unknown>(CairoOptionVariant.None);\n\n return CallData.compile({\n owner: axSigner,\n guardian: axGuardian,\n });\n }\n\n // ChipiWallet (default): Simple OpenZeppelin account with just public_key\n return CallData.compile({\n public_key: starkKeyPubAX,\n });\n }\n\n /**\n * Create a custodial merchant wallet\n */\n async createCustodialWallet({\n params,\n bearerToken,\n }: {\n params: Omit<CreateCustodialWalletParams, \"orgId\">;\n bearerToken: string;\n }): Promise<WalletData> {\n const response = await this.client.post<WalletData>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/custodial`,\n bearerToken,\n body: params,\n });\n\n return response!;\n }\n\n async getWallet(\n params: GetWalletParams,\n bearerToken: string\n ): Promise<GetWalletResponse | null> {\n try {\n const { externalUserId } = params;\n const getWalletResponse = await this.client.get<GetWalletResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/by-user`,\n params: { externalUserId },\n bearerToken,\n });\n\n return getWalletResponse;\n } catch (err) {\n // Check if it's a 404 error (wallet not found)\n if (err instanceof ChipiApiError && err.status === 404) {\n return null;\n }\n throw new Error(`getWallet error: ${String(err)}`);\n }\n }\n\n getPrivateKeyAX = () => {\n // Generate 32 random bytes (256 bits)\n // const privateKeyBytes = Crypto.getRandomBytes(32); old implementation\n const privateKeyBytes = CryptoES.lib.WordArray.random(32);\n // Convert to hex string and ensure it's 64 characters (32 bytes)\n const privateKey = privateKeyBytes.toString(CryptoES.enc.Hex);\n\n // Add '0x' prefix\n const fullPrivateKey = `0x${privateKey}`;\n\n // Ensure the private key is within Starknet's valid range (0 to 2^251 - 1)\n // Convert to BigInt and take modulo 2^251\n const maxStarknetValue = BigInt(\n \"0x800000000000000000000000000000000000000000000000000000000000000\"\n );\n const privateKeyBigInt = BigInt(fullPrivateKey) % maxStarknetValue;\n\n // Convert back to hex string with '0x' prefix\n return `0x${privateKeyBigInt.toString(16)}`;\n };\n\n async getTokenBalance({\n params,\n bearerToken,\n }: {\n params: GetTokenBalanceParams;\n bearerToken: string;\n }): Promise<GetTokenBalanceResponse> {\n const getBalanceResponse = await this.client.get<GetTokenBalanceResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/token-balance`,\n params,\n bearerToken,\n });\n\n return getBalanceResponse;\n }\n}\n"]}
|
package/dist/wallets.mjs
CHANGED
|
@@ -31,7 +31,8 @@ var ChipiWallets = class {
|
|
|
31
31
|
userId,
|
|
32
32
|
walletType = "CHIPI",
|
|
33
33
|
// Default to CHIPI wallet
|
|
34
|
-
usePasskey
|
|
34
|
+
usePasskey,
|
|
35
|
+
chain
|
|
35
36
|
} = params;
|
|
36
37
|
if (!encryptKey) {
|
|
37
38
|
if (usePasskey) {
|
|
@@ -61,6 +62,7 @@ var ChipiWallets = class {
|
|
|
61
62
|
endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/prepare-creation`,
|
|
62
63
|
bearerToken,
|
|
63
64
|
body: {
|
|
65
|
+
chain,
|
|
64
66
|
publicKey,
|
|
65
67
|
walletType,
|
|
66
68
|
starkKeyPubAX
|
|
@@ -84,6 +86,7 @@ var ChipiWallets = class {
|
|
|
84
86
|
userId,
|
|
85
87
|
publicKey,
|
|
86
88
|
walletType,
|
|
89
|
+
chain,
|
|
87
90
|
userSignature: {
|
|
88
91
|
r: userSignature.r.toString(),
|
|
89
92
|
s: userSignature.s.toString(),
|
package/dist/wallets.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/encryption.ts","../src/wallets.ts"],"names":["CryptoES"],"mappings":"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","file":"wallets.mjs","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (\n privateKey: string,\n password: string\n): string => {\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (\n encryptedPrivateKey: string,\n password: string\n): string => {\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n\n // Check if the decrypted string is empty\n if (!decrypted) throw new Error(\"Decryption failed\");\n\n return decrypted;\n } catch (error) {\n console.error(\"Decryption failed:\", error);\n throw new Error(`Decryption failed: ${error}`);\n }\n};\n","import type {\n CreateWalletParams,\n CreateWalletResponse,\n PrepareWalletCreationResponse,\n CreateCustodialWalletParams,\n GetWalletParams,\n WalletData,\n GetWalletResponse,\n GetTokenBalanceParams,\n GetTokenBalanceResponse,\n WalletType,\n DeploymentData,\n} from \"@chipi-stack/types\";\nimport {\n API_ENDPOINTS,\n WALLET_CLASS_HASHES,\n WALLET_RPC_ENDPOINTS,\n} from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\nimport CryptoES from \"crypto-es\";\n\nimport { ChipiTransactionError, ChipiApiError } from \"@chipi-stack/shared\";\nimport {\n Account,\n CairoCustomEnum,\n CairoOption,\n CairoOptionVariant,\n CallData,\n ec,\n hash,\n num,\n RpcProvider,\n stark,\n} from \"starknet\";\nimport { encryptPrivateKey } from \"./encryption\";\n\n// Local DeploymentData type (replacing @avnu/gasless-sdk dependency)\n/**\n * Wallet management utilities\n */\nexport class ChipiWallets {\n constructor(private client: ChipiClient) {}\n\n async createWallet(\n params: CreateWalletParams & { bearerToken: string }\n ): Promise<CreateWalletResponse> {\n try {\n const {\n encryptKey,\n externalUserId,\n bearerToken,\n userId,\n walletType = \"CHIPI\", // Default to CHIPI wallet\n usePasskey,\n } = params;\n\n if (!encryptKey) {\n if (usePasskey) {\n throw new Error(\n \"encryptKey is required when using passkey. The passkey authentication should have provided the encryptKey.\"\n );\n }\n throw new Error(\"encryptKey is required for wallet creation\");\n }\n\n // Select RPC endpoint based on wallet type\n const rpcUrl =\n walletType === \"READY\"\n ? WALLET_RPC_ENDPOINTS.READY\n : WALLET_RPC_ENDPOINTS.CHIPI;\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n // Generating the private key with Stark Curve\n const privateKeyAX = this.getPrivateKeyAX();\n const starkKeyPubAX = ec.starkCurve.getStarkKey(privateKeyAX);\n\n // Select class hash based on wallet type\n const accountClassHash =\n walletType === \"READY\"\n ? WALLET_CLASS_HASHES.READY\n : WALLET_CLASS_HASHES.CHIPI;\n\n // Build constructor calldata based on wallet type\n const constructorCallData = this.buildConstructorCallData(\n walletType,\n starkKeyPubAX\n );\n\n // Calculate future address of the account\n const publicKey = hash.calculateContractAddressFromHash(\n starkKeyPubAX,\n accountClassHash,\n constructorCallData,\n 0\n );\n\n // Initiating Account\n const account = new Account(provider, publicKey, privateKeyAX);\n\n const typedDataResponse =\n await this.client.post<PrepareWalletCreationResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/prepare-creation`,\n bearerToken,\n body: {\n publicKey,\n walletType,\n starkKeyPubAX, // Needed for backend to build deployment data\n },\n });\n\n const { typedData, accountClassHash: accountClassHashResponse } =\n typedDataResponse;\n\n const userSignature = await account.signMessage(typedData);\n\n const deploymentData: DeploymentData = {\n class_hash: accountClassHashResponse,\n salt: starkKeyPubAX,\n unique: `${num.toHex(0)}`,\n calldata: constructorCallData.map((value) => num.toHex(value)),\n };\n\n const encryptedPrivateKey = encryptPrivateKey(privateKeyAX, encryptKey);\n\n // Call the API to save the wallet in dashboard\n const executeTransactionResponse =\n await this.client.post<CreateWalletResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}`,\n bearerToken,\n body: {\n externalUserId,\n userId,\n publicKey,\n walletType,\n userSignature: {\n r: (userSignature as any).r.toString(),\n s: (userSignature as any).s.toString(),\n recovery: (userSignature as any).recovery,\n },\n typedData,\n encryptedPrivateKey,\n deploymentData: {\n ...deploymentData,\n salt: `${deploymentData.salt}`,\n calldata: deploymentData.calldata.map((data) => `${data}`),\n },\n },\n });\n\n return executeTransactionResponse;\n } catch (error: unknown) {\n console.error(\"Detailed error:\", error);\n\n if (error instanceof Error && error.message.includes(\"SSL\")) {\n throw new Error(\n \"SSL connection error. Try using NODE_TLS_REJECT_UNAUTHORIZED=0 or verify the RPC URL\"\n );\n }\n throw new ChipiTransactionError(\n `Failed to create wallet: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"WALLET_CREATION_FAILED\"\n );\n }\n }\n\n /**\n * Build constructor calldata based on wallet type\n * - CHIPI: Simple OpenZeppelin account with just public_key\n * - ARGENT: Argent X Account with owner/guardian structure\n */\n private buildConstructorCallData(\n walletType: WalletType,\n starkKeyPubAX: string\n ): string[] {\n if (walletType === \"READY\") {\n // Argent X Account: owner (CairoCustomEnum) + guardian (CairoOption None)\n const axSigner = new CairoCustomEnum({\n Starknet: { pubkey: starkKeyPubAX },\n });\n const axGuardian = new CairoOption<unknown>(CairoOptionVariant.None);\n\n return CallData.compile({\n owner: axSigner,\n guardian: axGuardian,\n });\n }\n\n // ChipiWallet (default): Simple OpenZeppelin account with just public_key\n return CallData.compile({\n public_key: starkKeyPubAX,\n });\n }\n\n /**\n * Create a custodial merchant wallet\n */\n async createCustodialWallet({\n params,\n bearerToken,\n }: {\n params: Omit<CreateCustodialWalletParams, \"orgId\">;\n bearerToken: string;\n }): Promise<WalletData> {\n const response = await this.client.post<WalletData>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/custodial`,\n bearerToken,\n body: params,\n });\n\n return response!;\n }\n\n async getWallet(\n params: GetWalletParams,\n bearerToken: string\n ): Promise<GetWalletResponse | null> {\n try {\n const { externalUserId } = params;\n const getWalletResponse = await this.client.get<GetWalletResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/by-user`,\n params: { externalUserId },\n bearerToken,\n });\n\n return getWalletResponse;\n } catch (err) {\n // Check if it's a 404 error (wallet not found)\n if (err instanceof ChipiApiError && err.status === 404) {\n return null;\n }\n throw new Error(`getWallet error: ${String(err)}`);\n }\n }\n\n getPrivateKeyAX = () => {\n // Generate 32 random bytes (256 bits)\n // const privateKeyBytes = Crypto.getRandomBytes(32); old implementation\n const privateKeyBytes = CryptoES.lib.WordArray.random(32);\n // Convert to hex string and ensure it's 64 characters (32 bytes)\n const privateKey = privateKeyBytes.toString(CryptoES.enc.Hex);\n\n // Add '0x' prefix\n const fullPrivateKey = `0x${privateKey}`;\n\n // Ensure the private key is within Starknet's valid range (0 to 2^251 - 1)\n // Convert to BigInt and take modulo 2^251\n const maxStarknetValue = BigInt(\n \"0x800000000000000000000000000000000000000000000000000000000000000\"\n );\n const privateKeyBigInt = BigInt(fullPrivateKey) % maxStarknetValue;\n\n // Convert back to hex string with '0x' prefix\n return `0x${privateKeyBigInt.toString(16)}`;\n };\n\n async getTokenBalance({\n params,\n bearerToken,\n }: {\n params: GetTokenBalanceParams;\n bearerToken: string;\n }): Promise<GetTokenBalanceResponse> {\n const getBalanceResponse = await this.client.get<GetTokenBalanceResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/token-balance`,\n params,\n bearerToken,\n });\n\n return getBalanceResponse;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/encryption.ts","../src/wallets.ts"],"names":["CryptoES"],"mappings":"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","file":"wallets.mjs","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (\n privateKey: string,\n password: string\n): string => {\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (\n encryptedPrivateKey: string,\n password: string\n): string => {\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n\n // Check if the decrypted string is empty\n if (!decrypted) throw new Error(\"Decryption failed\");\n\n return decrypted;\n } catch (error) {\n console.error(\"Decryption failed:\", error);\n throw new Error(`Decryption failed: ${error}`);\n }\n};\n","import type {\n CreateWalletParams,\n CreateWalletResponse,\n PrepareWalletCreationResponse,\n CreateCustodialWalletParams,\n GetWalletParams,\n WalletData,\n GetWalletResponse,\n GetTokenBalanceParams,\n GetTokenBalanceResponse,\n WalletType,\n DeploymentData,\n} from \"@chipi-stack/types\";\nimport {\n API_ENDPOINTS,\n WALLET_CLASS_HASHES,\n WALLET_RPC_ENDPOINTS,\n} from \"@chipi-stack/shared\";\nimport { ChipiClient } from \"./client\";\nimport CryptoES from \"crypto-es\";\n\nimport { ChipiTransactionError, ChipiApiError } from \"@chipi-stack/shared\";\nimport {\n Account,\n CairoCustomEnum,\n CairoOption,\n CairoOptionVariant,\n CallData,\n ec,\n hash,\n num,\n RpcProvider,\n stark,\n} from \"starknet\";\nimport { encryptPrivateKey } from \"./encryption\";\n\n// Local DeploymentData type (replacing @avnu/gasless-sdk dependency)\n/**\n * Wallet management utilities\n */\nexport class ChipiWallets {\n constructor(private client: ChipiClient) {}\n\n async createWallet(\n params: CreateWalletParams & { bearerToken: string }\n ): Promise<CreateWalletResponse> {\n try {\n const {\n encryptKey,\n externalUserId,\n bearerToken,\n userId,\n walletType = \"CHIPI\", // Default to CHIPI wallet\n usePasskey,\n chain,\n } = params;\n\n if (!encryptKey) {\n if (usePasskey) {\n throw new Error(\n \"encryptKey is required when using passkey. The passkey authentication should have provided the encryptKey.\"\n );\n }\n throw new Error(\"encryptKey is required for wallet creation\");\n }\n\n // Select RPC endpoint based on wallet type\n const rpcUrl =\n walletType === \"READY\"\n ? WALLET_RPC_ENDPOINTS.READY\n : WALLET_RPC_ENDPOINTS.CHIPI;\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n // Generating the private key with Stark Curve\n const privateKeyAX = this.getPrivateKeyAX();\n const starkKeyPubAX = ec.starkCurve.getStarkKey(privateKeyAX);\n\n // Select class hash based on wallet type\n const accountClassHash =\n walletType === \"READY\"\n ? WALLET_CLASS_HASHES.READY\n : WALLET_CLASS_HASHES.CHIPI;\n\n // Build constructor calldata based on wallet type\n const constructorCallData = this.buildConstructorCallData(\n walletType,\n starkKeyPubAX\n );\n\n // Calculate future address of the account\n const publicKey = hash.calculateContractAddressFromHash(\n starkKeyPubAX,\n accountClassHash,\n constructorCallData,\n 0\n );\n\n // Initiating Account\n const account = new Account(provider, publicKey, privateKeyAX);\n\n const typedDataResponse =\n await this.client.post<PrepareWalletCreationResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/prepare-creation`,\n bearerToken,\n body: {\n chain,\n publicKey,\n walletType,\n starkKeyPubAX, // Needed for backend to build deployment data\n },\n });\n\n const { typedData, accountClassHash: accountClassHashResponse } =\n typedDataResponse;\n\n const userSignature = await account.signMessage(typedData);\n\n const deploymentData: DeploymentData = {\n class_hash: accountClassHashResponse,\n salt: starkKeyPubAX,\n unique: `${num.toHex(0)}`,\n calldata: constructorCallData.map((value) => num.toHex(value)),\n };\n\n const encryptedPrivateKey = encryptPrivateKey(privateKeyAX, encryptKey);\n\n // Call the API to save the wallet in dashboard\n const executeTransactionResponse =\n await this.client.post<CreateWalletResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}`,\n bearerToken,\n body: {\n externalUserId,\n userId,\n publicKey,\n walletType,\n chain,\n userSignature: {\n r: (userSignature as any).r.toString(),\n s: (userSignature as any).s.toString(),\n recovery: (userSignature as any).recovery,\n },\n typedData,\n encryptedPrivateKey,\n deploymentData: {\n ...deploymentData,\n salt: `${deploymentData.salt}`,\n calldata: deploymentData.calldata.map((data) => `${data}`),\n },\n },\n });\n\n return executeTransactionResponse;\n } catch (error: unknown) {\n console.error(\"Detailed error:\", error);\n\n if (error instanceof Error && error.message.includes(\"SSL\")) {\n throw new Error(\n \"SSL connection error. Try using NODE_TLS_REJECT_UNAUTHORIZED=0 or verify the RPC URL\"\n );\n }\n throw new ChipiTransactionError(\n `Failed to create wallet: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n \"WALLET_CREATION_FAILED\"\n );\n }\n }\n\n /**\n * Build constructor calldata based on wallet type\n * - CHIPI: Simple OpenZeppelin account with just public_key\n * - ARGENT: Argent X Account with owner/guardian structure\n */\n private buildConstructorCallData(\n walletType: WalletType,\n starkKeyPubAX: string\n ): string[] {\n if (walletType === \"READY\") {\n // Argent X Account: owner (CairoCustomEnum) + guardian (CairoOption None)\n const axSigner = new CairoCustomEnum({\n Starknet: { pubkey: starkKeyPubAX },\n });\n const axGuardian = new CairoOption<unknown>(CairoOptionVariant.None);\n\n return CallData.compile({\n owner: axSigner,\n guardian: axGuardian,\n });\n }\n\n // ChipiWallet (default): Simple OpenZeppelin account with just public_key\n return CallData.compile({\n public_key: starkKeyPubAX,\n });\n }\n\n /**\n * Create a custodial merchant wallet\n */\n async createCustodialWallet({\n params,\n bearerToken,\n }: {\n params: Omit<CreateCustodialWalletParams, \"orgId\">;\n bearerToken: string;\n }): Promise<WalletData> {\n const response = await this.client.post<WalletData>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/custodial`,\n bearerToken,\n body: params,\n });\n\n return response!;\n }\n\n async getWallet(\n params: GetWalletParams,\n bearerToken: string\n ): Promise<GetWalletResponse | null> {\n try {\n const { externalUserId } = params;\n const getWalletResponse = await this.client.get<GetWalletResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/by-user`,\n params: { externalUserId },\n bearerToken,\n });\n\n return getWalletResponse;\n } catch (err) {\n // Check if it's a 404 error (wallet not found)\n if (err instanceof ChipiApiError && err.status === 404) {\n return null;\n }\n throw new Error(`getWallet error: ${String(err)}`);\n }\n }\n\n getPrivateKeyAX = () => {\n // Generate 32 random bytes (256 bits)\n // const privateKeyBytes = Crypto.getRandomBytes(32); old implementation\n const privateKeyBytes = CryptoES.lib.WordArray.random(32);\n // Convert to hex string and ensure it's 64 characters (32 bytes)\n const privateKey = privateKeyBytes.toString(CryptoES.enc.Hex);\n\n // Add '0x' prefix\n const fullPrivateKey = `0x${privateKey}`;\n\n // Ensure the private key is within Starknet's valid range (0 to 2^251 - 1)\n // Convert to BigInt and take modulo 2^251\n const maxStarknetValue = BigInt(\n \"0x800000000000000000000000000000000000000000000000000000000000000\"\n );\n const privateKeyBigInt = BigInt(fullPrivateKey) % maxStarknetValue;\n\n // Convert back to hex string with '0x' prefix\n return `0x${privateKeyBigInt.toString(16)}`;\n };\n\n async getTokenBalance({\n params,\n bearerToken,\n }: {\n params: GetTokenBalanceParams;\n bearerToken: string;\n }): Promise<GetTokenBalanceResponse> {\n const getBalanceResponse = await this.client.get<GetTokenBalanceResponse>({\n endpoint: `${API_ENDPOINTS.CHIPI_WALLETS}/token-balance`,\n params,\n bearerToken,\n });\n\n return getBalanceResponse;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chipi-stack/backend",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0",
|
|
4
4
|
"description": "Chipi Backend SDK - Server utilities for wallet creation, transactions, and SKU management",
|
|
5
5
|
"homepage": "https://github.com/chipi-pay/chipi-sdk",
|
|
6
6
|
"bugs": {
|
|
@@ -54,14 +54,14 @@
|
|
|
54
54
|
"default": "./dist/skus.js"
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
|
-
"./sku-
|
|
57
|
+
"./sku-purchases": {
|
|
58
58
|
"import": {
|
|
59
|
-
"types": "./dist/
|
|
60
|
-
"default": "./dist/
|
|
59
|
+
"types": "./dist/sku-purchases.d.ts",
|
|
60
|
+
"default": "./dist/sku-purchases.mjs"
|
|
61
61
|
},
|
|
62
62
|
"require": {
|
|
63
|
-
"types": "./dist/
|
|
64
|
-
"default": "./dist/
|
|
63
|
+
"types": "./dist/sku-purchases.d.ts",
|
|
64
|
+
"default": "./dist/sku-purchases.js"
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
"./package.json": "./package.json"
|
|
@@ -71,15 +71,15 @@
|
|
|
71
71
|
"dist",
|
|
72
72
|
"wallets",
|
|
73
73
|
"transactions",
|
|
74
|
-
"sku-
|
|
74
|
+
"sku-purchases",
|
|
75
75
|
"skus"
|
|
76
76
|
],
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"@avnu/gasless-sdk": "0.1.8",
|
|
79
79
|
"crypto-es": "^2.1.0",
|
|
80
80
|
"starknet": "6.11.0",
|
|
81
|
-
"@chipi-stack/
|
|
82
|
-
"@chipi-stack/
|
|
81
|
+
"@chipi-stack/types": "^13.0.0",
|
|
82
|
+
"@chipi-stack/shared": "^13.0.0"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
85
|
"@types/node": "^22.15.15",
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { CreateSkuTransactionParams, SkuTransaction } from '@chipi-stack/types';
|
|
2
|
-
import { C as ChipiClient } from './client-43S3tkH3.mjs';
|
|
3
|
-
|
|
4
|
-
declare class ChipiSkuTransactions {
|
|
5
|
-
private client;
|
|
6
|
-
private transactions;
|
|
7
|
-
constructor(client: ChipiClient);
|
|
8
|
-
/**
|
|
9
|
-
* Creates a SKU transaction with gasless execution
|
|
10
|
-
* @param params - Transaction parameters including amount, SKU ID, wallet, etc.
|
|
11
|
-
* @param bearerToken - Authentication token for API calls
|
|
12
|
-
* @returns Promise<SkuTransaction> - The created transaction record
|
|
13
|
-
*/
|
|
14
|
-
createSkuTransaction(params: CreateSkuTransactionParams, bearerToken: string): Promise<SkuTransaction>;
|
|
15
|
-
/**
|
|
16
|
-
* Get a SKU transaction by transaction id
|
|
17
|
-
* @param id - The SKU transaction id
|
|
18
|
-
* @param bearerToken - Authentication token for API calls
|
|
19
|
-
* @returns Promise<SkuTransaction> - Single SKU transaction
|
|
20
|
-
*/
|
|
21
|
-
getSkuTransaction(id: string, bearerToken: string): Promise<SkuTransaction>;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export { ChipiSkuTransactions };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { CreateSkuTransactionParams, SkuTransaction } from '@chipi-stack/types';
|
|
2
|
-
import { C as ChipiClient } from './client-43S3tkH3.js';
|
|
3
|
-
|
|
4
|
-
declare class ChipiSkuTransactions {
|
|
5
|
-
private client;
|
|
6
|
-
private transactions;
|
|
7
|
-
constructor(client: ChipiClient);
|
|
8
|
-
/**
|
|
9
|
-
* Creates a SKU transaction with gasless execution
|
|
10
|
-
* @param params - Transaction parameters including amount, SKU ID, wallet, etc.
|
|
11
|
-
* @param bearerToken - Authentication token for API calls
|
|
12
|
-
* @returns Promise<SkuTransaction> - The created transaction record
|
|
13
|
-
*/
|
|
14
|
-
createSkuTransaction(params: CreateSkuTransactionParams, bearerToken: string): Promise<SkuTransaction>;
|
|
15
|
-
/**
|
|
16
|
-
* Get a SKU transaction by transaction id
|
|
17
|
-
* @param id - The SKU transaction id
|
|
18
|
-
* @param bearerToken - Authentication token for API calls
|
|
19
|
-
* @returns Promise<SkuTransaction> - Single SKU transaction
|
|
20
|
-
*/
|
|
21
|
-
getSkuTransaction(id: string, bearerToken: string): Promise<SkuTransaction>;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export { ChipiSkuTransactions };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/encryption.ts","../src/execute-paymaster-transaction.ts","../src/transactions.ts","../src/sku-transactions.ts"],"names":["CryptoES","WALLET_RPC_ENDPOINTS","WALLET_CLASS_HASHES","RpcProvider","Account","typedData","STARKNET_CONTRACTS","formatAmount","API_ENDPOINTS","getUsdAmount","CallData","SKU_CONTRACTS","cairo","CARRIER_IDS","SERVICE_TYPES","hash","CHAIN_TYPES","CHAIN_TOKEN_TYPES"],"mappings":"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","file":"skuTransactions.js","sourcesContent":["import CryptoES from \"crypto-es\";\n\nexport const encryptPrivateKey = (\n privateKey: string,\n password: string\n): string => {\n return CryptoES.AES.encrypt(privateKey, password).toString();\n};\n\nexport const decryptPrivateKey = (\n encryptedPrivateKey: string,\n password: string\n): string => {\n try {\n const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);\n const decrypted = bytes.toString(CryptoES.enc.Utf8);\n\n // Check if the decrypted string is empty\n if (!decrypted) throw new Error(\"Decryption failed\");\n\n return decrypted;\n } catch (error) {\n console.error(\"Decryption failed:\", error);\n throw new Error(`Decryption failed: ${error}`);\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\";\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\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 // Select RPC endpoint based on wallet type\n // const rpcUrl =\n // walletType === \"READY\"\n // ? WALLET_RPC_ENDPOINTS.READY\n // : WALLET_RPC_ENDPOINTS.CHIPI;\n const rpcUrl = WALLET_RPC_ENDPOINTS.READY;\n\n // Select class hash based on wallet type\n // const accountClassHash =\n // walletType === \"READY\"\n // ? WALLET_CLASS_HASHES.READY\n // : WALLET_CLASS_HASHES.CHIPI;\n const accountClassHash = WALLET_CLASS_HASHES.READY;\n\n // Decrypt the private key\n const privateKeyDecrypted = decryptPrivateKey(\n wallet.encryptedPrivateKey,\n encryptKey\n );\n\n if (!privateKeyDecrypted) {\n throw new Error(\"Failed to decrypt private key\");\n }\n\n const provider = new RpcProvider({ nodeUrl: rpcUrl });\n\n const account = new Account(\n provider,\n wallet.publicKey,\n privateKeyDecrypted\n );\n\n // Build the type data via Chipi's backend\n const response = 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 let walletType \n let typedData\n \n if (response.walletType) {\n walletType = response.walletType;\n typedData = response.typedData;\n } else{\n typedData = response;\n walletType = \"READY\";\n }\n \n // Sign the message\n const userSignature = await account.signMessage(typedData as TypedData);\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: {\n r: (userSignature as any).r.toString(),\n s: (userSignature as any).s.toString(),\n recovery: (userSignature as any).recovery,\n },\n saveToDatabase: saveToDatabase,\n walletType:walletType,\n },\n });\n \n if (!result.transactionHash) {\n console.error(\"result\", result);\n throw new Error(\"The response does not contain the 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(\n \"[ChipiSDK:Session:Execute] Invalid wallet type for session execution\",\n {\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 );\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 const sessionPrivateKey = decryptPrivateKey(\n session.encryptedPrivateKey,\n encryptKey\n );\n\n if (!sessionPrivateKey) {\n console.error(\n \"[ChipiSDK:Session:Execute] Failed to decrypt session private key\",\n {\n sessionPubKey: session.publicKey?.slice(0, 15) + \"...\",\n hint: \"Ensure the encryptKey matches the one used when creating the session\",\n }\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 prepareResp = await client.post<TypedData>({\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 // Normalize shape: {typedData} | {typed_data} | flat\n const typeDataResult =\n (prepareResp as any)?.typedData ||\n (prepareResp as any)?.typed_data ||\n prepareResp;\n\n if (\n !typeDataResult ||\n !typeDataResult.message ||\n !typeDataResult.domain ||\n !typeDataResult.types\n ) {\n console.error(\"[ChipiSDK:Session:Execute] Invalid typed data response\", {\n prepareResp,\n });\n throw new Error(\"Invalid typed data response from prepare-typed-data\");\n }\n\n // Compute the message hash from typed data\n const msgHash = typedData.getMessageHash(typeDataResult, 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 typeData: typeDataResult,\n // Session signature format - array of 4 hex strings\n userSignature: sessionSignature,\n saveToDatabase: saveToDatabase,\n walletType: wallet.walletType,\n isSessionSignature: true, // Flag to indicate session signature format\n },\n });\n\n if (!result.transactionHash) {\n console.error(\n \"[ChipiSDK:Session:Execute] No transaction hash in response\",\n {\n result,\n }\n );\n throw new Error(\"Response does not contain transaction hash\");\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} 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","import { CreateSkuTransactionParams, Sku, SkuTransaction, STARKNET_CONTRACTS } from \"@chipi-stack/types\";\nimport { ChipiClient } from \"./client\";\nimport { ChipiTransactions } from \"./transactions\";\n\nimport { CARRIER_IDS, CHAIN_TOKEN_TYPES, CHAIN_TYPES, SERVICE_TYPES, SKU_CONTRACTS, formatAmount, getUsdAmount } from \"@chipi-stack/shared\";\nimport { Call, CallData, cairo, hash } from \"starknet\";\nimport { API_ENDPOINTS } from \"@chipi-stack/shared\";\nimport CryptoES from \"crypto-es\";\n\nexport class ChipiSkuTransactions {\n private transactions: ChipiTransactions;\n\n constructor(private client: ChipiClient) {\n this.transactions = new ChipiTransactions(client);\n }\n\n\n /**\n * Creates a SKU transaction with gasless execution\n * @param params - Transaction parameters including amount, SKU ID, wallet, etc.\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuTransaction> - The created transaction record\n */\n async createSkuTransaction(params: CreateSkuTransactionParams, bearerToken: string): Promise<SkuTransaction> {\n\n\n const { mxnAmount, skuId, wallet, reference, externalUserId } = params;\n const backendUrl = this.client.baseUrl;\n const usdAmount = await getUsdAmount(mxnAmount, bearerToken, this.client);\n const tokenAddress = STARKNET_CONTRACTS.USDC.contractAddress as `0x${string}`;\n if (usdAmount <= 0) {\n throw new Error(`Invalid USD amount: ${usdAmount}. Amount must be positive.`);\n }\n const minUsdAmount = Math.max(usdAmount, 0.000001);\n const parsedAmount = formatAmount(minUsdAmount.toString(), STARKNET_CONTRACTS.USDC.decimals);\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(externalUserId || \"0x0\").toString(),\n kyc: true,\n amount: cairo.uint256(parsedAmount),\n },\n }),\n },\n ];\n\n const transactionHash = await this.transactions.executeTransaction({\n params: {\n encryptKey: params.encryptKey,\n wallet: wallet,\n calls: calls,\n },\n bearerToken: bearerToken,\n saveToDatabase: false, // Internal: SKU transactions don't save to transactions table\n });\n\n const input = {\n walletAddress: wallet.publicKey,\n skuId: skuId,\n chain: CHAIN_TYPES.STARKNET,\n chainToken: CHAIN_TOKEN_TYPES.USDC,\n mxnAmount: mxnAmount,\n reference: reference,\n transactionHash: transactionHash,\n usdAmount: minUsdAmount,\n }\n // Record the transaction and fetch the purchase of the service \n const response = await this.client.post<SkuTransaction>({\n endpoint: `${API_ENDPOINTS.SKU_TRANSACTIONS}`,\n bearerToken,\n body: input,\n });\n\n return response;\n }\n\n\n\n /**\n * Get a SKU transaction by transaction id\n * @param id - The SKU transaction id\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuTransaction> - Single SKU transaction\n */\n async getSkuTransaction(\n id: string,\n bearerToken: string,\n ): Promise<SkuTransaction> {\n const response = await this.client.get<SkuTransaction>({\n endpoint: `${API_ENDPOINTS.SKU_TRANSACTIONS}/${id}`,\n bearerToken,\n });\n return response;\n }\n\n \n \n}"]}
|