@exagent/agent 0.3.6 → 0.3.8

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 (69) hide show
  1. package/dist/chunk-7UGLJO6W.js +6392 -0
  2. package/dist/chunk-EHAOPCTJ.js +6406 -0
  3. package/dist/chunk-FGMXTW5I.js +6540 -0
  4. package/dist/chunk-GYYW4EKM.js +6756 -0
  5. package/dist/chunk-IVA2SCSN.js +6756 -0
  6. package/dist/chunk-JHXCSGPC.js +6352 -0
  7. package/dist/chunk-V6O4UXVN.js +6345 -0
  8. package/dist/chunk-WTECTX2Z.js +6345 -0
  9. package/dist/cli.js +2 -2
  10. package/dist/index.d.ts +24 -2
  11. package/dist/index.js +1 -1
  12. package/package.json +12 -9
  13. package/src/bridge/across.ts +0 -240
  14. package/src/bridge/bridge-manager.ts +0 -87
  15. package/src/bridge/index.ts +0 -9
  16. package/src/bridge/types.ts +0 -77
  17. package/src/chains.ts +0 -105
  18. package/src/cli.ts +0 -250
  19. package/src/config.ts +0 -502
  20. package/src/diagnostics.ts +0 -335
  21. package/src/index.ts +0 -98
  22. package/src/llm/anthropic.ts +0 -63
  23. package/src/llm/base.ts +0 -264
  24. package/src/llm/deepseek.ts +0 -48
  25. package/src/llm/google.ts +0 -63
  26. package/src/llm/groq.ts +0 -48
  27. package/src/llm/index.ts +0 -42
  28. package/src/llm/mistral.ts +0 -48
  29. package/src/llm/ollama.ts +0 -52
  30. package/src/llm/openai.ts +0 -94
  31. package/src/llm/together.ts +0 -48
  32. package/src/llm-providers.ts +0 -8
  33. package/src/logger.ts +0 -137
  34. package/src/paper/executor.ts +0 -201
  35. package/src/paper/index.ts +0 -1
  36. package/src/perp/client.ts +0 -200
  37. package/src/perp/index.ts +0 -12
  38. package/src/perp/msgpack.ts +0 -272
  39. package/src/perp/orders.ts +0 -234
  40. package/src/perp/positions.ts +0 -126
  41. package/src/perp/signer.ts +0 -277
  42. package/src/perp/types.ts +0 -192
  43. package/src/perp/websocket.ts +0 -274
  44. package/src/position-tracker.ts +0 -243
  45. package/src/prediction/client.ts +0 -288
  46. package/src/prediction/index.ts +0 -3
  47. package/src/prediction/order-manager.ts +0 -297
  48. package/src/prediction/types.ts +0 -151
  49. package/src/relay.ts +0 -254
  50. package/src/runtime.ts +0 -1755
  51. package/src/scrub-secrets.ts +0 -39
  52. package/src/setup.ts +0 -392
  53. package/src/signal.ts +0 -212
  54. package/src/spot/aerodrome.ts +0 -158
  55. package/src/spot/client.ts +0 -138
  56. package/src/spot/index.ts +0 -11
  57. package/src/spot/swap-manager.ts +0 -219
  58. package/src/spot/types.ts +0 -203
  59. package/src/spot/uniswap.ts +0 -150
  60. package/src/store.ts +0 -50
  61. package/src/strategy/index.ts +0 -2
  62. package/src/strategy/loader.ts +0 -265
  63. package/src/strategy/templates.ts +0 -74
  64. package/src/trading/index.ts +0 -2
  65. package/src/trading/market.ts +0 -120
  66. package/src/trading/risk.ts +0 -107
  67. package/src/ui.ts +0 -75
  68. package/test/strategy-loader.test.ts +0 -150
  69. package/tsconfig.json +0 -8
package/dist/cli.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  updateSecureStore,
10
10
  writeConfigFile,
11
11
  writeSampleConfig
12
- } from "./chunk-ZRAOPQQW.js";
12
+ } from "./chunk-GYYW4EKM.js";
13
13
 
14
14
  // src/cli.ts
15
15
  import { Command } from "commander";
@@ -359,7 +359,7 @@ async function ensureLocalSetup(configPath) {
359
359
  // src/cli.ts
360
360
  import * as clack2 from "@clack/prompts";
361
361
  var program = new Command();
362
- program.name("exagent").description("Exagent \u2014 LLM trading agent runtime").version("0.3.5");
362
+ program.name("exagent").description("Exagent \u2014 LLM trading agent runtime").version("0.3.8");
363
363
  program.command("init").description("Create a sample agent configuration file").option("--agent-id <id>", "Agent ID (from dashboard)", "my-agent").option("--api-url <url>", "API server URL", "http://localhost:3002").option("--config <path>", "Config file path", "agent-config.json").action((opts) => {
364
364
  printBanner();
365
365
  writeSampleConfig(opts.agentId, opts.apiUrl, opts.config);
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { LLMProvider, RelayCommand, AgentStatusPayload, MessageType, MessageLevel, TradeSignal, StrategyStore, PositionSummary, TrackedPosition, TradeRecord, LLMAdapter, LLMConfig, LLMMessage, LLMResponse, LLMMetadata, StrategyFunction, StrategyTemplate, RiskParams, MarketData, OHLCV, PaperTrade, PaperMetrics } from '@exagent/sdk';
1
+ import { LLMProvider, StrategyProvenance, StrategyPermissions, RelayCommand, AgentStatusPayload, MessageType, MessageLevel, TradeSignal, StrategyStore, PositionSummary, TrackedPosition, TradeRecord, LLMAdapter, LLMConfig, LLMMessage, LLMResponse, LLMMetadata, StrategyFunction, StrategyTemplate, RiskParams, MarketData, OHLCV, PaperTrade, PaperMetrics } from '@exagent/sdk';
2
2
  import { WalletClient, PublicClient, Transport, Chain as Chain$1, Account } from 'viem';
3
3
  import { Chain } from 'viem/chains';
4
4
 
@@ -22,6 +22,8 @@ interface RuntimeConfig {
22
22
  code?: string;
23
23
  template?: string;
24
24
  venues?: string[];
25
+ provenance?: StrategyProvenance;
26
+ permissions?: StrategyPermissions;
25
27
  prompt?: {
26
28
  name?: string;
27
29
  systemPrompt: string;
@@ -137,6 +139,8 @@ declare class AgentRuntime {
137
139
  private buildRuntimeVenuesFromSelection;
138
140
  private buildStrategyFallbackPrompt;
139
141
  private extractStrategyConfigFromAgentConfig;
142
+ private extractStrategyProvenance;
143
+ private extractStrategyPermissions;
140
144
  private applyExecutionMode;
141
145
  private initializeVenues;
142
146
  private startTrading;
@@ -436,6 +440,8 @@ declare function loadStrategy(config: {
436
440
  systemPrompt: string;
437
441
  venues?: string[];
438
442
  };
443
+ provenance?: StrategyProvenance;
444
+ permissions?: StrategyPermissions;
439
445
  }): Promise<StrategyFunction>;
440
446
 
441
447
  declare function getTemplate(id: string): StrategyTemplate | undefined;
@@ -456,6 +462,7 @@ declare class RiskManager {
456
462
  getDailyPnL(): number;
457
463
  getDailyLossLimit(): number;
458
464
  private resetIfNewDay;
465
+ private validateUpdate;
459
466
  }
460
467
 
461
468
  declare class MarketDataService implements MarketData {
@@ -559,6 +566,7 @@ interface PerpConfig {
559
566
  wsUrl: string;
560
567
  maxLeverage: number;
561
568
  maxNotionalUSD: number;
569
+ marketOrderSlippageBps?: number;
562
570
  allowedInstruments?: string[];
563
571
  }
564
572
  type PerpAction = 'open_long' | 'open_short' | 'close_long' | 'close_short' | 'hold';
@@ -847,6 +855,13 @@ declare class HyperliquidSigner {
847
855
  * No builder fee — private group, not needed.
848
856
  */
849
857
 
858
+ interface CancelAllResult {
859
+ success: boolean;
860
+ total: number;
861
+ cancelled: number;
862
+ failed: number;
863
+ errors: string[];
864
+ }
850
865
  declare class HyperliquidOrderManager {
851
866
  private readonly client;
852
867
  private readonly signer;
@@ -854,11 +869,15 @@ declare class HyperliquidOrderManager {
854
869
  constructor(client: HyperliquidClient, signer: HyperliquidSigner, config: PerpConfig);
855
870
  placeOrder(signal: PerpTradeSignal): Promise<OrderResult>;
856
871
  cancelOrder(instrument: string, orderId: number): Promise<boolean>;
857
- closePosition(instrument: string, positionSize: number): Promise<OrderResult>;
872
+ cancelAllOrders(userAddress?: `0x${string}`): Promise<CancelAllResult>;
873
+ closePosition(instrument: string, positionSize: number, referencePrice?: number): Promise<OrderResult>;
858
874
  updateLeverage(instrument: string, leverage: number, isCross?: boolean): Promise<boolean>;
859
875
  private getMarketPrice;
876
+ private getReferencePrice;
877
+ private formatDecimal;
860
878
  private parseOrderResponse;
861
879
  private exchangeRequest;
880
+ private signedExchangeRequest;
862
881
  }
863
882
 
864
883
  /**
@@ -964,6 +983,7 @@ interface PredictionTradeSignal {
964
983
  amount: number;
965
984
  limitPrice: number;
966
985
  orderType: 'limit' | 'market';
986
+ marketOrderType?: 'FOK' | 'FAK';
967
987
  confidence: number;
968
988
  reasoning?: string;
969
989
  }
@@ -1078,6 +1098,8 @@ declare class PolymarketClient {
1078
1098
  tokenId: string;
1079
1099
  amount: number;
1080
1100
  side: 'BUY' | 'SELL';
1101
+ price?: number;
1102
+ orderType?: 'FOK' | 'FAK';
1081
1103
  }): Promise<{
1082
1104
  orderId: string;
1083
1105
  success: boolean;
package/dist/index.js CHANGED
@@ -43,7 +43,7 @@ import {
43
43
  loadConfig,
44
44
  loadStrategy,
45
45
  writeSampleConfig
46
- } from "./chunk-ZRAOPQQW.js";
46
+ } from "./chunk-GYYW4EKM.js";
47
47
  export {
48
48
  AcrossAdapter,
49
49
  AerodromeAdapter,
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "@exagent/agent",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
7
10
  "bin": {
8
11
  "exagent": "dist/cli.js"
9
12
  },
@@ -13,8 +16,14 @@
13
16
  "types": "./dist/index.d.ts"
14
17
  }
15
18
  },
19
+ "scripts": {
20
+ "build": "tsup src/index.ts src/cli.ts --format esm --dts",
21
+ "dev": "tsup src/index.ts src/cli.ts --format esm --dts --watch",
22
+ "test": "tsx --test test/**/*.test.ts"
23
+ },
16
24
  "dependencies": {
17
25
  "@clack/prompts": "^1.1.0",
26
+ "@exagent/sdk": "0.2.2",
18
27
  "@polymarket/clob-client": "^5.8.1",
19
28
  "boxen": "^8.0.1",
20
29
  "commander": "^12.1.0",
@@ -23,8 +32,7 @@
23
32
  "picocolors": "^1.1.1",
24
33
  "viem": "^2.48.11",
25
34
  "ws": "^8.20.0",
26
- "zod": "^3.25.76",
27
- "@exagent/sdk": "0.2.2"
35
+ "zod": "^3.25.76"
28
36
  },
29
37
  "devDependencies": {
30
38
  "@types/figlet": "^1.7.0",
@@ -34,10 +42,5 @@
34
42
  "tsup": "^8.5.1",
35
43
  "tsx": "^4.21.0",
36
44
  "typescript": "^5.9.3"
37
- },
38
- "scripts": {
39
- "build": "tsup src/index.ts src/cli.ts --format esm --dts",
40
- "dev": "tsup src/index.ts src/cli.ts --format esm --dts --watch",
41
- "test": "tsx --test test/**/*.test.ts"
42
45
  }
43
- }
46
+ }
@@ -1,240 +0,0 @@
1
- import { getChainConfig } from '../chains.js';
2
- import { ERC20_ABI } from '../spot/types.js';
3
- import type { SpotDEXClient } from '../spot/client.js';
4
- import {
5
- ACROSS_SPOKE_POOL_ABI,
6
- type BridgeRequest,
7
- type BridgeFeeEstimate,
8
- type BridgeResult,
9
- type BridgeConfig,
10
- } from './types.js';
11
-
12
- const ACROSS_API_BASE = 'https://app.across.to/api';
13
- const ZERO_ADDRESS: `0x${string}` = '0x0000000000000000000000000000000000000000';
14
-
15
- export class AcrossAdapter {
16
- private client: SpotDEXClient;
17
- private config: BridgeConfig;
18
-
19
- constructor(client: SpotDEXClient, config: BridgeConfig) {
20
- this.client = client;
21
- this.config = config;
22
- }
23
-
24
- async estimateFee(request: BridgeRequest): Promise<BridgeFeeEstimate> {
25
- const fromChain = getChainConfig(request.fromChain);
26
- const toChain = getChainConfig(request.toChain);
27
- if (!fromChain) throw new Error(`Unknown source chain: ${request.fromChain}`);
28
- if (!toChain) throw new Error(`Unknown destination chain: ${request.toChain}`);
29
-
30
- // Resolve output token on destination chain (same token, different address)
31
- const outputToken = this.resolveOutputToken(request.token, request.fromChain, request.toChain);
32
-
33
- const params = new URLSearchParams({
34
- inputToken: request.token,
35
- outputToken,
36
- originChainId: fromChain.chainId.toString(),
37
- destinationChainId: toChain.chainId.toString(),
38
- amount: request.amount.toString(),
39
- recipient: request.recipient ?? this.client.address,
40
- });
41
-
42
- const url = `${ACROSS_API_BASE}/suggested-fees?${params}`;
43
- const res = await fetch(url);
44
- if (!res.ok) {
45
- const body = await res.text();
46
- throw new Error(`Across fee API error (${res.status}): ${body}`);
47
- }
48
-
49
- const data = await res.json() as {
50
- totalRelayFee: { pct: string };
51
- relayerCapitalFee: { pct: string };
52
- relayerGasFee: { pct: string };
53
- lpFee: { pct: string };
54
- timestamp: string;
55
- estimatedFillTimeSec: number;
56
- isAmountTooLow: boolean;
57
- limits?: { minDeposit: string };
58
- };
59
-
60
- // Calculate output amount: inputAmount - totalFee
61
- const totalFeePct = parseFloat(data.totalRelayFee.pct) / 1e18;
62
- const feeAmount = BigInt(Math.floor(Number(request.amount) * totalFeePct));
63
- const outputAmount = request.amount - feeAmount;
64
-
65
- return {
66
- totalRelayFeePct: totalFeePct * 100,
67
- capitalFeePct: parseFloat(data.relayerCapitalFee.pct) / 1e18 * 100,
68
- lpFeePct: parseFloat(data.lpFee.pct) / 1e18 * 100,
69
- relayGasFeePct: parseFloat(data.relayerGasFee.pct) / 1e18 * 100,
70
- timestamp: parseInt(data.timestamp),
71
- estimatedFillTimeSec: data.estimatedFillTimeSec,
72
- isAmountTooLow: data.isAmountTooLow,
73
- outputAmount,
74
- };
75
- }
76
-
77
- async deposit(request: BridgeRequest): Promise<BridgeResult> {
78
- const fromChain = getChainConfig(request.fromChain);
79
- const toChain = getChainConfig(request.toChain);
80
- if (!fromChain?.acrossSpokePool) throw new Error(`No Across SpokePool on ${request.fromChain}`);
81
- if (!toChain) throw new Error(`Unknown destination chain: ${request.toChain}`);
82
-
83
- const spokePool = fromChain.acrossSpokePool;
84
- const outputToken = this.resolveOutputToken(request.token, request.fromChain, request.toChain) as `0x${string}`;
85
- const recipient = request.recipient ?? this.client.address;
86
-
87
- // IMPORTANT: Approve BEFORE getting the fee quote.
88
- // The Across SpokePool has a tight depositQuoteTimeBuffer — if there's any
89
- // delay between getting the quoteTimestamp and submitting depositV3, the tx
90
- // reverts with InvalidQuoteTimestamp. Approval can take 10+ seconds on L2s.
91
- await this.client.ensureApproval(request.token, spokePool, request.amount, request.fromChain);
92
-
93
- // Get fee estimate (immediately before submitting — no awaits after this!)
94
- const feeEstimate = await this.estimateFee(request);
95
- if (feeEstimate.isAmountTooLow) {
96
- return {
97
- success: false,
98
- depositTxHash: '0x0' as `0x${string}`,
99
- fromChain: request.fromChain,
100
- toChain: request.toChain,
101
- token: request.token,
102
- amount: request.amount,
103
- fee: 0n,
104
- error: 'Amount too low for Across bridge',
105
- };
106
- }
107
-
108
- const { publicClient, walletClient } = this.client.getClients(request.fromChain);
109
-
110
- // Fill deadline: 6 hours from now
111
- const fillDeadline = Math.floor(Date.now() / 1000) + 21600;
112
-
113
- try {
114
- const hash = await walletClient.writeContract({
115
- address: spokePool,
116
- abi: ACROSS_SPOKE_POOL_ABI,
117
- functionName: 'depositV3',
118
- args: [
119
- this.client.address, // depositor
120
- recipient, // recipient
121
- request.token, // inputToken
122
- outputToken, // outputToken
123
- request.amount, // inputAmount
124
- feeEstimate.outputAmount, // outputAmount (inputAmount - fees)
125
- BigInt(toChain.chainId), // destinationChainId
126
- ZERO_ADDRESS, // exclusiveRelayer (none)
127
- feeEstimate.timestamp, // quoteTimestamp
128
- fillDeadline, // fillDeadline
129
- 0, // exclusivityDeadline (none)
130
- '0x', // message (empty)
131
- ],
132
- });
133
-
134
- const receipt = await publicClient.waitForTransactionReceipt({ hash });
135
- const fee = request.amount - feeEstimate.outputAmount;
136
-
137
- console.log(`[bridge] Across deposit: ${hash} (${request.fromChain} → ${request.toChain})`);
138
-
139
- const result: BridgeResult = {
140
- success: true,
141
- depositTxHash: hash,
142
- fromChain: request.fromChain,
143
- toChain: request.toChain,
144
- token: request.token,
145
- amount: request.amount,
146
- fee,
147
- };
148
-
149
- // Poll for fill
150
- const fill = await this.waitForFill(hash, request.fromChain);
151
- if (fill.filled) {
152
- result.fillTxHash = fill.fillTxHash;
153
- result.fillTimestamp = Date.now();
154
- console.log(`[bridge] Across fill confirmed: ${fill.fillTxHash}`);
155
- } else {
156
- // Deposit tx succeeded but fill was not confirmed within the timeout.
157
- // Mark as failure so the trade signal system doesn't report a completed bridge.
158
- result.success = false;
159
- result.error = 'Bridge deposit submitted but fill not confirmed within timeout. Deposit tx may still be filled — check the Across explorer.';
160
- console.warn(`[bridge] Across fill not confirmed within timeout (deposit: ${hash})`);
161
- }
162
-
163
- return result;
164
- } catch (err) {
165
- return {
166
- success: false,
167
- depositTxHash: '0x0' as `0x${string}`,
168
- fromChain: request.fromChain,
169
- toChain: request.toChain,
170
- token: request.token,
171
- amount: request.amount,
172
- fee: 0n,
173
- error: (err as Error).message,
174
- };
175
- }
176
- }
177
-
178
- async waitForFill(
179
- depositTxHash: string,
180
- originChain: string,
181
- ): Promise<{ filled: boolean; fillTxHash?: `0x${string}` }> {
182
- const chainConfig = getChainConfig(originChain);
183
- if (!chainConfig) return { filled: false };
184
-
185
- const startTime = Date.now();
186
- const timeout = this.config.fillTimeoutMs;
187
- const interval = this.config.pollIntervalMs;
188
-
189
- while (Date.now() - startTime < timeout) {
190
- try {
191
- const params = new URLSearchParams({
192
- depositTxHash,
193
- originChainId: chainConfig.chainId.toString(),
194
- });
195
-
196
- const res = await fetch(`${ACROSS_API_BASE}/deposit/status?${params}`);
197
- if (res.ok) {
198
- const data = await res.json() as {
199
- status: string;
200
- fillTx?: string;
201
- };
202
-
203
- if (data.status === 'filled' && data.fillTx) {
204
- return { filled: true, fillTxHash: data.fillTx as `0x${string}` };
205
- }
206
-
207
- if (data.status === 'expired' || data.status === 'refunded') {
208
- return { filled: false };
209
- }
210
- }
211
- } catch {
212
- // Non-critical — retry on next poll
213
- }
214
-
215
- await new Promise(resolve => setTimeout(resolve, interval));
216
- }
217
-
218
- return { filled: false };
219
- }
220
-
221
- /** Resolve the equivalent token address on the destination chain */
222
- private resolveOutputToken(inputToken: `0x${string}`, fromChain: string, toChain: string): string {
223
- const from = getChainConfig(fromChain);
224
- const to = getChainConfig(toChain);
225
- if (!from || !to) return inputToken;
226
-
227
- // If input is USDC on source chain, output is USDC on destination chain
228
- if (inputToken.toLowerCase() === from.usdcAddress.toLowerCase()) {
229
- return to.usdcAddress;
230
- }
231
-
232
- // If input is WETH on source chain, output is WETH on destination chain
233
- if (inputToken.toLowerCase() === from.wethAddress.toLowerCase()) {
234
- return to.wethAddress;
235
- }
236
-
237
- // Default: same address (for tokens deployed at same address on both chains)
238
- return inputToken;
239
- }
240
- }
@@ -1,87 +0,0 @@
1
- import { getChainConfig } from '../chains.js';
2
- import type { SpotDEXClient } from '../spot/client.js';
3
- import { AcrossAdapter } from './across.js';
4
- import type { BridgeConfig, BridgeRequest, BridgeFeeEstimate, BridgeResult } from './types.js';
5
-
6
- const MIN_GAS_WEI = 100_000_000_000_000n; // 0.0001 ETH/POL
7
-
8
- export class BridgeManager {
9
- private across: AcrossAdapter;
10
- private client: SpotDEXClient;
11
- private config: BridgeConfig;
12
-
13
- constructor(client: SpotDEXClient, config: BridgeConfig) {
14
- this.config = config;
15
- this.client = client;
16
- this.across = new AcrossAdapter(client, config);
17
- }
18
-
19
- async estimateFee(request: BridgeRequest): Promise<BridgeFeeEstimate> {
20
- const bridge = request.bridge ?? this.config.defaultBridge;
21
- if (bridge !== 'across') {
22
- throw new Error(`Unsupported bridge: ${bridge}. Only "across" is currently supported.`);
23
- }
24
- return this.across.estimateFee(request);
25
- }
26
-
27
- async bridge(request: BridgeRequest): Promise<BridgeResult> {
28
- const bridge = request.bridge ?? this.config.defaultBridge;
29
- if (bridge !== 'across') {
30
- return {
31
- success: false,
32
- depositTxHash: '0x0' as `0x${string}`,
33
- fromChain: request.fromChain,
34
- toChain: request.toChain,
35
- token: request.token,
36
- amount: request.amount,
37
- fee: 0n,
38
- error: `Unsupported bridge: ${bridge}. Only "across" is currently supported.`,
39
- };
40
- }
41
-
42
- // Enforce max bridge value cap
43
- // Bridge amounts are in token decimals — estimate USD for common tokens (USDC = 6 decimals)
44
- try {
45
- const decimals = await this.client.getDecimals(request.token, request.fromChain);
46
- const amountFloat = Number(request.amount) / 10 ** decimals;
47
- if (amountFloat > this.config.maxBridgeValueUSD) {
48
- return {
49
- success: false,
50
- depositTxHash: '0x0' as `0x${string}`,
51
- fromChain: request.fromChain,
52
- toChain: request.toChain,
53
- token: request.token,
54
- amount: request.amount,
55
- fee: 0n,
56
- error: `Bridge value ${amountFloat.toFixed(2)} exceeds max $${this.config.maxBridgeValueUSD}. Reduce amount or increase maxBridgeValueUSD.`,
57
- };
58
- }
59
- } catch {
60
- // If decimals lookup fails, proceed — let the bridge itself validate
61
- }
62
-
63
- // Pre-check native gas balance on origin chain
64
- try {
65
- const nativeBalance = await this.client.getNativeBalance(request.fromChain);
66
- if (nativeBalance < MIN_GAS_WEI) {
67
- const chainConfig = getChainConfig(request.fromChain);
68
- const nativeName = chainConfig?.nativeCurrency ?? 'ETH';
69
- return {
70
- success: false,
71
- depositTxHash: '0x0' as `0x${string}`,
72
- fromChain: request.fromChain,
73
- toChain: request.toChain,
74
- token: request.token,
75
- amount: request.amount,
76
- fee: 0n,
77
- error: `Insufficient ${nativeName} for gas on ${request.fromChain}. Balance: ${nativeBalance} wei. Need at least 0.0001 ${nativeName}.`,
78
- };
79
- }
80
- } catch {
81
- // Non-critical — proceed and let the bridge itself surface the error
82
- }
83
-
84
- console.log(`[bridge] Bridging via Across: ${request.fromChain} → ${request.toChain} (${request.amount})`);
85
- return this.across.deposit(request);
86
- }
87
- }
@@ -1,9 +0,0 @@
1
- export { AcrossAdapter } from './across.js';
2
- export { BridgeManager } from './bridge-manager.js';
3
- export type {
4
- BridgeConfig,
5
- BridgeRequest,
6
- BridgeFeeEstimate,
7
- BridgeResult,
8
- } from './types.js';
9
- export { DEFAULT_BRIDGE_CONFIG } from './types.js';
@@ -1,77 +0,0 @@
1
- // ─── Bridge Config ──────────────────────────────────────────────
2
-
3
- export interface BridgeConfig {
4
- enabled: boolean;
5
- defaultBridge: string;
6
- maxBridgeValueUSD: number;
7
- fillTimeoutMs: number;
8
- pollIntervalMs: number;
9
- }
10
-
11
- export const DEFAULT_BRIDGE_CONFIG: BridgeConfig = {
12
- enabled: false,
13
- defaultBridge: 'across',
14
- maxBridgeValueUSD: 10_000,
15
- fillTimeoutMs: 300_000, // 5 minutes
16
- pollIntervalMs: 2_000, // 2 seconds
17
- };
18
-
19
- // ─── Bridge Request & Results ───────────────────────────────────
20
-
21
- export interface BridgeRequest {
22
- token: `0x${string}`;
23
- amount: bigint;
24
- fromChain: string;
25
- toChain: string;
26
- recipient?: `0x${string}`;
27
- bridge?: string;
28
- }
29
-
30
- export interface BridgeFeeEstimate {
31
- totalRelayFeePct: number;
32
- capitalFeePct: number;
33
- lpFeePct: number;
34
- relayGasFeePct: number;
35
- timestamp: number;
36
- estimatedFillTimeSec: number;
37
- isAmountTooLow: boolean;
38
- outputAmount: bigint;
39
- }
40
-
41
- export interface BridgeResult {
42
- success: boolean;
43
- depositTxHash: `0x${string}`;
44
- fromChain: string;
45
- toChain: string;
46
- token: `0x${string}`;
47
- amount: bigint;
48
- fee: bigint;
49
- fillTxHash?: `0x${string}`;
50
- fillTimestamp?: number;
51
- error?: string;
52
- }
53
-
54
- // ─── Across SpokePool ABI Fragment ──────────────────────────────
55
-
56
- export const ACROSS_SPOKE_POOL_ABI = [
57
- {
58
- type: 'function' as const,
59
- name: 'depositV3' as const,
60
- inputs: [
61
- { name: 'depositor', type: 'address' as const },
62
- { name: 'recipient', type: 'address' as const },
63
- { name: 'inputToken', type: 'address' as const },
64
- { name: 'outputToken', type: 'address' as const },
65
- { name: 'inputAmount', type: 'uint256' as const },
66
- { name: 'outputAmount', type: 'uint256' as const },
67
- { name: 'destinationChainId', type: 'uint256' as const },
68
- { name: 'exclusiveRelayer', type: 'address' as const },
69
- { name: 'quoteTimestamp', type: 'uint32' as const },
70
- { name: 'fillDeadline', type: 'uint32' as const },
71
- { name: 'exclusivityDeadline', type: 'uint32' as const },
72
- { name: 'message', type: 'bytes' as const },
73
- ],
74
- outputs: [],
75
- stateMutability: 'payable' as const,
76
- },
77
- ] as const;