@compass-labs/widgets 0.1.36 → 0.1.37

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.
@@ -93,17 +93,46 @@ function createCompassHandler(config) {
93
93
  return await handleCreditExecute(client, body, config);
94
94
  case "credit/transfer":
95
95
  return await handleCreditTransfer(client, body);
96
+ case "approval/execute":
97
+ return await handleApprovalExecute(body, config);
96
98
  default:
97
99
  return jsonResponse({ error: `Unknown POST route: ${route}` }, 404);
98
100
  }
99
101
  }
100
102
  return jsonResponse({ error: `Method ${method} not allowed` }, 405);
101
103
  } catch (error) {
102
- const message = error instanceof Error ? error.message : "Internal server error";
103
- return jsonResponse({ error: message }, 500);
104
+ const { message, status } = extractErrorMessage(error);
105
+ return jsonResponse({ error: message }, status);
104
106
  }
105
107
  };
106
108
  }
109
+ function extractErrorMessage(error) {
110
+ if (!(error instanceof Error)) {
111
+ return { message: "Something went wrong. Please try again.", status: 500 };
112
+ }
113
+ const raw = error.message || "";
114
+ const jsonMatch = raw.match(/Body:\s*(\{[\s\S]*\})/);
115
+ if (jsonMatch) {
116
+ try {
117
+ const body = JSON.parse(jsonMatch[1]);
118
+ if (Array.isArray(body.detail)) {
119
+ const msgs = body.detail.map((d) => d.msg || d.message).filter(Boolean);
120
+ if (msgs.length > 0) return { message: msgs.join(". "), status: 422 };
121
+ }
122
+ if (typeof body.detail === "string") return { message: body.detail, status: 422 };
123
+ if (typeof body.error === "string") return { message: body.error, status: 500 };
124
+ if (typeof body.description === "string") return { message: body.description, status: 500 };
125
+ } catch {
126
+ }
127
+ }
128
+ if (error.name === "SDKValidationError" || raw.startsWith("Input validation failed")) {
129
+ return { message: "Invalid request data. Please check your inputs and try again.", status: 400 };
130
+ }
131
+ if (raw.includes("Insufficient") || raw.includes("not deployed") || raw.includes("reverted") || raw.includes("not configured") || raw.includes("Unsupported chain")) {
132
+ return { message: raw, status: 500 };
133
+ }
134
+ return { message: "Something went wrong. Please try again.", status: 500 };
135
+ }
107
136
  function jsonResponse(data, status = 200) {
108
137
  return new Response(JSON.stringify(data), {
109
138
  status,
@@ -344,8 +373,53 @@ async function handleTransferApprove(client, body) {
344
373
  throw error;
345
374
  }
346
375
  }
376
+ async function handleApprovalExecute(body, config) {
377
+ const { owner, chain = "base", transaction } = body;
378
+ const { gasSponsorPrivateKey, rpcUrls } = config;
379
+ if (!owner || !transaction) {
380
+ return jsonResponse({ error: "Missing required parameters (owner, transaction)" }, 400);
381
+ }
382
+ if (!gasSponsorPrivateKey) {
383
+ return jsonResponse(
384
+ { error: "Gas sponsor not configured. Set gasSponsorPrivateKey in handler config." },
385
+ 500
386
+ );
387
+ }
388
+ const viemChain = CHAIN_MAP[chain.toLowerCase()];
389
+ if (!viemChain) {
390
+ return jsonResponse({ error: `Unsupported chain: ${chain}` }, 500);
391
+ }
392
+ const rpcUrl = rpcUrls?.[chain.toLowerCase()];
393
+ if (!rpcUrl) {
394
+ return jsonResponse({ error: `No RPC URL configured for chain: ${chain}` }, 500);
395
+ }
396
+ const sponsorAccount = accounts.privateKeyToAccount(gasSponsorPrivateKey);
397
+ const walletClient = viem.createWalletClient({
398
+ account: sponsorAccount,
399
+ chain: viemChain,
400
+ transport: viem.http(rpcUrl)
401
+ });
402
+ const publicClient = viem.createPublicClient({
403
+ chain: viemChain,
404
+ transport: viem.http(rpcUrl)
405
+ });
406
+ const txHash = await walletClient.sendTransaction({
407
+ to: transaction.to,
408
+ data: transaction.data,
409
+ value: transaction.value ? BigInt(transaction.value) : 0n,
410
+ gas: transaction.gas ? BigInt(transaction.gas) : void 0
411
+ });
412
+ const receipt = await publicClient.waitForTransactionReceipt({
413
+ hash: txHash,
414
+ timeout: 6e4
415
+ });
416
+ if (receipt.status === "reverted") {
417
+ return jsonResponse({ error: "Approval transaction reverted" }, 500);
418
+ }
419
+ return jsonResponse({ txHash, status: "success" });
420
+ }
347
421
  async function handleTransferPrepare(client, body, config) {
348
- const { owner, chain = "base", token, amount, action } = body;
422
+ const { owner, chain = "base", token, amount, action, product } = body;
349
423
  const { gasSponsorPrivateKey } = config;
350
424
  if (!owner || !token || !amount || !action) {
351
425
  return jsonResponse({ error: "Missing required parameters" }, 400);
@@ -355,15 +429,28 @@ async function handleTransferPrepare(client, body, config) {
355
429
  const sponsorAccount = accounts.privateKeyToAccount(gasSponsorPrivateKey);
356
430
  spender = sponsorAccount.address;
357
431
  }
358
- const response = await client.earn.earnTransfer({
359
- owner,
360
- chain,
361
- token,
362
- amount,
363
- action,
364
- gasSponsorship: true,
365
- ...spender && { spender }
366
- });
432
+ let response;
433
+ if (product === "credit") {
434
+ response = await client.credit.creditTransfer({
435
+ owner,
436
+ chain,
437
+ token,
438
+ amount,
439
+ action,
440
+ gasSponsorship: true,
441
+ ...spender && { spender }
442
+ });
443
+ } else {
444
+ response = await client.earn.earnTransfer({
445
+ owner,
446
+ chain,
447
+ token,
448
+ amount,
449
+ action,
450
+ gasSponsorship: true,
451
+ ...spender && { spender }
452
+ });
453
+ }
367
454
  const eip712 = response.eip712;
368
455
  if (!eip712) {
369
456
  return jsonResponse({ error: "No EIP-712 data returned from API" }, 500);
@@ -391,7 +478,7 @@ async function handleTransferPrepare(client, body, config) {
391
478
  });
392
479
  }
393
480
  async function handleTransferExecute(client, body, config) {
394
- const { owner, chain = "base", eip712, signature } = body;
481
+ const { owner, chain = "base", eip712, signature, product } = body;
395
482
  const { gasSponsorPrivateKey, rpcUrls } = config;
396
483
  if (!owner || !eip712 || !signature) {
397
484
  return jsonResponse({ error: "Missing required parameters" }, 400);
@@ -420,18 +507,14 @@ async function handleTransferExecute(client, body, config) {
420
507
  chain: viemChain,
421
508
  transport: viem.http(rpcUrl)
422
509
  });
423
- let response;
424
- try {
425
- response = await client.gasSponsorship.gasSponsorshipPrepare({
426
- chain,
427
- owner,
428
- sender: sponsorAccount.address,
429
- eip712,
430
- signature
431
- });
432
- } catch (prepareError) {
433
- throw prepareError;
434
- }
510
+ const response = await client.gasSponsorship.gasSponsorshipPrepare({
511
+ chain,
512
+ owner,
513
+ sender: sponsorAccount.address,
514
+ eip712,
515
+ signature,
516
+ ...product === "credit" && { product: "credit" }
517
+ });
435
518
  const transaction = response.transaction;
436
519
  if (!transaction) {
437
520
  return jsonResponse(
@@ -1362,6 +1445,7 @@ async function handleCreditTransfer(client, body) {
1362
1445
  chain,
1363
1446
  token,
1364
1447
  amount,
1448
+ action: "DEPOSIT",
1365
1449
  gasSponsorship: true
1366
1450
  });
1367
1451
  const eip712 = response.eip712;