@chipi-stack/backend 12.8.0 → 13.1.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
|
@@ -9,7 +9,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
9
9
|
|
|
10
10
|
var CryptoES__default = /*#__PURE__*/_interopDefault(CryptoES);
|
|
11
11
|
|
|
12
|
-
// src/sku-
|
|
12
|
+
// src/sku-purchases.ts
|
|
13
13
|
var decryptPrivateKey = (encryptedPrivateKey, password) => {
|
|
14
14
|
try {
|
|
15
15
|
const bytes = CryptoES__default.default.AES.decrypt(encryptedPrivateKey, password);
|
|
@@ -48,7 +48,7 @@ var executePaymasterTransaction = async ({
|
|
|
48
48
|
wallet.publicKey,
|
|
49
49
|
privateKeyDecrypted
|
|
50
50
|
);
|
|
51
|
-
const
|
|
51
|
+
const { typedData: typedData2, walletType } = await client.post({
|
|
52
52
|
endpoint: "/transactions/prepare-typed-data",
|
|
53
53
|
bearerToken,
|
|
54
54
|
body: {
|
|
@@ -57,15 +57,6 @@ var executePaymasterTransaction = async ({
|
|
|
57
57
|
accountClassHash
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
|
-
let walletType;
|
|
61
|
-
let typedData2;
|
|
62
|
-
if (response.walletType) {
|
|
63
|
-
walletType = response.walletType;
|
|
64
|
-
typedData2 = response.typedData;
|
|
65
|
-
} else {
|
|
66
|
-
typedData2 = response;
|
|
67
|
-
walletType = "READY";
|
|
68
|
-
}
|
|
69
60
|
const userSignature = await account.signMessage(typedData2);
|
|
70
61
|
const result = await client.post({
|
|
71
62
|
endpoint: "/transactions/execute-sponsored-transaction",
|
|
@@ -83,7 +74,6 @@ var executePaymasterTransaction = async ({
|
|
|
83
74
|
}
|
|
84
75
|
});
|
|
85
76
|
if (!result.transactionHash) {
|
|
86
|
-
console.error("result", result);
|
|
87
77
|
throw new Error("The response does not contain the transaction hash");
|
|
88
78
|
}
|
|
89
79
|
return result.transactionHash;
|
|
@@ -215,27 +205,59 @@ var ChipiTransactions = class {
|
|
|
215
205
|
return response;
|
|
216
206
|
}
|
|
217
207
|
};
|
|
218
|
-
var
|
|
208
|
+
var ChipiExchanges = class {
|
|
209
|
+
constructor(client) {
|
|
210
|
+
this.client = client;
|
|
211
|
+
}
|
|
212
|
+
async getUsdAmount(currencyAmount, currency, bearerToken) {
|
|
213
|
+
return this.client.get({
|
|
214
|
+
endpoint: `${shared.API_ENDPOINTS.EXCHANGES}/usd-amount`,
|
|
215
|
+
bearerToken,
|
|
216
|
+
params: { currencyAmount, currency }
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// src/sku-purchases.ts
|
|
222
|
+
var ChipiSkuPurchases = class {
|
|
219
223
|
constructor(client) {
|
|
220
224
|
this.client = client;
|
|
221
225
|
this.transactions = new ChipiTransactions(client);
|
|
226
|
+
this.exchanges = new ChipiExchanges(client);
|
|
222
227
|
}
|
|
223
228
|
/**
|
|
224
|
-
*
|
|
225
|
-
* @param params -
|
|
229
|
+
* Purchase a SKU with gasless execution
|
|
230
|
+
* @param params - Purchase parameters including transaction hash, SKU ID, wallet, etc.
|
|
226
231
|
* @param bearerToken - Authentication token for API calls
|
|
227
|
-
* @returns Promise<
|
|
232
|
+
* @returns Promise<SkuPurchaseResponse> - The purchase response with transaction details
|
|
228
233
|
*/
|
|
229
|
-
async
|
|
230
|
-
const {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
+
async purchaseSku(params, bearerToken) {
|
|
235
|
+
const {
|
|
236
|
+
skuId,
|
|
237
|
+
skuReference,
|
|
238
|
+
currencyAmount,
|
|
239
|
+
currency,
|
|
240
|
+
chain,
|
|
241
|
+
token,
|
|
242
|
+
encryptKey,
|
|
243
|
+
wallet
|
|
244
|
+
} = params;
|
|
245
|
+
const usdAmount = await this.exchanges.getUsdAmount(
|
|
246
|
+
currencyAmount,
|
|
247
|
+
currency,
|
|
248
|
+
bearerToken
|
|
249
|
+
);
|
|
250
|
+
const tokenAddress = types.STARKNET_CONTRACTS[token].contractAddress;
|
|
234
251
|
if (usdAmount <= 0) {
|
|
235
|
-
throw new Error(
|
|
252
|
+
throw new Error(
|
|
253
|
+
`Invalid USD amount: ${usdAmount}. Amount must be positive.`
|
|
254
|
+
);
|
|
236
255
|
}
|
|
237
256
|
const minUsdAmount = Math.max(usdAmount, 1e-6);
|
|
238
|
-
const parsedAmount = shared.formatAmount(
|
|
257
|
+
const parsedAmount = shared.formatAmount(
|
|
258
|
+
minUsdAmount.toString(),
|
|
259
|
+
types.STARKNET_CONTRACTS[token].decimals
|
|
260
|
+
);
|
|
239
261
|
const calls = [
|
|
240
262
|
{
|
|
241
263
|
contractAddress: tokenAddress,
|
|
@@ -267,55 +289,53 @@ var ChipiSkuTransactions = class {
|
|
|
267
289
|
metadata: {
|
|
268
290
|
service_type: shared.SERVICE_TYPES.BUY_SERVICE,
|
|
269
291
|
timestamp: Date.now(),
|
|
270
|
-
chipi_user_id: starknet.hash.starknetKeccak(
|
|
292
|
+
chipi_user_id: starknet.hash.starknetKeccak(wallet.publicKey || "0x0").toString(),
|
|
271
293
|
kyc: true,
|
|
272
294
|
amount: starknet.cairo.uint256(parsedAmount)
|
|
273
295
|
}
|
|
274
296
|
})
|
|
275
297
|
}
|
|
276
298
|
];
|
|
277
|
-
const
|
|
299
|
+
const txHash = await this.transactions.executeTransaction({
|
|
278
300
|
params: {
|
|
279
|
-
encryptKey
|
|
301
|
+
encryptKey,
|
|
280
302
|
wallet,
|
|
281
303
|
calls
|
|
282
304
|
},
|
|
283
305
|
bearerToken,
|
|
284
306
|
saveToDatabase: false
|
|
285
|
-
// Internal: SKU transactions don't save to transactions table
|
|
286
307
|
});
|
|
287
|
-
const
|
|
308
|
+
const body = {
|
|
309
|
+
transactionHash: txHash,
|
|
288
310
|
walletAddress: wallet.publicKey,
|
|
289
311
|
skuId,
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
transactionHash,
|
|
295
|
-
usdAmount: minUsdAmount
|
|
312
|
+
skuReference,
|
|
313
|
+
chain,
|
|
314
|
+
token,
|
|
315
|
+
currencyAmount
|
|
296
316
|
};
|
|
297
317
|
const response = await this.client.post({
|
|
298
|
-
endpoint: `${shared.API_ENDPOINTS.
|
|
318
|
+
endpoint: `${shared.API_ENDPOINTS.SKU_PURCHASES}`,
|
|
299
319
|
bearerToken,
|
|
300
|
-
body
|
|
320
|
+
body
|
|
301
321
|
});
|
|
302
322
|
return response;
|
|
303
323
|
}
|
|
304
324
|
/**
|
|
305
|
-
* Get a SKU
|
|
306
|
-
* @param id - The SKU
|
|
325
|
+
* Get a SKU purchase by id
|
|
326
|
+
* @param id - The SKU purchase id
|
|
307
327
|
* @param bearerToken - Authentication token for API calls
|
|
308
|
-
* @returns Promise<
|
|
328
|
+
* @returns Promise<SkuPurchaseResponse> - Single SKU purchase
|
|
309
329
|
*/
|
|
310
|
-
async
|
|
330
|
+
async getSkuPurchase(id, bearerToken) {
|
|
311
331
|
const response = await this.client.get({
|
|
312
|
-
endpoint: `${shared.API_ENDPOINTS.
|
|
332
|
+
endpoint: `${shared.API_ENDPOINTS.SKU_PURCHASES}/${id}`,
|
|
313
333
|
bearerToken
|
|
314
334
|
});
|
|
315
335
|
return response;
|
|
316
336
|
}
|
|
317
337
|
};
|
|
318
338
|
|
|
319
|
-
exports.
|
|
320
|
-
//# sourceMappingURL=
|
|
321
|
-
//# sourceMappingURL=
|
|
339
|
+
exports.ChipiSkuPurchases = ChipiSkuPurchases;
|
|
340
|
+
//# sourceMappingURL=skuPurchases.js.map
|
|
341
|
+
//# sourceMappingURL=skuPurchases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/encryption.ts","../src/execute-paymaster-transaction.ts","../src/transactions.ts","../src/exchanges.ts","../src/sku-purchases.ts"],"names":["CryptoES","WALLET_RPC_ENDPOINTS","WALLET_CLASS_HASHES","RpcProvider","Account","typedData","STARKNET_CONTRACTS","formatAmount","API_ENDPOINTS","CallData","SKU_CONTRACTS","cairo","CARRIER_IDS","SERVICE_TYPES","hash"],"mappings":"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","file":"skuPurchases.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","import { Currency } from \"@chipi-stack/types\";\nimport { ChipiClient } from \"./client\";\nimport { API_ENDPOINTS } from \"@chipi-stack/shared\";\n\nexport class ChipiExchanges {\n constructor(private client: ChipiClient) {}\n\n async getUsdAmount(\n currencyAmount: number,\n currency: Currency,\n bearerToken: string,\n ): Promise<number> {\n return this.client.get<number>({\n endpoint: `${API_ENDPOINTS.EXCHANGES}/usd-amount`,\n bearerToken,\n params: { currencyAmount, currency },\n });\n }\n}\n","import {\n CreateSkuPurchaseParams,\n Transaction,\n STARKNET_CONTRACTS,\n Chain,\n ChainToken,\n CreateSkuPurchaseBody,\n} from \"@chipi-stack/types\";\nimport { ChipiClient } from \"./client\";\nimport { ChipiTransactions } from \"./transactions\";\n\nimport {\n CARRIER_IDS,\n CHAIN_TOKEN_TYPES,\n CHAIN_TYPES,\n SERVICE_TYPES,\n SKU_CONTRACTS,\n formatAmount,\n} from \"@chipi-stack/shared\";\nimport { Call, CallData, cairo, hash } from \"starknet\";\nimport { API_ENDPOINTS } from \"@chipi-stack/shared\";\nimport CryptoES from \"crypto-es\";\nimport { ChipiExchanges } from \"./exchanges\";\n\nexport class ChipiSkuPurchases {\n private transactions: ChipiTransactions;\n private exchanges: ChipiExchanges;\n\n constructor(private client: ChipiClient) {\n this.transactions = new ChipiTransactions(client);\n this.exchanges = new ChipiExchanges(client);\n }\n\n /**\n * Purchase a SKU with gasless execution\n * @param params - Purchase parameters including transaction hash, SKU ID, wallet, etc.\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuPurchaseResponse> - The purchase response with transaction details\n */\n async purchaseSku(\n params: CreateSkuPurchaseParams,\n bearerToken: string,\n ): Promise<Transaction> {\n const {\n skuId,\n skuReference,\n currencyAmount,\n currency,\n chain,\n token,\n encryptKey,\n wallet,\n } = params;\n\n const usdAmount = await this.exchanges.getUsdAmount(\n currencyAmount,\n currency,\n bearerToken,\n );\n const tokenAddress = STARKNET_CONTRACTS[token]\n .contractAddress as `0x${string}`;\n\n if (usdAmount <= 0) {\n throw new Error(\n `Invalid USD amount: ${usdAmount}. Amount must be positive.`,\n );\n }\n\n const minUsdAmount = Math.max(usdAmount, 0.000001);\n const parsedAmount = formatAmount(\n minUsdAmount.toString(),\n STARKNET_CONTRACTS[token].decimals,\n );\n\n const calls: Call[] = [\n {\n contractAddress: tokenAddress,\n entrypoint: \"approve\",\n calldata: CallData.compile({\n spender: SKU_CONTRACTS.RECHARGER_WITH_STRK_MAINNET,\n amount: cairo.uint256(parsedAmount),\n }),\n },\n {\n contractAddress: SKU_CONTRACTS.RECHARGER_WITH_STRK_MAINNET,\n entrypoint: \"process_recharge\",\n calldata: CallData.compile({\n token: tokenAddress,\n amount: cairo.uint256(parsedAmount),\n recharge_id: CryptoES.SHA256(\n CryptoES.lib.WordArray.random(32), // 32 bytes = 256 bits entropy\n )\n .toString()\n .slice(0, 20),\n product_code: skuId,\n merchant_slug: CARRIER_IDS.CHIPI_PAY,\n }),\n },\n {\n contractAddress: SKU_CONTRACTS.CHIPI_BILL_SERVICE,\n entrypoint: \"mint_item\",\n calldata: CallData.compile({\n recipient: wallet.publicKey,\n metadata: {\n service_type: SERVICE_TYPES.BUY_SERVICE,\n timestamp: Date.now(),\n chipi_user_id: hash\n .starknetKeccak(wallet.publicKey || \"0x0\")\n .toString(),\n kyc: true,\n amount: cairo.uint256(parsedAmount),\n },\n }),\n },\n ];\n\n const txHash = await this.transactions.executeTransaction({\n params: {\n encryptKey: encryptKey,\n wallet: wallet,\n calls: calls,\n },\n bearerToken: bearerToken,\n saveToDatabase: false,\n });\n\n const body: CreateSkuPurchaseBody = {\n transactionHash: txHash,\n walletAddress: wallet.publicKey,\n skuId: skuId,\n skuReference: skuReference,\n chain: chain,\n token: token,\n currencyAmount: currencyAmount,\n };\n\n // Record the SKU purchase and fetch the purchase result\n const response = await this.client.post<Transaction>({\n endpoint: `${API_ENDPOINTS.SKU_PURCHASES}`,\n bearerToken,\n body,\n });\n\n return response;\n }\n\n /**\n * Get a SKU purchase by id\n * @param id - The SKU purchase id\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuPurchaseResponse> - Single SKU purchase\n */\n async getSkuPurchase(id: string, bearerToken: string): Promise<Transaction> {\n const response = await this.client.get<Transaction>({\n endpoint: `${API_ENDPOINTS.SKU_PURCHASES}/${id}`,\n bearerToken,\n });\n return response;\n }\n}\n"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { STARKNET_CONTRACTS } from '@chipi-stack/types';
|
|
2
|
-
import {
|
|
2
|
+
import { formatAmount, SKU_CONTRACTS, CARRIER_IDS, SERVICE_TYPES, API_ENDPOINTS, WALLET_RPC_ENDPOINTS, WALLET_CLASS_HASHES } from '@chipi-stack/shared';
|
|
3
3
|
import { CallData, cairo, hash, RpcProvider, Account } from 'starknet';
|
|
4
4
|
import CryptoES from 'crypto-es';
|
|
5
5
|
|
|
6
|
-
// src/sku-
|
|
6
|
+
// src/sku-purchases.ts
|
|
7
7
|
var decryptPrivateKey = (encryptedPrivateKey, password) => {
|
|
8
8
|
try {
|
|
9
9
|
const bytes = CryptoES.AES.decrypt(encryptedPrivateKey, password);
|
|
@@ -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;
|
|
@@ -209,27 +199,59 @@ var ChipiTransactions = class {
|
|
|
209
199
|
return response;
|
|
210
200
|
}
|
|
211
201
|
};
|
|
212
|
-
var
|
|
202
|
+
var ChipiExchanges = class {
|
|
203
|
+
constructor(client) {
|
|
204
|
+
this.client = client;
|
|
205
|
+
}
|
|
206
|
+
async getUsdAmount(currencyAmount, currency, bearerToken) {
|
|
207
|
+
return this.client.get({
|
|
208
|
+
endpoint: `${API_ENDPOINTS.EXCHANGES}/usd-amount`,
|
|
209
|
+
bearerToken,
|
|
210
|
+
params: { currencyAmount, currency }
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// src/sku-purchases.ts
|
|
216
|
+
var ChipiSkuPurchases = class {
|
|
213
217
|
constructor(client) {
|
|
214
218
|
this.client = client;
|
|
215
219
|
this.transactions = new ChipiTransactions(client);
|
|
220
|
+
this.exchanges = new ChipiExchanges(client);
|
|
216
221
|
}
|
|
217
222
|
/**
|
|
218
|
-
*
|
|
219
|
-
* @param params -
|
|
223
|
+
* Purchase a SKU with gasless execution
|
|
224
|
+
* @param params - Purchase parameters including transaction hash, SKU ID, wallet, etc.
|
|
220
225
|
* @param bearerToken - Authentication token for API calls
|
|
221
|
-
* @returns Promise<
|
|
226
|
+
* @returns Promise<SkuPurchaseResponse> - The purchase response with transaction details
|
|
222
227
|
*/
|
|
223
|
-
async
|
|
224
|
-
const {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
+
async purchaseSku(params, bearerToken) {
|
|
229
|
+
const {
|
|
230
|
+
skuId,
|
|
231
|
+
skuReference,
|
|
232
|
+
currencyAmount,
|
|
233
|
+
currency,
|
|
234
|
+
chain,
|
|
235
|
+
token,
|
|
236
|
+
encryptKey,
|
|
237
|
+
wallet
|
|
238
|
+
} = params;
|
|
239
|
+
const usdAmount = await this.exchanges.getUsdAmount(
|
|
240
|
+
currencyAmount,
|
|
241
|
+
currency,
|
|
242
|
+
bearerToken
|
|
243
|
+
);
|
|
244
|
+
const tokenAddress = STARKNET_CONTRACTS[token].contractAddress;
|
|
228
245
|
if (usdAmount <= 0) {
|
|
229
|
-
throw new Error(
|
|
246
|
+
throw new Error(
|
|
247
|
+
`Invalid USD amount: ${usdAmount}. Amount must be positive.`
|
|
248
|
+
);
|
|
230
249
|
}
|
|
231
250
|
const minUsdAmount = Math.max(usdAmount, 1e-6);
|
|
232
|
-
const parsedAmount = formatAmount(
|
|
251
|
+
const parsedAmount = formatAmount(
|
|
252
|
+
minUsdAmount.toString(),
|
|
253
|
+
STARKNET_CONTRACTS[token].decimals
|
|
254
|
+
);
|
|
233
255
|
const calls = [
|
|
234
256
|
{
|
|
235
257
|
contractAddress: tokenAddress,
|
|
@@ -261,55 +283,53 @@ var ChipiSkuTransactions = class {
|
|
|
261
283
|
metadata: {
|
|
262
284
|
service_type: SERVICE_TYPES.BUY_SERVICE,
|
|
263
285
|
timestamp: Date.now(),
|
|
264
|
-
chipi_user_id: hash.starknetKeccak(
|
|
286
|
+
chipi_user_id: hash.starknetKeccak(wallet.publicKey || "0x0").toString(),
|
|
265
287
|
kyc: true,
|
|
266
288
|
amount: cairo.uint256(parsedAmount)
|
|
267
289
|
}
|
|
268
290
|
})
|
|
269
291
|
}
|
|
270
292
|
];
|
|
271
|
-
const
|
|
293
|
+
const txHash = await this.transactions.executeTransaction({
|
|
272
294
|
params: {
|
|
273
|
-
encryptKey
|
|
295
|
+
encryptKey,
|
|
274
296
|
wallet,
|
|
275
297
|
calls
|
|
276
298
|
},
|
|
277
299
|
bearerToken,
|
|
278
300
|
saveToDatabase: false
|
|
279
|
-
// Internal: SKU transactions don't save to transactions table
|
|
280
301
|
});
|
|
281
|
-
const
|
|
302
|
+
const body = {
|
|
303
|
+
transactionHash: txHash,
|
|
282
304
|
walletAddress: wallet.publicKey,
|
|
283
305
|
skuId,
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
transactionHash,
|
|
289
|
-
usdAmount: minUsdAmount
|
|
306
|
+
skuReference,
|
|
307
|
+
chain,
|
|
308
|
+
token,
|
|
309
|
+
currencyAmount
|
|
290
310
|
};
|
|
291
311
|
const response = await this.client.post({
|
|
292
|
-
endpoint: `${API_ENDPOINTS.
|
|
312
|
+
endpoint: `${API_ENDPOINTS.SKU_PURCHASES}`,
|
|
293
313
|
bearerToken,
|
|
294
|
-
body
|
|
314
|
+
body
|
|
295
315
|
});
|
|
296
316
|
return response;
|
|
297
317
|
}
|
|
298
318
|
/**
|
|
299
|
-
* Get a SKU
|
|
300
|
-
* @param id - The SKU
|
|
319
|
+
* Get a SKU purchase by id
|
|
320
|
+
* @param id - The SKU purchase id
|
|
301
321
|
* @param bearerToken - Authentication token for API calls
|
|
302
|
-
* @returns Promise<
|
|
322
|
+
* @returns Promise<SkuPurchaseResponse> - Single SKU purchase
|
|
303
323
|
*/
|
|
304
|
-
async
|
|
324
|
+
async getSkuPurchase(id, bearerToken) {
|
|
305
325
|
const response = await this.client.get({
|
|
306
|
-
endpoint: `${API_ENDPOINTS.
|
|
326
|
+
endpoint: `${API_ENDPOINTS.SKU_PURCHASES}/${id}`,
|
|
307
327
|
bearerToken
|
|
308
328
|
});
|
|
309
329
|
return response;
|
|
310
330
|
}
|
|
311
331
|
};
|
|
312
332
|
|
|
313
|
-
export {
|
|
314
|
-
//# sourceMappingURL=
|
|
315
|
-
//# sourceMappingURL=
|
|
333
|
+
export { ChipiSkuPurchases };
|
|
334
|
+
//# sourceMappingURL=skuPurchases.mjs.map
|
|
335
|
+
//# sourceMappingURL=skuPurchases.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/encryption.ts","../src/execute-paymaster-transaction.ts","../src/transactions.ts","../src/exchanges.ts","../src/sku-purchases.ts"],"names":["typedData","API_ENDPOINTS","STARKNET_CONTRACTS","formatAmount","CryptoES"],"mappings":"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","file":"skuPurchases.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","import { Currency } from \"@chipi-stack/types\";\nimport { ChipiClient } from \"./client\";\nimport { API_ENDPOINTS } from \"@chipi-stack/shared\";\n\nexport class ChipiExchanges {\n constructor(private client: ChipiClient) {}\n\n async getUsdAmount(\n currencyAmount: number,\n currency: Currency,\n bearerToken: string,\n ): Promise<number> {\n return this.client.get<number>({\n endpoint: `${API_ENDPOINTS.EXCHANGES}/usd-amount`,\n bearerToken,\n params: { currencyAmount, currency },\n });\n }\n}\n","import {\n CreateSkuPurchaseParams,\n Transaction,\n STARKNET_CONTRACTS,\n Chain,\n ChainToken,\n CreateSkuPurchaseBody,\n} from \"@chipi-stack/types\";\nimport { ChipiClient } from \"./client\";\nimport { ChipiTransactions } from \"./transactions\";\n\nimport {\n CARRIER_IDS,\n CHAIN_TOKEN_TYPES,\n CHAIN_TYPES,\n SERVICE_TYPES,\n SKU_CONTRACTS,\n formatAmount,\n} from \"@chipi-stack/shared\";\nimport { Call, CallData, cairo, hash } from \"starknet\";\nimport { API_ENDPOINTS } from \"@chipi-stack/shared\";\nimport CryptoES from \"crypto-es\";\nimport { ChipiExchanges } from \"./exchanges\";\n\nexport class ChipiSkuPurchases {\n private transactions: ChipiTransactions;\n private exchanges: ChipiExchanges;\n\n constructor(private client: ChipiClient) {\n this.transactions = new ChipiTransactions(client);\n this.exchanges = new ChipiExchanges(client);\n }\n\n /**\n * Purchase a SKU with gasless execution\n * @param params - Purchase parameters including transaction hash, SKU ID, wallet, etc.\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuPurchaseResponse> - The purchase response with transaction details\n */\n async purchaseSku(\n params: CreateSkuPurchaseParams,\n bearerToken: string,\n ): Promise<Transaction> {\n const {\n skuId,\n skuReference,\n currencyAmount,\n currency,\n chain,\n token,\n encryptKey,\n wallet,\n } = params;\n\n const usdAmount = await this.exchanges.getUsdAmount(\n currencyAmount,\n currency,\n bearerToken,\n );\n const tokenAddress = STARKNET_CONTRACTS[token]\n .contractAddress as `0x${string}`;\n\n if (usdAmount <= 0) {\n throw new Error(\n `Invalid USD amount: ${usdAmount}. Amount must be positive.`,\n );\n }\n\n const minUsdAmount = Math.max(usdAmount, 0.000001);\n const parsedAmount = formatAmount(\n minUsdAmount.toString(),\n STARKNET_CONTRACTS[token].decimals,\n );\n\n const calls: Call[] = [\n {\n contractAddress: tokenAddress,\n entrypoint: \"approve\",\n calldata: CallData.compile({\n spender: SKU_CONTRACTS.RECHARGER_WITH_STRK_MAINNET,\n amount: cairo.uint256(parsedAmount),\n }),\n },\n {\n contractAddress: SKU_CONTRACTS.RECHARGER_WITH_STRK_MAINNET,\n entrypoint: \"process_recharge\",\n calldata: CallData.compile({\n token: tokenAddress,\n amount: cairo.uint256(parsedAmount),\n recharge_id: CryptoES.SHA256(\n CryptoES.lib.WordArray.random(32), // 32 bytes = 256 bits entropy\n )\n .toString()\n .slice(0, 20),\n product_code: skuId,\n merchant_slug: CARRIER_IDS.CHIPI_PAY,\n }),\n },\n {\n contractAddress: SKU_CONTRACTS.CHIPI_BILL_SERVICE,\n entrypoint: \"mint_item\",\n calldata: CallData.compile({\n recipient: wallet.publicKey,\n metadata: {\n service_type: SERVICE_TYPES.BUY_SERVICE,\n timestamp: Date.now(),\n chipi_user_id: hash\n .starknetKeccak(wallet.publicKey || \"0x0\")\n .toString(),\n kyc: true,\n amount: cairo.uint256(parsedAmount),\n },\n }),\n },\n ];\n\n const txHash = await this.transactions.executeTransaction({\n params: {\n encryptKey: encryptKey,\n wallet: wallet,\n calls: calls,\n },\n bearerToken: bearerToken,\n saveToDatabase: false,\n });\n\n const body: CreateSkuPurchaseBody = {\n transactionHash: txHash,\n walletAddress: wallet.publicKey,\n skuId: skuId,\n skuReference: skuReference,\n chain: chain,\n token: token,\n currencyAmount: currencyAmount,\n };\n\n // Record the SKU purchase and fetch the purchase result\n const response = await this.client.post<Transaction>({\n endpoint: `${API_ENDPOINTS.SKU_PURCHASES}`,\n bearerToken,\n body,\n });\n\n return response;\n }\n\n /**\n * Get a SKU purchase by id\n * @param id - The SKU purchase id\n * @param bearerToken - Authentication token for API calls\n * @returns Promise<SkuPurchaseResponse> - Single SKU purchase\n */\n async getSkuPurchase(id: string, bearerToken: string): Promise<Transaction> {\n const response = await this.client.get<Transaction>({\n endpoint: `${API_ENDPOINTS.SKU_PURCHASES}/${id}`,\n bearerToken,\n });\n return response;\n }\n}\n"]}
|
package/dist/transactions.js
CHANGED
|
@@ -48,7 +48,7 @@ var executePaymasterTransaction = async ({
|
|
|
48
48
|
wallet.publicKey,
|
|
49
49
|
privateKeyDecrypted
|
|
50
50
|
);
|
|
51
|
-
const
|
|
51
|
+
const { typedData: typedData2, walletType } = await client.post({
|
|
52
52
|
endpoint: "/transactions/prepare-typed-data",
|
|
53
53
|
bearerToken,
|
|
54
54
|
body: {
|
|
@@ -57,15 +57,6 @@ var executePaymasterTransaction = async ({
|
|
|
57
57
|
accountClassHash
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
|
-
let walletType;
|
|
61
|
-
let typedData2;
|
|
62
|
-
if (response.walletType) {
|
|
63
|
-
walletType = response.walletType;
|
|
64
|
-
typedData2 = response.typedData;
|
|
65
|
-
} else {
|
|
66
|
-
typedData2 = response;
|
|
67
|
-
walletType = "READY";
|
|
68
|
-
}
|
|
69
60
|
const userSignature = await account.signMessage(typedData2);
|
|
70
61
|
const result = await client.post({
|
|
71
62
|
endpoint: "/transactions/execute-sponsored-transaction",
|
|
@@ -83,7 +74,6 @@ var executePaymasterTransaction = async ({
|
|
|
83
74
|
}
|
|
84
75
|
});
|
|
85
76
|
if (!result.transactionHash) {
|
|
86
|
-
console.error("result", result);
|
|
87
77
|
throw new Error("The response does not contain the transaction hash");
|
|
88
78
|
}
|
|
89
79
|
return result.transactionHash;
|