amped-defi 1.0.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 (189) hide show
  1. package/README.md +757 -0
  2. package/dist/__mocks__/@sodax/sdk.d.ts +24 -0
  3. package/dist/__mocks__/@sodax/sdk.d.ts.map +1 -0
  4. package/dist/__mocks__/@sodax/sdk.js +24 -0
  5. package/dist/__mocks__/@sodax/sdk.js.map +1 -0
  6. package/dist/__tests__/setup.d.ts +4 -0
  7. package/dist/__tests__/setup.d.ts.map +1 -0
  8. package/dist/__tests__/setup.js +32 -0
  9. package/dist/__tests__/setup.js.map +1 -0
  10. package/dist/index.d.ts +66 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +281 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/policy/policyEngine.d.ts +119 -0
  15. package/dist/policy/policyEngine.d.ts.map +1 -0
  16. package/dist/policy/policyEngine.js +322 -0
  17. package/dist/policy/policyEngine.js.map +1 -0
  18. package/dist/providers/spokeProviderFactory.d.ts +38 -0
  19. package/dist/providers/spokeProviderFactory.d.ts.map +1 -0
  20. package/dist/providers/spokeProviderFactory.js +212 -0
  21. package/dist/providers/spokeProviderFactory.js.map +1 -0
  22. package/dist/sodax/client.d.ts +34 -0
  23. package/dist/sodax/client.d.ts.map +1 -0
  24. package/dist/sodax/client.js +99 -0
  25. package/dist/sodax/client.js.map +1 -0
  26. package/dist/tools/bridge.d.ts +105 -0
  27. package/dist/tools/bridge.d.ts.map +1 -0
  28. package/dist/tools/bridge.js +334 -0
  29. package/dist/tools/bridge.js.map +1 -0
  30. package/dist/tools/discovery.d.ts +141 -0
  31. package/dist/tools/discovery.d.ts.map +1 -0
  32. package/dist/tools/discovery.js +777 -0
  33. package/dist/tools/discovery.js.map +1 -0
  34. package/dist/tools/moneyMarket.d.ts +227 -0
  35. package/dist/tools/moneyMarket.d.ts.map +1 -0
  36. package/dist/tools/moneyMarket.js +867 -0
  37. package/dist/tools/moneyMarket.js.map +1 -0
  38. package/dist/tools/portfolio.d.ts +43 -0
  39. package/dist/tools/portfolio.d.ts.map +1 -0
  40. package/dist/tools/portfolio.js +538 -0
  41. package/dist/tools/portfolio.js.map +1 -0
  42. package/dist/tools/swap.d.ts +71 -0
  43. package/dist/tools/swap.d.ts.map +1 -0
  44. package/dist/tools/swap.js +762 -0
  45. package/dist/tools/swap.js.map +1 -0
  46. package/dist/tools/walletManagement.d.ts +80 -0
  47. package/dist/tools/walletManagement.d.ts.map +1 -0
  48. package/dist/tools/walletManagement.js +289 -0
  49. package/dist/tools/walletManagement.js.map +1 -0
  50. package/dist/types.d.ts +205 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +5 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/utils/errorUtils.d.ts +2 -0
  55. package/dist/utils/errorUtils.d.ts.map +1 -0
  56. package/dist/utils/errorUtils.js +19 -0
  57. package/dist/utils/errorUtils.js.map +1 -0
  58. package/dist/utils/errors.d.ts +144 -0
  59. package/dist/utils/errors.d.ts.map +1 -0
  60. package/dist/utils/errors.js +310 -0
  61. package/dist/utils/errors.js.map +1 -0
  62. package/dist/utils/positionAggregator.d.ts +122 -0
  63. package/dist/utils/positionAggregator.d.ts.map +1 -0
  64. package/dist/utils/positionAggregator.js +377 -0
  65. package/dist/utils/positionAggregator.js.map +1 -0
  66. package/dist/utils/priceService.d.ts +45 -0
  67. package/dist/utils/priceService.d.ts.map +1 -0
  68. package/dist/utils/priceService.js +108 -0
  69. package/dist/utils/priceService.js.map +1 -0
  70. package/dist/utils/sodaxApi.d.ts +92 -0
  71. package/dist/utils/sodaxApi.d.ts.map +1 -0
  72. package/dist/utils/sodaxApi.js +143 -0
  73. package/dist/utils/sodaxApi.js.map +1 -0
  74. package/dist/utils/tokenResolver.d.ts +54 -0
  75. package/dist/utils/tokenResolver.d.ts.map +1 -0
  76. package/dist/utils/tokenResolver.js +252 -0
  77. package/dist/utils/tokenResolver.js.map +1 -0
  78. package/dist/wallet/backendConfig.d.ts +37 -0
  79. package/dist/wallet/backendConfig.d.ts.map +1 -0
  80. package/dist/wallet/backendConfig.js +125 -0
  81. package/dist/wallet/backendConfig.js.map +1 -0
  82. package/dist/wallet/backends/BankrBackend.d.ts +73 -0
  83. package/dist/wallet/backends/BankrBackend.d.ts.map +1 -0
  84. package/dist/wallet/backends/BankrBackend.js +315 -0
  85. package/dist/wallet/backends/BankrBackend.js.map +1 -0
  86. package/dist/wallet/backends/BankrWalletProvider.d.ts +75 -0
  87. package/dist/wallet/backends/BankrWalletProvider.d.ts.map +1 -0
  88. package/dist/wallet/backends/BankrWalletProvider.js +243 -0
  89. package/dist/wallet/backends/BankrWalletProvider.js.map +1 -0
  90. package/dist/wallet/backends/EnvBackend.d.ts +50 -0
  91. package/dist/wallet/backends/EnvBackend.d.ts.map +1 -0
  92. package/dist/wallet/backends/EnvBackend.js +114 -0
  93. package/dist/wallet/backends/EnvBackend.js.map +1 -0
  94. package/dist/wallet/backends/EvmWalletSkillBackend.d.ts +40 -0
  95. package/dist/wallet/backends/EvmWalletSkillBackend.d.ts.map +1 -0
  96. package/dist/wallet/backends/EvmWalletSkillBackend.js +81 -0
  97. package/dist/wallet/backends/EvmWalletSkillBackend.js.map +1 -0
  98. package/dist/wallet/backends/index.d.ts +10 -0
  99. package/dist/wallet/backends/index.d.ts.map +1 -0
  100. package/dist/wallet/backends/index.js +10 -0
  101. package/dist/wallet/backends/index.js.map +1 -0
  102. package/dist/wallet/index.d.ts +9 -0
  103. package/dist/wallet/index.d.ts.map +1 -0
  104. package/dist/wallet/index.js +12 -0
  105. package/dist/wallet/index.js.map +1 -0
  106. package/dist/wallet/providers/AmpedWalletProvider.d.ts +107 -0
  107. package/dist/wallet/providers/AmpedWalletProvider.d.ts.map +1 -0
  108. package/dist/wallet/providers/AmpedWalletProvider.js +208 -0
  109. package/dist/wallet/providers/AmpedWalletProvider.js.map +1 -0
  110. package/dist/wallet/providers/BankrBackend.d.ts +105 -0
  111. package/dist/wallet/providers/BankrBackend.d.ts.map +1 -0
  112. package/dist/wallet/providers/BankrBackend.js +327 -0
  113. package/dist/wallet/providers/BankrBackend.js.map +1 -0
  114. package/dist/wallet/providers/LocalKeyBackend.d.ts +62 -0
  115. package/dist/wallet/providers/LocalKeyBackend.d.ts.map +1 -0
  116. package/dist/wallet/providers/LocalKeyBackend.js +152 -0
  117. package/dist/wallet/providers/LocalKeyBackend.js.map +1 -0
  118. package/dist/wallet/providers/chainConfig.d.ts +209 -0
  119. package/dist/wallet/providers/chainConfig.d.ts.map +1 -0
  120. package/dist/wallet/providers/chainConfig.js +175 -0
  121. package/dist/wallet/providers/chainConfig.js.map +1 -0
  122. package/dist/wallet/providers/index.d.ts +30 -0
  123. package/dist/wallet/providers/index.d.ts.map +1 -0
  124. package/dist/wallet/providers/index.js +32 -0
  125. package/dist/wallet/providers/index.js.map +1 -0
  126. package/dist/wallet/providers/types.d.ts +156 -0
  127. package/dist/wallet/providers/types.d.ts.map +1 -0
  128. package/dist/wallet/providers/types.js +11 -0
  129. package/dist/wallet/providers/types.js.map +1 -0
  130. package/dist/wallet/skillWalletAdapter.d.ts +96 -0
  131. package/dist/wallet/skillWalletAdapter.d.ts.map +1 -0
  132. package/dist/wallet/skillWalletAdapter.js +280 -0
  133. package/dist/wallet/skillWalletAdapter.js.map +1 -0
  134. package/dist/wallet/types.d.ts +134 -0
  135. package/dist/wallet/types.d.ts.map +1 -0
  136. package/dist/wallet/types.js +138 -0
  137. package/dist/wallet/types.js.map +1 -0
  138. package/dist/wallet/walletManager.d.ts +111 -0
  139. package/dist/wallet/walletManager.d.ts.map +1 -0
  140. package/dist/wallet/walletManager.js +476 -0
  141. package/dist/wallet/walletManager.js.map +1 -0
  142. package/dist/wallet/walletRegistry.d.ts +95 -0
  143. package/dist/wallet/walletRegistry.d.ts.map +1 -0
  144. package/dist/wallet/walletRegistry.js +184 -0
  145. package/dist/wallet/walletRegistry.js.map +1 -0
  146. package/index.js +2 -0
  147. package/openclaw.plugin.json +37 -0
  148. package/package.json +69 -0
  149. package/src/__mocks__/@sodax/sdk.ts +28 -0
  150. package/src/__tests__/errors.test.ts +238 -0
  151. package/src/__tests__/policyEngine.test.ts +354 -0
  152. package/src/__tests__/positionAggregator.test.ts +271 -0
  153. package/src/__tests__/setup.ts +35 -0
  154. package/src/__tests__/sodaxApi.test.ts +203 -0
  155. package/src/__tests__/walletRegistry.test.ts +155 -0
  156. package/src/index.ts +376 -0
  157. package/src/policy/policyEngine.ts +389 -0
  158. package/src/providers/spokeProviderFactory.ts +283 -0
  159. package/src/sodax/client.ts +113 -0
  160. package/src/tools/bridge.ts +425 -0
  161. package/src/tools/discovery.ts +989 -0
  162. package/src/tools/moneyMarket.ts +1265 -0
  163. package/src/tools/portfolio.ts +697 -0
  164. package/src/tools/swap.ts +926 -0
  165. package/src/tools/walletManagement.ts +359 -0
  166. package/src/types.ts +228 -0
  167. package/src/utils/errorUtils.ts +16 -0
  168. package/src/utils/errors.ts +396 -0
  169. package/src/utils/positionAggregator.ts +559 -0
  170. package/src/utils/priceService.ts +153 -0
  171. package/src/utils/sodaxApi.ts +261 -0
  172. package/src/utils/tokenResolver.ts +286 -0
  173. package/src/wallet/backendConfig.ts +151 -0
  174. package/src/wallet/backends/BankrBackend.ts +399 -0
  175. package/src/wallet/backends/BankrWalletProvider.ts +329 -0
  176. package/src/wallet/backends/EnvBackend.ts +149 -0
  177. package/src/wallet/backends/EvmWalletSkillBackend.ts +110 -0
  178. package/src/wallet/backends/index.ts +10 -0
  179. package/src/wallet/index.ts +14 -0
  180. package/src/wallet/providers/AmpedWalletProvider.ts +267 -0
  181. package/src/wallet/providers/BankrBackend.ts +407 -0
  182. package/src/wallet/providers/LocalKeyBackend.ts +184 -0
  183. package/src/wallet/providers/chainConfig.ts +194 -0
  184. package/src/wallet/providers/index.ts +62 -0
  185. package/src/wallet/providers/types.ts +186 -0
  186. package/src/wallet/skillWalletAdapter.ts +335 -0
  187. package/src/wallet/types.ts +248 -0
  188. package/src/wallet/walletManager.ts +561 -0
  189. package/src/wallet/walletRegistry.ts +216 -0
@@ -0,0 +1,113 @@
1
+ /**
2
+ * SODAX SDK Client Singleton
3
+ *
4
+ * Provides a singleton instance of the SODAX SDK client with lazy initialization.
5
+ * Uses dynamic configuration by default to fetch live token lists and routes.
6
+ */
7
+
8
+ import { Sodax } from "@sodax/sdk";
9
+
10
+ // Singleton instance
11
+ let sodaxClient: Sodax | null = null;
12
+
13
+ /**
14
+ * HARDCODED PARTNER CONFIGURATION
15
+ * These values are baked in and cannot be overridden.
16
+ *
17
+ * Fee is 0.2% (20 basis points)
18
+ * SDK expects: percentage in bps where 100 = 1%, so 20 = 0.2%
19
+ */
20
+ const PARTNER_FEE = {
21
+ address: "0xd99C871c8130B03C8BB597A74fb5EAA7a46864Bb" as `0x${string}`,
22
+ percentage: 20, // 20 bps = 0.2%
23
+ };
24
+
25
+ /**
26
+ * Initialize the SODAX SDK client
27
+ * Always uses dynamic config to fetch live token lists and routes
28
+ */
29
+ async function initializeSodax(): Promise<Sodax> {
30
+ // Initialize SODAX with hardcoded partner fee on ALL services
31
+ const sodax = new Sodax({
32
+ swaps: { partnerFee: PARTNER_FEE },
33
+ moneyMarket: { partnerFee: PARTNER_FEE },
34
+ bridge: { partnerFee: PARTNER_FEE },
35
+ } as any);
36
+
37
+ // Suppress SDK console output during initialization
38
+ const originalWarn = console.warn;
39
+ const originalLog = console.log;
40
+ console.warn = () => {};
41
+ console.log = () => {};
42
+
43
+ try {
44
+ // Initialize with dynamic config
45
+ await sodax.initialize();
46
+ } finally {
47
+ // Restore console
48
+ console.warn = originalWarn;
49
+ console.log = originalLog;
50
+ }
51
+
52
+ return sodax;
53
+ }
54
+
55
+ /**
56
+ * Get the singleton SODAX client instance
57
+ * Initializes on first call if not already initialized
58
+ */
59
+ export async function getSodaxClientAsync(): Promise<Sodax> {
60
+ if (!sodaxClient) {
61
+ sodaxClient = await initializeSodax();
62
+ }
63
+ return sodaxClient;
64
+ }
65
+
66
+ /**
67
+ * Synchronous accessor for the SODAX client
68
+ * Throws if the client hasn't been initialized yet
69
+ */
70
+ export function getSodaxClient(): Sodax {
71
+ if (!sodaxClient) {
72
+ throw new Error(
73
+ "SODAX client not initialized. Call getSodaxClientAsync() first.",
74
+ );
75
+ }
76
+ return sodaxClient;
77
+ }
78
+
79
+ /**
80
+ * Pre-initialize the SODAX client at plugin startup
81
+ */
82
+ export async function preInitializeSodax(): Promise<void> {
83
+ if (!sodaxClient) {
84
+ sodaxClient = await initializeSodax();
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Reset the SODAX client (useful for testing)
90
+ */
91
+ export function resetSodaxClient(): void {
92
+ sodaxClient = null;
93
+ }
94
+
95
+ /**
96
+ * SodaxClient class wrapper for backward compatibility
97
+ */
98
+ export class SodaxClient {
99
+ private static instance: Sodax | null = null;
100
+
101
+ static async getClient(): Promise<Sodax> {
102
+ if (!SodaxClient.instance) {
103
+ SodaxClient.instance = await initializeSodax();
104
+ sodaxClient = SodaxClient.instance;
105
+ }
106
+ return SodaxClient.instance;
107
+ }
108
+
109
+ static reset(): void {
110
+ SodaxClient.instance = null;
111
+ sodaxClient = null;
112
+ }
113
+ }
@@ -0,0 +1,425 @@
1
+ /**
2
+ * Bridge Tools for Amped DeFi Plugin
3
+ *
4
+ * NOTE: Bridge operations use the swap infrastructure internally.
5
+ * Cross-chain swaps and bridges are functionally equivalent in SODAX -
6
+ * both use the intent-based cross-chain messaging system.
7
+ *
8
+ * Tools:
9
+ * - amped_bridge_discover: Get bridgeable tokens for a route
10
+ * - amped_bridge_quote: Check bridgeability and max amounts
11
+ * - amped_bridge_execute: Execute bridge (delegates to swap)
12
+ *
13
+ * @module tools/bridge
14
+ */
15
+
16
+ import { Static, Type } from '@sinclair/typebox';
17
+ import { AgentTools, BridgeOperation } from '../types';
18
+ import { getSodaxClient } from '../sodax/client';
19
+ import { getSpokeProvider } from '../providers/spokeProviderFactory';
20
+ import { PolicyEngine } from '../policy/policyEngine';
21
+ import { getWalletManager } from '../wallet/walletManager';
22
+ import { serializeError } from '../utils/errorUtils';
23
+ import { resolveToken } from '../utils/tokenResolver';
24
+ import { toSodaxChainId } from '../wallet/types';
25
+ import { handleSwapQuote, handleSwapExecute } from './swap';
26
+
27
+ // ============================================================================
28
+ // TypeBox Schemas
29
+ // ============================================================================
30
+
31
+ /**
32
+ * Schema for amped_bridge_discover tool
33
+ * Discover bridgeable tokens for a given source chain, destination chain, and source token
34
+ */
35
+ const BridgeDiscoverSchema = Type.Object({
36
+ srcChainId: Type.String({
37
+ description: 'Source chain ID (e.g., "ethereum", "arbitrum")',
38
+ }),
39
+ dstChainId: Type.String({
40
+ description: 'Destination chain ID (e.g., "sonic", "optimism")',
41
+ }),
42
+ srcToken: Type.String({
43
+ description: 'Source token address or symbol',
44
+ }),
45
+ });
46
+
47
+ /**
48
+ * Schema for amped_bridge_quote tool
49
+ * Check if a bridge route is valid and get maximum bridgeable amount
50
+ */
51
+ const BridgeQuoteSchema = Type.Object({
52
+ srcChainId: Type.String({
53
+ description: 'Source chain ID',
54
+ }),
55
+ dstChainId: Type.String({
56
+ description: 'Destination chain ID',
57
+ }),
58
+ srcToken: Type.String({
59
+ description: 'Source token address or symbol',
60
+ }),
61
+ dstToken: Type.String({
62
+ description: 'Destination token address or symbol',
63
+ }),
64
+ });
65
+
66
+ /**
67
+ * Schema for amped_bridge_execute tool
68
+ * Execute a bridge operation with full allowance check and approval flow
69
+ */
70
+ const BridgeExecuteSchema = Type.Object({
71
+ walletId: Type.String({
72
+ description: 'Unique identifier for the wallet to use',
73
+ }),
74
+ srcChainId: Type.String({
75
+ description: 'Source chain ID',
76
+ }),
77
+ dstChainId: Type.String({
78
+ description: 'Destination chain ID',
79
+ }),
80
+ srcToken: Type.String({
81
+ description: 'Source token address or symbol to bridge from',
82
+ }),
83
+ dstToken: Type.String({
84
+ description: 'Destination token address or symbol to bridge to',
85
+ }),
86
+ amount: Type.String({
87
+ description: 'Amount to bridge in human-readable units (e.g., "100.5")',
88
+ }),
89
+ recipient: Type.Optional(
90
+ Type.String({
91
+ description: 'Recipient address on destination chain (defaults to wallet address)',
92
+ })
93
+ ),
94
+ timeoutMs: Type.Optional(
95
+ Type.Number({
96
+ description: 'Timeout for bridge operation in milliseconds',
97
+ default: 300000, // 5 minutes
98
+ })
99
+ ),
100
+ policyId: Type.Optional(
101
+ Type.String({
102
+ description: 'Optional policy profile ID for custom limits',
103
+ })
104
+ ),
105
+ });
106
+
107
+ // Type inference from schemas
108
+ type BridgeDiscoverParams = Static<typeof BridgeDiscoverSchema>;
109
+ type BridgeQuoteParams = Static<typeof BridgeQuoteSchema>;
110
+ type BridgeExecuteParams = Static<typeof BridgeExecuteSchema>;
111
+
112
+ // ============================================================================
113
+ // Bridge Discover Tool
114
+ // ============================================================================
115
+
116
+ /**
117
+ * Transaction result type for bridge execute
118
+ */
119
+ interface TransactionResult {
120
+ spokeTxHash: string;
121
+ hubTxHash?: string;
122
+ }
123
+
124
+ /**
125
+ * Handler for amped_bridge_discover
126
+ * Retrieves tokens that can be bridged from the source chain to destination chain
127
+ *
128
+ * @param params - Discovery parameters (srcChainId, dstChainId, srcToken)
129
+ * @returns List of bridgeable tokens
130
+ */
131
+ async function handleBridgeDiscover(
132
+ params: BridgeDiscoverParams
133
+ ): Promise<{ bridgeableTokens: string[] }> {
134
+ const { srcChainId, dstChainId, srcToken } = params;
135
+
136
+ // Resolve token symbol to address
137
+ const srcTokenAddr = await resolveToken(srcChainId, srcToken);
138
+
139
+ console.log('[bridge:discover] Discovering bridgeable tokens', {
140
+ srcChainId,
141
+ dstChainId,
142
+ srcToken,
143
+ });
144
+
145
+ try {
146
+ const sodax = getSodaxClient();
147
+
148
+ // Get bridgeable tokens from SODAX SDK
149
+ // SDK API: getBridgeableTokens(from: SpokeChainId, to: SpokeChainId, token: string)
150
+ const result = sodax.bridge.getBridgeableTokens(
151
+ toSodaxChainId(srcChainId) as any,
152
+ toSodaxChainId(dstChainId) as any,
153
+ srcTokenAddr
154
+ );
155
+
156
+ // Handle Result type - SDK returns Result<XToken[], unknown>
157
+ if (!result.ok) {
158
+ throw new Error(`Failed to get bridgeable tokens: ${serializeError((result as any).error) || 'Unknown error'}`);
159
+ }
160
+
161
+ const tokens = result.value;
162
+ const bridgeableTokens = tokens.map((t: any) => t.address || t.symbol || String(t));
163
+
164
+ console.log('[bridge:discover] Found bridgeable tokens', {
165
+ count: bridgeableTokens.length,
166
+ tokens: bridgeableTokens,
167
+ });
168
+
169
+ return { bridgeableTokens };
170
+ } catch (error) {
171
+ const errorMessage = error instanceof Error ? error.message : String(error);
172
+ console.error('[bridge:discover] Failed to discover bridgeable tokens', {
173
+ error: errorMessage,
174
+ srcChainId,
175
+ dstChainId,
176
+ srcToken,
177
+ });
178
+ throw new Error(`Failed to discover bridgeable tokens: ${errorMessage}`);
179
+ }
180
+ }
181
+
182
+ // ============================================================================
183
+ // Bridge Quote Tool
184
+ // ============================================================================
185
+
186
+ /**
187
+ * Handler for amped_bridge_quote
188
+ * Checks if a bridge route is valid and returns the maximum bridgeable amount
189
+ *
190
+ * @param params - Quote parameters (srcChainId, dstChainId, srcToken, dstToken)
191
+ * @returns Bridgeability status and maximum amount
192
+ */
193
+ async function handleBridgeQuote(
194
+ params: BridgeQuoteParams
195
+ ): Promise<{ isBridgeable: boolean; maxBridgeableAmount: string }> {
196
+ const { srcChainId, dstChainId, srcToken, dstToken } = params;
197
+
198
+ // Resolve token symbols to addresses
199
+ const srcTokenAddr = await resolveToken(srcChainId, srcToken);
200
+ const dstTokenAddr = await resolveToken(dstChainId, dstToken);
201
+
202
+ console.log('[bridge:quote] Checking bridge quote', {
203
+ srcChainId,
204
+ dstChainId,
205
+ srcToken,
206
+ dstToken,
207
+ });
208
+
209
+ try {
210
+ const sodax = getSodaxClient();
211
+
212
+ // Create XToken objects for the SDK
213
+ const fromToken = { chainId: toSodaxChainId(srcChainId), address: srcTokenAddr } as any;
214
+ const toToken = { chainId: toSodaxChainId(dstChainId), address: dstTokenAddr } as any;
215
+
216
+ // Check if the route is bridgeable using isBridgeable
217
+ // SDK may have different signature - adapting based on available methods
218
+ let isBridgeable = false;
219
+ try {
220
+ // Try to get bridgeable tokens to check if route exists
221
+ const result = sodax.bridge.getBridgeableTokens(
222
+ toSodaxChainId(srcChainId) as any,
223
+ toSodaxChainId(dstChainId) as any,
224
+ srcTokenAddr
225
+ );
226
+ if (result.ok && result.value.length > 0) {
227
+ isBridgeable = result.value.some((t: any) =>
228
+ t.address?.toLowerCase() === dstTokenAddr.toLowerCase() ||
229
+ t === dstTokenAddr
230
+ );
231
+ }
232
+ } catch {
233
+ isBridgeable = false;
234
+ }
235
+
236
+ // Get maximum bridgeable amount
237
+ let maxBridgeableAmount = '0';
238
+ if (isBridgeable) {
239
+ try {
240
+ // SDK API: getBridgeableAmount(from: XToken, to: XToken)
241
+ const maxAmountResult = await sodax.bridge.getBridgeableAmount(fromToken, toToken);
242
+ if (maxAmountResult.ok) {
243
+ const val = maxAmountResult.value as any;
244
+ // BridgeLimit may have different property names depending on SDK version
245
+ maxBridgeableAmount = val?.max?.toString() ||
246
+ val?.maxAmount?.toString() ||
247
+ val?.limit?.toString() ||
248
+ val?.toString() || '0';
249
+ }
250
+ } catch (e) {
251
+ console.warn('[bridge:quote] Could not get max bridgeable amount:', e);
252
+ }
253
+ }
254
+
255
+ console.log('[bridge:quote] Bridge quote result', {
256
+ isBridgeable,
257
+ maxBridgeableAmount,
258
+ });
259
+
260
+ return { isBridgeable, maxBridgeableAmount };
261
+ } catch (error) {
262
+ const errorMessage = error instanceof Error ? error.message : String(error);
263
+ console.error('[bridge:quote] Failed to get bridge quote', {
264
+ error: errorMessage,
265
+ srcChainId,
266
+ dstChainId,
267
+ srcToken,
268
+ dstToken,
269
+ });
270
+ throw new Error(`Failed to get bridge quote: ${errorMessage}`);
271
+ }
272
+ }
273
+
274
+ // ============================================================================
275
+ // Bridge Execute Tool (Delegates to Swap)
276
+ // ============================================================================
277
+
278
+ /**
279
+ * Handler for amped_bridge_execute
280
+ *
281
+ * NOTE: Bridge operations are implemented via swap infrastructure.
282
+ * Cross-chain swaps and bridges are functionally equivalent in SODAX -
283
+ * both use the intent-based cross-chain messaging system.
284
+ *
285
+ * Flow:
286
+ * 1. Get swap quote for the bridge route
287
+ * 2. Execute swap (handles allowance, approval, and execution)
288
+ *
289
+ * @param params - Execution parameters
290
+ * @returns Transaction result with status and tracking links
291
+ */
292
+ async function handleBridgeExecute(
293
+ params: BridgeExecuteParams
294
+ ): Promise<TransactionResult> {
295
+ const {
296
+ walletId,
297
+ srcChainId,
298
+ dstChainId,
299
+ srcToken,
300
+ dstToken,
301
+ amount,
302
+ recipient,
303
+ timeoutMs = 300000,
304
+ policyId,
305
+ } = params;
306
+
307
+ console.log('[bridge:execute] Delegating to swap infrastructure', {
308
+ walletId,
309
+ srcChainId,
310
+ dstChainId,
311
+ srcToken,
312
+ dstToken,
313
+ amount,
314
+ });
315
+
316
+ try {
317
+ // Step 1: Get a swap quote for this bridge route
318
+ const quoteResult = await handleSwapQuote({
319
+ walletId,
320
+ srcChainId,
321
+ dstChainId,
322
+ srcToken,
323
+ dstToken,
324
+ amount,
325
+ type: 'exact_input',
326
+ slippageBps: 100, // 1% slippage for bridges
327
+ recipient,
328
+ });
329
+
330
+ console.log('[bridge:execute] Got swap quote', quoteResult);
331
+
332
+ // Step 2: Execute the swap
333
+ const swapResult = await handleSwapExecute({
334
+ walletId,
335
+ quote: {
336
+ srcChainId,
337
+ dstChainId,
338
+ srcToken: String(quoteResult.srcToken),
339
+ dstToken: String(quoteResult.dstToken),
340
+ inputAmount: String(quoteResult.inputAmount),
341
+ outputAmount: String(quoteResult.outputAmount),
342
+ slippageBps: Number(quoteResult.slippageBps),
343
+ deadline: Number(quoteResult.deadline),
344
+ recipient,
345
+ },
346
+ policyId,
347
+ timeoutMs,
348
+ });
349
+
350
+ console.log('[bridge:execute] Swap executed', swapResult);
351
+
352
+ // Map swap result to bridge result format
353
+ return {
354
+ spokeTxHash: String(swapResult.initiationTx || swapResult.spokeTxHash || ''),
355
+ hubTxHash: swapResult.hubTxHash ? String(swapResult.hubTxHash) : undefined,
356
+ status: String(swapResult.status),
357
+ message: swapResult.message ? String(swapResult.message) : 'Bridge executed via swap infrastructure',
358
+ sodaxScanUrl: swapResult.sodaxScanUrl ? String(swapResult.sodaxScanUrl) : undefined,
359
+ } as TransactionResult;
360
+ } catch (error) {
361
+ const errorMessage = serializeError(error);
362
+ console.error('[bridge:execute] Bridge via swap failed:', errorMessage);
363
+ throw new Error(`Bridge execution failed: ${errorMessage}`);
364
+ }
365
+ }
366
+
367
+ // ============================================================================
368
+ // Tool Registration
369
+ // ============================================================================
370
+
371
+ /**
372
+ * Register all bridge tools with the agent tools registry
373
+ *
374
+ * @param agentTools - The agent tools registry
375
+ */
376
+ export function registerBridgeTools(agentTools: AgentTools): void {
377
+ // Register bridge discover tool
378
+ agentTools.register({
379
+ name: 'amped_bridge_discover',
380
+ summary: 'Discover bridgeable tokens for a given source chain and token',
381
+ description:
382
+ 'Retrieves a list of tokens that can be bridged from the specified source chain ' +
383
+ 'to the destination chain, starting from a specific source token. ' +
384
+ 'Use this to find valid bridge routes before requesting a quote.',
385
+ schema: BridgeDiscoverSchema,
386
+ handler: handleBridgeDiscover,
387
+ });
388
+
389
+ console.log('[bridge] Registered tool: amped_bridge_discover');
390
+
391
+ // Register bridge quote tool
392
+ agentTools.register({
393
+ name: 'amped_bridge_quote',
394
+ summary: 'Check bridgeability and get maximum bridgeable amount',
395
+ description:
396
+ 'Validates whether a specific bridge route (source chain/token → destination chain/token) ' +
397
+ 'is supported and returns the maximum amount that can be bridged. ' +
398
+ 'Always call this before executing a bridge to verify the route is valid.',
399
+ schema: BridgeQuoteSchema,
400
+ handler: handleBridgeQuote,
401
+ });
402
+
403
+ console.log('[bridge] Registered tool: amped_bridge_quote');
404
+
405
+ // Register bridge execute tool
406
+ agentTools.register({
407
+ name: 'amped_bridge_execute',
408
+ summary: 'Execute a cross-chain bridge operation',
409
+ description:
410
+ 'Executes a bridge operation that moves tokens from a source chain to a destination chain. ' +
411
+ 'This tool handles the complete flow: policy validation, allowance checking, ' +
412
+ 'token approval (if needed), and bridge execution. ' +
413
+ 'Returns transaction hashes for both the spoke chain and hub chain.',
414
+ schema: BridgeExecuteSchema,
415
+ handler: handleBridgeExecute,
416
+ });
417
+
418
+ console.log('[bridge] Registered tool: amped_bridge_execute');
419
+ }
420
+
421
+ // Export schemas for testing and reuse
422
+ export { BridgeDiscoverSchema, BridgeQuoteSchema, BridgeExecuteSchema };
423
+
424
+ // Export handlers
425
+ export { handleBridgeDiscover, handleBridgeQuote, handleBridgeExecute };