@teneo-protocol/sdk 3.1.5 → 3.2.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.
Files changed (54) hide show
  1. package/README.md +1 -1
  2. package/dist/core/websocket-client.d.ts +5 -0
  3. package/dist/core/websocket-client.d.ts.map +1 -1
  4. package/dist/core/websocket-client.js +51 -37
  5. package/dist/core/websocket-client.js.map +1 -1
  6. package/dist/handlers/webhook-handler.d.ts.map +1 -1
  7. package/dist/handlers/webhook-handler.js +4 -2
  8. package/dist/handlers/webhook-handler.js.map +1 -1
  9. package/dist/index.d.ts +7 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +12 -3
  12. package/dist/index.js.map +1 -1
  13. package/dist/managers/message-router.d.ts +2 -0
  14. package/dist/managers/message-router.d.ts.map +1 -1
  15. package/dist/managers/message-router.js +9 -2
  16. package/dist/managers/message-router.js.map +1 -1
  17. package/dist/teneo-sdk.d.ts +7 -3
  18. package/dist/teneo-sdk.d.ts.map +1 -1
  19. package/dist/teneo-sdk.js +7 -2
  20. package/dist/teneo-sdk.js.map +1 -1
  21. package/dist/types/config.d.ts +39 -12
  22. package/dist/types/config.d.ts.map +1 -1
  23. package/dist/types/config.js +22 -0
  24. package/dist/types/config.js.map +1 -1
  25. package/dist/types/index.d.ts +1 -1
  26. package/dist/types/index.d.ts.map +1 -1
  27. package/dist/types/index.js +3 -2
  28. package/dist/types/index.js.map +1 -1
  29. package/dist/types/messages.d.ts +65 -6
  30. package/dist/types/messages.d.ts.map +1 -1
  31. package/dist/types/messages.js +29 -8
  32. package/dist/types/messages.js.map +1 -1
  33. package/dist/utils/erc20.d.ts +65 -0
  34. package/dist/utils/erc20.d.ts.map +1 -0
  35. package/dist/utils/erc20.js +116 -0
  36. package/dist/utils/erc20.js.map +1 -0
  37. package/dist/utils/index.d.ts +5 -0
  38. package/dist/utils/index.d.ts.map +1 -1
  39. package/dist/utils/index.js +9 -1
  40. package/dist/utils/index.js.map +1 -1
  41. package/examples/api-key-payment-flow.ts +103 -0
  42. package/package.json +1 -1
  43. package/src/core/websocket-client.ts +60 -39
  44. package/src/handlers/webhook-handler.ts +4 -2
  45. package/src/index.ts +8 -1
  46. package/src/managers/message-router.ts +10 -2
  47. package/src/teneo-sdk.ts +8 -3
  48. package/src/types/config.ts +23 -0
  49. package/src/types/index.ts +1 -0
  50. package/src/types/messages.ts +38 -8
  51. package/src/utils/erc20.test.ts +161 -0
  52. package/src/utils/erc20.ts +125 -0
  53. package/src/utils/index.ts +10 -0
  54. package/tsconfig.json +2 -1
@@ -0,0 +1,125 @@
1
+ /**
2
+ * ERC20 utilities for wallet transaction flows.
3
+ *
4
+ * These helpers let SDK consumers check ERC20 token allowances before sending
5
+ * approval transactions, avoiding unnecessary approvals when allowance is
6
+ * already sufficient.
7
+ */
8
+
9
+ /** The 4-byte function selector for ERC20 approve(address,uint256) */
10
+ export const ERC20_APPROVE_SELECTOR = "0x095ea7b3";
11
+
12
+ /** The 4-byte function selector for ERC20 allowance(address,address) */
13
+ const ERC20_ALLOWANCE_SELECTOR = "0xdd62ed3e";
14
+
15
+ /**
16
+ * Check if a trigger_wallet_tx calldata is an ERC20 approve call.
17
+ * Returns the spender address if it is, or null otherwise.
18
+ *
19
+ * @param data - The calldata hex string from the trigger_wallet_tx
20
+ * @returns The spender address, or null if not an approve call
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * sdk.on("wallet:tx_requested", async (data) => {
25
+ * const approveInfo = parseApproveCalldata(data.tx.data);
26
+ * if (approveInfo) {
27
+ * // This is an ERC20 approve — check allowance first
28
+ * const allowance = await checkERC20Allowance(rpcUrl, data.tx.to, myAddress, approveInfo.spender);
29
+ * if (allowance >= approveInfo.amount) {
30
+ * // Allowance sufficient for requested amount, skip approval
31
+ * await sdk.sendTxResult(data.taskId, "confirmed", undefined, undefined, data.room, data.tx.chainId);
32
+ * return;
33
+ * }
34
+ * }
35
+ * // Proceed with normal tx signing...
36
+ * });
37
+ * ```
38
+ */
39
+ export function parseApproveCalldata(data?: string): { spender: string; amount: bigint } | null {
40
+ if (!data || !data.toLowerCase().startsWith(ERC20_APPROVE_SELECTOR)) {
41
+ return null;
42
+ }
43
+ // approve(address spender, uint256 amount)
44
+ // calldata = 0x095ea7b3 + 32-byte left-padded spender + 32-byte amount
45
+ // Full calldata: "0x" (2) + selector (8) + spender (64) + amount (64) = 138 chars
46
+ if (data.length < 138) return null;
47
+ const spender = "0x" + data.slice(34, 74);
48
+ const amount = BigInt("0x" + data.slice(74, 138));
49
+ return { spender, amount };
50
+ }
51
+
52
+ /**
53
+ * Build the eth_call data for checking ERC20 allowance(owner, spender).
54
+ * Returns the hex-encoded calldata string.
55
+ */
56
+ function buildAllowanceCalldata(owner: string, spender: string): string {
57
+ const ownerHex = owner.toLowerCase().replace("0x", "").padStart(64, "0");
58
+ const spenderHex = spender.toLowerCase().replace("0x", "").padStart(64, "0");
59
+ return ERC20_ALLOWANCE_SELECTOR + ownerHex + spenderHex;
60
+ }
61
+
62
+ /**
63
+ * Check the ERC20 allowance for a token via a JSON-RPC eth_call.
64
+ *
65
+ * This is a standalone utility that works with any JSON-RPC endpoint — it does
66
+ * not require wagmi, viem, or ethers. SDK consumers can use this in their
67
+ * `wallet:tx_requested` handler to skip unnecessary approval transactions.
68
+ *
69
+ * @param rpcUrl - The JSON-RPC endpoint URL for the token's chain
70
+ * @param tokenAddress - The ERC20 token contract address
71
+ * @param owner - The token owner (user's wallet address)
72
+ * @param spender - The spender address (from parseApproveCalldata)
73
+ * @returns The allowance as a bigint
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * const allowance = await checkERC20Allowance(
78
+ * "https://mainnet.base.org",
79
+ * "0xA0b8...USDC",
80
+ * userWallet,
81
+ * spenderAddress
82
+ * );
83
+ * if (allowance >= requiredAmount) {
84
+ * console.log("Sufficient allowance, skipping approval");
85
+ * }
86
+ * ```
87
+ */
88
+ export async function checkERC20Allowance(
89
+ rpcUrl: string,
90
+ tokenAddress: string,
91
+ owner: string,
92
+ spender: string,
93
+ ): Promise<bigint> {
94
+ const calldata = buildAllowanceCalldata(owner, spender);
95
+
96
+ const response = await fetch(rpcUrl, {
97
+ method: "POST",
98
+ headers: { "Content-Type": "application/json" },
99
+ body: JSON.stringify({
100
+ jsonrpc: "2.0",
101
+ id: 1,
102
+ method: "eth_call",
103
+ params: [
104
+ { to: tokenAddress, data: calldata },
105
+ "latest",
106
+ ],
107
+ }),
108
+ });
109
+
110
+ if (!response.ok) {
111
+ throw new Error(`RPC request failed with status ${response.status}`);
112
+ }
113
+
114
+ const result = await response.json() as { result?: string; error?: { message: string } };
115
+
116
+ if (result.error) {
117
+ throw new Error(`RPC error: ${result.error.message}`);
118
+ }
119
+
120
+ if (!result.result || result.result === "0x") {
121
+ return 0n;
122
+ }
123
+
124
+ return BigInt(result.result);
125
+ }
@@ -79,3 +79,13 @@ export {
79
79
  type ResolvedPricing,
80
80
  type PriceResolutionOptions
81
81
  } from "./pricing-resolver";
82
+
83
+ /**
84
+ * ERC20 utilities for wallet transaction flows.
85
+ * Check allowances to skip unnecessary approval transactions.
86
+ */
87
+ export {
88
+ checkERC20Allowance,
89
+ parseApproveCalldata,
90
+ ERC20_APPROVE_SELECTOR
91
+ } from "./erc20";
package/tsconfig.json CHANGED
@@ -25,7 +25,8 @@
25
25
  "strictBindCallApply": true,
26
26
  "strictPropertyInitialization": true,
27
27
  "noImplicitThis": true,
28
- "alwaysStrict": true
28
+ "alwaysStrict": true,
29
+ "types": []
29
30
  },
30
31
  "include": ["src/**/*"],
31
32
  "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]