@turnkey/gas-station 0.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 (45) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +726 -0
  3. package/dist/abi/gas-station.d.ts +546 -0
  4. package/dist/abi/gas-station.d.ts.map +1 -0
  5. package/dist/abi/gas-station.js +275 -0
  6. package/dist/abi/gas-station.js.map +1 -0
  7. package/dist/abi/gas-station.mjs +273 -0
  8. package/dist/abi/gas-station.mjs.map +1 -0
  9. package/dist/config.d.ts +44 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +57 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/config.mjs +51 -0
  14. package/dist/config.mjs.map +1 -0
  15. package/dist/gasStationClient.d.ts +71 -0
  16. package/dist/gasStationClient.d.ts.map +1 -0
  17. package/dist/gasStationClient.js +237 -0
  18. package/dist/gasStationClient.js.map +1 -0
  19. package/dist/gasStationClient.mjs +235 -0
  20. package/dist/gasStationClient.mjs.map +1 -0
  21. package/dist/gasStationUtils.d.ts +7069 -0
  22. package/dist/gasStationUtils.d.ts.map +1 -0
  23. package/dist/gasStationUtils.js +129 -0
  24. package/dist/gasStationUtils.js.map +1 -0
  25. package/dist/gasStationUtils.mjs +120 -0
  26. package/dist/gasStationUtils.mjs.map +1 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +29 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/index.mjs +6 -0
  32. package/dist/index.mjs.map +1 -0
  33. package/dist/intentBuilder.d.ts +61 -0
  34. package/dist/intentBuilder.d.ts.map +1 -0
  35. package/dist/intentBuilder.js +153 -0
  36. package/dist/intentBuilder.js.map +1 -0
  37. package/dist/intentBuilder.mjs +151 -0
  38. package/dist/intentBuilder.mjs.map +1 -0
  39. package/dist/policyUtils.d.ts +271 -0
  40. package/dist/policyUtils.d.ts.map +1 -0
  41. package/dist/policyUtils.js +387 -0
  42. package/dist/policyUtils.js.map +1 -0
  43. package/dist/policyUtils.mjs +381 -0
  44. package/dist/policyUtils.mjs.map +1 -0
  45. package/package.json +47 -0
@@ -0,0 +1,387 @@
1
+ 'use strict';
2
+
3
+ var gasStation = require('./abi/gas-station.js');
4
+
5
+ // Policy utilities for Turnkey gas station restrictions
6
+ /**
7
+ * Build a Turnkey policy to restrict what EIP-712 intents an EOA can sign
8
+ * This protects at the signing layer - EOA cannot create signatures outside policy
9
+ *
10
+ * @param config - Policy configuration
11
+ * @param config.organizationId - Turnkey organization ID
12
+ * @param config.eoaUserId - Turnkey user ID for the EOA (primary approver)
13
+ * @param config.additionalApprovers - Optional additional user IDs that must also approve (creates AND condition)
14
+ * @param config.customConsensus - Optional custom consensus expression (overrides eoaUserId and additionalApprovers)
15
+ * @param config.restrictions - Signing restrictions
16
+ * @param config.restrictions.allowedContracts - Whitelist of contract addresses EOA can sign intents for
17
+ * @param config.restrictions.disallowEthTransfer - Whether to disallow ETH transfers (if true, ethAmount must be 0)
18
+ * @param config.policyName - Optional policy name
19
+ * @returns Policy object ready to submit to Turnkey createPolicy API
20
+ *
21
+ * @example
22
+ * // Simple: single user approval, token-only transfers
23
+ * const policy = buildIntentSigningPolicy({
24
+ * organizationId: "org-123",
25
+ * eoaUserId: "user-456",
26
+ * restrictions: {
27
+ * allowedContracts: ["0x833...USDC", "0x6B1...DAI"],
28
+ * disallowEthTransfer: true,
29
+ * },
30
+ * policyName: "Stablecoin Only",
31
+ * });
32
+ *
33
+ * // Resulting policy:
34
+ * {
35
+ * organizationId: "org-123",
36
+ * policyName: "Stablecoin Only",
37
+ * effect: "EFFECT_ALLOW",
38
+ * consensus: "approvers.any(user, user.id == 'user-456')",
39
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
40
+ * "eth.eip_712.primary_type == 'Execution' && " +
41
+ * "(eth.eip_712.message['outputContract'] == '0x833...usdc' || " +
42
+ * "eth.eip_712.message['outputContract'] == '0x6b1...dai') && " +
43
+ * "eth.eip_712.message['ethAmount'] == '0'",
44
+ * notes: "Restricts which EIP-712 intents the EOA can sign for gas station execution"
45
+ * }
46
+ *
47
+ * @example
48
+ * // Multi-approval: EOA AND backup user must both approve
49
+ * const policy = buildIntentSigningPolicy({
50
+ * organizationId: "org-123",
51
+ * eoaUserId: "user-456",
52
+ * additionalApprovers: ["backup-user-789"],
53
+ * restrictions: {
54
+ * allowedContracts: ["0x833...USDC"],
55
+ * disallowEthTransfer: true,
56
+ * },
57
+ * });
58
+ *
59
+ * // Resulting policy:
60
+ * {
61
+ * organizationId: "org-123",
62
+ * policyName: "Gas Station Intent Signing Policy",
63
+ * effect: "EFFECT_ALLOW",
64
+ * consensus: "approvers.any(user, user.id == 'user-456') && " +
65
+ * "approvers.any(user, user.id == 'backup-user-789')",
66
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
67
+ * "eth.eip_712.primary_type == 'Execution' && " +
68
+ * "(eth.eip_712.message['outputContract'] == '0x833...usdc') && " +
69
+ * "eth.eip_712.message['ethAmount'] == '0'",
70
+ * notes: "Restricts which EIP-712 intents the EOA can sign for gas station execution"
71
+ * }
72
+ *
73
+ * @example
74
+ * // Advanced: custom consensus expression
75
+ * const policy = buildIntentSigningPolicy({
76
+ * organizationId: "org-123",
77
+ * eoaUserId: "user-456",
78
+ * customConsensus: "approvers.count() >= 2",
79
+ * restrictions: {
80
+ * disallowEthTransfer: false,
81
+ * },
82
+ * });
83
+ *
84
+ * await turnkeyClient.apiClient().createPolicy(policy);
85
+ */
86
+ function buildIntentSigningPolicy(config) {
87
+ const conditions = [
88
+ "activity.resource == 'PRIVATE_KEY'",
89
+ "activity.action == 'SIGN'",
90
+ "eth.eip_712.primary_type == 'Execution'",
91
+ ];
92
+ if (config.restrictions?.allowedContracts &&
93
+ config.restrictions.allowedContracts.length > 0) {
94
+ // Build OR conditions for each allowed contract
95
+ // Convert to lowercase for case-insensitive comparison
96
+ const contractConditions = config.restrictions.allowedContracts
97
+ .map((c) => `eth.eip_712.message['outputContract'] == '${c.toLowerCase()}'`)
98
+ .join(" || ");
99
+ conditions.push(`(${contractConditions})`);
100
+ }
101
+ if (!!config.restrictions?.disallowEthTransfer) {
102
+ conditions.push(`eth.eip_712.message['ethAmount'] == '0'`);
103
+ }
104
+ // Build consensus expression
105
+ let consensus;
106
+ if (config.customConsensus) {
107
+ // Use custom consensus if provided
108
+ consensus = config.customConsensus;
109
+ }
110
+ else if (config.additionalApprovers &&
111
+ config.additionalApprovers.length > 0) {
112
+ // Build multi-user AND condition: eoaUserId AND all additionalApprovers must approve
113
+ const approverConditions = [
114
+ `approvers.any(user, user.id == '${config.eoaUserId}')`,
115
+ ...config.additionalApprovers.map((id) => `approvers.any(user, user.id == '${id}')`),
116
+ ];
117
+ consensus = approverConditions.join(" && ");
118
+ }
119
+ else {
120
+ // Default: only eoaUserId can approve
121
+ consensus = `approvers.any(user, user.id == '${config.eoaUserId}')`;
122
+ }
123
+ return {
124
+ organizationId: config.organizationId,
125
+ policyName: config.policyName || "Gas Station Intent Signing Policy",
126
+ effect: "EFFECT_ALLOW",
127
+ consensus,
128
+ condition: conditions.join(" && "),
129
+ notes: "Restricts which EIP-712 intents the EOA can sign for gas station execution",
130
+ };
131
+ }
132
+ /**
133
+ * Build a Turnkey policy to restrict what the paymaster can execute on-chain.
134
+ * This protects at the execution layer - paymaster cannot submit transactions outside policy.
135
+ *
136
+ * This function uses Turnkey's Smart Contract Interface feature to parse the
137
+ * execute(address _targetEoA, address _to, uint256 ethAmount, bytes _data) ABI.
138
+ * Before using this function, ensure the Gas Station ABI is uploaded via
139
+ * ensureGasStationInterface() - this is typically handled automatically.
140
+ *
141
+ * @param config - Policy configuration
142
+ * @param config.organizationId - Turnkey organization ID
143
+ * @param config.paymasterUserId - Turnkey user ID for the paymaster (primary approver)
144
+ * @param config.additionalApprovers - Optional additional user IDs that can approve (creates OR condition)
145
+ * @param config.customConsensus - Optional custom consensus expression (overrides paymasterUserId and additionalApprovers)
146
+ * @param config.executionContractAddress - Gas station execution contract address
147
+ * @param config.restrictions - Execution restrictions
148
+ * @param config.restrictions.allowedEOAs - Whitelist of EOA addresses paymaster can execute for
149
+ * @param config.restrictions.allowedContracts - Whitelist of output contract addresses (target contracts)
150
+ * @param config.restrictions.maxEthAmount - Maximum ETH amount in wei that can be transferred
151
+ * @param config.restrictions.maxGasPrice - Maximum gas price in wei
152
+ * @param config.restrictions.maxGasLimit - Maximum gas limit
153
+ * @param config.policyName - Optional policy name
154
+ * @returns Policy object ready to submit to Turnkey createPolicy API
155
+ *
156
+ * @example
157
+ * // Simple: single paymaster approval with ETH amount limit
158
+ * const policy = buildPaymasterExecutionPolicy({
159
+ * organizationId: "org-paymaster",
160
+ * paymasterUserId: "paymaster-user-123",
161
+ * executionContractAddress: "0x576A4D741b96996cc93B4919a04c16545734481f",
162
+ * restrictions: {
163
+ * allowedEOAs: ["0xAli...ce", "0xBob...by"],
164
+ * allowedContracts: ["0x833...USDC", "0x6B1...DAI"],
165
+ * maxEthAmount: parseEther("0.1"), // Max 0.1 ETH per transaction
166
+ * maxGasPrice: parseGwei("50"),
167
+ * maxGasLimit: 500000n,
168
+ * },
169
+ * policyName: "Paymaster Protection",
170
+ * });
171
+ *
172
+ * // Resulting policy (uses ABI parsing):
173
+ * {
174
+ * organizationId: "org-paymaster",
175
+ * policyName: "Paymaster Protection",
176
+ * effect: "EFFECT_ALLOW",
177
+ * consensus: "approvers.any(user, user.id == 'paymaster-user-123')",
178
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
179
+ * "eth.tx.to == '0x576a...481f' && " +
180
+ * "(eth.tx.contract_call_args['_to'] == '0x833...usdc' || " +
181
+ * "eth.tx.contract_call_args['_to'] == '0x6b1...dai') && " +
182
+ * "(eth.tx.contract_call_args['_targetEoA'] == '0xali...ce' || " +
183
+ * "eth.tx.contract_call_args['_targetEoA'] == '0xbob...by') && " +
184
+ * "eth.tx.contract_call_args['ethAmount'] <= 100000000000000000 && " +
185
+ * "eth.tx.gasPrice <= 50000000000 && eth.tx.gas <= 500000",
186
+ * notes: "Restricts which execute() transactions the paymaster can submit on-chain"
187
+ * }
188
+ *
189
+ * @example
190
+ * // Multi-user: primary paymaster OR backup can approve
191
+ * const policy = buildPaymasterExecutionPolicy({
192
+ * organizationId: "org-paymaster",
193
+ * paymasterUserId: "paymaster-user-123",
194
+ * additionalApprovers: ["backup-paymaster-456"],
195
+ * executionContractAddress: "0x576A4D741b96996cc93B4919a04c16545734481f",
196
+ * restrictions: {
197
+ * allowedEOAs: ["0xAli...ce"],
198
+ * maxEthAmount: parseEther("1"), // Max 1 ETH
199
+ * maxGasPrice: parseGwei("100"),
200
+ * },
201
+ * });
202
+ *
203
+ * // Resulting policy (uses ABI parsing):
204
+ * {
205
+ * organizationId: "org-paymaster",
206
+ * policyName: "Gas Station Paymaster Execution Policy",
207
+ * effect: "EFFECT_ALLOW",
208
+ * consensus: "approvers.any(user, user.id == 'paymaster-user-123' || " +
209
+ * "user.id == 'backup-paymaster-456')",
210
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
211
+ * "eth.tx.to == '0x576a...481f' && " +
212
+ * "(eth.tx.contract_call_args['_targetEoA'] == '0xali...ce') && " +
213
+ * "eth.tx.contract_call_args['ethAmount'] <= 1000000000000000000 && " +
214
+ * "eth.tx.gasPrice <= 100000000000",
215
+ * notes: "Restricts which execute() transactions the paymaster can submit on-chain"
216
+ * }
217
+ *
218
+ * @example
219
+ * // Advanced: require multiple approvals
220
+ * const policy = buildPaymasterExecutionPolicy({
221
+ * organizationId: "org-paymaster",
222
+ * paymasterUserId: "paymaster-user-123",
223
+ * customConsensus: "approvers.count() >= 2",
224
+ * executionContractAddress: "0x576A4D741b96996cc93B4919a04c16545734481f",
225
+ * restrictions: { ... },
226
+ * });
227
+ *
228
+ * await turnkeyClient.apiClient().createPolicy(policy);
229
+ */
230
+ function buildPaymasterExecutionPolicy(config) {
231
+ const conditions = [
232
+ "activity.resource == 'PRIVATE_KEY'",
233
+ "activity.action == 'SIGN'",
234
+ `eth.tx.to == '${config.executionContractAddress.toLowerCase()}'`,
235
+ ];
236
+ // Check output contract address using ABI parsing
237
+ // Turnkey parses execute(address _targetEoA, address _to, uint256 ethAmount, bytes _data)
238
+ // and exposes arguments via eth.tx.contract_call_args
239
+ if (config.restrictions?.allowedContracts &&
240
+ config.restrictions.allowedContracts.length > 0) {
241
+ const contracts = config.restrictions.allowedContracts
242
+ .map((addr) => {
243
+ const cleanAddr = addr.toLowerCase();
244
+ return `eth.tx.contract_call_args['_to'] == '${cleanAddr}'`;
245
+ })
246
+ .join(" || ");
247
+ conditions.push(`(${contracts})`);
248
+ }
249
+ // Check EOA address using ABI parsing
250
+ if (config.restrictions?.allowedEOAs &&
251
+ config.restrictions.allowedEOAs.length > 0) {
252
+ const eoas = config.restrictions.allowedEOAs
253
+ .map((addr) => {
254
+ const cleanAddr = addr.toLowerCase();
255
+ return `eth.tx.contract_call_args['_target'] == '${cleanAddr}'`;
256
+ })
257
+ .join(" || ");
258
+ conditions.push(`(${eoas})`);
259
+ }
260
+ // Check ETH amount using ABI parsing (direct uint256 comparison)
261
+ if (config.restrictions?.maxEthAmount !== undefined) {
262
+ conditions.push(`eth.tx.contract_call_args['_ethAmount'] <= ${config.restrictions.maxEthAmount}`);
263
+ }
264
+ if (config.restrictions?.maxGasPrice !== undefined) {
265
+ conditions.push(`eth.tx.gasPrice <= ${config.restrictions.maxGasPrice}`);
266
+ }
267
+ if (config.restrictions?.maxGasLimit !== undefined) {
268
+ conditions.push(`eth.tx.gas <= ${config.restrictions.maxGasLimit}`);
269
+ }
270
+ // Build consensus expression
271
+ let consensus;
272
+ if (config.customConsensus) {
273
+ // Use custom consensus if provided
274
+ consensus = config.customConsensus;
275
+ }
276
+ else if (config.additionalApprovers &&
277
+ config.additionalApprovers.length > 0) {
278
+ // Build multi-user AND condition: paymasterUserId AND all additionalApprovers must approve
279
+ const approverConditions = [
280
+ `approvers.any(user, user.id == '${config.paymasterUserId}')`,
281
+ ...config.additionalApprovers.map((id) => `approvers.any(user, user.id == '${id}')`),
282
+ ];
283
+ consensus = approverConditions.join(" && ");
284
+ }
285
+ else {
286
+ // Default: only paymasterUserId can approve
287
+ consensus = `approvers.any(user, user.id == '${config.paymasterUserId}')`;
288
+ }
289
+ return {
290
+ organizationId: config.organizationId,
291
+ policyName: config.policyName || "Gas Station Paymaster Execution Policy",
292
+ effect: "EFFECT_ALLOW",
293
+ consensus,
294
+ condition: conditions.join(" && "),
295
+ notes: "Restricts which execute() transactions the paymaster can submit on-chain",
296
+ };
297
+ }
298
+ /**
299
+ * Retrieves an existing smart contract interface for the given contract address.
300
+ * Returns the interface ID if found, undefined otherwise.
301
+ */
302
+ async function getSmartContractInterface({ client, organizationId, contractAddress, }) {
303
+ // Query Turnkey for existing interfaces
304
+ const response = await client.getSmartContractInterfaces({
305
+ organizationId,
306
+ });
307
+ // Find interface matching the contract address (case-insensitive)
308
+ const normalizedAddress = contractAddress.toLowerCase();
309
+ const existingInterface = response.smartContractInterfaces.find((iface) => iface.smartContractAddress.toLowerCase() === normalizedAddress);
310
+ if (existingInterface) {
311
+ return existingInterface.smartContractInterfaceId;
312
+ }
313
+ return undefined;
314
+ }
315
+ /**
316
+ * Uploads the Gas Station ABI to Turnkey as a Smart Contract Interface.
317
+ * Returns the newly created interface ID.
318
+ */
319
+ async function uploadGasStationInterface({ client, organizationId, contractAddress, label, chainName, }) {
320
+ const defaultLabel = chainName
321
+ ? `Gas Station - ${chainName}`
322
+ : `Gas Station - ${contractAddress}`;
323
+ const result = await client.createSmartContractInterface({
324
+ organizationId,
325
+ type: "SMART_CONTRACT_INTERFACE_TYPE_ETHEREUM",
326
+ label: label || defaultLabel,
327
+ notes: `EIP-7702 Gas Station execution contract ABI. Automatically uploaded by @turnkey/gas-station SDK.`,
328
+ smartContractAddress: contractAddress,
329
+ smartContractInterface: JSON.stringify(gasStation.gasStationAbi),
330
+ });
331
+ const interfaceId = result.activity.result.createSmartContractInterfaceResult
332
+ ?.smartContractInterfaceId;
333
+ if (!interfaceId) {
334
+ throw new Error("Failed to create smart contract interface: no interface ID returned");
335
+ }
336
+ return interfaceId;
337
+ }
338
+ /**
339
+ * Ensures that a Gas Station ABI is registered with Turnkey for the given contract.
340
+ * Checks if an interface already exists; if not, uploads it automatically.
341
+ * Returns the interface ID (existing or newly created).
342
+ *
343
+ * This function is called automatically by policy builders to enable ABI-based
344
+ * policy conditions that can directly access and compare function arguments.
345
+ *
346
+ * @param client - Turnkey API client (from turnkeySDK.apiClient())
347
+ * @param organizationId - Turnkey organization ID
348
+ * @param contractAddress - Gas station contract address
349
+ * @param label - Optional custom label for the interface
350
+ * @param chainName - Optional chain name for labeling (e.g., "Base Mainnet")
351
+ * @returns The smart contract interface ID
352
+ *
353
+ * @example
354
+ * const interfaceId = await ensureGasStationInterface(
355
+ * turnkeyClient.apiClient(),
356
+ * "org-123",
357
+ * "0x576A4D741b96996cc93B4919a04c16545734481f",
358
+ * undefined,
359
+ * "Base Sepolia"
360
+ * );
361
+ */
362
+ async function ensureGasStationInterface({ client, organizationId, contractAddress, label, chainName, }) {
363
+ // Check if interface already exists
364
+ const existingId = await getSmartContractInterface({
365
+ client,
366
+ organizationId,
367
+ contractAddress,
368
+ });
369
+ if (existingId) {
370
+ return existingId;
371
+ }
372
+ // Upload new interface
373
+ return uploadGasStationInterface({
374
+ client,
375
+ organizationId,
376
+ contractAddress,
377
+ label: label || "",
378
+ chainName: chainName || "",
379
+ });
380
+ }
381
+
382
+ exports.buildIntentSigningPolicy = buildIntentSigningPolicy;
383
+ exports.buildPaymasterExecutionPolicy = buildPaymasterExecutionPolicy;
384
+ exports.ensureGasStationInterface = ensureGasStationInterface;
385
+ exports.getSmartContractInterface = getSmartContractInterface;
386
+ exports.uploadGasStationInterface = uploadGasStationInterface;
387
+ //# sourceMappingURL=policyUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policyUtils.js","sources":["../src/policyUtils.ts"],"sourcesContent":[null],"names":["gasStationAbi"],"mappings":"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"}