@t402/smart-router 1.0.0-beta.1

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.
@@ -0,0 +1,169 @@
1
+ // src/routing/types.ts
2
+ import { z } from "zod";
3
+ var ChainId = z.string().regex(/^[a-z0-9]+:[a-zA-Z0-9]+$/);
4
+ var AssetId = z.string();
5
+ var OptimizationStrategy = z.enum([
6
+ "cost",
7
+ // Minimize total cost (fees + gas)
8
+ "speed",
9
+ // Minimize execution time
10
+ "privacy",
11
+ // Maximize privacy
12
+ "balanced",
13
+ // Balance all factors
14
+ "slippage"
15
+ // Minimize slippage
16
+ ]);
17
+ var RouteStepType = z.enum([
18
+ "transfer",
19
+ // Simple token transfer
20
+ "swap",
21
+ // DEX swap
22
+ "bridge",
23
+ // Cross-chain bridge
24
+ "wrap",
25
+ // Wrap native token
26
+ "unwrap",
27
+ // Unwrap to native
28
+ "approve",
29
+ // Token approval
30
+ "deposit",
31
+ // Deposit to contract
32
+ "withdraw"
33
+ // Withdraw from contract
34
+ ]);
35
+ var ProtocolId = z.string();
36
+ var RouteRequest = z.object({
37
+ // Source
38
+ sourceChain: ChainId,
39
+ sourceAsset: AssetId,
40
+ sourceAmount: z.string(),
41
+ // Amount to send
42
+ // Destination
43
+ destinationChain: ChainId,
44
+ destinationAsset: AssetId.optional(),
45
+ // If different from source
46
+ recipient: z.string(),
47
+ // Options
48
+ optimization: OptimizationStrategy.default("balanced"),
49
+ maxSlippage: z.string().default("0.5"),
50
+ // Percentage
51
+ maxHops: z.number().int().min(1).max(10).default(5),
52
+ deadline: z.number().optional(),
53
+ // Unix timestamp
54
+ // Preferences
55
+ preferredProtocols: z.array(ProtocolId).optional(),
56
+ excludedProtocols: z.array(ProtocolId).optional(),
57
+ preferredBridges: z.array(ProtocolId).optional(),
58
+ excludedBridges: z.array(ProtocolId).optional(),
59
+ // Sender info
60
+ sender: z.string(),
61
+ // Feature flags
62
+ includeMevProtection: z.boolean().default(true),
63
+ includeGasEstimate: z.boolean().default(true)
64
+ });
65
+ var RouteStep = z.object({
66
+ id: z.string(),
67
+ type: RouteStepType,
68
+ chain: ChainId,
69
+ protocol: ProtocolId.optional(),
70
+ // Assets
71
+ inputAsset: AssetId,
72
+ outputAsset: AssetId,
73
+ inputAmount: z.string(),
74
+ outputAmount: z.string(),
75
+ // Expected output
76
+ minOutputAmount: z.string(),
77
+ // Minimum after slippage
78
+ // Contract interaction
79
+ contract: z.string(),
80
+ calldata: z.string().optional(),
81
+ value: z.string().optional(),
82
+ // Native token value
83
+ // Estimates
84
+ estimatedGas: z.string(),
85
+ estimatedTime: z.number(),
86
+ // Seconds
87
+ // Fees
88
+ protocolFee: z.string().optional(),
89
+ bridgeFee: z.string().optional(),
90
+ // Metadata
91
+ priceImpact: z.string().optional(),
92
+ exchangeRate: z.string().optional(),
93
+ metadata: z.record(z.unknown()).optional()
94
+ });
95
+ var Route = z.object({
96
+ id: z.string(),
97
+ steps: z.array(RouteStep),
98
+ // Summary
99
+ sourceChain: ChainId,
100
+ destinationChain: ChainId,
101
+ sourceAsset: AssetId,
102
+ destinationAsset: AssetId,
103
+ sourceAmount: z.string(),
104
+ destinationAmount: z.string(),
105
+ // Expected output
106
+ minDestinationAmount: z.string(),
107
+ // After slippage
108
+ // Costs
109
+ totalGasCost: z.string(),
110
+ // In USD
111
+ totalProtocolFees: z.string(),
112
+ // In USD
113
+ totalBridgeFees: z.string(),
114
+ // In USD
115
+ totalCost: z.string(),
116
+ // Total fees in USD
117
+ // Time
118
+ estimatedTime: z.number(),
119
+ // Total seconds
120
+ // Quality metrics
121
+ priceImpact: z.string(),
122
+ // Percentage
123
+ confidence: z.number().min(0).max(100),
124
+ // Route reliability score
125
+ // Metadata
126
+ optimization: OptimizationStrategy,
127
+ warnings: z.array(z.string()),
128
+ createdAt: z.number(),
129
+ expiresAt: z.number()
130
+ });
131
+ var RouteComparison = z.object({
132
+ bestRoute: Route,
133
+ alternatives: z.array(Route),
134
+ comparison: z.object({
135
+ costSavings: z.string(),
136
+ // Best vs worst
137
+ timeDifference: z.number(),
138
+ // Seconds
139
+ riskDifference: z.number()
140
+ // Confidence difference
141
+ })
142
+ });
143
+ var RouteValidation = z.object({
144
+ valid: z.boolean(),
145
+ errors: z.array(z.object({
146
+ step: z.number().optional(),
147
+ code: z.string(),
148
+ message: z.string()
149
+ })),
150
+ warnings: z.array(z.object({
151
+ step: z.number().optional(),
152
+ code: z.string(),
153
+ message: z.string()
154
+ }))
155
+ });
156
+
157
+ export {
158
+ ChainId,
159
+ AssetId,
160
+ OptimizationStrategy,
161
+ RouteStepType,
162
+ ProtocolId,
163
+ RouteRequest,
164
+ RouteStep,
165
+ Route,
166
+ RouteComparison,
167
+ RouteValidation
168
+ };
169
+ //# sourceMappingURL=chunk-QIZPPHGB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/routing/types.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Supported chain identifiers (CAIP-2 format)\n */\nexport const ChainId = z.string().regex(/^[a-z0-9]+:[a-zA-Z0-9]+$/);\nexport type ChainId = z.infer<typeof ChainId>;\n\n/**\n * Asset identifier\n */\nexport const AssetId = z.string();\nexport type AssetId = z.infer<typeof AssetId>;\n\n/**\n * Route optimization strategy\n */\nexport const OptimizationStrategy = z.enum([\n 'cost', // Minimize total cost (fees + gas)\n 'speed', // Minimize execution time\n 'privacy', // Maximize privacy\n 'balanced', // Balance all factors\n 'slippage', // Minimize slippage\n]);\nexport type OptimizationStrategy = z.infer<typeof OptimizationStrategy>;\n\n/**\n * Route step type\n */\nexport const RouteStepType = z.enum([\n 'transfer', // Simple token transfer\n 'swap', // DEX swap\n 'bridge', // Cross-chain bridge\n 'wrap', // Wrap native token\n 'unwrap', // Unwrap to native\n 'approve', // Token approval\n 'deposit', // Deposit to contract\n 'withdraw', // Withdraw from contract\n]);\nexport type RouteStepType = z.infer<typeof RouteStepType>;\n\n/**\n * Protocol identifier\n */\nexport const ProtocolId = z.string();\nexport type ProtocolId = z.infer<typeof ProtocolId>;\n\n/**\n * Route request\n */\nexport const RouteRequest = z.object({\n // Source\n sourceChain: ChainId,\n sourceAsset: AssetId,\n sourceAmount: z.string(), // Amount to send\n\n // Destination\n destinationChain: ChainId,\n destinationAsset: AssetId.optional(), // If different from source\n recipient: z.string(),\n\n // Options\n optimization: OptimizationStrategy.default('balanced'),\n maxSlippage: z.string().default('0.5'), // Percentage\n maxHops: z.number().int().min(1).max(10).default(5),\n deadline: z.number().optional(), // Unix timestamp\n\n // Preferences\n preferredProtocols: z.array(ProtocolId).optional(),\n excludedProtocols: z.array(ProtocolId).optional(),\n preferredBridges: z.array(ProtocolId).optional(),\n excludedBridges: z.array(ProtocolId).optional(),\n\n // Sender info\n sender: z.string(),\n\n // Feature flags\n includeMevProtection: z.boolean().default(true),\n includeGasEstimate: z.boolean().default(true),\n});\nexport type RouteRequest = z.infer<typeof RouteRequest>;\n\n/**\n * Individual route step\n */\nexport const RouteStep = z.object({\n id: z.string(),\n type: RouteStepType,\n chain: ChainId,\n protocol: ProtocolId.optional(),\n\n // Assets\n inputAsset: AssetId,\n outputAsset: AssetId,\n inputAmount: z.string(),\n outputAmount: z.string(), // Expected output\n minOutputAmount: z.string(), // Minimum after slippage\n\n // Contract interaction\n contract: z.string(),\n calldata: z.string().optional(),\n value: z.string().optional(), // Native token value\n\n // Estimates\n estimatedGas: z.string(),\n estimatedTime: z.number(), // Seconds\n\n // Fees\n protocolFee: z.string().optional(),\n bridgeFee: z.string().optional(),\n\n // Metadata\n priceImpact: z.string().optional(),\n exchangeRate: z.string().optional(),\n metadata: z.record(z.unknown()).optional(),\n});\nexport type RouteStep = z.infer<typeof RouteStep>;\n\n/**\n * Complete route\n */\nexport const Route = z.object({\n id: z.string(),\n steps: z.array(RouteStep),\n\n // Summary\n sourceChain: ChainId,\n destinationChain: ChainId,\n sourceAsset: AssetId,\n destinationAsset: AssetId,\n sourceAmount: z.string(),\n destinationAmount: z.string(), // Expected output\n minDestinationAmount: z.string(), // After slippage\n\n // Costs\n totalGasCost: z.string(), // In USD\n totalProtocolFees: z.string(), // In USD\n totalBridgeFees: z.string(), // In USD\n totalCost: z.string(), // Total fees in USD\n\n // Time\n estimatedTime: z.number(), // Total seconds\n\n // Quality metrics\n priceImpact: z.string(), // Percentage\n confidence: z.number().min(0).max(100), // Route reliability score\n\n // Metadata\n optimization: OptimizationStrategy,\n warnings: z.array(z.string()),\n createdAt: z.number(),\n expiresAt: z.number(),\n});\nexport type Route = z.infer<typeof Route>;\n\n/**\n * Route comparison result\n */\nexport const RouteComparison = z.object({\n bestRoute: Route,\n alternatives: z.array(Route),\n comparison: z.object({\n costSavings: z.string(), // Best vs worst\n timeDifference: z.number(), // Seconds\n riskDifference: z.number(), // Confidence difference\n }),\n});\nexport type RouteComparison = z.infer<typeof RouteComparison>;\n\n/**\n * Route validation result\n */\nexport const RouteValidation = z.object({\n valid: z.boolean(),\n errors: z.array(z.object({\n step: z.number().optional(),\n code: z.string(),\n message: z.string(),\n })),\n warnings: z.array(z.object({\n step: z.number().optional(),\n code: z.string(),\n message: z.string(),\n })),\n});\nexport type RouteValidation = z.infer<typeof RouteValidation>;\n\n/**\n * Network graph edge (for routing algorithms)\n */\nexport interface GraphEdge {\n from: ChainId;\n to: ChainId;\n fromAsset: AssetId;\n toAsset: AssetId;\n protocol: ProtocolId;\n type: RouteStepType;\n cost: number; // Normalized cost for algorithm\n liquidity: string;\n maxAmount: string;\n minAmount: string;\n estimatedTime: number;\n}\n\n/**\n * Network graph node\n */\nexport interface GraphNode {\n chain: ChainId;\n asset: AssetId;\n edges: GraphEdge[];\n}\n\n/**\n * Routing graph\n */\nexport interface RoutingGraph {\n nodes: Map<string, GraphNode>; // key: chain:asset\n edges: GraphEdge[];\n lastUpdated: number;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,504 @@
1
+ // src/execution/types.ts
2
+ import { z } from "zod";
3
+ var TransactionStatus = z.enum([
4
+ "pending",
5
+ "submitted",
6
+ "confirmed",
7
+ "failed",
8
+ "replaced"
9
+ ]);
10
+ var MevProtectionStrategy = z.enum([
11
+ "none",
12
+ // No protection
13
+ "flashbots",
14
+ // Use Flashbots (Ethereum)
15
+ "private_mempool",
16
+ // Use private mempool
17
+ "timing",
18
+ // Submit at optimal time
19
+ "splitting"
20
+ // Split into smaller transactions
21
+ ]);
22
+ var TransactionRequest = z.object({
23
+ to: z.string(),
24
+ data: z.string(),
25
+ value: z.string().default("0"),
26
+ gasLimit: z.string(),
27
+ maxFeePerGas: z.string().optional(),
28
+ maxPriorityFeePerGas: z.string().optional(),
29
+ gasPrice: z.string().optional(),
30
+ nonce: z.number().optional(),
31
+ chainId: z.number()
32
+ });
33
+ var SignedTransaction = z.object({
34
+ raw: z.string(),
35
+ hash: z.string(),
36
+ from: z.string(),
37
+ to: z.string(),
38
+ nonce: z.number(),
39
+ gasLimit: z.string(),
40
+ value: z.string()
41
+ });
42
+ var TransactionReceipt = z.object({
43
+ hash: z.string(),
44
+ status: TransactionStatus,
45
+ blockNumber: z.number().optional(),
46
+ blockHash: z.string().optional(),
47
+ gasUsed: z.string().optional(),
48
+ effectiveGasPrice: z.string().optional(),
49
+ logs: z.array(z.object({
50
+ address: z.string(),
51
+ topics: z.array(z.string()),
52
+ data: z.string()
53
+ })).optional(),
54
+ timestamp: z.number()
55
+ });
56
+ var ExecutionStepResult = z.object({
57
+ stepId: z.string(),
58
+ status: TransactionStatus,
59
+ transaction: TransactionReceipt.optional(),
60
+ actualOutput: z.string().optional(),
61
+ error: z.string().optional(),
62
+ startedAt: z.number(),
63
+ completedAt: z.number().optional()
64
+ });
65
+ var ExecutionResult = z.object({
66
+ routeId: z.string(),
67
+ status: z.enum(["pending", "partial", "completed", "failed", "reverted"]),
68
+ steps: z.array(ExecutionStepResult),
69
+ actualOutput: z.string().optional(),
70
+ totalGasUsed: z.string().optional(),
71
+ totalGasCost: z.string().optional(),
72
+ error: z.string().optional(),
73
+ startedAt: z.number(),
74
+ completedAt: z.number().optional()
75
+ });
76
+ var ExecutionOptions = z.object({
77
+ // Gas settings
78
+ gasSpeed: z.enum(["slow", "standard", "fast", "instant"]).default("standard"),
79
+ maxGasPrice: z.string().optional(),
80
+ // MEV protection
81
+ mevProtection: MevProtectionStrategy.default("none"),
82
+ flashbotsRelay: z.string().optional(),
83
+ // Retry settings
84
+ maxRetries: z.number().default(3),
85
+ retryDelay: z.number().default(5e3),
86
+ // ms
87
+ // Timeout
88
+ timeout: z.number().default(3e5),
89
+ // 5 minutes
90
+ // Simulation
91
+ simulate: z.boolean().default(true),
92
+ // Approval handling
93
+ autoApprove: z.boolean().default(true),
94
+ approvalBuffer: z.string().default("0")
95
+ // Extra approval amount
96
+ });
97
+ var SimulationResult = z.object({
98
+ success: z.boolean(),
99
+ gasUsed: z.string(),
100
+ output: z.string().optional(),
101
+ error: z.string().optional(),
102
+ logs: z.array(z.object({
103
+ address: z.string(),
104
+ topics: z.array(z.string()),
105
+ data: z.string()
106
+ })),
107
+ stateChanges: z.array(z.object({
108
+ address: z.string(),
109
+ key: z.string(),
110
+ before: z.string(),
111
+ after: z.string()
112
+ })).optional()
113
+ });
114
+
115
+ // src/execution/builder.ts
116
+ var CHAIN_IDS = {
117
+ "eip155:1": 1,
118
+ // Ethereum
119
+ "eip155:8453": 8453,
120
+ // Base
121
+ "eip155:42161": 42161,
122
+ // Arbitrum
123
+ "eip155:10": 10,
124
+ // Optimism
125
+ "eip155:137": 137,
126
+ // Polygon
127
+ "eip155:56": 56,
128
+ // BSC
129
+ "eip155:43114": 43114
130
+ // Avalanche
131
+ };
132
+ var FUNCTION_SELECTORS = {
133
+ // ERC20
134
+ transfer: "0xa9059cbb",
135
+ approve: "0x095ea7b3",
136
+ transferFrom: "0x23b872dd",
137
+ // Uniswap V2 Router
138
+ swapExactTokensForTokens: "0x38ed1739",
139
+ swapTokensForExactTokens: "0x8803dbee",
140
+ // Uniswap V3 Router
141
+ exactInputSingle: "0x414bf389",
142
+ exactInput: "0xc04b8d59",
143
+ // WETH
144
+ deposit: "0xd0e30db0",
145
+ withdraw: "0x2e1a7d4d"
146
+ };
147
+ var TransactionBuilder = class {
148
+ gasOracle;
149
+ config;
150
+ constructor(gasOracle, config = {}) {
151
+ this.gasOracle = gasOracle;
152
+ this.config = {
153
+ defaultGasBuffer: config.defaultGasBuffer ?? 20
154
+ // 20% buffer
155
+ };
156
+ }
157
+ /**
158
+ * Build all transactions for a route
159
+ */
160
+ async buildRoute(route, sender, options) {
161
+ const transactions = [];
162
+ for (const step of route.steps) {
163
+ const tx = await this.buildStep(step, sender, options);
164
+ transactions.push(tx);
165
+ }
166
+ return transactions;
167
+ }
168
+ /**
169
+ * Build a single step transaction
170
+ */
171
+ async buildStep(step, sender, options) {
172
+ const chainId = CHAIN_IDS[step.chain];
173
+ if (!chainId) {
174
+ throw new BuilderError(`Unsupported chain: ${step.chain}`, "UNSUPPORTED_CHAIN");
175
+ }
176
+ const gasPrice = await this.gasOracle.getGasPrice(step.chain);
177
+ const gasPriceWei = gasPrice[options.gasSpeed];
178
+ let finalGasPrice = gasPriceWei;
179
+ if (options.maxGasPrice && BigInt(gasPriceWei) > BigInt(options.maxGasPrice)) {
180
+ finalGasPrice = options.maxGasPrice;
181
+ }
182
+ const { data, value } = this.buildCalldata(step, sender);
183
+ const gasWithBuffer = this.applyGasBuffer(step.estimatedGas);
184
+ const isEip1559 = gasPrice.baseFee !== void 0;
185
+ const tx = {
186
+ to: step.contract,
187
+ data,
188
+ value: value ?? "0",
189
+ gasLimit: gasWithBuffer,
190
+ chainId
191
+ };
192
+ if (isEip1559 && gasPrice.priorityFee) {
193
+ tx.maxFeePerGas = finalGasPrice;
194
+ tx.maxPriorityFeePerGas = gasPrice.priorityFee[options.gasSpeed];
195
+ } else {
196
+ tx.gasPrice = finalGasPrice;
197
+ }
198
+ return tx;
199
+ }
200
+ /**
201
+ * Build approval transaction if needed
202
+ */
203
+ buildApproval(tokenAddress, spender, amount, _chainId, infinite = false) {
204
+ const approvalAmount = infinite ? "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" : BigInt(amount).toString(16).padStart(64, "0");
205
+ const data = FUNCTION_SELECTORS.approve + spender.slice(2).padStart(64, "0").toLowerCase() + approvalAmount;
206
+ return {
207
+ to: tokenAddress,
208
+ data
209
+ };
210
+ }
211
+ /**
212
+ * Build transfer transaction
213
+ */
214
+ buildTransfer(tokenAddress, recipient, amount) {
215
+ const data = FUNCTION_SELECTORS.transfer + recipient.slice(2).padStart(64, "0").toLowerCase() + BigInt(amount).toString(16).padStart(64, "0");
216
+ return {
217
+ to: tokenAddress,
218
+ data
219
+ };
220
+ }
221
+ /**
222
+ * Estimate required approvals for a route
223
+ */
224
+ getRequiredApprovals(route, _sender) {
225
+ const approvals = [];
226
+ const approvedPairs = /* @__PURE__ */ new Set();
227
+ for (const step of route.steps) {
228
+ if (step.type === "approve") continue;
229
+ const key = `${step.inputAsset}:${step.contract}`;
230
+ if (approvedPairs.has(key)) continue;
231
+ approvals.push({
232
+ token: step.inputAsset,
233
+ spender: step.contract,
234
+ amount: step.inputAmount
235
+ });
236
+ approvedPairs.add(key);
237
+ }
238
+ return approvals;
239
+ }
240
+ buildCalldata(step, sender) {
241
+ switch (step.type) {
242
+ case "transfer":
243
+ return this.buildTransferCalldata(step);
244
+ case "approve":
245
+ return this.buildApproveCalldata(step);
246
+ case "swap":
247
+ return this.buildSwapCalldata(step, sender);
248
+ case "bridge":
249
+ return this.buildBridgeCalldata(step, sender);
250
+ case "wrap":
251
+ return this.buildWrapCalldata(step);
252
+ case "unwrap":
253
+ return this.buildUnwrapCalldata(step);
254
+ case "deposit":
255
+ case "withdraw":
256
+ return { data: step.calldata ?? "0x", value: step.value };
257
+ default:
258
+ throw new BuilderError(`Unknown step type: ${step.type}`, "UNKNOWN_STEP_TYPE");
259
+ }
260
+ }
261
+ buildTransferCalldata(step) {
262
+ const data = FUNCTION_SELECTORS.transfer + step.contract.slice(2).padStart(64, "0").toLowerCase() + BigInt(step.inputAmount).toString(16).padStart(64, "0");
263
+ return { data };
264
+ }
265
+ buildApproveCalldata(step) {
266
+ const data = FUNCTION_SELECTORS.approve + step.contract.slice(2).padStart(64, "0").toLowerCase() + BigInt(step.inputAmount).toString(16).padStart(64, "0");
267
+ return { data };
268
+ }
269
+ buildSwapCalldata(step, sender) {
270
+ const deadline = Math.floor(Date.now() / 1e3) + 1800;
271
+ const amountIn = BigInt(step.inputAmount).toString(16).padStart(64, "0");
272
+ const amountOutMin = BigInt(step.minOutputAmount).toString(16).padStart(64, "0");
273
+ const pathOffset = "00000000000000000000000000000000000000000000000000000000000000a0";
274
+ const to = sender.slice(2).padStart(64, "0").toLowerCase();
275
+ const deadlineHex = deadline.toString(16).padStart(64, "0");
276
+ const pathLength = "0000000000000000000000000000000000000000000000000000000000000002";
277
+ const token0 = step.inputAsset.slice(2).padStart(64, "0").toLowerCase();
278
+ const token1 = step.outputAsset.slice(2).padStart(64, "0").toLowerCase();
279
+ const data = FUNCTION_SELECTORS.swapExactTokensForTokens + amountIn + amountOutMin + pathOffset + to + deadlineHex + pathLength + token0 + token1;
280
+ return { data };
281
+ }
282
+ buildBridgeCalldata(step, _sender) {
283
+ return {
284
+ data: step.calldata ?? "0x",
285
+ value: step.value
286
+ };
287
+ }
288
+ buildWrapCalldata(step) {
289
+ return {
290
+ data: FUNCTION_SELECTORS.deposit,
291
+ value: step.inputAmount
292
+ };
293
+ }
294
+ buildUnwrapCalldata(step) {
295
+ const data = FUNCTION_SELECTORS.withdraw + BigInt(step.inputAmount).toString(16).padStart(64, "0");
296
+ return { data };
297
+ }
298
+ applyGasBuffer(gasEstimate) {
299
+ const gas = BigInt(gasEstimate);
300
+ const buffer = BigInt(this.config.defaultGasBuffer);
301
+ return (gas + gas * buffer / 100n).toString();
302
+ }
303
+ };
304
+ var BuilderError = class extends Error {
305
+ code;
306
+ constructor(message, code) {
307
+ super(message);
308
+ this.name = "BuilderError";
309
+ this.code = code;
310
+ }
311
+ };
312
+
313
+ // src/execution/mev.ts
314
+ var MevProtection = class {
315
+ config;
316
+ constructor(config = {}) {
317
+ this.config = {
318
+ flashbotsRelay: config.flashbotsRelay ?? "https://relay.flashbots.net",
319
+ privateRpcUrls: config.privateRpcUrls ?? {},
320
+ simulationRpc: config.simulationRpc ?? "",
321
+ maxBundleSize: config.maxBundleSize ?? 5
322
+ };
323
+ }
324
+ /**
325
+ * Apply MEV protection to a transaction
326
+ */
327
+ async protect(_tx, signedTx, strategy, chain) {
328
+ switch (strategy) {
329
+ case "none":
330
+ return { method: "public_mempool" };
331
+ case "flashbots":
332
+ return this.useFlashbots(signedTx, chain);
333
+ case "private_mempool":
334
+ return this.usePrivateMempool(signedTx, chain);
335
+ case "timing":
336
+ return this.useTimingProtection(signedTx, chain);
337
+ case "splitting":
338
+ return { method: "splitting", bundleHash: "split-not-implemented" };
339
+ default:
340
+ return { method: "public_mempool" };
341
+ }
342
+ }
343
+ /**
344
+ * Submit transaction bundle to Flashbots
345
+ */
346
+ async submitBundle(signedTxs, targetBlock, _chain) {
347
+ if (signedTxs.length > this.config.maxBundleSize) {
348
+ return {
349
+ bundleHash: "",
350
+ submitted: false,
351
+ error: `Bundle size ${signedTxs.length} exceeds max ${this.config.maxBundleSize}`
352
+ };
353
+ }
354
+ const bundleHash = this.generateBundleHash(signedTxs, targetBlock);
355
+ const simulationResult = {
356
+ success: true,
357
+ gasUsed: signedTxs.reduce((sum, tx) => sum + BigInt(tx.gasLimit), 0n).toString(),
358
+ logs: []
359
+ };
360
+ return {
361
+ bundleHash,
362
+ submitted: true,
363
+ simulationResult
364
+ };
365
+ }
366
+ /**
367
+ * Simulate transaction without executing
368
+ */
369
+ async simulate(tx, _chain) {
370
+ return {
371
+ success: true,
372
+ gasUsed: tx.gasLimit,
373
+ logs: []
374
+ };
375
+ }
376
+ /**
377
+ * Estimate MEV risk for a transaction
378
+ */
379
+ estimateMevRisk(tx, _chain) {
380
+ const value = BigInt(tx.value);
381
+ const recommendations = [];
382
+ let riskLevel = "low";
383
+ let estimatedMevCost = "0";
384
+ const isSwap = tx.data.startsWith("0x38ed") || // swapExactTokensForTokens
385
+ tx.data.startsWith("0x8803") || // swapTokensForExactTokens
386
+ tx.data.startsWith("0x414b") || // V3 exactInputSingle
387
+ tx.data.startsWith("0xc04b");
388
+ if (isSwap) {
389
+ riskLevel = "high";
390
+ estimatedMevCost = (value * 3n / 1000n).toString();
391
+ recommendations.push("Use Flashbots or private mempool");
392
+ recommendations.push("Consider splitting into smaller transactions");
393
+ recommendations.push("Set tight slippage tolerance");
394
+ }
395
+ if (value > BigInt("1000000000000000000000")) {
396
+ riskLevel = "medium";
397
+ recommendations.push("Consider using private mempool");
398
+ }
399
+ if (tx.data.startsWith("0x095e")) {
400
+ riskLevel = "medium";
401
+ recommendations.push("Bundle approval with swap in same block");
402
+ }
403
+ return { riskLevel, estimatedMevCost, recommendations };
404
+ }
405
+ /**
406
+ * Get optimal block for transaction submission
407
+ */
408
+ getOptimalSubmissionTime(_chain) {
409
+ return {
410
+ targetBlock: 0,
411
+ // Next block
412
+ delay: 0,
413
+ reason: "Immediate submission recommended"
414
+ };
415
+ }
416
+ /**
417
+ * Check if Flashbots is available for a chain
418
+ */
419
+ isFlashbotsAvailable(chain) {
420
+ return chain === "eip155:1";
421
+ }
422
+ /**
423
+ * Get private RPC URL for a chain
424
+ */
425
+ getPrivateRpcUrl(chain) {
426
+ return this.config.privateRpcUrls[chain];
427
+ }
428
+ async useFlashbots(signedTx, chain) {
429
+ if (!this.isFlashbotsAvailable(chain)) {
430
+ return { method: "public_mempool" };
431
+ }
432
+ const bundleResult = await this.submitBundle([signedTx], 0, chain);
433
+ return {
434
+ method: "flashbots",
435
+ endpoint: this.config.flashbotsRelay,
436
+ bundleHash: bundleResult.bundleHash
437
+ };
438
+ }
439
+ async usePrivateMempool(_signedTx, chain) {
440
+ const privateRpc = this.getPrivateRpcUrl(chain);
441
+ if (!privateRpc) {
442
+ return { method: "public_mempool" };
443
+ }
444
+ return {
445
+ method: "private_mempool",
446
+ endpoint: privateRpc
447
+ };
448
+ }
449
+ async useTimingProtection(_signedTx, chain) {
450
+ const timing = this.getOptimalSubmissionTime(chain);
451
+ if (timing.delay > 0) {
452
+ await new Promise((resolve) => setTimeout(resolve, timing.delay));
453
+ }
454
+ return { method: "timing_protected" };
455
+ }
456
+ generateBundleHash(txs, targetBlock) {
457
+ const txHashes = txs.map((tx) => tx.hash).join("");
458
+ return `0x${this.simpleHash(txHashes + targetBlock.toString())}`;
459
+ }
460
+ simpleHash(input) {
461
+ let hash = 0;
462
+ for (let i = 0; i < input.length; i++) {
463
+ const char = input.charCodeAt(i);
464
+ hash = (hash << 5) - hash + char;
465
+ hash = hash & hash;
466
+ }
467
+ return Math.abs(hash).toString(16).padStart(64, "0");
468
+ }
469
+ };
470
+ function createMevProtectedOptions(chain, value) {
471
+ if (chain === "eip155:1" && BigInt(value) > BigInt("100000000000000000000")) {
472
+ return {
473
+ strategy: "flashbots",
474
+ reason: "High value transaction on Ethereum mainnet"
475
+ };
476
+ }
477
+ if (chain.startsWith("eip155:") && ["8453", "42161", "10"].some((id) => chain.includes(id))) {
478
+ return {
479
+ strategy: "none",
480
+ reason: "L2 chain with limited MEV activity"
481
+ };
482
+ }
483
+ return {
484
+ strategy: "private_mempool",
485
+ reason: "Default protection for moderate value transactions"
486
+ };
487
+ }
488
+
489
+ export {
490
+ TransactionStatus,
491
+ MevProtectionStrategy,
492
+ TransactionRequest,
493
+ SignedTransaction,
494
+ TransactionReceipt,
495
+ ExecutionStepResult,
496
+ ExecutionResult,
497
+ ExecutionOptions,
498
+ SimulationResult,
499
+ TransactionBuilder,
500
+ BuilderError,
501
+ MevProtection,
502
+ createMevProtectedOptions
503
+ };
504
+ //# sourceMappingURL=chunk-XKFKUWJY.js.map