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.
- package/README.md +757 -0
- package/dist/__mocks__/@sodax/sdk.d.ts +24 -0
- package/dist/__mocks__/@sodax/sdk.d.ts.map +1 -0
- package/dist/__mocks__/@sodax/sdk.js +24 -0
- package/dist/__mocks__/@sodax/sdk.js.map +1 -0
- package/dist/__tests__/setup.d.ts +4 -0
- package/dist/__tests__/setup.d.ts.map +1 -0
- package/dist/__tests__/setup.js +32 -0
- package/dist/__tests__/setup.js.map +1 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +281 -0
- package/dist/index.js.map +1 -0
- package/dist/policy/policyEngine.d.ts +119 -0
- package/dist/policy/policyEngine.d.ts.map +1 -0
- package/dist/policy/policyEngine.js +322 -0
- package/dist/policy/policyEngine.js.map +1 -0
- package/dist/providers/spokeProviderFactory.d.ts +38 -0
- package/dist/providers/spokeProviderFactory.d.ts.map +1 -0
- package/dist/providers/spokeProviderFactory.js +212 -0
- package/dist/providers/spokeProviderFactory.js.map +1 -0
- package/dist/sodax/client.d.ts +34 -0
- package/dist/sodax/client.d.ts.map +1 -0
- package/dist/sodax/client.js +99 -0
- package/dist/sodax/client.js.map +1 -0
- package/dist/tools/bridge.d.ts +105 -0
- package/dist/tools/bridge.d.ts.map +1 -0
- package/dist/tools/bridge.js +334 -0
- package/dist/tools/bridge.js.map +1 -0
- package/dist/tools/discovery.d.ts +141 -0
- package/dist/tools/discovery.d.ts.map +1 -0
- package/dist/tools/discovery.js +777 -0
- package/dist/tools/discovery.js.map +1 -0
- package/dist/tools/moneyMarket.d.ts +227 -0
- package/dist/tools/moneyMarket.d.ts.map +1 -0
- package/dist/tools/moneyMarket.js +867 -0
- package/dist/tools/moneyMarket.js.map +1 -0
- package/dist/tools/portfolio.d.ts +43 -0
- package/dist/tools/portfolio.d.ts.map +1 -0
- package/dist/tools/portfolio.js +538 -0
- package/dist/tools/portfolio.js.map +1 -0
- package/dist/tools/swap.d.ts +71 -0
- package/dist/tools/swap.d.ts.map +1 -0
- package/dist/tools/swap.js +762 -0
- package/dist/tools/swap.js.map +1 -0
- package/dist/tools/walletManagement.d.ts +80 -0
- package/dist/tools/walletManagement.d.ts.map +1 -0
- package/dist/tools/walletManagement.js +289 -0
- package/dist/tools/walletManagement.js.map +1 -0
- package/dist/types.d.ts +205 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/errorUtils.d.ts +2 -0
- package/dist/utils/errorUtils.d.ts.map +1 -0
- package/dist/utils/errorUtils.js +19 -0
- package/dist/utils/errorUtils.js.map +1 -0
- package/dist/utils/errors.d.ts +144 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +310 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/positionAggregator.d.ts +122 -0
- package/dist/utils/positionAggregator.d.ts.map +1 -0
- package/dist/utils/positionAggregator.js +377 -0
- package/dist/utils/positionAggregator.js.map +1 -0
- package/dist/utils/priceService.d.ts +45 -0
- package/dist/utils/priceService.d.ts.map +1 -0
- package/dist/utils/priceService.js +108 -0
- package/dist/utils/priceService.js.map +1 -0
- package/dist/utils/sodaxApi.d.ts +92 -0
- package/dist/utils/sodaxApi.d.ts.map +1 -0
- package/dist/utils/sodaxApi.js +143 -0
- package/dist/utils/sodaxApi.js.map +1 -0
- package/dist/utils/tokenResolver.d.ts +54 -0
- package/dist/utils/tokenResolver.d.ts.map +1 -0
- package/dist/utils/tokenResolver.js +252 -0
- package/dist/utils/tokenResolver.js.map +1 -0
- package/dist/wallet/backendConfig.d.ts +37 -0
- package/dist/wallet/backendConfig.d.ts.map +1 -0
- package/dist/wallet/backendConfig.js +125 -0
- package/dist/wallet/backendConfig.js.map +1 -0
- package/dist/wallet/backends/BankrBackend.d.ts +73 -0
- package/dist/wallet/backends/BankrBackend.d.ts.map +1 -0
- package/dist/wallet/backends/BankrBackend.js +315 -0
- package/dist/wallet/backends/BankrBackend.js.map +1 -0
- package/dist/wallet/backends/BankrWalletProvider.d.ts +75 -0
- package/dist/wallet/backends/BankrWalletProvider.d.ts.map +1 -0
- package/dist/wallet/backends/BankrWalletProvider.js +243 -0
- package/dist/wallet/backends/BankrWalletProvider.js.map +1 -0
- package/dist/wallet/backends/EnvBackend.d.ts +50 -0
- package/dist/wallet/backends/EnvBackend.d.ts.map +1 -0
- package/dist/wallet/backends/EnvBackend.js +114 -0
- package/dist/wallet/backends/EnvBackend.js.map +1 -0
- package/dist/wallet/backends/EvmWalletSkillBackend.d.ts +40 -0
- package/dist/wallet/backends/EvmWalletSkillBackend.d.ts.map +1 -0
- package/dist/wallet/backends/EvmWalletSkillBackend.js +81 -0
- package/dist/wallet/backends/EvmWalletSkillBackend.js.map +1 -0
- package/dist/wallet/backends/index.d.ts +10 -0
- package/dist/wallet/backends/index.d.ts.map +1 -0
- package/dist/wallet/backends/index.js +10 -0
- package/dist/wallet/backends/index.js.map +1 -0
- package/dist/wallet/index.d.ts +9 -0
- package/dist/wallet/index.d.ts.map +1 -0
- package/dist/wallet/index.js +12 -0
- package/dist/wallet/index.js.map +1 -0
- package/dist/wallet/providers/AmpedWalletProvider.d.ts +107 -0
- package/dist/wallet/providers/AmpedWalletProvider.d.ts.map +1 -0
- package/dist/wallet/providers/AmpedWalletProvider.js +208 -0
- package/dist/wallet/providers/AmpedWalletProvider.js.map +1 -0
- package/dist/wallet/providers/BankrBackend.d.ts +105 -0
- package/dist/wallet/providers/BankrBackend.d.ts.map +1 -0
- package/dist/wallet/providers/BankrBackend.js +327 -0
- package/dist/wallet/providers/BankrBackend.js.map +1 -0
- package/dist/wallet/providers/LocalKeyBackend.d.ts +62 -0
- package/dist/wallet/providers/LocalKeyBackend.d.ts.map +1 -0
- package/dist/wallet/providers/LocalKeyBackend.js +152 -0
- package/dist/wallet/providers/LocalKeyBackend.js.map +1 -0
- package/dist/wallet/providers/chainConfig.d.ts +209 -0
- package/dist/wallet/providers/chainConfig.d.ts.map +1 -0
- package/dist/wallet/providers/chainConfig.js +175 -0
- package/dist/wallet/providers/chainConfig.js.map +1 -0
- package/dist/wallet/providers/index.d.ts +30 -0
- package/dist/wallet/providers/index.d.ts.map +1 -0
- package/dist/wallet/providers/index.js +32 -0
- package/dist/wallet/providers/index.js.map +1 -0
- package/dist/wallet/providers/types.d.ts +156 -0
- package/dist/wallet/providers/types.d.ts.map +1 -0
- package/dist/wallet/providers/types.js +11 -0
- package/dist/wallet/providers/types.js.map +1 -0
- package/dist/wallet/skillWalletAdapter.d.ts +96 -0
- package/dist/wallet/skillWalletAdapter.d.ts.map +1 -0
- package/dist/wallet/skillWalletAdapter.js +280 -0
- package/dist/wallet/skillWalletAdapter.js.map +1 -0
- package/dist/wallet/types.d.ts +134 -0
- package/dist/wallet/types.d.ts.map +1 -0
- package/dist/wallet/types.js +138 -0
- package/dist/wallet/types.js.map +1 -0
- package/dist/wallet/walletManager.d.ts +111 -0
- package/dist/wallet/walletManager.d.ts.map +1 -0
- package/dist/wallet/walletManager.js +476 -0
- package/dist/wallet/walletManager.js.map +1 -0
- package/dist/wallet/walletRegistry.d.ts +95 -0
- package/dist/wallet/walletRegistry.d.ts.map +1 -0
- package/dist/wallet/walletRegistry.js +184 -0
- package/dist/wallet/walletRegistry.js.map +1 -0
- package/index.js +2 -0
- package/openclaw.plugin.json +37 -0
- package/package.json +69 -0
- package/src/__mocks__/@sodax/sdk.ts +28 -0
- package/src/__tests__/errors.test.ts +238 -0
- package/src/__tests__/policyEngine.test.ts +354 -0
- package/src/__tests__/positionAggregator.test.ts +271 -0
- package/src/__tests__/setup.ts +35 -0
- package/src/__tests__/sodaxApi.test.ts +203 -0
- package/src/__tests__/walletRegistry.test.ts +155 -0
- package/src/index.ts +376 -0
- package/src/policy/policyEngine.ts +389 -0
- package/src/providers/spokeProviderFactory.ts +283 -0
- package/src/sodax/client.ts +113 -0
- package/src/tools/bridge.ts +425 -0
- package/src/tools/discovery.ts +989 -0
- package/src/tools/moneyMarket.ts +1265 -0
- package/src/tools/portfolio.ts +697 -0
- package/src/tools/swap.ts +926 -0
- package/src/tools/walletManagement.ts +359 -0
- package/src/types.ts +228 -0
- package/src/utils/errorUtils.ts +16 -0
- package/src/utils/errors.ts +396 -0
- package/src/utils/positionAggregator.ts +559 -0
- package/src/utils/priceService.ts +153 -0
- package/src/utils/sodaxApi.ts +261 -0
- package/src/utils/tokenResolver.ts +286 -0
- package/src/wallet/backendConfig.ts +151 -0
- package/src/wallet/backends/BankrBackend.ts +399 -0
- package/src/wallet/backends/BankrWalletProvider.ts +329 -0
- package/src/wallet/backends/EnvBackend.ts +149 -0
- package/src/wallet/backends/EvmWalletSkillBackend.ts +110 -0
- package/src/wallet/backends/index.ts +10 -0
- package/src/wallet/index.ts +14 -0
- package/src/wallet/providers/AmpedWalletProvider.ts +267 -0
- package/src/wallet/providers/BankrBackend.ts +407 -0
- package/src/wallet/providers/LocalKeyBackend.ts +184 -0
- package/src/wallet/providers/chainConfig.ts +194 -0
- package/src/wallet/providers/index.ts +62 -0
- package/src/wallet/providers/types.ts +186 -0
- package/src/wallet/skillWalletAdapter.ts +335 -0
- package/src/wallet/types.ts +248 -0
- package/src/wallet/walletManager.ts +561 -0
- 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 };
|