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,377 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Chain Money Market Position Aggregator
|
|
3
|
+
*
|
|
4
|
+
* Aggregates user positions across all supported chains to provide a unified view
|
|
5
|
+
* of their money market portfolio, including:
|
|
6
|
+
* - Total supplied/borrowed across all chains
|
|
7
|
+
* - Health factor and liquidation risk
|
|
8
|
+
* - Available borrowing power
|
|
9
|
+
* - Net position (supply - borrow)
|
|
10
|
+
* - Cross-chain collateral utilization
|
|
11
|
+
*/
|
|
12
|
+
import { getSodaxClient } from '../sodax/client';
|
|
13
|
+
import { getSpokeProvider } from '../providers/spokeProviderFactory';
|
|
14
|
+
import { getWalletManager } from '../wallet/walletManager';
|
|
15
|
+
import { normalizeChainId } from '../wallet/types';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Position Aggregation Functions
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Aggregate money market positions across all supported chains
|
|
21
|
+
*
|
|
22
|
+
* @param walletId - The wallet identifier
|
|
23
|
+
* @param options - Aggregation options
|
|
24
|
+
* @returns Complete cross-chain position view
|
|
25
|
+
*/
|
|
26
|
+
export async function aggregateCrossChainPositions(walletId, options = {}) {
|
|
27
|
+
const startTime = Date.now();
|
|
28
|
+
// Get wallet
|
|
29
|
+
const walletManager = getWalletManager();
|
|
30
|
+
const wallet = await walletManager.resolve(walletId);
|
|
31
|
+
const walletAddress = await wallet.getAddress();
|
|
32
|
+
// Get supported chains from SODAX
|
|
33
|
+
const sodax = getSodaxClient();
|
|
34
|
+
const sodaxChains = sodax.config.getSupportedSpokeChains();
|
|
35
|
+
// Map SDK chains to string IDs
|
|
36
|
+
const allSodaxChains = sodaxChains.map((c) => typeof c === 'string' ? c : c.id);
|
|
37
|
+
// Filter chains by what the wallet supports
|
|
38
|
+
// This is important for Bankr which only supports ethereum/polygon/base
|
|
39
|
+
const walletSupportedChains = wallet.supportedChains;
|
|
40
|
+
const filteredChains = allSodaxChains.filter((chainId) => wallet.supportsChain(normalizeChainId(chainId)));
|
|
41
|
+
// Determine which chains to query
|
|
42
|
+
const chainsToQuery = options.chainIds || filteredChains;
|
|
43
|
+
console.log('[positionAggregator] Wallet chain filter', {
|
|
44
|
+
walletType: wallet.type,
|
|
45
|
+
walletSupports: walletSupportedChains,
|
|
46
|
+
sodaxChains: allSodaxChains,
|
|
47
|
+
filteredChains: filteredChains,
|
|
48
|
+
normalizedFiltered: filteredChains.map(normalizeChainId),
|
|
49
|
+
});
|
|
50
|
+
console.log('[positionAggregator] Querying positions across chains', {
|
|
51
|
+
walletId,
|
|
52
|
+
address: walletAddress,
|
|
53
|
+
chains: chainsToQuery,
|
|
54
|
+
});
|
|
55
|
+
// Query positions from all chains in parallel
|
|
56
|
+
const chainResults = await Promise.allSettled(chainsToQuery.map(chainId => queryChainPositions(walletId, walletAddress, chainId)));
|
|
57
|
+
// Collect all positions
|
|
58
|
+
const allPositions = [];
|
|
59
|
+
const chainSummaries = [];
|
|
60
|
+
chainResults.forEach((result, index) => {
|
|
61
|
+
const chainId = chainsToQuery[index];
|
|
62
|
+
if (result.status === 'fulfilled') {
|
|
63
|
+
const { positions, summary } = result.value;
|
|
64
|
+
if (positions.length > 0 || options.includeZeroBalances) {
|
|
65
|
+
allPositions.push(...positions);
|
|
66
|
+
chainSummaries.push(summary);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.warn(`[positionAggregator] Failed to query chain ${chainId}:`, result.reason);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
// Calculate aggregated summary
|
|
74
|
+
const summary = calculateAggregatedSummary(allPositions);
|
|
75
|
+
// Calculate collateral utilization
|
|
76
|
+
const collateralUtilization = calculateCollateralUtilization(allPositions, summary);
|
|
77
|
+
// Calculate risk metrics
|
|
78
|
+
const riskMetrics = calculateRiskMetrics(allPositions, summary);
|
|
79
|
+
const view = {
|
|
80
|
+
walletId,
|
|
81
|
+
address: walletAddress,
|
|
82
|
+
timestamp: new Date().toISOString(),
|
|
83
|
+
summary,
|
|
84
|
+
chainSummaries: chainSummaries.sort((a, b) => b.netWorthUsd - a.netWorthUsd),
|
|
85
|
+
positions: allPositions.sort((a, b) => (parseFloat(b.supply.balanceUsd) + parseFloat(b.borrow.balanceUsd)) -
|
|
86
|
+
(parseFloat(a.supply.balanceUsd) + parseFloat(a.borrow.balanceUsd))),
|
|
87
|
+
collateralUtilization,
|
|
88
|
+
riskMetrics,
|
|
89
|
+
};
|
|
90
|
+
console.log('[positionAggregator] Aggregation complete', {
|
|
91
|
+
durationMs: Date.now() - startTime,
|
|
92
|
+
totalPositions: allPositions.length,
|
|
93
|
+
totalSupplyUsd: summary.totalSupplyUsd,
|
|
94
|
+
totalBorrowUsd: summary.totalBorrowUsd,
|
|
95
|
+
healthFactor: summary.healthFactor,
|
|
96
|
+
});
|
|
97
|
+
return view;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Query positions for a single chain
|
|
101
|
+
*
|
|
102
|
+
* IMPORTANT: getUserReservesHumanized() only returns raw balances without token metadata.
|
|
103
|
+
* To get token symbols/names, we must:
|
|
104
|
+
* 1. Fetch getReservesHumanized() for token metadata
|
|
105
|
+
* 2. Format with formatReservesUSD(buildReserveDataWithPrice())
|
|
106
|
+
* 3. Join with formatUserSummary(buildUserSummaryRequest())
|
|
107
|
+
*
|
|
108
|
+
* Reference: sodax-frontend/packages/dapp-kit/src/hooks/mm/useUserFormattedSummary.ts
|
|
109
|
+
*/
|
|
110
|
+
async function queryChainPositions(walletId, address, chainId) {
|
|
111
|
+
try {
|
|
112
|
+
// Use address for spoke provider lookup
|
|
113
|
+
const spokeProvider = await getSpokeProvider(walletId, chainId);
|
|
114
|
+
const sodax = getSodaxClient();
|
|
115
|
+
// Step 1: Fetch reserves with token metadata (symbols, names, decimals)
|
|
116
|
+
// This is the key fix - getUserReservesHumanized alone doesn't include token metadata
|
|
117
|
+
const reserves = await sodax.moneyMarket.data.getReservesHumanized();
|
|
118
|
+
// Step 2: Format reserves with USD prices
|
|
119
|
+
const formattedReserves = sodax.moneyMarket.data.formatReservesUSD(sodax.moneyMarket.data.buildReserveDataWithPrice(reserves));
|
|
120
|
+
// Step 3: Fetch user-specific balances
|
|
121
|
+
const userReserves = await sodax.moneyMarket.data.getUserReservesHumanized(spokeProvider);
|
|
122
|
+
// Step 4: Join reserves metadata with user balances via formatUserSummary
|
|
123
|
+
const userSummary = sodax.moneyMarket.data.formatUserSummary(sodax.moneyMarket.data.buildUserSummaryRequest(reserves, formattedReserves, userReserves));
|
|
124
|
+
// Extract user reserves from the formatted summary
|
|
125
|
+
// The formatted summary has userReservesData with proper token metadata
|
|
126
|
+
const userReservesData = userSummary.userReservesData || [];
|
|
127
|
+
// Convert to TokenPosition format
|
|
128
|
+
const positions = userReservesData.map((reserve) => {
|
|
129
|
+
// Get supply balance (underlyingBalance is the human-readable supply amount)
|
|
130
|
+
const supplyBalance = reserve.underlyingBalance || '0';
|
|
131
|
+
const supplyBalanceUsd = reserve.underlyingBalanceUSD || '0';
|
|
132
|
+
// Get borrow balance (variableBorrows is the human-readable borrow amount)
|
|
133
|
+
const borrowBalance = reserve.variableBorrows || reserve.totalBorrows || '0';
|
|
134
|
+
const borrowBalanceUsd = reserve.variableBorrowsUSD || reserve.totalBorrowsUSD || '0';
|
|
135
|
+
// Get APY values (formatted reserves have these)
|
|
136
|
+
const supplyApy = parseFloat(reserve.reserve?.supplyAPY || '0') * 100;
|
|
137
|
+
const borrowApy = parseFloat(reserve.reserve?.variableBorrowAPY || '0') * 100;
|
|
138
|
+
return {
|
|
139
|
+
chainId,
|
|
140
|
+
token: {
|
|
141
|
+
address: reserve.underlyingAsset || reserve.reserve?.underlyingAsset || '',
|
|
142
|
+
symbol: reserve.reserve?.symbol || '',
|
|
143
|
+
name: reserve.reserve?.name || '',
|
|
144
|
+
decimals: reserve.reserve?.decimals || 18,
|
|
145
|
+
logoURI: reserve.reserve?.iconSymbol || undefined,
|
|
146
|
+
},
|
|
147
|
+
supply: {
|
|
148
|
+
balance: supplyBalance,
|
|
149
|
+
balanceUsd: supplyBalanceUsd,
|
|
150
|
+
balanceRaw: reserve.scaledATokenBalance || '0',
|
|
151
|
+
apy: supplyApy,
|
|
152
|
+
isCollateral: reserve.usageAsCollateralEnabledOnUser ?? false,
|
|
153
|
+
},
|
|
154
|
+
borrow: {
|
|
155
|
+
balance: borrowBalance,
|
|
156
|
+
balanceUsd: borrowBalanceUsd,
|
|
157
|
+
balanceRaw: reserve.scaledVariableDebt || '0',
|
|
158
|
+
apy: borrowApy,
|
|
159
|
+
},
|
|
160
|
+
loanToValue: parseFloat(reserve.reserve?.baseLTVasCollateral || '0') / 10000,
|
|
161
|
+
liquidationThreshold: parseFloat(reserve.reserve?.reserveLiquidationThreshold || '0') / 10000,
|
|
162
|
+
};
|
|
163
|
+
});
|
|
164
|
+
// Filter out positions with zero balance (unless explicitly requested)
|
|
165
|
+
const activePositions = positions.filter(p => parseFloat(p.supply.balance) > 0 || parseFloat(p.borrow.balance) > 0);
|
|
166
|
+
// Calculate chain summary
|
|
167
|
+
const supplyUsd = activePositions.reduce((sum, p) => sum + parseFloat(p.supply.balanceUsd || '0'), 0);
|
|
168
|
+
const borrowUsd = activePositions.reduce((sum, p) => sum + parseFloat(p.borrow.balanceUsd || '0'), 0);
|
|
169
|
+
// Calculate health factor for this chain
|
|
170
|
+
const healthFactor = calculateChainHealthFactor(activePositions);
|
|
171
|
+
const summary = {
|
|
172
|
+
chainId,
|
|
173
|
+
supplyUsd,
|
|
174
|
+
borrowUsd,
|
|
175
|
+
netWorthUsd: supplyUsd - borrowUsd,
|
|
176
|
+
healthFactor,
|
|
177
|
+
positionCount: activePositions.length,
|
|
178
|
+
};
|
|
179
|
+
console.log(`[positionAggregator] Chain ${chainId}: ${activePositions.length} positions, supply=$${supplyUsd.toFixed(2)}, borrow=$${borrowUsd.toFixed(2)}`);
|
|
180
|
+
return { positions: activePositions, summary };
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
console.error(`[positionAggregator] Error querying ${chainId}:`, error);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// ============================================================================
|
|
188
|
+
// Calculation Helpers
|
|
189
|
+
// ============================================================================
|
|
190
|
+
/**
|
|
191
|
+
* Calculate aggregated summary across all positions
|
|
192
|
+
*/
|
|
193
|
+
function calculateAggregatedSummary(positions) {
|
|
194
|
+
let totalSupplyUsd = 0;
|
|
195
|
+
let totalBorrowUsd = 0;
|
|
196
|
+
let weightedSupplyApy = 0;
|
|
197
|
+
let weightedBorrowApy = 0;
|
|
198
|
+
positions.forEach(pos => {
|
|
199
|
+
const supplyUsd = parseFloat(pos.supply.balanceUsd || '0');
|
|
200
|
+
const borrowUsd = parseFloat(pos.borrow.balanceUsd || '0');
|
|
201
|
+
totalSupplyUsd += supplyUsd;
|
|
202
|
+
totalBorrowUsd += borrowUsd;
|
|
203
|
+
weightedSupplyApy += supplyUsd * pos.supply.apy;
|
|
204
|
+
weightedBorrowApy += borrowUsd * pos.borrow.apy;
|
|
205
|
+
});
|
|
206
|
+
// Calculate weighted average APYs
|
|
207
|
+
const avgSupplyApy = totalSupplyUsd > 0 ? weightedSupplyApy / totalSupplyUsd : 0;
|
|
208
|
+
const avgBorrowApy = totalBorrowUsd > 0 ? weightedBorrowApy / totalBorrowUsd : 0;
|
|
209
|
+
// Calculate health factor
|
|
210
|
+
const healthFactor = calculateHealthFactor(positions);
|
|
211
|
+
// Determine liquidation risk
|
|
212
|
+
let liquidationRisk = 'none';
|
|
213
|
+
if (healthFactor !== null) {
|
|
214
|
+
if (healthFactor < 1.1)
|
|
215
|
+
liquidationRisk = 'high';
|
|
216
|
+
else if (healthFactor < 1.5)
|
|
217
|
+
liquidationRisk = 'medium';
|
|
218
|
+
else if (healthFactor < 2)
|
|
219
|
+
liquidationRisk = 'low';
|
|
220
|
+
}
|
|
221
|
+
// Calculate available borrow (simplified - would need proper oracle prices)
|
|
222
|
+
// This is a conservative estimate based on average LTV
|
|
223
|
+
const avgLtv = positions.length > 0
|
|
224
|
+
? positions.reduce((sum, p) => sum + p.loanToValue, 0) / positions.length
|
|
225
|
+
: 0;
|
|
226
|
+
const availableBorrowUsd = totalSupplyUsd * avgLtv - totalBorrowUsd;
|
|
227
|
+
return {
|
|
228
|
+
totalSupplyUsd,
|
|
229
|
+
totalBorrowUsd,
|
|
230
|
+
netWorthUsd: totalSupplyUsd - totalBorrowUsd,
|
|
231
|
+
availableBorrowUsd: Math.max(0, availableBorrowUsd),
|
|
232
|
+
healthFactor,
|
|
233
|
+
liquidationRisk,
|
|
234
|
+
weightedSupplyApy: avgSupplyApy,
|
|
235
|
+
weightedBorrowApy: avgBorrowApy,
|
|
236
|
+
netApy: totalSupplyUsd > 0
|
|
237
|
+
? (avgSupplyApy * totalSupplyUsd - avgBorrowApy * totalBorrowUsd) / totalSupplyUsd
|
|
238
|
+
: 0,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Calculate collateral utilization metrics
|
|
243
|
+
*/
|
|
244
|
+
function calculateCollateralUtilization(positions, summary) {
|
|
245
|
+
// Only count collateral-enabled supplies
|
|
246
|
+
const totalCollateralUsd = positions
|
|
247
|
+
.filter(p => p.supply.isCollateral)
|
|
248
|
+
.reduce((sum, p) => sum + parseFloat(p.supply.balanceUsd || '0'), 0);
|
|
249
|
+
const usedCollateralUsd = summary.totalBorrowUsd;
|
|
250
|
+
const availableCollateralUsd = Math.max(0, totalCollateralUsd - usedCollateralUsd);
|
|
251
|
+
const utilizationRate = totalCollateralUsd > 0 ? (usedCollateralUsd / totalCollateralUsd) * 100 : 0;
|
|
252
|
+
return {
|
|
253
|
+
totalCollateralUsd,
|
|
254
|
+
usedCollateralUsd,
|
|
255
|
+
availableCollateralUsd,
|
|
256
|
+
utilizationRate,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Calculate risk metrics
|
|
261
|
+
*/
|
|
262
|
+
function calculateRiskMetrics(positions, summary) {
|
|
263
|
+
// Calculate max LTV across all positions (weighted by supply)
|
|
264
|
+
let totalSupply = 0;
|
|
265
|
+
let weightedLtvSum = 0;
|
|
266
|
+
let liquidationThresholdSum = 0;
|
|
267
|
+
positions.forEach(pos => {
|
|
268
|
+
const supplyUsd = parseFloat(pos.supply.balanceUsd || '0');
|
|
269
|
+
totalSupply += supplyUsd;
|
|
270
|
+
weightedLtvSum += supplyUsd * pos.loanToValue;
|
|
271
|
+
liquidationThresholdSum += supplyUsd * pos.liquidationThreshold;
|
|
272
|
+
});
|
|
273
|
+
const maxLtv = totalSupply > 0 ? weightedLtvSum / totalSupply : 0;
|
|
274
|
+
const avgLiquidationThreshold = totalSupply > 0 ? liquidationThresholdSum / totalSupply : 0;
|
|
275
|
+
// Current LTV
|
|
276
|
+
const currentLtv = summary.totalSupplyUsd > 0
|
|
277
|
+
? summary.totalBorrowUsd / summary.totalSupplyUsd
|
|
278
|
+
: 0;
|
|
279
|
+
// Buffer until liquidation (percentage points)
|
|
280
|
+
const bufferUntilLiquidation = Math.max(0, avgLiquidationThreshold - currentLtv) * 100;
|
|
281
|
+
// Safe max borrow (at 80% of liquidation threshold for safety)
|
|
282
|
+
const safeMaxBorrowUsd = summary.totalSupplyUsd * avgLiquidationThreshold * 0.8;
|
|
283
|
+
return {
|
|
284
|
+
maxLtv,
|
|
285
|
+
currentLtv,
|
|
286
|
+
bufferUntilLiquidation,
|
|
287
|
+
safeMaxBorrowUsd,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Calculate health factor for a set of positions
|
|
292
|
+
* Health Factor = (Total Collateral in ETH * Liquidation Threshold) / Total Borrow in ETH
|
|
293
|
+
*/
|
|
294
|
+
function calculateHealthFactor(positions) {
|
|
295
|
+
let totalCollateralEth = 0;
|
|
296
|
+
let totalBorrowEth = 0;
|
|
297
|
+
positions.forEach(pos => {
|
|
298
|
+
const supplyUsd = parseFloat(pos.supply.balanceUsd || '0');
|
|
299
|
+
const borrowUsd = parseFloat(pos.borrow.balanceUsd || '0');
|
|
300
|
+
// Only count collateral-enabled supplies
|
|
301
|
+
if (pos.supply.isCollateral) {
|
|
302
|
+
totalCollateralEth += supplyUsd * pos.liquidationThreshold;
|
|
303
|
+
}
|
|
304
|
+
totalBorrowEth += borrowUsd;
|
|
305
|
+
});
|
|
306
|
+
if (totalBorrowEth === 0) {
|
|
307
|
+
return totalCollateralEth > 0 ? Infinity : null;
|
|
308
|
+
}
|
|
309
|
+
return totalCollateralEth / totalBorrowEth;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Calculate health factor for a single chain
|
|
313
|
+
*/
|
|
314
|
+
function calculateChainHealthFactor(positions) {
|
|
315
|
+
return calculateHealthFactor(positions);
|
|
316
|
+
}
|
|
317
|
+
// ============================================================================
|
|
318
|
+
// Utility Functions
|
|
319
|
+
// ============================================================================
|
|
320
|
+
/**
|
|
321
|
+
* Format health factor for display
|
|
322
|
+
*/
|
|
323
|
+
export function formatHealthFactor(hf) {
|
|
324
|
+
if (hf === null)
|
|
325
|
+
return 'N/A';
|
|
326
|
+
if (hf === Infinity)
|
|
327
|
+
return '∞';
|
|
328
|
+
return hf.toFixed(2);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get health factor color/styling indicator
|
|
332
|
+
*/
|
|
333
|
+
export function getHealthFactorStatus(hf) {
|
|
334
|
+
if (hf === null)
|
|
335
|
+
return { status: 'healthy', color: 'green' };
|
|
336
|
+
if (hf === Infinity)
|
|
337
|
+
return { status: 'healthy', color: 'green' };
|
|
338
|
+
if (hf < 1.1)
|
|
339
|
+
return { status: 'critical', color: 'red' };
|
|
340
|
+
if (hf < 1.5)
|
|
341
|
+
return { status: 'danger', color: 'orange' };
|
|
342
|
+
if (hf < 2)
|
|
343
|
+
return { status: 'caution', color: 'yellow' };
|
|
344
|
+
return { status: 'healthy', color: 'green' };
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Get recommendation based on position health
|
|
348
|
+
*/
|
|
349
|
+
export function getPositionRecommendation(view) {
|
|
350
|
+
const recommendations = [];
|
|
351
|
+
const { summary } = view;
|
|
352
|
+
// Health factor recommendations
|
|
353
|
+
if (summary.healthFactor !== null && summary.healthFactor < 1.5) {
|
|
354
|
+
recommendations.push('⚠️ Health factor is low. Consider repaying debt or adding collateral.');
|
|
355
|
+
}
|
|
356
|
+
// Borrowing capacity recommendations
|
|
357
|
+
if (summary.availableBorrowUsd > 1000 && summary.healthFactor !== null && summary.healthFactor > 2) {
|
|
358
|
+
recommendations.push(`💡 You have $${summary.availableBorrowUsd.toFixed(2)} in available borrowing power.`);
|
|
359
|
+
}
|
|
360
|
+
// Collateral utilization
|
|
361
|
+
if (view.collateralUtilization.utilizationRate > 80) {
|
|
362
|
+
recommendations.push('⚠️ High collateral utilization. Avoid borrowing more to maintain safety margin.');
|
|
363
|
+
}
|
|
364
|
+
// Net APY optimization
|
|
365
|
+
if (summary.netApy < 0) {
|
|
366
|
+
recommendations.push('📉 Your borrowing costs exceed supply earnings. Consider reducing debt or finding higher APY supply opportunities.');
|
|
367
|
+
}
|
|
368
|
+
// Cross-chain opportunities
|
|
369
|
+
const highApyChains = view.chainSummaries
|
|
370
|
+
.filter(cs => cs.supplyUsd > 100)
|
|
371
|
+
.sort((a, b) => (b.healthFactor || Infinity) - (a.healthFactor || Infinity));
|
|
372
|
+
if (highApyChains.length > 1) {
|
|
373
|
+
recommendations.push(`🌐 You have positions across ${highApyChains.length} chains. Monitor each chain's health factor independently.`);
|
|
374
|
+
}
|
|
375
|
+
return recommendations;
|
|
376
|
+
}
|
|
377
|
+
//# sourceMappingURL=positionAggregator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"positionAggregator.js","sourceRoot":"","sources":["../../src/utils/positionAggregator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Price Service - Fetches USD prices from SODAX reserves
|
|
3
|
+
*
|
|
4
|
+
* Uses the money market reserve data to get accurate USD prices
|
|
5
|
+
* for tokens supported by the protocol.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/priceService
|
|
8
|
+
*/
|
|
9
|
+
export interface TokenPrice {
|
|
10
|
+
symbol: string;
|
|
11
|
+
priceUsd: number;
|
|
12
|
+
underlyingAsset: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PriceMap {
|
|
15
|
+
/** Map of symbol (lowercase) to USD price */
|
|
16
|
+
bySymbol: Map<string, number>;
|
|
17
|
+
/** Map of address (lowercase) to USD price */
|
|
18
|
+
byAddress: Map<string, number>;
|
|
19
|
+
/** Last update timestamp */
|
|
20
|
+
timestamp: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Fetch token prices from SODAX money market reserves
|
|
24
|
+
*
|
|
25
|
+
* The reserves contain `priceInMarketReferenceCurrency` which represents
|
|
26
|
+
* the price in 8 decimal USD (100000000 = $1.00)
|
|
27
|
+
*/
|
|
28
|
+
export declare function fetchTokenPrices(): Promise<PriceMap>;
|
|
29
|
+
/**
|
|
30
|
+
* Get USD price for a token by symbol
|
|
31
|
+
*/
|
|
32
|
+
export declare function getTokenPriceBySymbol(symbol: string): Promise<number | null>;
|
|
33
|
+
/**
|
|
34
|
+
* Get USD price for a token by address
|
|
35
|
+
*/
|
|
36
|
+
export declare function getTokenPriceByAddress(address: string): Promise<number | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Calculate USD value for a token amount
|
|
39
|
+
*/
|
|
40
|
+
export declare function calculateUsdValue(symbol: string, amount: string | number): Promise<number | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Clear the price cache (useful for testing)
|
|
43
|
+
*/
|
|
44
|
+
export declare function clearPriceCache(): void;
|
|
45
|
+
//# sourceMappingURL=priceService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"priceService.d.ts","sourceRoot":"","sources":["../../src/utils/priceService.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,6CAA6C;IAC7C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,8CAA8C;IAC9C,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAaD;;;;;GAKG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,QAAQ,CAAC,CA2C1D;AAcD;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAgBlF;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGpF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GAAG,MAAM,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMxB;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Price Service - Fetches USD prices from SODAX reserves
|
|
3
|
+
*
|
|
4
|
+
* Uses the money market reserve data to get accurate USD prices
|
|
5
|
+
* for tokens supported by the protocol.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/priceService
|
|
8
|
+
*/
|
|
9
|
+
import { getSodaxClient } from '../sodax/client';
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Cache
|
|
12
|
+
// ============================================================================
|
|
13
|
+
let cachedPrices = null;
|
|
14
|
+
const CACHE_TTL_MS = 60_000; // 1 minute cache
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Price Fetching
|
|
17
|
+
// ============================================================================
|
|
18
|
+
/**
|
|
19
|
+
* Fetch token prices from SODAX money market reserves
|
|
20
|
+
*
|
|
21
|
+
* The reserves contain `priceInMarketReferenceCurrency` which represents
|
|
22
|
+
* the price in 8 decimal USD (100000000 = $1.00)
|
|
23
|
+
*/
|
|
24
|
+
export async function fetchTokenPrices() {
|
|
25
|
+
// Return cached if fresh
|
|
26
|
+
if (cachedPrices && Date.now() - cachedPrices.timestamp < CACHE_TTL_MS) {
|
|
27
|
+
return cachedPrices;
|
|
28
|
+
}
|
|
29
|
+
console.log('[priceService] Fetching token prices from SODAX reserves');
|
|
30
|
+
const sodax = await getSodaxClient();
|
|
31
|
+
const reserves = await sodax.moneyMarket.data.getReservesHumanized();
|
|
32
|
+
const bySymbol = new Map();
|
|
33
|
+
const byAddress = new Map();
|
|
34
|
+
// Market reference currency decimals (typically 8)
|
|
35
|
+
const PRICE_DECIMALS = 8;
|
|
36
|
+
for (const reserve of reserves.reservesData) {
|
|
37
|
+
// priceInMarketReferenceCurrency is a string representing the raw value
|
|
38
|
+
const priceRaw = BigInt(reserve.priceInMarketReferenceCurrency);
|
|
39
|
+
const priceUsd = Number(priceRaw) / Math.pow(10, PRICE_DECIMALS);
|
|
40
|
+
// Use symbol for matching (e.g., "sodaUSDC" -> "USDC")
|
|
41
|
+
const symbol = reserve.symbol.toLowerCase();
|
|
42
|
+
const normalizedSymbol = normalizeSymbol(reserve.symbol);
|
|
43
|
+
const address = reserve.underlyingAsset.toLowerCase();
|
|
44
|
+
bySymbol.set(symbol, priceUsd);
|
|
45
|
+
bySymbol.set(normalizedSymbol, priceUsd);
|
|
46
|
+
byAddress.set(address, priceUsd);
|
|
47
|
+
console.log(`[priceService] ${reserve.symbol}: $${priceUsd.toFixed(4)}`);
|
|
48
|
+
}
|
|
49
|
+
cachedPrices = {
|
|
50
|
+
bySymbol,
|
|
51
|
+
byAddress,
|
|
52
|
+
timestamp: Date.now(),
|
|
53
|
+
};
|
|
54
|
+
console.log(`[priceService] Cached ${bySymbol.size} token prices`);
|
|
55
|
+
return cachedPrices;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Normalize SODAX symbol to standard symbol
|
|
59
|
+
* e.g., "sodaUSDC" -> "usdc", "sodaETH" -> "eth"
|
|
60
|
+
*/
|
|
61
|
+
function normalizeSymbol(symbol) {
|
|
62
|
+
const lower = symbol.toLowerCase();
|
|
63
|
+
if (lower.startsWith('soda')) {
|
|
64
|
+
return lower.slice(4); // Remove 'soda' prefix
|
|
65
|
+
}
|
|
66
|
+
return lower;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get USD price for a token by symbol
|
|
70
|
+
*/
|
|
71
|
+
export async function getTokenPriceBySymbol(symbol) {
|
|
72
|
+
const prices = await fetchTokenPrices();
|
|
73
|
+
const normalizedSymbol = symbol.toLowerCase();
|
|
74
|
+
// Try exact match first
|
|
75
|
+
if (prices.bySymbol.has(normalizedSymbol)) {
|
|
76
|
+
return prices.bySymbol.get(normalizedSymbol);
|
|
77
|
+
}
|
|
78
|
+
// Try with 'soda' prefix
|
|
79
|
+
const sodaSymbol = 'soda' + normalizedSymbol;
|
|
80
|
+
if (prices.bySymbol.has(sodaSymbol)) {
|
|
81
|
+
return prices.bySymbol.get(sodaSymbol);
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get USD price for a token by address
|
|
87
|
+
*/
|
|
88
|
+
export async function getTokenPriceByAddress(address) {
|
|
89
|
+
const prices = await fetchTokenPrices();
|
|
90
|
+
return prices.byAddress.get(address.toLowerCase()) ?? null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Calculate USD value for a token amount
|
|
94
|
+
*/
|
|
95
|
+
export async function calculateUsdValue(symbol, amount) {
|
|
96
|
+
const price = await getTokenPriceBySymbol(symbol);
|
|
97
|
+
if (price === null)
|
|
98
|
+
return null;
|
|
99
|
+
const amountNum = typeof amount === 'string' ? parseFloat(amount) : amount;
|
|
100
|
+
return amountNum * price;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Clear the price cache (useful for testing)
|
|
104
|
+
*/
|
|
105
|
+
export function clearPriceCache() {
|
|
106
|
+
cachedPrices = null;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=priceService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"priceService.js","sourceRoot":"","sources":["../../src/utils/priceService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SODAX API Client
|
|
3
|
+
*
|
|
4
|
+
* Provides access to SODAX backend API endpoints for querying intents,
|
|
5
|
+
* user history, and other off-chain data.
|
|
6
|
+
*/
|
|
7
|
+
export interface SodaxApiConfig {
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface PaginationParams {
|
|
13
|
+
offset?: number;
|
|
14
|
+
limit?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface PaginatedResponse<T> {
|
|
17
|
+
items: T[];
|
|
18
|
+
total: number;
|
|
19
|
+
offset: number;
|
|
20
|
+
limit: number;
|
|
21
|
+
}
|
|
22
|
+
export interface IntentState {
|
|
23
|
+
exists: boolean;
|
|
24
|
+
remainingInput: string;
|
|
25
|
+
receivedOutput: string;
|
|
26
|
+
pendingPayment: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface IntentEvent {
|
|
29
|
+
eventType: string;
|
|
30
|
+
txHash: string;
|
|
31
|
+
logIndex: number;
|
|
32
|
+
blockNumber: number;
|
|
33
|
+
intentState: IntentState;
|
|
34
|
+
}
|
|
35
|
+
export interface IntentDetails {
|
|
36
|
+
intentId: string;
|
|
37
|
+
creator: string;
|
|
38
|
+
inputToken: string;
|
|
39
|
+
outputToken: string;
|
|
40
|
+
inputAmount: string;
|
|
41
|
+
minOutputAmount: string;
|
|
42
|
+
deadline: string;
|
|
43
|
+
allowPartialFill: boolean;
|
|
44
|
+
srcChain: number;
|
|
45
|
+
dstChain: number;
|
|
46
|
+
srcAddress: string;
|
|
47
|
+
dstAddress: string;
|
|
48
|
+
solver: string;
|
|
49
|
+
data: string;
|
|
50
|
+
}
|
|
51
|
+
export interface UserIntent {
|
|
52
|
+
intentHash: string;
|
|
53
|
+
txHash: string;
|
|
54
|
+
logIndex: number;
|
|
55
|
+
chainId: number;
|
|
56
|
+
blockNumber: number;
|
|
57
|
+
open: boolean;
|
|
58
|
+
intent: IntentDetails;
|
|
59
|
+
events: IntentEvent[];
|
|
60
|
+
createdAt: string;
|
|
61
|
+
}
|
|
62
|
+
export interface UserIntentFilters {
|
|
63
|
+
open?: boolean;
|
|
64
|
+
srcChain?: number;
|
|
65
|
+
dstChain?: number;
|
|
66
|
+
inputToken?: string;
|
|
67
|
+
outputToken?: string;
|
|
68
|
+
}
|
|
69
|
+
export declare class SodaxApiClient {
|
|
70
|
+
private baseUrl;
|
|
71
|
+
private apiKey?;
|
|
72
|
+
private timeoutMs;
|
|
73
|
+
constructor(config?: SodaxApiConfig);
|
|
74
|
+
/**
|
|
75
|
+
* Get intent by intentHash
|
|
76
|
+
* Most reliable lookup method - works for all intents
|
|
77
|
+
*/
|
|
78
|
+
getIntentByHash(intentHash: string): Promise<UserIntent | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Get intent by transaction hash
|
|
81
|
+
* NOTE: This expects the HUB chain (Sonic) transaction hash, NOT spoke chain tx
|
|
82
|
+
*/
|
|
83
|
+
getIntentByTxHash(txHash: string): Promise<UserIntent | null>;
|
|
84
|
+
getUserIntents(userAddress: string, pagination?: PaginationParams, filters?: UserIntentFilters): Promise<PaginatedResponse<UserIntent>>;
|
|
85
|
+
getOpenIntents(userAddress: string, pagination?: PaginationParams): Promise<PaginatedResponse<UserIntent>>;
|
|
86
|
+
getIntentHistory(userAddress: string, pagination?: PaginationParams): Promise<PaginatedResponse<UserIntent>>;
|
|
87
|
+
private fetchWithTimeout;
|
|
88
|
+
private isValidAddress;
|
|
89
|
+
}
|
|
90
|
+
export declare function getSodaxApiClient(config?: SodaxApiConfig): SodaxApiClient;
|
|
91
|
+
export declare function resetSodaxApiClient(): void;
|
|
92
|
+
//# sourceMappingURL=sodaxApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sodaxApi.d.ts","sourceRoot":"","sources":["../../src/utils/sodaxApi.ts"],"names":[],"mappings":"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"}
|