@0xkey-io/gas-station 0.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.
Files changed (51) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +655 -0
  3. package/dist/abi/gas-station.d.ts +500 -0
  4. package/dist/abi/gas-station.d.ts.map +1 -0
  5. package/dist/abi/gas-station.js +252 -0
  6. package/dist/abi/gas-station.js.map +1 -0
  7. package/dist/abi/gas-station.mjs +250 -0
  8. package/dist/abi/gas-station.mjs.map +1 -0
  9. package/dist/abi/reimbursable-gas-station.d.ts +756 -0
  10. package/dist/abi/reimbursable-gas-station.d.ts.map +1 -0
  11. package/dist/abi/reimbursable-gas-station.js +625 -0
  12. package/dist/abi/reimbursable-gas-station.js.map +1 -0
  13. package/dist/abi/reimbursable-gas-station.mjs +623 -0
  14. package/dist/abi/reimbursable-gas-station.mjs.map +1 -0
  15. package/dist/config.d.ts +57 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +59 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/config.mjs +52 -0
  20. package/dist/config.mjs.map +1 -0
  21. package/dist/gasStationClient.d.ts +110 -0
  22. package/dist/gasStationClient.d.ts.map +1 -0
  23. package/dist/gasStationClient.js +415 -0
  24. package/dist/gasStationClient.js.map +1 -0
  25. package/dist/gasStationClient.mjs +413 -0
  26. package/dist/gasStationClient.mjs.map +1 -0
  27. package/dist/gasStationUtils.d.ts +7250 -0
  28. package/dist/gasStationUtils.d.ts.map +1 -0
  29. package/dist/gasStationUtils.js +147 -0
  30. package/dist/gasStationUtils.js.map +1 -0
  31. package/dist/gasStationUtils.mjs +137 -0
  32. package/dist/gasStationUtils.mjs.map +1 -0
  33. package/dist/index.d.ts +10 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +36 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/index.mjs +8 -0
  38. package/dist/index.mjs.map +1 -0
  39. package/dist/intentBuilder.d.ts +75 -0
  40. package/dist/intentBuilder.d.ts.map +1 -0
  41. package/dist/intentBuilder.js +259 -0
  42. package/dist/intentBuilder.js.map +1 -0
  43. package/dist/intentBuilder.mjs +257 -0
  44. package/dist/intentBuilder.mjs.map +1 -0
  45. package/dist/policyUtils.d.ts +271 -0
  46. package/dist/policyUtils.d.ts.map +1 -0
  47. package/dist/policyUtils.js +386 -0
  48. package/dist/policyUtils.js.map +1 -0
  49. package/dist/policyUtils.mjs +380 -0
  50. package/dist/policyUtils.mjs.map +1 -0
  51. package/package.json +61 -0
@@ -0,0 +1,271 @@
1
+ import type { ZeroXKeyApiClient } from "@0xkey-io/sdk-server";
2
+ import type { Hex } from "viem";
3
+ /**
4
+ * Build a ZeroXKey policy to restrict what EIP-712 intents an EOA can sign
5
+ * This protects at the signing layer - EOA cannot create signatures outside policy
6
+ *
7
+ * @param config - Policy configuration
8
+ * @param config.organizationId - ZeroXKey organization ID
9
+ * @param config.eoaUserId - ZeroXKey user ID for the EOA (primary approver)
10
+ * @param config.additionalApprovers - Optional additional user IDs that must also approve (creates AND condition)
11
+ * @param config.customConsensus - Optional custom consensus expression (overrides eoaUserId and additionalApprovers)
12
+ * @param config.restrictions - Signing restrictions
13
+ * @param config.restrictions.allowedContracts - Whitelist of contract addresses EOA can sign intents for
14
+ * @param config.restrictions.disallowEthTransfer - Whether to disallow ETH transfers (if true, value must be 0)
15
+ * @param config.policyName - Optional policy name
16
+ * @returns Policy object ready to submit to ZeroXKey createPolicy API
17
+ *
18
+ * @example
19
+ * // Simple: single user approval, token-only transfers
20
+ * const policy = buildIntentSigningPolicy({
21
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
22
+ * eoaUserId: "3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
23
+ * restrictions: {
24
+ * allowedContracts: ["0x833...USDC", "0x6B1...DAI"],
25
+ * disallowEthTransfer: true,
26
+ * },
27
+ * policyName: "Stablecoin Only",
28
+ * });
29
+ *
30
+ * // Resulting policy:
31
+ * {
32
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
33
+ * policyName: "Stablecoin Only",
34
+ * effect: "EFFECT_ALLOW",
35
+ * consensus: "approvers.any(user, user.id == '3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a')",
36
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
37
+ * "eth.eip_712.primary_type == 'Execution' && " +
38
+ * "(eth.eip_712.message['to'] == '0x833...usdc' || " +
39
+ * "eth.eip_712.message['to'] == '0x6b1...dai') && " +
40
+ * "eth.eip_712.message['value'] == '0'",
41
+ * notes: "Restricts which EIP-712 intents the EOA can sign for gas station execution"
42
+ * }
43
+ *
44
+ * @example
45
+ * // Multi-approval: EOA AND backup user must both approve
46
+ * const policy = buildIntentSigningPolicy({
47
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
48
+ * eoaUserId: "3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
49
+ * additionalApprovers: ["9d4e2f5b-6c7d-8e9f-0a1b-2c3d4e5f6a7b"],
50
+ * restrictions: {
51
+ * allowedContracts: ["0x833...USDC"],
52
+ * disallowEthTransfer: true,
53
+ * },
54
+ * });
55
+ *
56
+ * // Resulting policy:
57
+ * {
58
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
59
+ * policyName: "Gas Station Intent Signing Policy",
60
+ * effect: "EFFECT_ALLOW",
61
+ * consensus: "approvers.any(user, user.id == '3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a') && " +
62
+ * "approvers.any(user, user.id == '9d4e2f5b-6c7d-8e9f-0a1b-2c3d4e5f6a7b')",
63
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
64
+ * "eth.eip_712.primary_type == 'Execution' && " +
65
+ * "(eth.eip_712.message['to'] == '0x833...usdc') && " +
66
+ * "eth.eip_712.message['value'] == '0'",
67
+ * notes: "Restricts which EIP-712 intents the EOA can sign for gas station execution"
68
+ * }
69
+ *
70
+ * @example
71
+ * // Advanced: custom consensus expression
72
+ * const policy = buildIntentSigningPolicy({
73
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
74
+ * eoaUserId: "3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
75
+ * customConsensus: "approvers.count() >= 2",
76
+ * restrictions: {
77
+ * disallowEthTransfer: false,
78
+ * },
79
+ * });
80
+ *
81
+ * await 0xkeyClient.apiClient().createPolicy(policy);
82
+ */
83
+ export declare function buildIntentSigningPolicy(config: {
84
+ organizationId: string;
85
+ eoaUserId: string;
86
+ additionalApprovers?: string[];
87
+ customConsensus?: string;
88
+ restrictions?: {
89
+ allowedContracts?: Hex[];
90
+ disallowEthTransfer?: boolean;
91
+ };
92
+ policyName?: string;
93
+ }): {
94
+ organizationId: string;
95
+ policyName: string;
96
+ effect: "EFFECT_ALLOW";
97
+ consensus: string;
98
+ condition: string;
99
+ notes: string;
100
+ };
101
+ /**
102
+ * Build a ZeroXKey policy to restrict what the paymaster can execute on-chain.
103
+ * This protects at the execution layer - paymaster cannot submit transactions outside policy.
104
+ *
105
+ * This function uses ZeroXKey's Smart Contract Interface feature to parse the
106
+ * execute(address _targetEoA, address _to, uint256 ethAmount, bytes _data) ABI.
107
+ * Before using this function, ensure the Gas Station ABI is uploaded via
108
+ * ensureGasStationInterface() - this is typically handled automatically.
109
+ *
110
+ * @param config - Policy configuration
111
+ * @param config.organizationId - ZeroXKey organization ID
112
+ * @param config.paymasterUserId - ZeroXKey user ID for the paymaster (primary approver)
113
+ * @param config.additionalApprovers - Optional additional user IDs that can approve (creates OR condition)
114
+ * @param config.customConsensus - Optional custom consensus expression (overrides paymasterUserId and additionalApprovers)
115
+ * @param config.executionContractAddress - Gas station execution contract address
116
+ * @param config.restrictions - Execution restrictions
117
+ * @param config.restrictions.allowedEOAs - Whitelist of EOA addresses paymaster can execute for
118
+ * @param config.restrictions.allowedContracts - Whitelist of output contract addresses (target contracts)
119
+ * @param config.restrictions.maxEthAmount - Maximum ETH amount in wei that can be transferred
120
+ * @param config.restrictions.maxGasPrice - Maximum gas price in wei
121
+ * @param config.restrictions.maxGasLimit - Maximum gas limit
122
+ * @param config.policyName - Optional policy name
123
+ * @returns Policy object ready to submit to ZeroXKey createPolicy API
124
+ *
125
+ * @example
126
+ * // Simple: single paymaster approval with ETH amount limit
127
+ * const policy = buildPaymasterExecutionPolicy({
128
+ * organizationId: "f8c3a5e7-9876-5432-1abc-def098765432",
129
+ * paymasterUserId: "8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c",
130
+ * executionContractAddress: "0x00000000008c57a1CE37836a5e9d36759D070d8c",
131
+ * restrictions: {
132
+ * allowedEOAs: ["0xAli...ce", "0xBob...by"],
133
+ * allowedContracts: ["0x833...USDC", "0x6B1...DAI"],
134
+ * maxEthAmount: parseEther("0.1"), // Max 0.1 ETH per transaction
135
+ * maxGasPrice: parseGwei("50"),
136
+ * maxGasLimit: 500000n,
137
+ * },
138
+ * policyName: "Paymaster Protection",
139
+ * });
140
+ *
141
+ * // Resulting policy (uses ABI parsing):
142
+ * {
143
+ * organizationId: "f8c3a5e7-9876-5432-1abc-def098765432",
144
+ * policyName: "Paymaster Protection",
145
+ * effect: "EFFECT_ALLOW",
146
+ * consensus: "approvers.any(user, user.id == '8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c')",
147
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
148
+ * "eth.tx.to == '0x00000000008c57a1ce37836a5e9d36759d070d8c' && " +
149
+ * "(eth.tx.contract_call_args['_to'] == '0x833...usdc' || " +
150
+ * "eth.tx.contract_call_args['_to'] == '0x6b1...dai') && " +
151
+ * "(eth.tx.contract_call_args['_target'] == '0xali...ce' || " +
152
+ * "eth.tx.contract_call_args['_target'] == '0xbob...by') && " +
153
+ * "eth.tx.contract_call_args['_ethAmount'] <= 100000000000000000 && " +
154
+ * "eth.tx.gasPrice <= 50000000000 && eth.tx.gas <= 500000",
155
+ * notes: "Restricts which execute() transactions the paymaster can submit on-chain"
156
+ * }
157
+ *
158
+ * @example
159
+ * // Multi-user: primary paymaster OR backup can approve
160
+ * const policy = buildPaymasterExecutionPolicy({
161
+ * organizationId: "f8c3a5e7-9876-5432-1abc-def098765432",
162
+ * paymasterUserId: "8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c",
163
+ * additionalApprovers: ["2e4f6a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b"],
164
+ * executionContractAddress: "0x00000000008c57a1CE37836a5e9d36759D070d8c",
165
+ * restrictions: {
166
+ * allowedEOAs: ["0xAli...ce"],
167
+ * maxEthAmount: parseEther("1"), // Max 1 ETH
168
+ * maxGasPrice: parseGwei("100"),
169
+ * },
170
+ * });
171
+ *
172
+ * // Resulting policy (uses ABI parsing):
173
+ * {
174
+ * organizationId: "f8c3a5e7-9876-5432-1abc-def098765432",
175
+ * policyName: "Gas Station Paymaster Execution Policy",
176
+ * effect: "EFFECT_ALLOW",
177
+ * consensus: "approvers.any(user, user.id == '8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c' || " +
178
+ * "user.id == '2e4f6a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b')",
179
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
180
+ * "eth.tx.to == '0x00000000008c57a1ce37836a5e9d36759d070d8c' && " +
181
+ * "(eth.tx.contract_call_args['_target'] == '0xali...ce') && " +
182
+ * "eth.tx.contract_call_args['_ethAmount'] <= 1000000000000000000 && " +
183
+ * "eth.tx.gasPrice <= 100000000000",
184
+ * notes: "Restricts which execute() transactions the paymaster can submit on-chain"
185
+ * }
186
+ *
187
+ * @example
188
+ * // Advanced: require multiple approvals
189
+ * const policy = buildPaymasterExecutionPolicy({
190
+ * organizationId: "f8c3a5e7-9876-5432-1abc-def098765432",
191
+ * paymasterUserId: "8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c",
192
+ * customConsensus: "approvers.count() >= 2",
193
+ * executionContractAddress: "0x00000000008c57a1CE37836a5e9d36759D070d8c",
194
+ * restrictions: { ... },
195
+ * });
196
+ *
197
+ * await 0xkeyClient.apiClient().createPolicy(policy);
198
+ */
199
+ export declare function buildPaymasterExecutionPolicy(config: {
200
+ organizationId: string;
201
+ paymasterUserId: string;
202
+ additionalApprovers?: string[];
203
+ customConsensus?: string;
204
+ executionContractAddress: Hex;
205
+ restrictions?: {
206
+ allowedEOAs?: Hex[];
207
+ allowedContracts?: Hex[];
208
+ maxEthAmount?: bigint;
209
+ maxGasPrice?: bigint;
210
+ maxGasLimit?: bigint;
211
+ };
212
+ policyName?: string;
213
+ }): {
214
+ organizationId: string;
215
+ policyName: string;
216
+ effect: "EFFECT_ALLOW";
217
+ consensus: string;
218
+ condition: string;
219
+ notes: string;
220
+ };
221
+ /**
222
+ * Retrieves an existing smart contract interface for the given contract address.
223
+ * Returns the interface ID if found, undefined otherwise.
224
+ */
225
+ export declare function getSmartContractInterface({ client, organizationId, contractAddress, }: {
226
+ client: ZeroXKeyApiClient;
227
+ organizationId: string;
228
+ contractAddress: Hex;
229
+ }): Promise<string | undefined>;
230
+ /**
231
+ * Uploads the Gas Station ABI to ZeroXKey as a Smart Contract Interface.
232
+ * Returns the newly created interface ID.
233
+ */
234
+ export declare function uploadGasStationInterface({ client, organizationId, contractAddress, label, chainName, }: {
235
+ client: ZeroXKeyApiClient;
236
+ organizationId: string;
237
+ contractAddress: Hex;
238
+ label?: string;
239
+ chainName?: string;
240
+ }): Promise<string>;
241
+ /**
242
+ * Ensures that a Gas Station ABI is registered with ZeroXKey for the given contract.
243
+ * Checks if an interface already exists; if not, uploads it automatically.
244
+ * Returns the interface ID (existing or newly created).
245
+ *
246
+ * This function is called automatically by policy builders to enable ABI-based
247
+ * policy conditions that can directly access and compare function arguments.
248
+ *
249
+ * @param client - ZeroXKey API client (from 0xkeySDK.apiClient())
250
+ * @param organizationId - ZeroXKey organization ID
251
+ * @param contractAddress - Gas station contract address
252
+ * @param label - Optional custom label for the interface
253
+ * @param chainName - Optional chain name for labeling (e.g., "Base Mainnet")
254
+ * @returns The smart contract interface ID
255
+ *
256
+ * @example
257
+ * const interfaceId = await ensureGasStationInterface({
258
+ * client: 0xkeyClient.apiClient(),
259
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
260
+ * contractAddress: "0x00000000008c57a1CE37836a5e9d36759D070d8c",
261
+ * chainName: "Base Sepolia"
262
+ * });
263
+ */
264
+ export declare function ensureGasStationInterface({ client, organizationId, contractAddress, label, chainName, }: {
265
+ client: ZeroXKeyApiClient;
266
+ organizationId: string;
267
+ contractAddress: Hex;
268
+ label?: string;
269
+ chainName?: string;
270
+ }): Promise<string>;
271
+ //# sourceMappingURL=policyUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policyUtils.d.ts","sourceRoot":"","sources":["../src/policyUtils.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEhC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE;QACb,gBAAgB,CAAC,EAAE,GAAG,EAAE,CAAC;QACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;;;;;;;EAsDA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiGG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE;IACpD,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wBAAwB,EAAE,GAAG,CAAC;IAC9B,YAAY,CAAC,EAAE;QACb,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC;QACpB,gBAAgB,CAAC,EAAE,GAAG,EAAE,CAAC;QACzB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;;;;;;;EAmFA;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAAC,EAC9C,MAAM,EACN,cAAc,EACd,eAAe,GAChB,EAAE;IACD,MAAM,EAAE,iBAAiB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,GAAG,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAoB9B;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAAC,EAC9C,MAAM,EACN,cAAc,EACd,eAAe,EACf,KAAK,EACL,SAAS,GACV,EAAE;IACD,MAAM,EAAE,iBAAiB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,GAAG,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBlB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,yBAAyB,CAAC,EAC9C,MAAM,EACN,cAAc,EACd,eAAe,EACf,KAAK,EACL,SAAS,GACV,EAAE;IACD,MAAM,EAAE,iBAAiB,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,GAAG,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBlB"}
@@ -0,0 +1,386 @@
1
+ 'use strict';
2
+
3
+ var gasStation = require('./abi/gas-station.js');
4
+
5
+ // Policy utilities for ZeroXKey gas station restrictions
6
+ /**
7
+ * Build a ZeroXKey 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 - ZeroXKey organization ID
12
+ * @param config.eoaUserId - ZeroXKey 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, value must be 0)
18
+ * @param config.policyName - Optional policy name
19
+ * @returns Policy object ready to submit to ZeroXKey createPolicy API
20
+ *
21
+ * @example
22
+ * // Simple: single user approval, token-only transfers
23
+ * const policy = buildIntentSigningPolicy({
24
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
25
+ * eoaUserId: "3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
26
+ * restrictions: {
27
+ * allowedContracts: ["0x833...USDC", "0x6B1...DAI"],
28
+ * disallowEthTransfer: true,
29
+ * },
30
+ * policyName: "Stablecoin Only",
31
+ * });
32
+ *
33
+ * // Resulting policy:
34
+ * {
35
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
36
+ * policyName: "Stablecoin Only",
37
+ * effect: "EFFECT_ALLOW",
38
+ * consensus: "approvers.any(user, user.id == '3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a')",
39
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
40
+ * "eth.eip_712.primary_type == 'Execution' && " +
41
+ * "(eth.eip_712.message['to'] == '0x833...usdc' || " +
42
+ * "eth.eip_712.message['to'] == '0x6b1...dai') && " +
43
+ * "eth.eip_712.message['value'] == '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: "a5b89e4f-1234-5678-9abc-def012345678",
51
+ * eoaUserId: "3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
52
+ * additionalApprovers: ["9d4e2f5b-6c7d-8e9f-0a1b-2c3d4e5f6a7b"],
53
+ * restrictions: {
54
+ * allowedContracts: ["0x833...USDC"],
55
+ * disallowEthTransfer: true,
56
+ * },
57
+ * });
58
+ *
59
+ * // Resulting policy:
60
+ * {
61
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
62
+ * policyName: "Gas Station Intent Signing Policy",
63
+ * effect: "EFFECT_ALLOW",
64
+ * consensus: "approvers.any(user, user.id == '3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a') && " +
65
+ * "approvers.any(user, user.id == '9d4e2f5b-6c7d-8e9f-0a1b-2c3d4e5f6a7b')",
66
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
67
+ * "eth.eip_712.primary_type == 'Execution' && " +
68
+ * "(eth.eip_712.message['to'] == '0x833...usdc') && " +
69
+ * "eth.eip_712.message['value'] == '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: "a5b89e4f-1234-5678-9abc-def012345678",
77
+ * eoaUserId: "3c7d6e8a-4b5c-6d7e-8f9a-0b1c2d3e4f5a",
78
+ * customConsensus: "approvers.count() >= 2",
79
+ * restrictions: {
80
+ * disallowEthTransfer: false,
81
+ * },
82
+ * });
83
+ *
84
+ * await 0xkeyClient.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['to'] == '${c.toLowerCase()}'`)
98
+ .join(" || ");
99
+ conditions.push(`(${contractConditions})`);
100
+ }
101
+ if (!!config.restrictions?.disallowEthTransfer) {
102
+ conditions.push(`eth.eip_712.message['value'] == '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 ZeroXKey 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 ZeroXKey'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 - ZeroXKey organization ID
143
+ * @param config.paymasterUserId - ZeroXKey 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 ZeroXKey createPolicy API
155
+ *
156
+ * @example
157
+ * // Simple: single paymaster approval with ETH amount limit
158
+ * const policy = buildPaymasterExecutionPolicy({
159
+ * organizationId: "f8c3a5e7-9876-5432-1abc-def098765432",
160
+ * paymasterUserId: "8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c",
161
+ * executionContractAddress: "0x00000000008c57a1CE37836a5e9d36759D070d8c",
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: "f8c3a5e7-9876-5432-1abc-def098765432",
175
+ * policyName: "Paymaster Protection",
176
+ * effect: "EFFECT_ALLOW",
177
+ * consensus: "approvers.any(user, user.id == '8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c')",
178
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
179
+ * "eth.tx.to == '0x00000000008c57a1ce37836a5e9d36759d070d8c' && " +
180
+ * "(eth.tx.contract_call_args['_to'] == '0x833...usdc' || " +
181
+ * "eth.tx.contract_call_args['_to'] == '0x6b1...dai') && " +
182
+ * "(eth.tx.contract_call_args['_target'] == '0xali...ce' || " +
183
+ * "eth.tx.contract_call_args['_target'] == '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: "f8c3a5e7-9876-5432-1abc-def098765432",
193
+ * paymasterUserId: "8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c",
194
+ * additionalApprovers: ["2e4f6a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b"],
195
+ * executionContractAddress: "0x00000000008c57a1CE37836a5e9d36759D070d8c",
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: "f8c3a5e7-9876-5432-1abc-def098765432",
206
+ * policyName: "Gas Station Paymaster Execution Policy",
207
+ * effect: "EFFECT_ALLOW",
208
+ * consensus: "approvers.any(user, user.id == '8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c' || " +
209
+ * "user.id == '2e4f6a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b')",
210
+ * condition: "activity.resource == 'PRIVATE_KEY' && activity.action == 'SIGN' && " +
211
+ * "eth.tx.to == '0x00000000008c57a1ce37836a5e9d36759d070d8c' && " +
212
+ * "(eth.tx.contract_call_args['_target'] == '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: "f8c3a5e7-9876-5432-1abc-def098765432",
222
+ * paymasterUserId: "8f2a1b4c-5d6e-7f8a-9b0c-1d2e3f4a5b6c",
223
+ * customConsensus: "approvers.count() >= 2",
224
+ * executionContractAddress: "0x00000000008c57a1CE37836a5e9d36759D070d8c",
225
+ * restrictions: { ... },
226
+ * });
227
+ *
228
+ * await 0xkeyClient.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
+ // ZeroXKey parses execute(address _target, 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 ZeroXKey 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 ZeroXKey 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 @0xkey-io/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 ZeroXKey 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 - ZeroXKey API client (from 0xkeySDK.apiClient())
347
+ * @param organizationId - ZeroXKey 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
+ * client: 0xkeyClient.apiClient(),
356
+ * organizationId: "a5b89e4f-1234-5678-9abc-def012345678",
357
+ * contractAddress: "0x00000000008c57a1CE37836a5e9d36759D070d8c",
358
+ * chainName: "Base Sepolia"
359
+ * });
360
+ */
361
+ async function ensureGasStationInterface({ client, organizationId, contractAddress, label, chainName, }) {
362
+ // Check if interface already exists
363
+ const existingId = await getSmartContractInterface({
364
+ client,
365
+ organizationId,
366
+ contractAddress,
367
+ });
368
+ if (existingId) {
369
+ return existingId;
370
+ }
371
+ // Upload new interface
372
+ return uploadGasStationInterface({
373
+ client,
374
+ organizationId,
375
+ contractAddress,
376
+ label: label || "",
377
+ chainName: chainName || "",
378
+ });
379
+ }
380
+
381
+ exports.buildIntentSigningPolicy = buildIntentSigningPolicy;
382
+ exports.buildPaymasterExecutionPolicy = buildPaymasterExecutionPolicy;
383
+ exports.ensureGasStationInterface = ensureGasStationInterface;
384
+ exports.getSmartContractInterface = getSmartContractInterface;
385
+ exports.uploadGasStationInterface = uploadGasStationInterface;
386
+ //# 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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"}