@sodax/sdk 2.0.0-rc.11 → 2.0.0-rc.13
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/dist/index.cjs +1482 -282
- package/dist/index.d.cts +692 -95
- package/dist/index.d.ts +692 -95
- package/dist/index.mjs +1464 -284
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getAbiItem, isAddress, toHex, hexToBytes, encodeAbiParameters, parseAbiParameters, defineChain, encodeFunctionData, erc20Abi as erc20Abi$1, createPublicClient, http, bytesToHex, keccak256, fromHex, encodePacked, decodeAbiParameters, parseEventLogs, maxUint160, maxUint48 } from 'viem';
|
|
1
|
+
import { getAbiItem, parseAbi, isAddress, toHex, hexToBytes, encodeAbiParameters, parseAbiParameters, defineChain, encodeFunctionData, erc20Abi as erc20Abi$1, createPublicClient, http, bytesToHex, keccak256, stringToBytes, fromHex, encodePacked, decodeAbiParameters, parseEventLogs, maxUint160, maxUint48 } from 'viem';
|
|
2
2
|
import { bcs } from '@mysten/sui/bcs';
|
|
3
3
|
import { PublicKey, Connection, VersionedTransaction, SystemProgram, ComputeBudgetProgram, TransactionMessage, TransactionInstruction } from '@solana/web3.js';
|
|
4
4
|
import { rpc, Address, xdr, Account, Horizon, Contract, TransactionBuilder, nativeToScVal, TimeoutInfinite, scValToBigInt, Operation, Asset, FeeBumpTransaction } from '@stellar/stellar-sdk';
|
|
@@ -169,7 +169,8 @@ var SODAX_FEATURES = [
|
|
|
169
169
|
"migration",
|
|
170
170
|
"dex",
|
|
171
171
|
"partner",
|
|
172
|
-
"recovery"
|
|
172
|
+
"recovery",
|
|
173
|
+
"leverageYield"
|
|
173
174
|
];
|
|
174
175
|
|
|
175
176
|
// src/shared/utils/tiny-invariant.ts
|
|
@@ -531,6 +532,27 @@ var SodaTokens = {
|
|
|
531
532
|
vault: "0x243b0c26c8b38793908d7C64e8510f21B19B4613"
|
|
532
533
|
}
|
|
533
534
|
};
|
|
535
|
+
var LsodaSymbols = ["lsodaWEETH", "lsodaWSTETH"];
|
|
536
|
+
var LsodaTokens = {
|
|
537
|
+
lsodaWEETH: {
|
|
538
|
+
symbol: "lsodaWEETH",
|
|
539
|
+
name: "Leveraged Soda weETH",
|
|
540
|
+
decimals: 18,
|
|
541
|
+
address: "0xD09de2f5070699A909c0FD32fb5A909d3886701D",
|
|
542
|
+
chainKey: ChainKeys.SONIC_MAINNET,
|
|
543
|
+
hubAsset: "0xD09de2f5070699A909c0FD32fb5A909d3886701D",
|
|
544
|
+
vault: "0xD09de2f5070699A909c0FD32fb5A909d3886701D"
|
|
545
|
+
},
|
|
546
|
+
lsodaWSTETH: {
|
|
547
|
+
symbol: "lsodaWSTETH",
|
|
548
|
+
name: "Leveraged Soda wstETH",
|
|
549
|
+
decimals: 18,
|
|
550
|
+
address: "0x136E5D1CEC5db1829E24941Eddd9C8640E02Ce7a",
|
|
551
|
+
chainKey: ChainKeys.SONIC_MAINNET,
|
|
552
|
+
hubAsset: "0x136E5D1CEC5db1829E24941Eddd9C8640E02Ce7a",
|
|
553
|
+
vault: "0x136E5D1CEC5db1829E24941Eddd9C8640E02Ce7a"
|
|
554
|
+
}
|
|
555
|
+
};
|
|
534
556
|
var sonicSupportedTokens = {
|
|
535
557
|
S: {
|
|
536
558
|
symbol: "S",
|
|
@@ -595,7 +617,8 @@ var sonicSupportedTokens = {
|
|
|
595
617
|
hubAsset: "0x7c7d53EEcda37a87ce0D5bf8E0b24512A48dC963",
|
|
596
618
|
vault: SodaTokens.sodaSODA.address
|
|
597
619
|
},
|
|
598
|
-
...SodaTokens
|
|
620
|
+
...SodaTokens,
|
|
621
|
+
...LsodaTokens
|
|
599
622
|
};
|
|
600
623
|
var redbellySupportedTokens = {
|
|
601
624
|
RBNT: {
|
|
@@ -3024,9 +3047,9 @@ var spokeChainConfig = {
|
|
|
3024
3047
|
supportedTokens: bitcoinSupportedTokens,
|
|
3025
3048
|
radfi: {
|
|
3026
3049
|
walletMode: "TRADING",
|
|
3027
|
-
apiUrl: "https://api.
|
|
3050
|
+
apiUrl: "https://api.bound.exchange/api",
|
|
3028
3051
|
apiKey: "",
|
|
3029
|
-
umsUrl: "https://ums.
|
|
3052
|
+
umsUrl: "https://api.ums.bound.exchange/api",
|
|
3030
3053
|
accessToken: "",
|
|
3031
3054
|
refreshToken: ""
|
|
3032
3055
|
},
|
|
@@ -3596,7 +3619,8 @@ var swapSupportedTokens = {
|
|
|
3596
3619
|
spokeChainConfig[ChainKeys.SONIC_MAINNET].supportedTokens.USDT,
|
|
3597
3620
|
spokeChainConfig[ChainKeys.SONIC_MAINNET].supportedTokens.wS,
|
|
3598
3621
|
spokeChainConfig[ChainKeys.SONIC_MAINNET].supportedTokens.SODA,
|
|
3599
|
-
...Object.values(SodaTokens)
|
|
3622
|
+
...Object.values(SodaTokens),
|
|
3623
|
+
...Object.values(LsodaTokens)
|
|
3600
3624
|
],
|
|
3601
3625
|
[ChainKeys.AVALANCHE_MAINNET]: [
|
|
3602
3626
|
spokeChainConfig[ChainKeys.AVALANCHE_MAINNET].supportedTokens.AVAX,
|
|
@@ -3836,6 +3860,41 @@ var swapsConfig = {
|
|
|
3836
3860
|
var getSupportedSolverTokens = (chainId) => swapSupportedTokens[chainId];
|
|
3837
3861
|
var isSwapSupportedToken = (chainId, token) => swapSupportedTokens[chainId].some((t) => t.address.toLowerCase() === token.toLowerCase());
|
|
3838
3862
|
|
|
3863
|
+
// ../types/dist/leverageYield/leverageYield.js
|
|
3864
|
+
var leverageYieldVaults = [
|
|
3865
|
+
{
|
|
3866
|
+
name: LsodaTokens.lsodaWEETH.symbol,
|
|
3867
|
+
vault: LsodaTokens.lsodaWEETH.vault,
|
|
3868
|
+
asset: SodaTokens.sodaWEETH.address,
|
|
3869
|
+
// sodaWEETH on Sonic
|
|
3870
|
+
borrowToken: SodaTokens.sodaETH.address,
|
|
3871
|
+
// sodaETH on Sonic
|
|
3872
|
+
lsdSource: {
|
|
3873
|
+
// DefiLlama pool for EtherFi's weETH on Ethereum (project: 'ether.fi-stake').
|
|
3874
|
+
poolId: "46bd2bdf-6d92-4066-b482-e885ee172264",
|
|
3875
|
+
fallbackAprPct: 3,
|
|
3876
|
+
label: "EtherFi (weETH)"
|
|
3877
|
+
}
|
|
3878
|
+
},
|
|
3879
|
+
{
|
|
3880
|
+
name: LsodaTokens.lsodaWSTETH.symbol,
|
|
3881
|
+
vault: LsodaTokens.lsodaWSTETH.vault,
|
|
3882
|
+
asset: SodaTokens.sodaWSTETH.address,
|
|
3883
|
+
// sodaWSTETH on Sonic
|
|
3884
|
+
borrowToken: SodaTokens.sodaETH.address,
|
|
3885
|
+
// sodaETH on Sonic
|
|
3886
|
+
lsdSource: {
|
|
3887
|
+
// DefiLlama pool for Lido's stETH on Ethereum (wstETH inherits this rate via redeem).
|
|
3888
|
+
poolId: "747c1d2a-c668-4682-b9f9-296708a3dd90",
|
|
3889
|
+
fallbackAprPct: 2.4,
|
|
3890
|
+
label: "Lido (stETH)"
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
];
|
|
3894
|
+
var leverageYieldConfig = {
|
|
3895
|
+
vaults: leverageYieldVaults
|
|
3896
|
+
};
|
|
3897
|
+
|
|
3839
3898
|
// ../types/dist/sodax-config/sodax-config.js
|
|
3840
3899
|
var bridgeConfig = {
|
|
3841
3900
|
partnerFee: void 0
|
|
@@ -3847,6 +3906,7 @@ var sodaxConfig = {
|
|
|
3847
3906
|
moneyMarket: moneyMarketConfig,
|
|
3848
3907
|
bridge: bridgeConfig,
|
|
3849
3908
|
dex: dexConfig,
|
|
3909
|
+
leverageYield: leverageYieldConfig,
|
|
3850
3910
|
hub: hubConfig,
|
|
3851
3911
|
api: apiConfig,
|
|
3852
3912
|
solver: solverConfig,
|
|
@@ -3868,6 +3928,9 @@ function detectBitcoinAddressType(address) {
|
|
|
3868
3928
|
return "P2PKH";
|
|
3869
3929
|
throw new Error(`Unknown Bitcoin address type: ${address}`);
|
|
3870
3930
|
}
|
|
3931
|
+
function usesBip322MessageSigning(addressType) {
|
|
3932
|
+
return addressType === "P2WPKH" || addressType === "P2TR";
|
|
3933
|
+
}
|
|
3871
3934
|
var BTC_WALLET_ADDRESS_TYPES = ["taproot", "segwit"];
|
|
3872
3935
|
var BTC_ADDRESS_TYPES = ["P2PKH", "P2SH", "P2WPKH", "P2TR"];
|
|
3873
3936
|
|
|
@@ -3985,7 +4048,7 @@ function isValidWalletProviderForChainKey(chainKey, walletProvider) {
|
|
|
3985
4048
|
}
|
|
3986
4049
|
|
|
3987
4050
|
// ../types/dist/index.js
|
|
3988
|
-
var CONFIG_VERSION =
|
|
4051
|
+
var CONFIG_VERSION = 211;
|
|
3989
4052
|
function isEvmSpokeChainConfig(value) {
|
|
3990
4053
|
return typeof value === "object" && value !== null && value.chain.type === "EVM" && value.chain.key !== HUB_CHAIN_KEY;
|
|
3991
4054
|
}
|
|
@@ -4412,7 +4475,7 @@ async function waitUntilIntentExecuted(payload) {
|
|
|
4412
4475
|
}
|
|
4413
4476
|
async function relayTxAndWaitPacket(params) {
|
|
4414
4477
|
try {
|
|
4415
|
-
const { srcTxHash, data, chainKey, relayerApiEndpoint, timeout = DEFAULT_RELAY_TX_TIMEOUT } = params;
|
|
4478
|
+
const { srcTxHash, data, chainKey, relayerApiEndpoint, timeout = DEFAULT_RELAY_TX_TIMEOUT, pollTxHash } = params;
|
|
4416
4479
|
const intentRelayChainId = getIntentRelayChainId(chainKey).toString();
|
|
4417
4480
|
const isSplitTxChain = isSolanaChainKeyType(chainKey) || isBitcoinChainKeyType(chainKey);
|
|
4418
4481
|
invariant(!isSplitTxChain || data !== void 0, "Data is required for Solana and Bitcoin chain keys");
|
|
@@ -4431,7 +4494,9 @@ async function relayTxAndWaitPacket(params) {
|
|
|
4431
4494
|
if (!submitResult.ok) return submitResult;
|
|
4432
4495
|
return await waitUntilIntentExecuted({
|
|
4433
4496
|
intentRelayChainId,
|
|
4434
|
-
|
|
4497
|
+
// The relay may track the packet under a different id than the submit tx_hash (Bitcoin
|
|
4498
|
+
// on-demand: submit "withdraw", poll the derived `od:<hash>`). Defaults to the submit id.
|
|
4499
|
+
srcTxHash: pollTxHash ?? srcTxHash,
|
|
4435
4500
|
timeout,
|
|
4436
4501
|
apiUrl: relayerApiEndpoint
|
|
4437
4502
|
});
|
|
@@ -13270,11 +13335,43 @@ function mergeSodaxConfig(base2, override) {
|
|
|
13270
13335
|
return merged;
|
|
13271
13336
|
}
|
|
13272
13337
|
|
|
13338
|
+
// src/shared/logger.ts
|
|
13339
|
+
var consoleLogger = {
|
|
13340
|
+
debug: (message, data) => data ? console.debug(message, data) : console.debug(message),
|
|
13341
|
+
info: (message, data) => data ? console.info(message, data) : console.info(message),
|
|
13342
|
+
warn: (message, data) => data ? console.warn(message, data) : console.warn(message),
|
|
13343
|
+
error: (message, error, data) => {
|
|
13344
|
+
if (error !== void 0 && data !== void 0) console.error(message, error, data);
|
|
13345
|
+
else if (error !== void 0) console.error(message, error);
|
|
13346
|
+
else console.error(message);
|
|
13347
|
+
}
|
|
13348
|
+
};
|
|
13349
|
+
var silentLogger = {
|
|
13350
|
+
debug: () => {
|
|
13351
|
+
},
|
|
13352
|
+
info: () => {
|
|
13353
|
+
},
|
|
13354
|
+
warn: () => {
|
|
13355
|
+
},
|
|
13356
|
+
error: () => {
|
|
13357
|
+
}
|
|
13358
|
+
};
|
|
13359
|
+
function resolveLogger(option) {
|
|
13360
|
+
if (option === void 0 || option === "console") return consoleLogger;
|
|
13361
|
+
if (option === "silent") return silentLogger;
|
|
13362
|
+
return option;
|
|
13363
|
+
}
|
|
13364
|
+
|
|
13273
13365
|
// src/shared/config/ConfigService.ts
|
|
13274
13366
|
var ConfigService = class {
|
|
13275
13367
|
sodax;
|
|
13276
13368
|
api;
|
|
13277
13369
|
userConfig;
|
|
13370
|
+
/**
|
|
13371
|
+
* SDK log sink. Resolved once at construction and kept independent of {@link sodax} so that
|
|
13372
|
+
* {@link initialize}'s dynamic-config swap never clobbers it. Read by services via `config.logger`.
|
|
13373
|
+
*/
|
|
13374
|
+
logger;
|
|
13278
13375
|
initialized = false;
|
|
13279
13376
|
// data structures for quick lookup
|
|
13280
13377
|
supportedHubAssetsSet;
|
|
@@ -13286,10 +13383,11 @@ var ConfigService = class {
|
|
|
13286
13383
|
stakedATokenAddressesSet;
|
|
13287
13384
|
chainToSupportedTokenAddressMap;
|
|
13288
13385
|
hubAssetToXTokenMap;
|
|
13289
|
-
constructor({ api, config, userConfig }) {
|
|
13386
|
+
constructor({ api, config, userConfig, logger }) {
|
|
13290
13387
|
this.api = api;
|
|
13291
13388
|
this.sodax = config;
|
|
13292
13389
|
this.userConfig = userConfig;
|
|
13390
|
+
this.logger = logger ?? resolveLogger(void 0);
|
|
13293
13391
|
this.loadSodaxConfigDataStructures(config);
|
|
13294
13392
|
}
|
|
13295
13393
|
async initialize() {
|
|
@@ -13298,7 +13396,7 @@ var ConfigService = class {
|
|
|
13298
13396
|
if (!result.ok) return result;
|
|
13299
13397
|
const response = result.value;
|
|
13300
13398
|
if (!response.version || response.version < CONFIG_VERSION) {
|
|
13301
|
-
|
|
13399
|
+
this.logger.warn(
|
|
13302
13400
|
`Dynamic config version is less than the current version, resorting to the default one. Current version: ${CONFIG_VERSION}, response version: ${response.version}`
|
|
13303
13401
|
);
|
|
13304
13402
|
} else {
|
|
@@ -14456,7 +14554,7 @@ var RadfiProvider = class {
|
|
|
14456
14554
|
}
|
|
14457
14555
|
}
|
|
14458
14556
|
/**
|
|
14459
|
-
* Authenticate with
|
|
14557
|
+
* Authenticate with Bound Exchange: BIP322-sign a login message, then call the Bound Exchange API.
|
|
14460
14558
|
* Returns accessToken, refreshToken, and tradingAddress.
|
|
14461
14559
|
*/
|
|
14462
14560
|
async authenticateWithWallet(walletProvider, cachedPublicKey) {
|
|
@@ -14472,15 +14570,14 @@ var RadfiProvider = class {
|
|
|
14472
14570
|
throw new Error("Failed to retrieve public key from wallet. Please unlock your wallet and try again.");
|
|
14473
14571
|
}
|
|
14474
14572
|
const message = `${Date.now()}`;
|
|
14475
|
-
const
|
|
14476
|
-
const signature = addressType === "P2WPKH" || addressType === "P2TR" ? await walletProvider.signBip322Message(message) : await walletProvider.signEcdsaMessage(message);
|
|
14573
|
+
const signature = usesBip322MessageSigning(detectBitcoinAddressType(address)) ? await walletProvider.signBip322Message(message) : await walletProvider.signEcdsaMessage(message);
|
|
14477
14574
|
const result = await this.authenticate({ message, signature, address, publicKey });
|
|
14478
14575
|
this.setRadfiAccessToken(result.accessToken, result.refreshToken);
|
|
14479
14576
|
return { ...result, publicKey };
|
|
14480
14577
|
}
|
|
14481
14578
|
/**
|
|
14482
|
-
* Ensure a valid
|
|
14483
|
-
* If a token exists, validates it via the
|
|
14579
|
+
* Ensure a valid Bound Exchange access token is set on this provider.
|
|
14580
|
+
* If a token exists, validates it via the Bound Exchange API.
|
|
14484
14581
|
* If invalid, tries refreshing with the refresh token first.
|
|
14485
14582
|
* If refresh also fails, falls back to full re-authentication (BIP322 sign).
|
|
14486
14583
|
*/
|
|
@@ -14513,7 +14610,7 @@ var RadfiProvider = class {
|
|
|
14513
14610
|
});
|
|
14514
14611
|
if (!res.ok) {
|
|
14515
14612
|
const err = await res.json();
|
|
14516
|
-
throw new RadfiApiError(res.status, err, "
|
|
14613
|
+
throw new RadfiApiError(res.status, err, "Bound Exchange authentication failed");
|
|
14517
14614
|
}
|
|
14518
14615
|
return res.json().then((r) => ({
|
|
14519
14616
|
accessToken: r.data?.accessToken ?? "",
|
|
@@ -14605,12 +14702,20 @@ var RadfiProvider = class {
|
|
|
14605
14702
|
}
|
|
14606
14703
|
})
|
|
14607
14704
|
});
|
|
14608
|
-
|
|
14609
|
-
|
|
14610
|
-
throw new RadfiApiError(res.status,
|
|
14705
|
+
const body = await res.json();
|
|
14706
|
+
if (!res.ok || !body?.data) {
|
|
14707
|
+
throw new RadfiApiError(res.status, body, "Bound Exchange transaction request failed");
|
|
14611
14708
|
}
|
|
14612
|
-
return
|
|
14709
|
+
return body.data;
|
|
14613
14710
|
}
|
|
14711
|
+
/**
|
|
14712
|
+
* Co-sign and broadcast a `sodax-withdraw` deposit via the Bound Exchange API.
|
|
14713
|
+
*
|
|
14714
|
+
* `relayData` ({ address, payload }) is the same `RelayExtraData` the SDK returns from
|
|
14715
|
+
* `createIntent()` / money-market supply etc. It is optional and non-breaking: when supplied,
|
|
14716
|
+
* the Bound Exchange backend persists it so it can auto-resubmit the intent relay if the relay
|
|
14717
|
+
* gets stuck (otherwise a stuck relay eventually refunds instead of completing the swap).
|
|
14718
|
+
*/
|
|
14614
14719
|
async requestRadfiSignature(params, accessToken) {
|
|
14615
14720
|
const res = await this.request("/sodax/transaction/sign", {
|
|
14616
14721
|
method: "POST",
|
|
@@ -14624,7 +14729,7 @@ var RadfiProvider = class {
|
|
|
14624
14729
|
});
|
|
14625
14730
|
if (!res.ok) {
|
|
14626
14731
|
const err = await res.json();
|
|
14627
|
-
throw new RadfiApiError(res.status, err, "
|
|
14732
|
+
throw new RadfiApiError(res.status, err, "Bound Exchange signature request failed");
|
|
14628
14733
|
}
|
|
14629
14734
|
return res.json().then((r) => r.data.txId);
|
|
14630
14735
|
}
|
|
@@ -14648,7 +14753,7 @@ var RadfiProvider = class {
|
|
|
14648
14753
|
return res.json();
|
|
14649
14754
|
}
|
|
14650
14755
|
/**
|
|
14651
|
-
* Build a renew-utxo transaction via the
|
|
14756
|
+
* Build a renew-utxo transaction via the Bound Exchange API.
|
|
14652
14757
|
* Returns a PSBT that needs to be signed by the user.
|
|
14653
14758
|
*/
|
|
14654
14759
|
async buildRenewUtxoTransaction(params, accessToken) {
|
|
@@ -14672,8 +14777,8 @@ var RadfiProvider = class {
|
|
|
14672
14777
|
return res.json().then((r) => r.data);
|
|
14673
14778
|
}
|
|
14674
14779
|
/**
|
|
14675
|
-
* Sign and broadcast a renew-utxo transaction via the
|
|
14676
|
-
* The user signs the PSBT first, then
|
|
14780
|
+
* Sign and broadcast a renew-utxo transaction via the Bound Exchange API.
|
|
14781
|
+
* The user signs the PSBT first, then Bound Exchange co-signs and broadcasts.
|
|
14677
14782
|
*/
|
|
14678
14783
|
async signAndBroadcastRenewUtxo(params, accessToken) {
|
|
14679
14784
|
const res = await this.request("/transactions/sign", {
|
|
@@ -14714,7 +14819,7 @@ var RadfiProvider = class {
|
|
|
14714
14819
|
return res.json().then((r) => r.data);
|
|
14715
14820
|
}
|
|
14716
14821
|
/**
|
|
14717
|
-
* Sign and broadcast a withdraw transaction via
|
|
14822
|
+
* Sign and broadcast a withdraw transaction via Bound Exchange.
|
|
14718
14823
|
*/
|
|
14719
14824
|
async signAndBroadcastWithdraw(params, accessToken) {
|
|
14720
14825
|
const res = await this.request("/transactions/sign", {
|
|
@@ -14768,7 +14873,20 @@ var RadfiProvider = class {
|
|
|
14768
14873
|
};
|
|
14769
14874
|
|
|
14770
14875
|
// src/shared/entities/btc/btc-utils.ts
|
|
14771
|
-
|
|
14876
|
+
var BITCOIN_FEE_SAFETY_VBYTES = 20;
|
|
14877
|
+
function calcOpReturnOutputVbytes(payloadByteLength) {
|
|
14878
|
+
let scriptSize;
|
|
14879
|
+
if (payloadByteLength <= 75) {
|
|
14880
|
+
scriptSize = 3 + payloadByteLength;
|
|
14881
|
+
} else if (payloadByteLength <= 255) {
|
|
14882
|
+
scriptSize = 4 + payloadByteLength;
|
|
14883
|
+
} else {
|
|
14884
|
+
scriptSize = 5 + payloadByteLength;
|
|
14885
|
+
}
|
|
14886
|
+
const scriptLenVarint = scriptSize <= 252 ? 1 : 3;
|
|
14887
|
+
return 8 + scriptLenVarint + scriptSize;
|
|
14888
|
+
}
|
|
14889
|
+
function estimateBitcoinTxSize(inputCount, outputCount, addressType, opReturnOutputVbytes = 44) {
|
|
14772
14890
|
let inputWeight;
|
|
14773
14891
|
switch (addressType) {
|
|
14774
14892
|
case "P2PKH":
|
|
@@ -14784,7 +14902,9 @@ function estimateBitcoinTxSize(inputCount, outputCount, addressType) {
|
|
|
14784
14902
|
inputWeight = 68;
|
|
14785
14903
|
break;
|
|
14786
14904
|
}
|
|
14787
|
-
return Math.ceil(
|
|
14905
|
+
return Math.ceil(
|
|
14906
|
+
10.5 + opReturnOutputVbytes + BITCOIN_FEE_SAFETY_VBYTES + inputCount * inputWeight + outputCount * 31
|
|
14907
|
+
);
|
|
14788
14908
|
}
|
|
14789
14909
|
function encodeBtcPayloadToBytes(payload) {
|
|
14790
14910
|
return JSON.stringify({
|
|
@@ -14801,6 +14921,10 @@ function normalizePsbtToBase64(signedPsbt) {
|
|
|
14801
14921
|
const isHex = /^[0-9a-fA-F]+$/.test(signedPsbt);
|
|
14802
14922
|
return isHex ? Buffer.from(signedPsbt, "hex").toString("base64") : signedPsbt;
|
|
14803
14923
|
}
|
|
14924
|
+
function normalizeSignatureToBase64(signature) {
|
|
14925
|
+
const isHex = /^[0-9a-fA-F]+$/.test(signature);
|
|
14926
|
+
return isHex ? Buffer.from(signature, "hex").toString("base64") : signature;
|
|
14927
|
+
}
|
|
14804
14928
|
|
|
14805
14929
|
// src/shared/services/spoke/BitcoinSpokeService.ts
|
|
14806
14930
|
initEccLib(ecc);
|
|
@@ -14909,7 +15033,7 @@ var BitcoinSpokeService = class {
|
|
|
14909
15033
|
return BigInt(totalBalance);
|
|
14910
15034
|
}
|
|
14911
15035
|
/**
|
|
14912
|
-
* Fund the
|
|
15036
|
+
* Fund the Bound Exchange trading wallet by sending BTC from the user's personal wallet
|
|
14913
15037
|
*
|
|
14914
15038
|
* @param {bigint} amount - Amount in satoshis to send
|
|
14915
15039
|
* @param {BitcoinSpokeProvider} spokeProvider - The Bitcoin spoke provider (must have signing capability)
|
|
@@ -14933,10 +15057,28 @@ var BitcoinSpokeService = class {
|
|
|
14933
15057
|
async sendMessage(params) {
|
|
14934
15058
|
return await this.encodeWithdrawalData(params);
|
|
14935
15059
|
}
|
|
15060
|
+
/**
|
|
15061
|
+
* Build the relay submit/poll identity for an on-demand action (borrow/withdraw).
|
|
15062
|
+
*
|
|
15063
|
+
* Bitcoin borrow/withdraw are on-demand: there is no broadcast transaction — the spoke result is
|
|
15064
|
+
* the signed payload JSON produced by {@link encodeWithdrawalData}/{@link sendMessage}. The relay
|
|
15065
|
+
* accepts the submit under the literal `withdraw` tx_hash with the signed payload (as a JSON object)
|
|
15066
|
+
* in `data`, then tracks the resulting packet under a derived id: `od:` + keccak256 of the ASCII
|
|
15067
|
+
* `payload_hex` string (hash the hex characters, not the decoded bytes). Polling must use that
|
|
15068
|
+
* derived id (`pollTxHash`), not `withdraw`.
|
|
15069
|
+
*
|
|
15070
|
+
* @param tx - The JSON-stringified signed payload returned by `sendMessage` / `encodeWithdrawalData`.
|
|
15071
|
+
*/
|
|
15072
|
+
getOnDemandRelayIdentity(tx) {
|
|
15073
|
+
const data = JSON.parse(tx);
|
|
15074
|
+
const payloadHex = data.payload_hex.startsWith("0x") ? data.payload_hex.slice(2) : data.payload_hex;
|
|
15075
|
+
const pollTxHash = `od:${keccak256(stringToBytes(payloadHex)).slice(2)}`;
|
|
15076
|
+
return { srcTxHash: "withdraw", data, pollTxHash };
|
|
15077
|
+
}
|
|
14936
15078
|
/**
|
|
14937
15079
|
* Build a priority Bitcoin transaction with proper fee calculation
|
|
14938
15080
|
*/
|
|
14939
|
-
async buildBitcoinTransaction(utxos, outputs, changeAddress, chainId, walletProvider, feeRate) {
|
|
15081
|
+
async buildBitcoinTransaction(utxos, outputs, changeAddress, chainId, walletProvider, feeRate, opReturnOutputVbytes) {
|
|
14940
15082
|
const psbt = new Psbt({ network: this.getBtcNetwork(chainId) });
|
|
14941
15083
|
const effectiveFeeRate = feeRate ?? await this.getFeeRateEstimate();
|
|
14942
15084
|
const walletAddress = await walletProvider.getWalletAddress();
|
|
@@ -14999,7 +15141,7 @@ var BitcoinSpokeService = class {
|
|
|
14999
15141
|
});
|
|
15000
15142
|
}
|
|
15001
15143
|
inputSum += utxo.value;
|
|
15002
|
-
const estimatedSize = estimateBitcoinTxSize(psbt.inputCount, outputs.length, addressType);
|
|
15144
|
+
const estimatedSize = estimateBitcoinTxSize(psbt.inputCount, outputs.length, addressType, opReturnOutputVbytes);
|
|
15003
15145
|
const estimatedFee = Math.ceil(effectiveFeeRate * estimatedSize);
|
|
15004
15146
|
if (inputSum >= outputSum + estimatedFee + DUST_THRESHOLD) {
|
|
15005
15147
|
break;
|
|
@@ -15011,8 +15153,13 @@ var BitcoinSpokeService = class {
|
|
|
15011
15153
|
value: output.value
|
|
15012
15154
|
});
|
|
15013
15155
|
}
|
|
15014
|
-
const sizeWithChange = estimateBitcoinTxSize(
|
|
15015
|
-
|
|
15156
|
+
const sizeWithChange = estimateBitcoinTxSize(
|
|
15157
|
+
psbt.inputCount,
|
|
15158
|
+
outputs.length + 1,
|
|
15159
|
+
addressType,
|
|
15160
|
+
opReturnOutputVbytes
|
|
15161
|
+
);
|
|
15162
|
+
const sizeWithoutChange = estimateBitcoinTxSize(psbt.inputCount, outputs.length, addressType, opReturnOutputVbytes);
|
|
15016
15163
|
const feeWithChange = Math.ceil(effectiveFeeRate * sizeWithChange);
|
|
15017
15164
|
const feeWithoutChange = Math.ceil(effectiveFeeRate * sizeWithoutChange);
|
|
15018
15165
|
let change = inputSum - outputSum - feeWithChange;
|
|
@@ -15081,7 +15228,12 @@ var BitcoinSpokeService = class {
|
|
|
15081
15228
|
return await this.radfi.requestRadfiSignature(
|
|
15082
15229
|
{
|
|
15083
15230
|
userAddress: from,
|
|
15084
|
-
signedBase64Tx
|
|
15231
|
+
signedBase64Tx,
|
|
15232
|
+
// Forward the relay identity ({ hub wallet address, full payload }) so the Bound Exchange
|
|
15233
|
+
// backend can auto-resubmit the intent relay if it gets stuck. `to` is the hub wallet
|
|
15234
|
+
// (relayData.address) and `data` is the full payload (relayData.payload) — the same pair
|
|
15235
|
+
// feature services return as `relayData` from createIntent()/supply().
|
|
15236
|
+
relayData: { address: params.to, payload: data }
|
|
15085
15237
|
},
|
|
15086
15238
|
accessToken
|
|
15087
15239
|
);
|
|
@@ -15091,7 +15243,11 @@ var BitcoinSpokeService = class {
|
|
|
15091
15243
|
"Raw mode is not supported for normal Bitcoin deposits. Use TRADING wallet mode for raw transactions."
|
|
15092
15244
|
);
|
|
15093
15245
|
}
|
|
15094
|
-
const
|
|
15246
|
+
const [allUtxos, mempoolSpent] = await Promise.all([
|
|
15247
|
+
this.fetchUTXOs(from),
|
|
15248
|
+
this.fetchMempoolSpentOutpoints(from)
|
|
15249
|
+
]);
|
|
15250
|
+
const utxos = allUtxos.filter((u) => !mempoolSpent.has(`${u.txid}:${u.vout}`));
|
|
15095
15251
|
if (!utxos?.length) {
|
|
15096
15252
|
throw new Error("No UTXOs available for deposit");
|
|
15097
15253
|
}
|
|
@@ -15106,7 +15262,7 @@ var BitcoinSpokeService = class {
|
|
|
15106
15262
|
);
|
|
15107
15263
|
return await this.signAndBroadcastTransaction(depositPsbt, params.walletProvider);
|
|
15108
15264
|
} catch (error) {
|
|
15109
|
-
|
|
15265
|
+
this.config.logger.error("Error during deposit", error);
|
|
15110
15266
|
throw error;
|
|
15111
15267
|
}
|
|
15112
15268
|
}
|
|
@@ -15114,22 +15270,37 @@ var BitcoinSpokeService = class {
|
|
|
15114
15270
|
* Build deposit PSBT with embedded cross-chain data
|
|
15115
15271
|
*/
|
|
15116
15272
|
async buildDepositPsbt(walletAddress, walletProvider, srcChainKey, token, amount, data, utxos) {
|
|
15117
|
-
const
|
|
15118
|
-
|
|
15273
|
+
const chainConfig = this.config.getChainConfig(srcChainKey);
|
|
15274
|
+
const assetManagerAddress = chainConfig.addresses.assetManager;
|
|
15275
|
+
const normalizedToken = token.toLocaleLowerCase();
|
|
15276
|
+
const nativeBtcTokens = new Set(
|
|
15277
|
+
["btc", chainConfig.nativeToken, chainConfig.supportedTokens.BTC?.address].filter((value) => !!value).map((value) => value.toLocaleLowerCase())
|
|
15278
|
+
);
|
|
15279
|
+
const isNativeBtc = nativeBtcTokens.has(normalizedToken);
|
|
15280
|
+
if (isNativeBtc) {
|
|
15281
|
+
const OP_RETURN = opcodes.OP_RETURN;
|
|
15282
|
+
const OP_12 = opcodes.OP_12;
|
|
15283
|
+
if (OP_RETURN === void 0 || OP_12 === void 0) {
|
|
15284
|
+
throw new Error("bitcoinjs-lib opcodes OP_RETURN or OP_12 are undefined");
|
|
15285
|
+
}
|
|
15286
|
+
const OP_RADFI_SODAX_DATA = 49;
|
|
15287
|
+
const payload = Buffer.concat([Buffer.from([OP_RADFI_SODAX_DATA]), Buffer.from(data.slice(2), "hex")]);
|
|
15288
|
+
const opReturnOutputVbytes = calcOpReturnOutputVbytes(payload.length);
|
|
15119
15289
|
const outputs = [
|
|
15120
15290
|
{
|
|
15121
15291
|
address: assetManagerAddress,
|
|
15122
15292
|
value: Number(amount)
|
|
15123
15293
|
}
|
|
15124
15294
|
];
|
|
15125
|
-
const psbt = await this.buildBitcoinTransaction(
|
|
15126
|
-
|
|
15127
|
-
|
|
15128
|
-
|
|
15129
|
-
|
|
15130
|
-
|
|
15131
|
-
|
|
15132
|
-
|
|
15295
|
+
const psbt = await this.buildBitcoinTransaction(
|
|
15296
|
+
utxos,
|
|
15297
|
+
outputs,
|
|
15298
|
+
walletAddress,
|
|
15299
|
+
srcChainKey,
|
|
15300
|
+
walletProvider,
|
|
15301
|
+
void 0,
|
|
15302
|
+
opReturnOutputVbytes
|
|
15303
|
+
);
|
|
15133
15304
|
const compiledScript = script.compile([OP_RETURN, OP_12, payload]);
|
|
15134
15305
|
psbt.addOutput({
|
|
15135
15306
|
script: compiledScript,
|
|
@@ -15149,6 +15320,27 @@ var BitcoinSpokeService = class {
|
|
|
15149
15320
|
}
|
|
15150
15321
|
return await response.json();
|
|
15151
15322
|
}
|
|
15323
|
+
/**
|
|
15324
|
+
* Returns the set of "txid:vout" outpoints currently being spent by
|
|
15325
|
+
* unconfirmed transactions in the mempool for the given address.
|
|
15326
|
+
* Used to prevent double-spend when building a new PSBT.
|
|
15327
|
+
*/
|
|
15328
|
+
async fetchMempoolSpentOutpoints(address) {
|
|
15329
|
+
try {
|
|
15330
|
+
const response = await fetch(`${this.rpcUrl}/address/${address}/txs/mempool`);
|
|
15331
|
+
if (!response.ok) return /* @__PURE__ */ new Set();
|
|
15332
|
+
const mempoolTxs = await response.json();
|
|
15333
|
+
const spent = /* @__PURE__ */ new Set();
|
|
15334
|
+
for (const tx of mempoolTxs) {
|
|
15335
|
+
for (const input of tx.vin) {
|
|
15336
|
+
spent.add(`${input.txid}:${input.vout}`);
|
|
15337
|
+
}
|
|
15338
|
+
}
|
|
15339
|
+
return spent;
|
|
15340
|
+
} catch {
|
|
15341
|
+
return /* @__PURE__ */ new Set();
|
|
15342
|
+
}
|
|
15343
|
+
}
|
|
15152
15344
|
/**
|
|
15153
15345
|
* Fetch raw transaction hex
|
|
15154
15346
|
*/
|
|
@@ -15164,7 +15356,7 @@ var BitcoinSpokeService = class {
|
|
|
15164
15356
|
let srcAddress = from;
|
|
15165
15357
|
const addressType = detectBitcoinAddressType(from);
|
|
15166
15358
|
if (walletMode === "TRADING") {
|
|
15167
|
-
srcAddress = await this.radfi.getTradingWallet(srcAddress)
|
|
15359
|
+
srcAddress = (await this.radfi.getTradingWallet(srcAddress)).tradingAddress;
|
|
15168
15360
|
}
|
|
15169
15361
|
const payload = {
|
|
15170
15362
|
src_address: srcAddress,
|
|
@@ -15183,8 +15375,12 @@ var BitcoinSpokeService = class {
|
|
|
15183
15375
|
if (params.raw === true) {
|
|
15184
15376
|
return JSON.stringify(onDemandWithdraw);
|
|
15185
15377
|
}
|
|
15186
|
-
|
|
15187
|
-
|
|
15378
|
+
if (!params.walletProvider.getPublicKey) {
|
|
15379
|
+
throw new Error("Wallet provider does not support getPublicKey");
|
|
15380
|
+
}
|
|
15381
|
+
const rawSignature = usesBip322MessageSigning(addressType) ? await params.walletProvider.signBip322Message(orderedPayload) : await params.walletProvider.signEcdsaMessage(orderedPayload);
|
|
15382
|
+
onDemandWithdraw.signature = normalizeSignatureToBase64(rawSignature);
|
|
15383
|
+
onDemandWithdraw.public_key = await params.walletProvider.getPublicKey();
|
|
15188
15384
|
return JSON.stringify(onDemandWithdraw);
|
|
15189
15385
|
}
|
|
15190
15386
|
/**
|
|
@@ -15192,8 +15388,14 @@ var BitcoinSpokeService = class {
|
|
|
15192
15388
|
*/
|
|
15193
15389
|
async signAndBroadcastTransaction(psbt, walletProvider) {
|
|
15194
15390
|
const psbtBase64 = typeof psbt === "string" ? psbt : psbt.toBase64();
|
|
15195
|
-
const
|
|
15196
|
-
const
|
|
15391
|
+
const signedRaw = await walletProvider.signTransaction(psbtBase64, false);
|
|
15392
|
+
const signedPsbt = Psbt.fromBase64(normalizePsbtToBase64(signedRaw));
|
|
15393
|
+
try {
|
|
15394
|
+
signedPsbt.finalizeAllInputs();
|
|
15395
|
+
} catch {
|
|
15396
|
+
}
|
|
15397
|
+
const txHex = signedPsbt.extractTransaction().toHex();
|
|
15398
|
+
const txHash = await this.broadcastTransaction(txHex);
|
|
15197
15399
|
return txHash;
|
|
15198
15400
|
}
|
|
15199
15401
|
/**
|
|
@@ -17432,7 +17634,7 @@ function base64Decode(str) {
|
|
|
17432
17634
|
}
|
|
17433
17635
|
var encoder = new TextEncoder();
|
|
17434
17636
|
var decoder = new TextDecoder();
|
|
17435
|
-
function
|
|
17637
|
+
function stringToBytes2(str) {
|
|
17436
17638
|
return encoder.encode(str);
|
|
17437
17639
|
}
|
|
17438
17640
|
function bytesToString(bytes) {
|
|
@@ -20829,7 +21031,7 @@ var JsonRpcProvider = class {
|
|
|
20829
21031
|
};
|
|
20830
21032
|
}
|
|
20831
21033
|
async viewContractState({ contractId, prefix: prefix2, blockQuery = { finality: DEFAULT_FINALITY } }) {
|
|
20832
|
-
const prefixBase64 = base64Encode(
|
|
21034
|
+
const prefixBase64 = base64Encode(stringToBytes2(prefix2 || ""));
|
|
20833
21035
|
let reference;
|
|
20834
21036
|
if ("blockId" in blockQuery) {
|
|
20835
21037
|
reference = { block_id: blockQuery.blockId };
|
|
@@ -20857,7 +21059,7 @@ var JsonRpcProvider = class {
|
|
|
20857
21059
|
}
|
|
20858
21060
|
}
|
|
20859
21061
|
async callFunctionRaw({ contractId, method, args, blockQuery = { finality: DEFAULT_FINALITY } }) {
|
|
20860
|
-
const argsBytes = args instanceof Uint8Array ? args :
|
|
21062
|
+
const argsBytes = args instanceof Uint8Array ? args : stringToBytes2(JSON.stringify(args));
|
|
20861
21063
|
const argsBase64 = base64Encode(argsBytes);
|
|
20862
21064
|
if ("blockId" in blockQuery) {
|
|
20863
21065
|
return this.query({
|
|
@@ -21123,6 +21325,7 @@ var JsonRpcProvider = class {
|
|
|
21123
21325
|
|
|
21124
21326
|
// src/shared/services/spoke/NearSpokeService.ts
|
|
21125
21327
|
var NEAR_DEFAULT_GAS = BigInt("300000000000000");
|
|
21328
|
+
var NEAR_STORAGE_DEPOSIT = BigInt("1250000000000000000000");
|
|
21126
21329
|
var NearSpokeService = class {
|
|
21127
21330
|
config;
|
|
21128
21331
|
rpcProvider;
|
|
@@ -21172,7 +21375,7 @@ var NearSpokeService = class {
|
|
|
21172
21375
|
token: Array.from(Buffer.from(fillData.token, "utf-8"))
|
|
21173
21376
|
};
|
|
21174
21377
|
}
|
|
21175
|
-
async fillIntent(fromInfo, fillData, deposit = BigInt("
|
|
21378
|
+
async fillIntent(fromInfo, fillData, deposit = BigInt("1"), gas = BigInt("300000000000000")) {
|
|
21176
21379
|
const intentFiller = this.config.getChainConfig(fromInfo.srcChainKey).addresses.intentFiller;
|
|
21177
21380
|
if (isNativeToken(fromInfo.srcChainKey, fillData.token)) {
|
|
21178
21381
|
deposit = BigInt(fillData.amount);
|
|
@@ -21246,7 +21449,8 @@ var NearSpokeService = class {
|
|
|
21246
21449
|
data: inputParams.data
|
|
21247
21450
|
})
|
|
21248
21451
|
},
|
|
21249
|
-
|
|
21452
|
+
// NEP-141 requires exactly 1 yoctoNEAR attached to ft_transfer_call.
|
|
21453
|
+
deposit: BigInt("1"),
|
|
21250
21454
|
gas: NEAR_DEFAULT_GAS
|
|
21251
21455
|
}
|
|
21252
21456
|
};
|
|
@@ -21277,6 +21481,52 @@ var NearSpokeService = class {
|
|
|
21277
21481
|
}
|
|
21278
21482
|
return BigInt(bal);
|
|
21279
21483
|
}
|
|
21484
|
+
/**
|
|
21485
|
+
* Whether `accountId` is storage-registered on a NEP-141 `token` contract. NEP-141 requires an
|
|
21486
|
+
* account to pay a one-time storage bond before it can receive (hold a balance of) the token, so
|
|
21487
|
+
* this gates any leg that delivers a token to a user on NEAR (swap output on NEAR, bridge into
|
|
21488
|
+
* NEAR, money-market borrow/withdraw to NEAR).
|
|
21489
|
+
*
|
|
21490
|
+
* Native NEAR is not a NEP-141 token and has no storage registration, so this returns `true` for
|
|
21491
|
+
* the native token. The view goes through {@link queryContract}, i.e. the configurable RPC from
|
|
21492
|
+
* chain config — a custom `rpcUrl` passed to the SDK is honoured.
|
|
21493
|
+
*/
|
|
21494
|
+
async isStorageRegistered(token, accountId) {
|
|
21495
|
+
if (isNativeToken(ChainKeys.NEAR_MAINNET, token)) {
|
|
21496
|
+
return true;
|
|
21497
|
+
}
|
|
21498
|
+
const balance = await this.queryContract(token, "storage_balance_of", { account_id: accountId });
|
|
21499
|
+
return balance != null;
|
|
21500
|
+
}
|
|
21501
|
+
/**
|
|
21502
|
+
* Build (and, unless `raw`, submit) a NEP-141 `storage_deposit` registration for `accountId` on
|
|
21503
|
+
* the `token` contract. Call this when {@link isStorageRegistered} is `false` before a token is
|
|
21504
|
+
* delivered to the account on NEAR.
|
|
21505
|
+
*
|
|
21506
|
+
* Native NEAR has no storage registration — passing the native token throws.
|
|
21507
|
+
*
|
|
21508
|
+
* @param params.deposit Storage bond to attach; defaults to {@link NEAR_STORAGE_DEPOSIT}
|
|
21509
|
+
* (0.00125 NEAR). Override per token if its `storage_balance_bounds.min` differs.
|
|
21510
|
+
*/
|
|
21511
|
+
async registerStorage(params) {
|
|
21512
|
+
if (isNativeToken(ChainKeys.NEAR_MAINNET, params.token)) {
|
|
21513
|
+
throw new Error("[NearSpokeService.registerStorage] Native NEAR has no NEP-141 storage registration.");
|
|
21514
|
+
}
|
|
21515
|
+
const tx = {
|
|
21516
|
+
signerId: params.accountId,
|
|
21517
|
+
params: {
|
|
21518
|
+
contractId: params.token,
|
|
21519
|
+
method: "storage_deposit",
|
|
21520
|
+
args: { account_id: params.accountId, registration_only: true },
|
|
21521
|
+
deposit: params.deposit ?? NEAR_STORAGE_DEPOSIT,
|
|
21522
|
+
gas: NEAR_DEFAULT_GAS
|
|
21523
|
+
}
|
|
21524
|
+
};
|
|
21525
|
+
if (params.raw === true) {
|
|
21526
|
+
return tx;
|
|
21527
|
+
}
|
|
21528
|
+
return params.walletProvider.signAndSubmitTxn(tx);
|
|
21529
|
+
}
|
|
21280
21530
|
/**
|
|
21281
21531
|
* Sends a message to the hub chain.
|
|
21282
21532
|
* @param {SendMessageParams} params - Includes dstChainKey, the chain key of the hub chain.
|
|
@@ -22077,17 +22327,11 @@ var SuiSpokeService = class {
|
|
|
22077
22327
|
]
|
|
22078
22328
|
});
|
|
22079
22329
|
if (params.raw === true) {
|
|
22080
|
-
tx.setSender(from);
|
|
22081
|
-
const transactionRaw = await tx.build({
|
|
22082
|
-
client: this.publicClient,
|
|
22083
|
-
onlyTransactionKind: true
|
|
22084
|
-
});
|
|
22085
|
-
const transactionRawBase64String = Buffer.from(transactionRaw).toString("base64");
|
|
22086
22330
|
return {
|
|
22087
22331
|
from,
|
|
22088
22332
|
to: `${assetManager.packageId}::${assetManager.moduleId}::transfer`,
|
|
22089
22333
|
value: amount,
|
|
22090
|
-
data:
|
|
22334
|
+
data: tx.serialize()
|
|
22091
22335
|
};
|
|
22092
22336
|
}
|
|
22093
22337
|
return params.walletProvider.signAndExecuteTxn(tx);
|
|
@@ -22107,17 +22351,11 @@ var SuiSpokeService = class {
|
|
|
22107
22351
|
]
|
|
22108
22352
|
});
|
|
22109
22353
|
if (params.raw === true) {
|
|
22110
|
-
txb.setSender(from);
|
|
22111
|
-
const transactionRaw = await txb.build({
|
|
22112
|
-
client: this.publicClient,
|
|
22113
|
-
onlyTransactionKind: true
|
|
22114
|
-
});
|
|
22115
|
-
const transactionRawBase64String = Buffer.from(transactionRaw).toString("base64");
|
|
22116
22354
|
return {
|
|
22117
22355
|
from,
|
|
22118
22356
|
to: `${connection.packageId}::${connection.moduleId}::send_message_ua`,
|
|
22119
22357
|
value: 0n,
|
|
22120
|
-
data:
|
|
22358
|
+
data: txb.serialize()
|
|
22121
22359
|
};
|
|
22122
22360
|
}
|
|
22123
22361
|
return params.walletProvider.signAndExecuteTxn(txb);
|
|
@@ -22128,7 +22366,7 @@ var SuiSpokeService = class {
|
|
|
22128
22366
|
* @returns {Promise<bigint>} The estimated computation cost.
|
|
22129
22367
|
*/
|
|
22130
22368
|
async estimateGas({ tx }) {
|
|
22131
|
-
const txb = Transaction$1.
|
|
22369
|
+
const txb = Transaction$1.from(tx.data);
|
|
22132
22370
|
const result = await this.publicClient.devInspectTransactionBlock({
|
|
22133
22371
|
sender: tx.from,
|
|
22134
22372
|
transactionBlock: txb
|
|
@@ -22359,6 +22597,7 @@ var CustomStellarAccount = class {
|
|
|
22359
22597
|
decrementSequenceNumber() {
|
|
22360
22598
|
if (this.sequenceNumber > this.startingSequenceNumber) {
|
|
22361
22599
|
this.sequenceNumber--;
|
|
22600
|
+
return;
|
|
22362
22601
|
}
|
|
22363
22602
|
throw new Error(
|
|
22364
22603
|
`Sequence number cannot be decremented below the starting sequence number: ${this.startingSequenceNumber}`
|
|
@@ -22465,7 +22704,7 @@ var StellarSpokeService = class {
|
|
|
22465
22704
|
);
|
|
22466
22705
|
const assembledPriorityTx = rpc.assembleTransaction(rawPriorityTx, simulation).build();
|
|
22467
22706
|
if (params.raw) {
|
|
22468
|
-
const transactionXdr =
|
|
22707
|
+
const transactionXdr = assembledPriorityTx.toXDR();
|
|
22469
22708
|
return {
|
|
22470
22709
|
from,
|
|
22471
22710
|
to: this.config.getChainConfig(srcChainKey).addresses.assetManager,
|
|
@@ -22484,13 +22723,13 @@ var StellarSpokeService = class {
|
|
|
22484
22723
|
);
|
|
22485
22724
|
return `${hash}`;
|
|
22486
22725
|
} catch (error) {
|
|
22487
|
-
|
|
22726
|
+
this.config.logger.error("Error during sendMessage", error);
|
|
22488
22727
|
throw error;
|
|
22489
22728
|
}
|
|
22490
22729
|
}
|
|
22491
22730
|
handleSendTransactionError(response) {
|
|
22492
22731
|
if (response.status === "ERROR") {
|
|
22493
|
-
|
|
22732
|
+
this.config.logger.error(JSON.stringify(response, null, 2));
|
|
22494
22733
|
throw new Error(JSON.stringify(response, null, 2));
|
|
22495
22734
|
}
|
|
22496
22735
|
return response;
|
|
@@ -22582,7 +22821,7 @@ var StellarSpokeService = class {
|
|
|
22582
22821
|
);
|
|
22583
22822
|
const assembledPriorityTx = rpc.assembleTransaction(rawPriorityTx, simulation).build();
|
|
22584
22823
|
if (params.raw) {
|
|
22585
|
-
const transactionXdr =
|
|
22824
|
+
const transactionXdr = assembledPriorityTx.toXDR();
|
|
22586
22825
|
return {
|
|
22587
22826
|
from,
|
|
22588
22827
|
to: this.config.getChainConfig(srcChainKey).addresses.assetManager,
|
|
@@ -22601,7 +22840,7 @@ var StellarSpokeService = class {
|
|
|
22601
22840
|
);
|
|
22602
22841
|
return `${hash}`;
|
|
22603
22842
|
} catch (error) {
|
|
22604
|
-
|
|
22843
|
+
this.config.logger.error("Error during deposit", error);
|
|
22605
22844
|
throw error;
|
|
22606
22845
|
}
|
|
22607
22846
|
}
|
|
@@ -22629,7 +22868,7 @@ var StellarSpokeService = class {
|
|
|
22629
22868
|
(balance2) => "limit" in balance2 && "balance" in balance2 && "asset_code" in balance2 && trustlineConfig.assetCode.toLowerCase() === balance2.asset_code?.toLowerCase() && "asset_issuer" in balance2 && trustlineConfig.assetIssuer.toLowerCase() === balance2.asset_issuer?.toLowerCase()
|
|
22630
22869
|
);
|
|
22631
22870
|
if (!tokenBalance) {
|
|
22632
|
-
|
|
22871
|
+
this.config.logger.error(`No token balances found for token: ${token}`);
|
|
22633
22872
|
return false;
|
|
22634
22873
|
}
|
|
22635
22874
|
const limit = parseToStroops(tokenBalance.limit);
|
|
@@ -22678,7 +22917,7 @@ var StellarSpokeService = class {
|
|
|
22678
22917
|
const hash = await this.signAndSendTransaction(walletProvider, transaction);
|
|
22679
22918
|
return `${hash}`;
|
|
22680
22919
|
} catch (error) {
|
|
22681
|
-
|
|
22920
|
+
this.config.logger.error("Error during requestTrustline", error);
|
|
22682
22921
|
throw error;
|
|
22683
22922
|
}
|
|
22684
22923
|
}
|
|
@@ -23537,7 +23776,7 @@ var SpokeService = class _SpokeService {
|
|
|
23537
23776
|
}
|
|
23538
23777
|
default: {
|
|
23539
23778
|
const exhaustiveCheck = chainType;
|
|
23540
|
-
|
|
23779
|
+
this.config.logger.debug("Unhandled exhaustive case", { value: exhaustiveCheck });
|
|
23541
23780
|
throw new Error(`[getSpokeService] Invalid chain type. Valid chain types: ${ChainTypeArr.join(", ")}`);
|
|
23542
23781
|
}
|
|
23543
23782
|
}
|
|
@@ -23710,7 +23949,7 @@ var SpokeService = class _SpokeService {
|
|
|
23710
23949
|
}
|
|
23711
23950
|
default: {
|
|
23712
23951
|
const exhaustiveCheck = chainType;
|
|
23713
|
-
|
|
23952
|
+
this.config.logger.debug("Unhandled exhaustive case", { value: exhaustiveCheck });
|
|
23714
23953
|
return {
|
|
23715
23954
|
ok: false,
|
|
23716
23955
|
error: new Error(`[estimateGas] Invalid chain type. Valid chain types: ${ChainTypeArr.join(", ")}`)
|
|
@@ -23817,17 +24056,17 @@ var SpokeService = class _SpokeService {
|
|
|
23817
24056
|
args: [params.srcChainId, params.srcAddress, params.payload]
|
|
23818
24057
|
})
|
|
23819
24058
|
});
|
|
23820
|
-
|
|
24059
|
+
this.config.logger.warn("simulateRecvMessage did not revert as expected", { result });
|
|
23821
24060
|
return {
|
|
23822
24061
|
ok: false,
|
|
23823
24062
|
error: new Error('Function should have reverted with "Simulation completed"')
|
|
23824
24063
|
};
|
|
23825
24064
|
} catch (error) {
|
|
23826
24065
|
if (error instanceof Error && error.message?.includes("Simulation completed")) {
|
|
23827
|
-
|
|
24066
|
+
this.config.logger.warn("simulateRecvMessage completed successfully with expected revert");
|
|
23828
24067
|
return { ok: true, value: true };
|
|
23829
24068
|
}
|
|
23830
|
-
|
|
24069
|
+
this.config.logger.error("simulateRecvMessage failed with unexpected error", error);
|
|
23831
24070
|
return { ok: false, error };
|
|
23832
24071
|
}
|
|
23833
24072
|
}
|
|
@@ -23912,7 +24151,7 @@ var SpokeService = class _SpokeService {
|
|
|
23912
24151
|
}
|
|
23913
24152
|
default: {
|
|
23914
24153
|
const exhaustiveCheck = chainType;
|
|
23915
|
-
|
|
24154
|
+
this.config.logger.debug("Unhandled exhaustive case", { value: exhaustiveCheck });
|
|
23916
24155
|
return {
|
|
23917
24156
|
ok: false,
|
|
23918
24157
|
error: new Error(`[deposit] Invalid chain type. Valid chain types: ${ChainTypeArr.join(", ")}`)
|
|
@@ -23989,7 +24228,7 @@ var SpokeService = class _SpokeService {
|
|
|
23989
24228
|
}
|
|
23990
24229
|
default: {
|
|
23991
24230
|
const exhaustiveCheck = chainType;
|
|
23992
|
-
|
|
24231
|
+
this.config.logger.debug("Unhandled exhaustive case", { value: exhaustiveCheck });
|
|
23993
24232
|
return {
|
|
23994
24233
|
ok: false,
|
|
23995
24234
|
error: new Error(`[getDeposit] Invalid chain type. Valid chain types: ${ChainTypeArr.join(", ")}`)
|
|
@@ -24098,7 +24337,7 @@ var SpokeService = class _SpokeService {
|
|
|
24098
24337
|
}
|
|
24099
24338
|
default: {
|
|
24100
24339
|
const exhaustiveCheck = chainType;
|
|
24101
|
-
|
|
24340
|
+
this.config.logger.debug("Unhandled exhaustive case", { value: exhaustiveCheck });
|
|
24102
24341
|
return {
|
|
24103
24342
|
ok: false,
|
|
24104
24343
|
error: new Error(`[sendMessage] Invalid chain type. Valid chain types: ${ChainTypeArr.join(", ")}`)
|
|
@@ -24177,10 +24416,10 @@ var SpokeService = class _SpokeService {
|
|
|
24177
24416
|
if (isSolanaChainKeyType(chainKey)) {
|
|
24178
24417
|
const result = await this.solana.waitForTransactionReceipt({ txHash, chainKey });
|
|
24179
24418
|
if (!result.ok || result.value.status !== "success") {
|
|
24180
|
-
|
|
24419
|
+
this.config.logger.warn(
|
|
24181
24420
|
`Solana verifyTxHash failed: ${!result.ok ? result.error : "error" in result.value ? result.value.error : "unknown"}`
|
|
24182
24421
|
);
|
|
24183
|
-
|
|
24422
|
+
this.config.logger.warn("Returning true to assume transaction exists on chain in future ");
|
|
24184
24423
|
return { ok: true, value: true };
|
|
24185
24424
|
}
|
|
24186
24425
|
return { ok: true, value: true };
|
|
@@ -24267,7 +24506,7 @@ var SpokeService = class _SpokeService {
|
|
|
24267
24506
|
}
|
|
24268
24507
|
default: {
|
|
24269
24508
|
const exhaustiveCheck = chainType;
|
|
24270
|
-
|
|
24509
|
+
this.config.logger.debug("Unhandled exhaustive case", { value: exhaustiveCheck });
|
|
24271
24510
|
return { ok: false, error: new Error(`waitForTransactionReceipt not supported for ${params.chainKey}`) };
|
|
24272
24511
|
}
|
|
24273
24512
|
}
|
|
@@ -25318,6 +25557,7 @@ var EvmHubProvider = class {
|
|
|
25318
25557
|
};
|
|
25319
25558
|
|
|
25320
25559
|
// src/swap/SolverApiService.ts
|
|
25560
|
+
var bigintReplacer = (_key, value) => typeof value === "bigint" ? value.toString() : value;
|
|
25321
25561
|
var SolverApiService = class {
|
|
25322
25562
|
constructor() {
|
|
25323
25563
|
}
|
|
@@ -25386,13 +25626,16 @@ var SolverApiService = class {
|
|
|
25386
25626
|
}
|
|
25387
25627
|
};
|
|
25388
25628
|
} catch (e) {
|
|
25389
|
-
|
|
25629
|
+
configService.logger.error(
|
|
25630
|
+
"[SolverApiService.getQuote] failed",
|
|
25631
|
+
e instanceof Error ? e : new Error(JSON.stringify(e, bigintReplacer))
|
|
25632
|
+
);
|
|
25390
25633
|
return {
|
|
25391
25634
|
ok: false,
|
|
25392
25635
|
error: {
|
|
25393
25636
|
detail: {
|
|
25394
25637
|
code: SolverIntentErrorCode.UNKNOWN,
|
|
25395
|
-
message: e ? JSON.stringify(e) : "Unknown error"
|
|
25638
|
+
message: e ? JSON.stringify(e, bigintReplacer) : "Unknown error"
|
|
25396
25639
|
}
|
|
25397
25640
|
}
|
|
25398
25641
|
};
|
|
@@ -25409,7 +25652,7 @@ var SolverApiService = class {
|
|
|
25409
25652
|
* @param config - Solver endpoint configuration.
|
|
25410
25653
|
* @returns A `Result` containing `{ answer: 'OK', intent_hash: Hex }` on success.
|
|
25411
25654
|
*/
|
|
25412
|
-
static async postExecution(request, config) {
|
|
25655
|
+
static async postExecution(request, config, logger = silentLogger) {
|
|
25413
25656
|
try {
|
|
25414
25657
|
const response = await retry(
|
|
25415
25658
|
() => fetch(`${config.solverApiEndpoint}/execute`, {
|
|
@@ -25431,13 +25674,16 @@ var SolverApiService = class {
|
|
|
25431
25674
|
value: await response.json()
|
|
25432
25675
|
};
|
|
25433
25676
|
} catch (e) {
|
|
25434
|
-
|
|
25677
|
+
logger.error(
|
|
25678
|
+
"[SolverApiService.postExecution] failed",
|
|
25679
|
+
e instanceof Error ? e : new Error(JSON.stringify(e, bigintReplacer))
|
|
25680
|
+
);
|
|
25435
25681
|
return {
|
|
25436
25682
|
ok: false,
|
|
25437
25683
|
error: {
|
|
25438
25684
|
detail: {
|
|
25439
25685
|
code: SolverIntentErrorCode.UNKNOWN,
|
|
25440
|
-
message: e ? JSON.stringify(e) : "Unknown error"
|
|
25686
|
+
message: e ? JSON.stringify(e, bigintReplacer) : "Unknown error"
|
|
25441
25687
|
}
|
|
25442
25688
|
}
|
|
25443
25689
|
};
|
|
@@ -25452,7 +25698,7 @@ var SolverApiService = class {
|
|
|
25452
25698
|
* `fill_tx_hash` is set only when `status === SolverIntentStatusCode.SOLVED (3)`.
|
|
25453
25699
|
* @throws Invariant error if `intent_tx_hash` is empty (thrown before the async request).
|
|
25454
25700
|
*/
|
|
25455
|
-
static async getStatus(request, config) {
|
|
25701
|
+
static async getStatus(request, config, logger = silentLogger) {
|
|
25456
25702
|
invariant(request.intent_tx_hash.length > 0, "Empty intent_tx_hash");
|
|
25457
25703
|
try {
|
|
25458
25704
|
const response = await fetch(`${config.solverApiEndpoint}/status`, {
|
|
@@ -25473,13 +25719,16 @@ var SolverApiService = class {
|
|
|
25473
25719
|
value: await response.json()
|
|
25474
25720
|
};
|
|
25475
25721
|
} catch (e) {
|
|
25476
|
-
|
|
25722
|
+
logger.error(
|
|
25723
|
+
"[SolverApiService.getStatus] failed",
|
|
25724
|
+
e instanceof Error ? e : new Error(JSON.stringify(e, bigintReplacer))
|
|
25725
|
+
);
|
|
25477
25726
|
return {
|
|
25478
25727
|
ok: false,
|
|
25479
25728
|
error: {
|
|
25480
25729
|
detail: {
|
|
25481
25730
|
code: SolverIntentErrorCode.UNKNOWN,
|
|
25482
|
-
message: e ? JSON.stringify(e) : "Unknown error"
|
|
25731
|
+
message: e ? JSON.stringify(e, bigintReplacer) : "Unknown error"
|
|
25483
25732
|
}
|
|
25484
25733
|
}
|
|
25485
25734
|
};
|
|
@@ -25599,7 +25848,7 @@ var SwapService = class {
|
|
|
25599
25848
|
* `fill_tx_hash` is populated only when `status === SolverIntentStatusCode.SOLVED (3)`.
|
|
25600
25849
|
*/
|
|
25601
25850
|
async getStatus(request) {
|
|
25602
|
-
return SolverApiService.getStatus(request, this.solver);
|
|
25851
|
+
return SolverApiService.getStatus(request, this.solver, this.config.logger);
|
|
25603
25852
|
}
|
|
25604
25853
|
/**
|
|
25605
25854
|
* Notifies the solver API that an intent has been registered on the hub chain, triggering
|
|
@@ -25622,7 +25871,7 @@ var SwapService = class {
|
|
|
25622
25871
|
*/
|
|
25623
25872
|
async postExecution(request) {
|
|
25624
25873
|
try {
|
|
25625
|
-
const result = await SolverApiService.postExecution(request, this.solver);
|
|
25874
|
+
const result = await SolverApiService.postExecution(request, this.solver, this.config.logger);
|
|
25626
25875
|
if (result.ok) return result;
|
|
25627
25876
|
const detail = result.error?.detail ?? {
|
|
25628
25877
|
code: -999,
|
|
@@ -25895,7 +26144,7 @@ var SwapService = class {
|
|
|
25895
26144
|
* - `raw: false` — broadcasts the transaction; `walletProvider` is required and must match `K`.
|
|
25896
26145
|
*
|
|
25897
26146
|
* Validates tokens and chain keys against the active `ConfigService` before constructing the
|
|
25898
|
-
* intent. Bitcoin source chains require an additional
|
|
26147
|
+
* intent. Bitcoin source chains require an additional Bound Exchange access token step.
|
|
25899
26148
|
*
|
|
25900
26149
|
* @param _params - Intent parameters, source chain key, wallet provider (when `raw: false`),
|
|
25901
26150
|
* and optional `skipSimulation` flag.
|
|
@@ -28376,11 +28625,13 @@ var MigrationService = class {
|
|
|
28376
28625
|
|
|
28377
28626
|
// src/backendApi/BackendApiService.ts
|
|
28378
28627
|
var BackendApiService = class {
|
|
28379
|
-
constructor(config) {
|
|
28628
|
+
constructor(config, logger = consoleLogger) {
|
|
28380
28629
|
this.config = config;
|
|
28381
28630
|
this.headers = { ...config.headers };
|
|
28631
|
+
this.logger = logger;
|
|
28382
28632
|
}
|
|
28383
28633
|
headers;
|
|
28634
|
+
logger;
|
|
28384
28635
|
/**
|
|
28385
28636
|
* Execute a single HTTP request and return the parsed JSON body.
|
|
28386
28637
|
*
|
|
@@ -28419,10 +28670,10 @@ var BackendApiService = class {
|
|
|
28419
28670
|
if (error.name === "AbortError") {
|
|
28420
28671
|
throw new Error("REQUEST_TIMEOUT", { cause: new Error(`Request timeout after ${timeout}ms`) });
|
|
28421
28672
|
}
|
|
28422
|
-
|
|
28673
|
+
this.logger.error("[BackendApiService] Request error", error);
|
|
28423
28674
|
throw error;
|
|
28424
28675
|
}
|
|
28425
|
-
|
|
28676
|
+
this.logger.error("[BackendApiService] Unknown error", error);
|
|
28426
28677
|
throw new Error("UNKNOWN_REQUEST_ERROR", { cause: error });
|
|
28427
28678
|
}
|
|
28428
28679
|
}
|
|
@@ -29092,7 +29343,7 @@ var BridgeService = class {
|
|
|
29092
29343
|
* transaction simulation or batching). When `raw` is `false`, signs and submits the deposit
|
|
29093
29344
|
* transaction via the provided wallet provider.
|
|
29094
29345
|
*
|
|
29095
|
-
* Bitcoin is only supported with `raw: false` because it requires the
|
|
29346
|
+
* Bitcoin is only supported with `raw: false` because it requires the Bound Exchange trading wallet
|
|
29096
29347
|
* derivation flow.
|
|
29097
29348
|
*
|
|
29098
29349
|
* @param _params - Bridge parameters including source/destination chain keys, token addresses,
|
|
@@ -29125,9 +29376,12 @@ var BridgeService = class {
|
|
|
29125
29376
|
{ ...baseCtx, field: "walletProvider" }
|
|
29126
29377
|
);
|
|
29127
29378
|
walletAddress = await this.spoke.bitcoin.getEffectiveWalletAddress(personalAddress);
|
|
29128
|
-
|
|
29379
|
+
if (this.spoke.bitcoin.walletMode === "TRADING") {
|
|
29380
|
+
await this.spoke.bitcoin.radfi.ensureRadfiAccessToken(_params.walletProvider);
|
|
29381
|
+
}
|
|
29129
29382
|
}
|
|
29130
|
-
const hubWallet = await this.hubProvider.getUserHubWalletAddress(
|
|
29383
|
+
const hubWallet = await this.hubProvider.getUserHubWalletAddress(walletAddress, params.srcChainKey);
|
|
29384
|
+
const effectiveSkipSimulation = skipSimulation || isBitcoinChainKeyType(params.srcChainKey) && this.spoke.bitcoin.walletMode === "USER";
|
|
29131
29385
|
const data = this.buildBridgeData(params, srcToken, dstToken, this.config.bridge.partnerFee);
|
|
29132
29386
|
const coreParams = {
|
|
29133
29387
|
srcChainKey: params.srcChainKey,
|
|
@@ -29136,7 +29390,7 @@ var BridgeService = class {
|
|
|
29136
29390
|
token: params.srcToken,
|
|
29137
29391
|
amount: params.amount,
|
|
29138
29392
|
data,
|
|
29139
|
-
skipSimulation
|
|
29393
|
+
skipSimulation: effectiveSkipSimulation
|
|
29140
29394
|
};
|
|
29141
29395
|
const txResult = await this.spoke.deposit(
|
|
29142
29396
|
_params.raw ? {
|
|
@@ -29149,7 +29403,7 @@ var BridgeService = class {
|
|
|
29149
29403
|
}
|
|
29150
29404
|
);
|
|
29151
29405
|
if (!txResult.ok) {
|
|
29152
|
-
|
|
29406
|
+
this.config.logger.error("createBridgeIntent failed", txResult.error);
|
|
29153
29407
|
if (isBridgeCreateIntentError(txResult.error)) return { ok: false, error: txResult.error };
|
|
29154
29408
|
return {
|
|
29155
29409
|
ok: false,
|
|
@@ -29164,7 +29418,7 @@ var BridgeService = class {
|
|
|
29164
29418
|
}
|
|
29165
29419
|
};
|
|
29166
29420
|
} catch (error) {
|
|
29167
|
-
|
|
29421
|
+
this.config.logger.error("createBridgeIntent failed", error);
|
|
29168
29422
|
if (isBridgeCreateIntentError(error)) return { ok: false, error };
|
|
29169
29423
|
return {
|
|
29170
29424
|
ok: false,
|
|
@@ -29334,7 +29588,7 @@ var BridgeService = class {
|
|
|
29334
29588
|
value: availableDepositNormalised.isLessThan(assetManagerBalanceNormalised) ? { amount: availableDeposit, decimals: fromTokenInfo.decimals, type: "DEPOSIT_LIMIT" } : { amount: assetManagerBalance, decimals: toTokenInfo.decimals, type: "WITHDRAWAL_LIMIT" }
|
|
29335
29589
|
};
|
|
29336
29590
|
} catch (error) {
|
|
29337
|
-
|
|
29591
|
+
this.config.logger.error("getBridgeableAmount failed", error);
|
|
29338
29592
|
if (isBridgeLookupError(error)) return { ok: false, error };
|
|
29339
29593
|
return {
|
|
29340
29594
|
ok: false,
|
|
@@ -29381,7 +29635,7 @@ var BridgeService = class {
|
|
|
29381
29635
|
});
|
|
29382
29636
|
return srcToken.vault.toLowerCase() === dstToken.vault.toLowerCase();
|
|
29383
29637
|
} catch (error) {
|
|
29384
|
-
|
|
29638
|
+
this.config.logger.error("isBridgeable check failed", error);
|
|
29385
29639
|
return false;
|
|
29386
29640
|
}
|
|
29387
29641
|
}
|
|
@@ -31771,7 +32025,7 @@ var ClService = class _ClService {
|
|
|
31771
32025
|
};
|
|
31772
32026
|
const txResult = await this.spoke.sendMessage(sendMessageParams);
|
|
31773
32027
|
if (!txResult.ok) {
|
|
31774
|
-
|
|
32028
|
+
this.config.logger.error("executeSupplyLiquidity error", txResult.error);
|
|
31775
32029
|
return {
|
|
31776
32030
|
ok: false,
|
|
31777
32031
|
error: txResult.error
|
|
@@ -31785,7 +32039,7 @@ var ClService = class _ClService {
|
|
|
31785
32039
|
}
|
|
31786
32040
|
};
|
|
31787
32041
|
} catch (error) {
|
|
31788
|
-
|
|
32042
|
+
this.config.logger.error("executeSupplyLiquidity error", error);
|
|
31789
32043
|
return {
|
|
31790
32044
|
ok: false,
|
|
31791
32045
|
error
|
|
@@ -32058,7 +32312,7 @@ var ClService = class _ClService {
|
|
|
32058
32312
|
}
|
|
32059
32313
|
return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
|
|
32060
32314
|
} catch (error) {
|
|
32061
|
-
|
|
32315
|
+
this.config.logger.error("supplyLiquidity error", error);
|
|
32062
32316
|
return {
|
|
32063
32317
|
ok: false,
|
|
32064
32318
|
error
|
|
@@ -32202,7 +32456,7 @@ var ClService = class _ClService {
|
|
|
32202
32456
|
}
|
|
32203
32457
|
};
|
|
32204
32458
|
} catch (error) {
|
|
32205
|
-
|
|
32459
|
+
this.config.logger.error("getPoolRewardConfig error", error);
|
|
32206
32460
|
return {
|
|
32207
32461
|
ok: false,
|
|
32208
32462
|
error: lookupFailed("dex", "getPoolRewardConfig", error)
|
|
@@ -32263,7 +32517,7 @@ var ClService = class _ClService {
|
|
|
32263
32517
|
};
|
|
32264
32518
|
const txResult = await this.spoke.sendMessage(sendMessageParams);
|
|
32265
32519
|
if (!txResult.ok) {
|
|
32266
|
-
|
|
32520
|
+
this.config.logger.error("executeClaimRewards error", txResult.error);
|
|
32267
32521
|
return {
|
|
32268
32522
|
ok: false,
|
|
32269
32523
|
error: txResult.error
|
|
@@ -32277,7 +32531,7 @@ var ClService = class _ClService {
|
|
|
32277
32531
|
}
|
|
32278
32532
|
};
|
|
32279
32533
|
} catch (error) {
|
|
32280
|
-
|
|
32534
|
+
this.config.logger.error("executeClaimRewards error", error);
|
|
32281
32535
|
return {
|
|
32282
32536
|
ok: false,
|
|
32283
32537
|
error
|
|
@@ -32319,7 +32573,7 @@ var ClService = class _ClService {
|
|
|
32319
32573
|
}
|
|
32320
32574
|
return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
|
|
32321
32575
|
} catch (error) {
|
|
32322
|
-
|
|
32576
|
+
this.config.logger.error("claimRewards error", error);
|
|
32323
32577
|
return {
|
|
32324
32578
|
ok: false,
|
|
32325
32579
|
error
|
|
@@ -32367,7 +32621,7 @@ var ClService = class _ClService {
|
|
|
32367
32621
|
address: tokenAddress
|
|
32368
32622
|
};
|
|
32369
32623
|
} catch (error) {
|
|
32370
|
-
|
|
32624
|
+
this.config.logger.error(`Failed to fetch token info for ${tokenAddress}`, error);
|
|
32371
32625
|
return {
|
|
32372
32626
|
symbol: "UNKNOWN",
|
|
32373
32627
|
name: "Unknown Token",
|
|
@@ -32392,12 +32646,12 @@ var ClService = class _ClService {
|
|
|
32392
32646
|
const oneShare = BigInt(10 ** 18);
|
|
32393
32647
|
const result = await Erc4626Service.convertToAssets(statATokenAddress, oneShare, this.hubProvider.publicClient);
|
|
32394
32648
|
if (!result.ok) {
|
|
32395
|
-
|
|
32649
|
+
this.config.logger.error("[getStatATokenConversionRate] Failed to get conversion rate", result.error);
|
|
32396
32650
|
return oneShare;
|
|
32397
32651
|
}
|
|
32398
32652
|
return result.value;
|
|
32399
32653
|
} catch (error) {
|
|
32400
|
-
|
|
32654
|
+
this.config.logger.error("[getStatATokenConversionRate] Error", error);
|
|
32401
32655
|
return BigInt(10 ** 18);
|
|
32402
32656
|
}
|
|
32403
32657
|
}
|
|
@@ -32434,7 +32688,7 @@ var ClService = class _ClService {
|
|
|
32434
32688
|
underlyingToken
|
|
32435
32689
|
};
|
|
32436
32690
|
} catch (error) {
|
|
32437
|
-
|
|
32691
|
+
this.config.logger.error(`[getTokenEnrichmentData] Failed to enrich token ${token.address}`, error);
|
|
32438
32692
|
return {
|
|
32439
32693
|
token,
|
|
32440
32694
|
isStatAToken: true
|
|
@@ -32504,7 +32758,7 @@ var ClService = class _ClService {
|
|
|
32504
32758
|
rewardConfig = rewardConfigResult.value;
|
|
32505
32759
|
}
|
|
32506
32760
|
} catch (error) {
|
|
32507
|
-
|
|
32761
|
+
this.config.logger.warn("Failed to fetch reward config for pool", { error });
|
|
32508
32762
|
}
|
|
32509
32763
|
}
|
|
32510
32764
|
return {
|
|
@@ -32540,7 +32794,7 @@ var ClService = class _ClService {
|
|
|
32540
32794
|
}
|
|
32541
32795
|
};
|
|
32542
32796
|
} catch (error) {
|
|
32543
|
-
|
|
32797
|
+
this.config.logger.error("Failed to fetch pool data", error);
|
|
32544
32798
|
return {
|
|
32545
32799
|
ok: false,
|
|
32546
32800
|
error: lookupFailed("dex", "getPoolData", error)
|
|
@@ -35324,14 +35578,25 @@ var MoneyMarketService = class _MoneyMarketService {
|
|
|
35324
35578
|
);
|
|
35325
35579
|
const dstChainKey = params.dstChainKey ?? srcChainKey;
|
|
35326
35580
|
const dstAddress = params.dstAddress ?? params.srcAddress;
|
|
35327
|
-
const
|
|
35328
|
-
|
|
35329
|
-
|
|
35330
|
-
|
|
35581
|
+
const isBitcoinSrc = isBitcoinChainKeyType(srcChainKey);
|
|
35582
|
+
if (isBitcoinSrc && !_params.raw) {
|
|
35583
|
+
mmInvariant(
|
|
35584
|
+
walletProvider !== void 0 && isBitcoinWalletProviderType(walletProvider),
|
|
35585
|
+
`Invalid wallet provider for chain key: ${srcChainKey}. Expected bitcoin wallet provider.`,
|
|
35586
|
+
{ ...baseCtx, field: "walletProvider" }
|
|
35587
|
+
);
|
|
35588
|
+
await this.spoke.bitcoin.radfi.ensureRadfiAccessToken(walletProvider);
|
|
35589
|
+
}
|
|
35590
|
+
const srcEffectiveAddress = isBitcoinSrc ? await this.spoke.bitcoin.getEffectiveWalletAddress(params.srcAddress) : params.srcAddress;
|
|
35591
|
+
const fromHubWallet = await this.hubProvider.getUserHubWalletAddress(srcEffectiveAddress, srcChainKey);
|
|
35592
|
+
const toHubWallet = dstChainKey === srcChainKey && dstAddress === params.srcAddress ? fromHubWallet : await this.hubProvider.getUserHubWalletAddress(
|
|
35593
|
+
isBitcoinChainKeyType(dstChainKey) ? await this.spoke.bitcoin.getEffectiveWalletAddress(dstAddress) : dstAddress,
|
|
35594
|
+
dstChainKey
|
|
35595
|
+
);
|
|
35331
35596
|
const data = this.buildSupplyData(srcChainKey, params.token, params.amount, toHubWallet);
|
|
35332
35597
|
const coreParams = {
|
|
35333
35598
|
srcChainKey,
|
|
35334
|
-
srcAddress:
|
|
35599
|
+
srcAddress: srcEffectiveAddress,
|
|
35335
35600
|
to: fromHubWallet,
|
|
35336
35601
|
token: params.token,
|
|
35337
35602
|
amount: params.amount,
|
|
@@ -35371,6 +35636,17 @@ var MoneyMarketService = class _MoneyMarketService {
|
|
|
35371
35636
|
}
|
|
35372
35637
|
}
|
|
35373
35638
|
// ==== borrow ==========================================================================
|
|
35639
|
+
/**
|
|
35640
|
+
* Build the relay submit/poll identity for a money-market borrow/withdraw.
|
|
35641
|
+
*
|
|
35642
|
+
* Bitcoin borrow/withdraw are on-demand: the spoke result is a signed payload JSON that the relay
|
|
35643
|
+
* submits under the literal "withdraw" tx_hash and tracks under a derived `od:<hash>` poll id
|
|
35644
|
+
* (see {@link BitcoinSpokeService.getOnDemandRelayIdentity}). Every other chain relays and polls by
|
|
35645
|
+
* its real spoke tx hash, so `pollTxHash` is undefined and `srcChainTxHash` stays the spoke tx.
|
|
35646
|
+
*/
|
|
35647
|
+
buildRelayIdentity(srcChainKey, tx, relayData) {
|
|
35648
|
+
return isBitcoinChainKeyType(srcChainKey) ? this.spoke.bitcoin.getOnDemandRelayIdentity(tx) : { srcTxHash: tx, data: relayData, pollTxHash: void 0 };
|
|
35649
|
+
}
|
|
35374
35650
|
/**
|
|
35375
35651
|
* Borrow tokens from the money market lending pool and wait for the cross-chain relay to
|
|
35376
35652
|
* deliver the funds to the destination address.
|
|
@@ -35406,9 +35682,9 @@ var MoneyMarketService = class _MoneyMarketService {
|
|
|
35406
35682
|
value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
|
|
35407
35683
|
};
|
|
35408
35684
|
}
|
|
35685
|
+
const relayIdentity = this.buildRelayIdentity(srcChainKey, txResult.value.tx, txResult.value.relayData);
|
|
35409
35686
|
const packet = await relayTxAndWaitPacket({
|
|
35410
|
-
|
|
35411
|
-
data: txResult.value.relayData,
|
|
35687
|
+
...relayIdentity,
|
|
35412
35688
|
chainKey: srcChainKey,
|
|
35413
35689
|
relayerApiEndpoint: this.relayerApiEndpoint,
|
|
35414
35690
|
timeout
|
|
@@ -35423,7 +35699,13 @@ var MoneyMarketService = class _MoneyMarketService {
|
|
|
35423
35699
|
dstChainKey: baseCtx.dstChainKey
|
|
35424
35700
|
})
|
|
35425
35701
|
};
|
|
35426
|
-
return {
|
|
35702
|
+
return {
|
|
35703
|
+
ok: true,
|
|
35704
|
+
value: {
|
|
35705
|
+
srcChainTxHash: relayIdentity.pollTxHash ?? txResult.value.tx,
|
|
35706
|
+
dstChainTxHash: packet.value.dst_tx_hash
|
|
35707
|
+
}
|
|
35708
|
+
};
|
|
35427
35709
|
} catch (error) {
|
|
35428
35710
|
if (isMoneyMarketOrchestrationError(error)) return { ok: false, error };
|
|
35429
35711
|
return {
|
|
@@ -35465,7 +35747,8 @@ var MoneyMarketService = class _MoneyMarketService {
|
|
|
35465
35747
|
field: "token"
|
|
35466
35748
|
});
|
|
35467
35749
|
const encodedDstAddress = encodeAddress(dstChainKey, dstAddress);
|
|
35468
|
-
const
|
|
35750
|
+
const srcEffectiveAddress = isBitcoinChainKeyType(srcChainKey) ? await this.spoke.bitcoin.getEffectiveWalletAddress(params.srcAddress) : params.srcAddress;
|
|
35751
|
+
const fromHubWallet = await this.hubProvider.getUserHubWalletAddress(srcEffectiveAddress, srcChainKey);
|
|
35469
35752
|
const payload = this.buildBorrowData(
|
|
35470
35753
|
fromHubWallet,
|
|
35471
35754
|
encodedDstAddress,
|
|
@@ -35544,144 +35827,151 @@ var MoneyMarketService = class _MoneyMarketService {
|
|
|
35544
35827
|
}
|
|
35545
35828
|
const needsRelay = srcChainKey !== hubChainId || params.dstChainKey != null && params.dstAddress != null && params.dstChainKey !== hubChainId && params.dstAddress !== walletRouter;
|
|
35546
35829
|
if (!needsRelay) {
|
|
35547
|
-
return {
|
|
35548
|
-
ok: true,
|
|
35549
|
-
value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
|
|
35550
|
-
};
|
|
35551
|
-
}
|
|
35552
|
-
const
|
|
35553
|
-
|
|
35554
|
-
|
|
35555
|
-
chainKey: srcChainKey,
|
|
35556
|
-
relayerApiEndpoint: this.relayerApiEndpoint,
|
|
35557
|
-
timeout
|
|
35558
|
-
});
|
|
35559
|
-
if (!packet.ok)
|
|
35560
|
-
return {
|
|
35561
|
-
ok: false,
|
|
35562
|
-
error: mapRelayFailure(packet.error, {
|
|
35563
|
-
feature: "moneyMarket",
|
|
35564
|
-
action: baseCtx.action,
|
|
35565
|
-
srcChainKey: baseCtx.srcChainKey,
|
|
35566
|
-
dstChainKey: baseCtx.dstChainKey
|
|
35567
|
-
})
|
|
35568
|
-
};
|
|
35569
|
-
return {
|
|
35570
|
-
|
|
35571
|
-
|
|
35572
|
-
|
|
35573
|
-
|
|
35574
|
-
|
|
35575
|
-
};
|
|
35576
|
-
}
|
|
35577
|
-
|
|
35578
|
-
|
|
35579
|
-
|
|
35580
|
-
|
|
35581
|
-
|
|
35582
|
-
|
|
35583
|
-
|
|
35584
|
-
|
|
35585
|
-
*
|
|
35586
|
-
*
|
|
35587
|
-
*
|
|
35588
|
-
|
|
35589
|
-
|
|
35590
|
-
|
|
35591
|
-
|
|
35592
|
-
|
|
35593
|
-
|
|
35594
|
-
|
|
35595
|
-
|
|
35596
|
-
|
|
35597
|
-
|
|
35598
|
-
|
|
35599
|
-
|
|
35600
|
-
|
|
35601
|
-
|
|
35602
|
-
);
|
|
35603
|
-
|
|
35604
|
-
|
|
35605
|
-
|
|
35606
|
-
|
|
35607
|
-
|
|
35608
|
-
|
|
35609
|
-
|
|
35610
|
-
const
|
|
35611
|
-
|
|
35612
|
-
|
|
35613
|
-
|
|
35614
|
-
|
|
35615
|
-
|
|
35616
|
-
|
|
35617
|
-
|
|
35618
|
-
);
|
|
35619
|
-
const
|
|
35620
|
-
|
|
35621
|
-
|
|
35622
|
-
|
|
35623
|
-
|
|
35624
|
-
|
|
35625
|
-
|
|
35626
|
-
|
|
35627
|
-
|
|
35628
|
-
|
|
35629
|
-
|
|
35630
|
-
|
|
35631
|
-
|
|
35632
|
-
|
|
35633
|
-
|
|
35634
|
-
|
|
35635
|
-
|
|
35636
|
-
|
|
35637
|
-
|
|
35638
|
-
|
|
35639
|
-
|
|
35640
|
-
|
|
35641
|
-
|
|
35642
|
-
|
|
35643
|
-
|
|
35644
|
-
ok:
|
|
35645
|
-
|
|
35646
|
-
|
|
35647
|
-
|
|
35648
|
-
}
|
|
35649
|
-
}
|
|
35650
|
-
|
|
35651
|
-
|
|
35652
|
-
|
|
35653
|
-
|
|
35654
|
-
|
|
35655
|
-
|
|
35656
|
-
|
|
35657
|
-
|
|
35658
|
-
|
|
35659
|
-
|
|
35660
|
-
|
|
35661
|
-
|
|
35662
|
-
|
|
35663
|
-
|
|
35664
|
-
|
|
35665
|
-
|
|
35666
|
-
|
|
35667
|
-
*
|
|
35668
|
-
*
|
|
35669
|
-
|
|
35670
|
-
|
|
35671
|
-
|
|
35672
|
-
|
|
35673
|
-
|
|
35674
|
-
|
|
35675
|
-
|
|
35676
|
-
|
|
35677
|
-
|
|
35678
|
-
|
|
35679
|
-
|
|
35680
|
-
|
|
35681
|
-
|
|
35682
|
-
|
|
35683
|
-
}
|
|
35684
|
-
|
|
35830
|
+
return {
|
|
35831
|
+
ok: true,
|
|
35832
|
+
value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
|
|
35833
|
+
};
|
|
35834
|
+
}
|
|
35835
|
+
const relayIdentity = this.buildRelayIdentity(srcChainKey, txResult.value.tx, txResult.value.relayData);
|
|
35836
|
+
const packet = await relayTxAndWaitPacket({
|
|
35837
|
+
...relayIdentity,
|
|
35838
|
+
chainKey: srcChainKey,
|
|
35839
|
+
relayerApiEndpoint: this.relayerApiEndpoint,
|
|
35840
|
+
timeout
|
|
35841
|
+
});
|
|
35842
|
+
if (!packet.ok)
|
|
35843
|
+
return {
|
|
35844
|
+
ok: false,
|
|
35845
|
+
error: mapRelayFailure(packet.error, {
|
|
35846
|
+
feature: "moneyMarket",
|
|
35847
|
+
action: baseCtx.action,
|
|
35848
|
+
srcChainKey: baseCtx.srcChainKey,
|
|
35849
|
+
dstChainKey: baseCtx.dstChainKey
|
|
35850
|
+
})
|
|
35851
|
+
};
|
|
35852
|
+
return {
|
|
35853
|
+
ok: true,
|
|
35854
|
+
value: {
|
|
35855
|
+
srcChainTxHash: relayIdentity.pollTxHash ?? txResult.value.tx,
|
|
35856
|
+
dstChainTxHash: packet.value.dst_tx_hash
|
|
35857
|
+
}
|
|
35858
|
+
};
|
|
35859
|
+
} catch (error) {
|
|
35860
|
+
if (isMoneyMarketOrchestrationError(error)) return { ok: false, error };
|
|
35861
|
+
return {
|
|
35862
|
+
ok: false,
|
|
35863
|
+
error: executionFailed("moneyMarket", error, { ...baseCtx, phase: "intentCreation" })
|
|
35864
|
+
};
|
|
35865
|
+
}
|
|
35866
|
+
}
|
|
35867
|
+
/**
|
|
35868
|
+
* Build and optionally broadcast the spoke-side withdraw message without waiting for the
|
|
35869
|
+
* cross-chain relay to deliver funds.
|
|
35870
|
+
*
|
|
35871
|
+
* Use this when you need manual relay control or want to sign and broadcast the transaction
|
|
35872
|
+
* yourself. Pass `{ raw: true }` to receive unsigned calldata instead of executing.
|
|
35873
|
+
*
|
|
35874
|
+
* @param _params - Withdraw action params plus `raw` flag and optional `skipSimulation`.
|
|
35875
|
+
* @returns The spoke transaction result (hash or raw calldata) plus `relayData` required to
|
|
35876
|
+
* trigger the hub-side withdrawal via {@link relayTxAndWaitPacket}.
|
|
35877
|
+
*/
|
|
35878
|
+
async createWithdrawIntent(_params) {
|
|
35879
|
+
const { params, walletProvider } = _params;
|
|
35880
|
+
const srcChainKey = params.srcChainKey;
|
|
35881
|
+
const skipSimulation = _params.skipSimulation ?? false;
|
|
35882
|
+
const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "withdraw" };
|
|
35883
|
+
try {
|
|
35884
|
+
mmInvariant(params.action === "withdraw", "Invalid action", { ...baseCtx, field: "action" });
|
|
35885
|
+
mmInvariant(params.token.length > 0, "Token is required", { ...baseCtx, field: "token" });
|
|
35886
|
+
mmInvariant(params.amount > 0n, "Amount must be greater than 0", { ...baseCtx, field: "amount" });
|
|
35887
|
+
mmInvariant(
|
|
35888
|
+
isUndefinedOrValidWalletProviderForChainKey(srcChainKey, walletProvider),
|
|
35889
|
+
`Invalid wallet provider for chain key: ${srcChainKey}, walletProvider.chainType: ${walletProvider?.chainType}`,
|
|
35890
|
+
{ ...baseCtx, field: "walletProvider" }
|
|
35891
|
+
);
|
|
35892
|
+
const dstChainKey = params.dstChainKey ?? srcChainKey;
|
|
35893
|
+
const dstAddress = params.dstAddress ?? params.srcAddress;
|
|
35894
|
+
mmInvariant(
|
|
35895
|
+
this.config.isMoneyMarketSupportedToken(dstChainKey, params.token),
|
|
35896
|
+
`Unsupported spoke chain (${dstChainKey}) token: ${params.token}`,
|
|
35897
|
+
{ ...baseCtx, field: "token" }
|
|
35898
|
+
);
|
|
35899
|
+
const encodedDstAddress = encodeAddress(dstChainKey, dstAddress);
|
|
35900
|
+
const srcEffectiveAddress = isBitcoinChainKeyType(srcChainKey) ? await this.spoke.bitcoin.getEffectiveWalletAddress(params.srcAddress) : params.srcAddress;
|
|
35901
|
+
const fromHubWallet = await this.hubProvider.getUserHubWalletAddress(srcEffectiveAddress, srcChainKey);
|
|
35902
|
+
const payload = this.buildWithdrawData(
|
|
35903
|
+
fromHubWallet,
|
|
35904
|
+
encodedDstAddress,
|
|
35905
|
+
params.token,
|
|
35906
|
+
params.amount,
|
|
35907
|
+
dstChainKey
|
|
35908
|
+
);
|
|
35909
|
+
const coreParams = {
|
|
35910
|
+
srcChainKey,
|
|
35911
|
+
srcAddress: params.srcAddress,
|
|
35912
|
+
dstChainKey: HUB_CHAIN_KEY,
|
|
35913
|
+
dstAddress: fromHubWallet,
|
|
35914
|
+
payload,
|
|
35915
|
+
skipSimulation
|
|
35916
|
+
};
|
|
35917
|
+
const sendMessageParams = _params.raw ? {
|
|
35918
|
+
...coreParams,
|
|
35919
|
+
raw: true
|
|
35920
|
+
} : {
|
|
35921
|
+
...coreParams,
|
|
35922
|
+
raw: false,
|
|
35923
|
+
walletProvider: _params.walletProvider
|
|
35924
|
+
};
|
|
35925
|
+
const txResult = await this.spoke.sendMessage(sendMessageParams);
|
|
35926
|
+
if (!txResult.ok) {
|
|
35927
|
+
if (isMoneyMarketCreateIntentError(txResult.error)) return { ok: false, error: txResult.error };
|
|
35928
|
+
return {
|
|
35929
|
+
ok: false,
|
|
35930
|
+
error: intentCreationFailed("moneyMarket", txResult.error, baseCtx)
|
|
35931
|
+
};
|
|
35932
|
+
}
|
|
35933
|
+
return {
|
|
35934
|
+
ok: true,
|
|
35935
|
+
value: {
|
|
35936
|
+
tx: txResult.value,
|
|
35937
|
+
relayData: { address: fromHubWallet, payload }
|
|
35938
|
+
}
|
|
35939
|
+
};
|
|
35940
|
+
} catch (error) {
|
|
35941
|
+
if (isMoneyMarketCreateIntentError(error)) return { ok: false, error };
|
|
35942
|
+
return {
|
|
35943
|
+
ok: false,
|
|
35944
|
+
error: intentCreationFailed("moneyMarket", error, baseCtx)
|
|
35945
|
+
};
|
|
35946
|
+
}
|
|
35947
|
+
}
|
|
35948
|
+
// ==== repay ===========================================================================
|
|
35949
|
+
/**
|
|
35950
|
+
* Repay a borrowed position in the money market lending pool and wait for the cross-chain
|
|
35951
|
+
* relay to settle on the hub.
|
|
35952
|
+
*
|
|
35953
|
+
* Hub-chain callers skip the relay step. The repayment is credited to `dstAddress` on
|
|
35954
|
+
* `dstChainKey` (defaulting to the source address and chain when omitted).
|
|
35955
|
+
*
|
|
35956
|
+
* @param _params - Repay action params: `srcChainKey`, `srcAddress`, `token`, `amount`,
|
|
35957
|
+
* `walletProvider`, and optional `dstChainKey`/`dstAddress`.
|
|
35958
|
+
* @returns A pair of transaction hashes — `srcChainTxHash` (spoke) and `dstChainTxHash` (hub).
|
|
35959
|
+
*/
|
|
35960
|
+
async repay(_params) {
|
|
35961
|
+
const { params, timeout = DEFAULT_RELAY_TX_TIMEOUT } = _params;
|
|
35962
|
+
const srcChainKey = params.srcChainKey;
|
|
35963
|
+
const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "repay" };
|
|
35964
|
+
try {
|
|
35965
|
+
const txResult = await this.createRepayIntent(_params);
|
|
35966
|
+
if (!txResult.ok) return { ok: false, error: txResult.error };
|
|
35967
|
+
const verify = await this.spoke.verifyTxHash({ txHash: txResult.value.tx, chainKey: srcChainKey });
|
|
35968
|
+
if (!verify.ok) {
|
|
35969
|
+
return {
|
|
35970
|
+
ok: false,
|
|
35971
|
+
error: verifyFailed("moneyMarket", verify.error, baseCtx)
|
|
35972
|
+
};
|
|
35973
|
+
}
|
|
35974
|
+
if (isHubChainKeyType(srcChainKey)) {
|
|
35685
35975
|
return {
|
|
35686
35976
|
ok: true,
|
|
35687
35977
|
value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
|
|
@@ -35745,14 +36035,25 @@ var MoneyMarketService = class _MoneyMarketService {
|
|
|
35745
36035
|
);
|
|
35746
36036
|
const dstChainKey = params.dstChainKey ?? srcChainKey;
|
|
35747
36037
|
const dstAddress = params.dstAddress ?? params.srcAddress;
|
|
35748
|
-
const
|
|
35749
|
-
|
|
35750
|
-
|
|
35751
|
-
|
|
36038
|
+
const isBitcoinSrc = isBitcoinChainKeyType(srcChainKey);
|
|
36039
|
+
if (isBitcoinSrc && !_params.raw) {
|
|
36040
|
+
mmInvariant(
|
|
36041
|
+
walletProvider !== void 0 && isBitcoinWalletProviderType(walletProvider),
|
|
36042
|
+
`Invalid wallet provider for chain key: ${srcChainKey}. Expected bitcoin wallet provider.`,
|
|
36043
|
+
{ ...baseCtx, field: "walletProvider" }
|
|
36044
|
+
);
|
|
36045
|
+
await this.spoke.bitcoin.radfi.ensureRadfiAccessToken(walletProvider);
|
|
36046
|
+
}
|
|
36047
|
+
const srcEffectiveAddress = isBitcoinSrc ? await this.spoke.bitcoin.getEffectiveWalletAddress(params.srcAddress) : params.srcAddress;
|
|
36048
|
+
const fromHubWallet = await this.hubProvider.getUserHubWalletAddress(srcEffectiveAddress, srcChainKey);
|
|
36049
|
+
const toHubWallet = dstChainKey === srcChainKey && dstAddress === params.srcAddress ? fromHubWallet : await this.hubProvider.getUserHubWalletAddress(
|
|
36050
|
+
isBitcoinChainKeyType(dstChainKey) ? await this.spoke.bitcoin.getEffectiveWalletAddress(dstAddress) : dstAddress,
|
|
36051
|
+
dstChainKey
|
|
36052
|
+
);
|
|
35752
36053
|
const data = this.buildRepayData(srcChainKey, params.token, params.amount, toHubWallet);
|
|
35753
36054
|
const coreParams = {
|
|
35754
36055
|
srcChainKey,
|
|
35755
|
-
srcAddress:
|
|
36056
|
+
srcAddress: srcEffectiveAddress,
|
|
35756
36057
|
to: fromHubWallet,
|
|
35757
36058
|
token: params.token,
|
|
35758
36059
|
amount: params.amount,
|
|
@@ -36313,9 +36614,9 @@ var PartnerFeeClaimService = class {
|
|
|
36313
36614
|
if (typeof balanceResult === "bigint") {
|
|
36314
36615
|
balance = balanceResult;
|
|
36315
36616
|
} else {
|
|
36316
|
-
|
|
36317
|
-
`[PartnerFeeClaimService] Unexpected balance result format for ${entry.hubAsset.symbol} (${entry.assetAddress})
|
|
36318
|
-
balanceResult
|
|
36617
|
+
this.config.logger.warn(
|
|
36618
|
+
`[PartnerFeeClaimService] Unexpected balance result format for ${entry.hubAsset.symbol} (${entry.assetAddress})`,
|
|
36619
|
+
{ balanceResult }
|
|
36319
36620
|
);
|
|
36320
36621
|
balance = 0n;
|
|
36321
36622
|
}
|
|
@@ -36651,7 +36952,8 @@ var PartnerFeeClaimService = class {
|
|
|
36651
36952
|
}
|
|
36652
36953
|
const solverExecutionResponse = await SolverApiService.postExecution(
|
|
36653
36954
|
{ intent_tx_hash: intentTxHash },
|
|
36654
|
-
this.config.solver
|
|
36955
|
+
this.config.solver,
|
|
36956
|
+
this.config.logger
|
|
36655
36957
|
);
|
|
36656
36958
|
if (!solverExecutionResponse.ok) {
|
|
36657
36959
|
return solverExecutionResponse;
|
|
@@ -36732,7 +37034,12 @@ var RecoveryService = class {
|
|
|
36732
37034
|
srcChainKey: chainKey,
|
|
36733
37035
|
field: "chainKey"
|
|
36734
37036
|
});
|
|
36735
|
-
const
|
|
37037
|
+
const leverageVaultAddresses = new Set(
|
|
37038
|
+
this.config.sodaxConfig.leverageYield.vaults.map((vault) => vault.vault.toLowerCase())
|
|
37039
|
+
);
|
|
37040
|
+
const entries = Object.values(chainConfig.supportedTokens).filter(
|
|
37041
|
+
(token) => isAddress(token.hubAsset) && !leverageVaultAddresses.has(token.hubAsset.toLowerCase())
|
|
37042
|
+
);
|
|
36736
37043
|
if (entries.length === 0) {
|
|
36737
37044
|
return { ok: true, value: [] };
|
|
36738
37045
|
}
|
|
@@ -36834,6 +37141,871 @@ var RecoveryService = class {
|
|
|
36834
37141
|
}
|
|
36835
37142
|
};
|
|
36836
37143
|
|
|
37144
|
+
// src/leverageYield/errors.ts
|
|
37145
|
+
var leverageYieldInvariant = createInvariant("leverageYield");
|
|
37146
|
+
var LEVERAGE_YIELD_CODES = /* @__PURE__ */ new Set([
|
|
37147
|
+
"VALIDATION_FAILED",
|
|
37148
|
+
"INTENT_CREATION_FAILED",
|
|
37149
|
+
"APPROVE_FAILED",
|
|
37150
|
+
"ALLOWANCE_CHECK_FAILED",
|
|
37151
|
+
"LOOKUP_FAILED",
|
|
37152
|
+
"TX_VERIFICATION_FAILED",
|
|
37153
|
+
"TX_SUBMIT_FAILED",
|
|
37154
|
+
"RELAY_TIMEOUT",
|
|
37155
|
+
"RELAY_FAILED",
|
|
37156
|
+
"EXECUTION_FAILED",
|
|
37157
|
+
"EXTERNAL_API_ERROR",
|
|
37158
|
+
"UNKNOWN"
|
|
37159
|
+
]);
|
|
37160
|
+
var LEVERAGE_YIELD_POST_EXECUTION_CODES = /* @__PURE__ */ new Set([
|
|
37161
|
+
"EXECUTION_FAILED",
|
|
37162
|
+
"EXTERNAL_API_ERROR",
|
|
37163
|
+
"UNKNOWN"
|
|
37164
|
+
]);
|
|
37165
|
+
var LEVERAGE_YIELD_SWAP_CODES = /* @__PURE__ */ new Set([
|
|
37166
|
+
"VALIDATION_FAILED",
|
|
37167
|
+
"INTENT_CREATION_FAILED",
|
|
37168
|
+
"TX_VERIFICATION_FAILED",
|
|
37169
|
+
"TX_SUBMIT_FAILED",
|
|
37170
|
+
"RELAY_TIMEOUT",
|
|
37171
|
+
"RELAY_FAILED",
|
|
37172
|
+
"EXECUTION_FAILED",
|
|
37173
|
+
"EXTERNAL_API_ERROR",
|
|
37174
|
+
"UNKNOWN"
|
|
37175
|
+
]);
|
|
37176
|
+
var isLeverageYieldCreateIntentError = isCodeMember(CREATE_INTENT_CODES);
|
|
37177
|
+
var isLeverageYieldApproveError = isCodeMember(APPROVE_CODES);
|
|
37178
|
+
var isLeverageYieldAllowanceCheckError = isCodeMember(ALLOWANCE_CHECK_CODES);
|
|
37179
|
+
var isLeverageYieldLookupError = isCodeMember(LOOKUP_CODES);
|
|
37180
|
+
var isLeverageYieldPostExecutionError = isCodeMember(
|
|
37181
|
+
LEVERAGE_YIELD_POST_EXECUTION_CODES
|
|
37182
|
+
);
|
|
37183
|
+
var isLeverageYieldSwapError = isCodeMember(LEVERAGE_YIELD_SWAP_CODES);
|
|
37184
|
+
var isLeverageYieldError = isCodeMember(LEVERAGE_YIELD_CODES);
|
|
37185
|
+
|
|
37186
|
+
// src/leverageYield/LeverageYieldService.ts
|
|
37187
|
+
var leverageYieldVaultAbi = parseAbi([
|
|
37188
|
+
"function asset() view returns (address)",
|
|
37189
|
+
"function getPositionDetails() view returns (uint256 collateral, uint256 debt, uint256 ltv, uint256 healthFactor, uint256 idleAsset)",
|
|
37190
|
+
// Used by getApr() — read-only metadata that doesn't change per pass.
|
|
37191
|
+
"function pool() view returns (address)",
|
|
37192
|
+
"function borrowToken() view returns (address)",
|
|
37193
|
+
"function targetLTV() view returns (uint256)"
|
|
37194
|
+
]);
|
|
37195
|
+
var INTENT_DEADLINE_BUFFER_SECONDS = 5 * 60;
|
|
37196
|
+
var ANY_SOLVER_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
37197
|
+
var MAX_WITHDRAW_DUST_BUFFER = 1000n;
|
|
37198
|
+
function pctToRay(aprPct) {
|
|
37199
|
+
return BigInt(Math.round(aprPct * 1e9)) * 10n ** 16n;
|
|
37200
|
+
}
|
|
37201
|
+
var DEFILLAMA_FETCH_TIMEOUT_MS = 1e4;
|
|
37202
|
+
var DEFILLAMA_FETCH_MAX_ATTEMPTS = 2;
|
|
37203
|
+
async function fetchWithTimeout(url, timeoutMs) {
|
|
37204
|
+
const controller = new AbortController();
|
|
37205
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
37206
|
+
try {
|
|
37207
|
+
return await fetch(url, { signal: controller.signal });
|
|
37208
|
+
} finally {
|
|
37209
|
+
clearTimeout(timeoutId);
|
|
37210
|
+
}
|
|
37211
|
+
}
|
|
37212
|
+
async function fetchDefillamaApr(poolId) {
|
|
37213
|
+
return retry(async () => {
|
|
37214
|
+
const response = await fetchWithTimeout(`https://yields.llama.fi/chart/${poolId}`, DEFILLAMA_FETCH_TIMEOUT_MS);
|
|
37215
|
+
if (!response.ok) throw new Error(`DefiLlama APR fetch failed: HTTP ${response.status}`);
|
|
37216
|
+
const json = await response.json();
|
|
37217
|
+
const series = json?.data;
|
|
37218
|
+
if (!Array.isArray(series) || series.length === 0) {
|
|
37219
|
+
throw new Error("DefiLlama APR response: empty time series");
|
|
37220
|
+
}
|
|
37221
|
+
const latest = series[series.length - 1]?.apy;
|
|
37222
|
+
if (typeof latest !== "number") throw new Error("DefiLlama APR: latest entry missing numeric apy");
|
|
37223
|
+
return latest;
|
|
37224
|
+
}, DEFILLAMA_FETCH_MAX_ATTEMPTS);
|
|
37225
|
+
}
|
|
37226
|
+
var LeverageYieldService = class {
|
|
37227
|
+
hubProvider;
|
|
37228
|
+
config;
|
|
37229
|
+
spoke;
|
|
37230
|
+
constructor({ hubProvider, config, spoke }) {
|
|
37231
|
+
this.hubProvider = hubProvider;
|
|
37232
|
+
this.config = config;
|
|
37233
|
+
this.spoke = spoke;
|
|
37234
|
+
}
|
|
37235
|
+
// ─── Registry ──────────────────────────────────────────────────────────
|
|
37236
|
+
/** Returns the static registry of known leverage-yield vaults. */
|
|
37237
|
+
listVaults() {
|
|
37238
|
+
return this.config.sodaxConfig.leverageYield.vaults;
|
|
37239
|
+
}
|
|
37240
|
+
/** Looks up a vault by its `name` field. Returns `undefined` when not registered. */
|
|
37241
|
+
getVault(name) {
|
|
37242
|
+
return this.listVaults().find((v) => v.name === name);
|
|
37243
|
+
}
|
|
37244
|
+
/**
|
|
37245
|
+
* Looks up a registered vault by its on-chain proxy address (case-insensitive).
|
|
37246
|
+
* Returns `undefined` when the address isn't in the registry.
|
|
37247
|
+
*/
|
|
37248
|
+
getVaultByAddress(address) {
|
|
37249
|
+
const normalized = address.toLowerCase();
|
|
37250
|
+
return this.listVaults().find((v) => v.vault.toLowerCase() === normalized);
|
|
37251
|
+
}
|
|
37252
|
+
/**
|
|
37253
|
+
* Resolves the intent `deadline`: returns the caller-supplied value verbatim, otherwise
|
|
37254
|
+
* derives a default from the hub-chain (Sonic) block timestamp plus
|
|
37255
|
+
* {@link INTENT_DEADLINE_BUFFER_SECONDS}. The deadline is enforced on-chain against the hub
|
|
37256
|
+
* block time, so the default is anchored to that block — never the client clock, which can
|
|
37257
|
+
* drift and produce an already-expired or over-extended deadline.
|
|
37258
|
+
*
|
|
37259
|
+
* Returns a {@link Result}: a `getBlock` RPC outage is a read failure, surfaced as
|
|
37260
|
+
* `LOOKUP_FAILED` (`method: 'resolveDeadline'`) rather than masquerading as an intent-build
|
|
37261
|
+
* failure. The `deposit` / `withdraw` callers forward it verbatim.
|
|
37262
|
+
*/
|
|
37263
|
+
async resolveDeadline(deadline, srcChainKey) {
|
|
37264
|
+
if (deadline !== void 0) return { ok: true, value: deadline };
|
|
37265
|
+
try {
|
|
37266
|
+
const block = await this.hubProvider.publicClient.getBlock({
|
|
37267
|
+
includeTransactions: false,
|
|
37268
|
+
blockTag: "latest"
|
|
37269
|
+
});
|
|
37270
|
+
return { ok: true, value: block.timestamp + BigInt(INTENT_DEADLINE_BUFFER_SECONDS) };
|
|
37271
|
+
} catch (error) {
|
|
37272
|
+
return { ok: false, error: lookupFailed("leverageYield", "resolveDeadline", error, { srcChainKey }) };
|
|
37273
|
+
}
|
|
37274
|
+
}
|
|
37275
|
+
/**
|
|
37276
|
+
* Builds the {@link LeverageYieldSwapPayload} for a leverage-yield deposit (any token → lsoda*).
|
|
37277
|
+
* The lsoda* output is delivered to the user's hub wallet on Sonic so a later
|
|
37278
|
+
* {@link LeverageYieldService.withdraw} can swap it back. Spread the result into
|
|
37279
|
+
* {@link LeverageYieldService.vaultSwap}: `vaultSwap({ ...payload, walletProvider })`.
|
|
37280
|
+
* An optional `partnerFee` is forwarded on the payload as the per-intent fee override.
|
|
37281
|
+
*
|
|
37282
|
+
* For `minOutputAmount`, quote via `sodax.swaps.getQuote` with the vault address as the
|
|
37283
|
+
* destination token (`token_dst`) — vault shares are solver-tradeable, so the generic swap
|
|
37284
|
+
* quote applies; then subtract your slippage tolerance.
|
|
37285
|
+
*/
|
|
37286
|
+
async deposit(params) {
|
|
37287
|
+
const baseCtx = { srcChainKey: params.srcChainKey, action: "deposit" };
|
|
37288
|
+
try {
|
|
37289
|
+
leverageYieldInvariant(params.inputAmount > 0n, "inputAmount must be greater than 0", {
|
|
37290
|
+
...baseCtx,
|
|
37291
|
+
field: "inputAmount"
|
|
37292
|
+
});
|
|
37293
|
+
leverageYieldInvariant(params.vault.length > 0, "Vault address is required", { ...baseCtx, field: "vault" });
|
|
37294
|
+
leverageYieldInvariant(params.inputToken.length > 0, "inputToken is required", {
|
|
37295
|
+
...baseCtx,
|
|
37296
|
+
field: "inputToken"
|
|
37297
|
+
});
|
|
37298
|
+
const hubWallet = await this.hubProvider.getUserHubWalletAddress(params.srcAddress, params.srcChainKey);
|
|
37299
|
+
const deadlineResult = await this.resolveDeadline(params.deadline, params.srcChainKey);
|
|
37300
|
+
if (!deadlineResult.ok) return deadlineResult;
|
|
37301
|
+
const deadline = deadlineResult.value;
|
|
37302
|
+
return {
|
|
37303
|
+
ok: true,
|
|
37304
|
+
value: {
|
|
37305
|
+
params: {
|
|
37306
|
+
inputToken: params.inputToken,
|
|
37307
|
+
outputToken: params.vault,
|
|
37308
|
+
inputAmount: params.inputAmount,
|
|
37309
|
+
minOutputAmount: params.minOutputAmount,
|
|
37310
|
+
deadline,
|
|
37311
|
+
allowPartialFill: false,
|
|
37312
|
+
srcChainKey: params.srcChainKey,
|
|
37313
|
+
dstChainKey: this.hubProvider.chainConfig.chain.key,
|
|
37314
|
+
srcAddress: params.srcAddress,
|
|
37315
|
+
dstAddress: hubWallet,
|
|
37316
|
+
solver: params.solver ?? ANY_SOLVER_ADDRESS,
|
|
37317
|
+
data: "0x"
|
|
37318
|
+
},
|
|
37319
|
+
// Per-intent fee override — only included when the caller supplies one, so the
|
|
37320
|
+
// payload stays free of undefined-valued keys.
|
|
37321
|
+
...params.partnerFee !== void 0 && { partnerFee: params.partnerFee }
|
|
37322
|
+
}
|
|
37323
|
+
};
|
|
37324
|
+
} catch (error) {
|
|
37325
|
+
if (isLeverageYieldCreateIntentError(error)) return { ok: false, error };
|
|
37326
|
+
return { ok: false, error: intentCreationFailed("leverageYield", error, baseCtx) };
|
|
37327
|
+
}
|
|
37328
|
+
}
|
|
37329
|
+
/**
|
|
37330
|
+
* Builds the {@link LeverageYieldSwapPayload} for a leverage-yield withdraw (lsoda* → any
|
|
37331
|
+
* token). The payload carries `hubWalletSwap: true` — {@link LeverageYieldService.vaultSwap}
|
|
37332
|
+
* then spends the lsoda* held in the user's hub wallet by authorising it via a
|
|
37333
|
+
* `Connection.sendMessage` the user signs on `srcChainKey`. Wrapped in a {@link Result} for
|
|
37334
|
+
* a call shape uniform with {@link LeverageYieldService.deposit}; async because the default
|
|
37335
|
+
* `deadline` is read from the hub block timestamp.
|
|
37336
|
+
*
|
|
37337
|
+
* For `minOutputAmount`, quote via `sodax.swaps.getQuote` with the vault address as the
|
|
37338
|
+
* source token (`token_src`) — vault shares are solver-tradeable, so the generic swap quote
|
|
37339
|
+
* applies; then subtract your slippage tolerance.
|
|
37340
|
+
*/
|
|
37341
|
+
async withdraw(params) {
|
|
37342
|
+
const baseCtx = { srcChainKey: params.srcChainKey, action: "withdraw" };
|
|
37343
|
+
try {
|
|
37344
|
+
leverageYieldInvariant(params.inputAmount > 0n, "inputAmount must be greater than 0", {
|
|
37345
|
+
...baseCtx,
|
|
37346
|
+
field: "inputAmount"
|
|
37347
|
+
});
|
|
37348
|
+
leverageYieldInvariant(params.vault.length > 0, "Vault address is required", { ...baseCtx, field: "vault" });
|
|
37349
|
+
leverageYieldInvariant(params.outputToken.length > 0, "outputToken is required", {
|
|
37350
|
+
...baseCtx,
|
|
37351
|
+
field: "outputToken"
|
|
37352
|
+
});
|
|
37353
|
+
const deadlineResult = await this.resolveDeadline(params.deadline, params.srcChainKey);
|
|
37354
|
+
if (!deadlineResult.ok) return deadlineResult;
|
|
37355
|
+
const deadline = deadlineResult.value;
|
|
37356
|
+
return {
|
|
37357
|
+
ok: true,
|
|
37358
|
+
value: {
|
|
37359
|
+
params: {
|
|
37360
|
+
inputToken: params.vault,
|
|
37361
|
+
outputToken: params.outputToken,
|
|
37362
|
+
inputAmount: params.inputAmount,
|
|
37363
|
+
minOutputAmount: params.minOutputAmount,
|
|
37364
|
+
deadline,
|
|
37365
|
+
allowPartialFill: false,
|
|
37366
|
+
srcChainKey: params.srcChainKey,
|
|
37367
|
+
dstChainKey: params.dstChainKey,
|
|
37368
|
+
srcAddress: params.srcAddress,
|
|
37369
|
+
dstAddress: params.recipient ?? params.srcAddress,
|
|
37370
|
+
solver: params.solver ?? ANY_SOLVER_ADDRESS,
|
|
37371
|
+
data: "0x"
|
|
37372
|
+
},
|
|
37373
|
+
hubWalletSwap: true
|
|
37374
|
+
}
|
|
37375
|
+
};
|
|
37376
|
+
} catch (error) {
|
|
37377
|
+
if (isLeverageYieldCreateIntentError(error)) return { ok: false, error };
|
|
37378
|
+
return { ok: false, error: intentCreationFailed("leverageYield", error, baseCtx) };
|
|
37379
|
+
}
|
|
37380
|
+
}
|
|
37381
|
+
/**
|
|
37382
|
+
* Creates a vault swap intent on the user's source spoke chain without submitting it to
|
|
37383
|
+
* the solver. Leverage-yield copy of the swap domain's `createIntent`, specialised for
|
|
37384
|
+
* vault flows — duplicated deliberately so the vault-specific execution modifiers
|
|
37385
|
+
* (`hubWalletSwap`, per-intent `partnerFee`) stay off the generic swap surface.
|
|
37386
|
+
*
|
|
37387
|
+
* Use {@link LeverageYieldService.vaultSwap} for the full end-to-end flow
|
|
37388
|
+
* (create → relay → notify solver); use this directly when you need the raw transaction
|
|
37389
|
+
* or drive the relay yourself (e.g. the backend submit-tx path). To complete a manual flow,
|
|
37390
|
+
* relay the returned `relayData` (the shared `relayTxAndWaitPacket` helper) and then call
|
|
37391
|
+
* {@link LeverageYieldService.notifySolver} with the hub-side intent tx hash.
|
|
37392
|
+
*
|
|
37393
|
+
* @param _params - Intent parameters, source chain key, wallet provider (when `raw: false`),
|
|
37394
|
+
* and optional `skipSimulation` / `hubWalletSwap` / `partnerFee`.
|
|
37395
|
+
* @returns A `Result<CreateVaultIntentResult<K, Raw>, LeverageYieldCreateIntentError>`.
|
|
37396
|
+
* On success contains:
|
|
37397
|
+
* - `tx` — chain-specific tx hash (executed) or raw tx data (raw mode).
|
|
37398
|
+
* - `intent` — the fully constructed `Intent` object augmented with `feeAmount`.
|
|
37399
|
+
* - `relayData` — `{ address, payload }` needed to submit the intent to the relayer.
|
|
37400
|
+
*
|
|
37401
|
+
* On failure `result.error` is a SodaxError with `VALIDATION_FAILED` (invariant
|
|
37402
|
+
* precondition), `INTENT_CREATION_FAILED` (spoke-side creation/deposit failed) or
|
|
37403
|
+
* `UNKNOWN` (defensive fallback).
|
|
37404
|
+
*/
|
|
37405
|
+
async createVaultIntent(_params) {
|
|
37406
|
+
const { params, skipSimulation, hubWalletSwap, partnerFee = this.config.swaps.partnerFee } = _params;
|
|
37407
|
+
const baseCtx = { srcChainKey: params.srcChainKey, dstChainKey: params.dstChainKey };
|
|
37408
|
+
try {
|
|
37409
|
+
leverageYieldInvariant(
|
|
37410
|
+
isUndefinedOrValidWalletProviderForChainKey(params.srcChainKey, _params.walletProvider),
|
|
37411
|
+
`Invalid wallet provider for chain key: ${params.srcChainKey}`,
|
|
37412
|
+
baseCtx
|
|
37413
|
+
);
|
|
37414
|
+
const hubChainKey = this.hubProvider.chainConfig.chain.key;
|
|
37415
|
+
const inputTokenChainKey = hubWalletSwap ? hubChainKey : params.srcChainKey;
|
|
37416
|
+
leverageYieldInvariant(
|
|
37417
|
+
this.config.isValidOriginalAssetAddress(inputTokenChainKey, params.inputToken),
|
|
37418
|
+
`Unsupported spoke chain token (srcChainKey: ${inputTokenChainKey}, inputToken: ${params.inputToken})`,
|
|
37419
|
+
{ ...baseCtx, field: "inputToken" }
|
|
37420
|
+
);
|
|
37421
|
+
leverageYieldInvariant(
|
|
37422
|
+
this.config.isValidOriginalAssetAddress(params.dstChainKey, params.outputToken),
|
|
37423
|
+
`Unsupported spoke chain token (params.dstChain: ${params.dstChainKey}, params.outputToken: ${params.outputToken})`,
|
|
37424
|
+
{ ...baseCtx, field: "outputToken" }
|
|
37425
|
+
);
|
|
37426
|
+
leverageYieldInvariant(
|
|
37427
|
+
this.config.isValidSpokeChainKey(params.srcChainKey),
|
|
37428
|
+
`Invalid spoke chain (srcChainKey): ${params.srcChainKey}`,
|
|
37429
|
+
{ ...baseCtx, field: "srcChainKey" }
|
|
37430
|
+
);
|
|
37431
|
+
leverageYieldInvariant(
|
|
37432
|
+
this.config.isValidSpokeChainKey(params.dstChainKey),
|
|
37433
|
+
`Invalid spoke chain (params.dstChain): ${params.dstChainKey}`,
|
|
37434
|
+
{ ...baseCtx, field: "dstChainKey" }
|
|
37435
|
+
);
|
|
37436
|
+
if (isBitcoinChainKey(params.dstChainKey) && params.outputToken === "BTC") {
|
|
37437
|
+
leverageYieldInvariant(
|
|
37438
|
+
params.minOutputAmount >= 546n,
|
|
37439
|
+
`Invalid minOutputAmount (params.minOutputAmount): ${params.minOutputAmount}`,
|
|
37440
|
+
{ ...baseCtx, field: "minOutputAmount" }
|
|
37441
|
+
);
|
|
37442
|
+
}
|
|
37443
|
+
const personalAddress = params.srcAddress;
|
|
37444
|
+
let walletAddress = personalAddress;
|
|
37445
|
+
if (isBitcoinChainKeyType(params.srcChainKey) && _params.raw === false) {
|
|
37446
|
+
leverageYieldInvariant(
|
|
37447
|
+
isBitcoinWalletProviderType(_params.walletProvider),
|
|
37448
|
+
`Invalid wallet provider for chain key: ${params.srcChainKey}`,
|
|
37449
|
+
baseCtx
|
|
37450
|
+
);
|
|
37451
|
+
walletAddress = await this.spoke.bitcoin.getEffectiveWalletAddress(personalAddress);
|
|
37452
|
+
await this.spoke.bitcoin.radfi.ensureRadfiAccessToken(_params.walletProvider);
|
|
37453
|
+
}
|
|
37454
|
+
const creatorHubWalletAddress = await this.hubProvider.getUserHubWalletAddress(walletAddress, params.srcChainKey);
|
|
37455
|
+
if (hubWalletSwap) {
|
|
37456
|
+
const [data2, intent2, feeAmount2] = EvmSolverService.constructCreateIntentData(
|
|
37457
|
+
{ ...params, srcChainKey: hubChainKey, srcAddress: creatorHubWalletAddress },
|
|
37458
|
+
creatorHubWalletAddress,
|
|
37459
|
+
this.config,
|
|
37460
|
+
partnerFee
|
|
37461
|
+
);
|
|
37462
|
+
const coreSendMessageParams = {
|
|
37463
|
+
srcChainKey: params.srcChainKey,
|
|
37464
|
+
// Personal address — NOT the resolved trading `walletAddress`. SpokeService.sendMessage
|
|
37465
|
+
// re-resolves the effective (Bitcoin trading) address itself; passing the already-resolved
|
|
37466
|
+
// trading address here would double-resolve it (getTradingWallet(tradingAddress) →
|
|
37467
|
+
// "Trading wallet not found"). The trading address is used only for the hub-wallet
|
|
37468
|
+
// derivation above (creatorHubWalletAddress). Mirrors MoneyMarketService borrow/withdraw.
|
|
37469
|
+
srcAddress: personalAddress,
|
|
37470
|
+
dstChainKey: hubChainKey,
|
|
37471
|
+
dstAddress: creatorHubWalletAddress,
|
|
37472
|
+
payload: data2,
|
|
37473
|
+
skipSimulation
|
|
37474
|
+
};
|
|
37475
|
+
const txResult2 = await this.spoke.sendMessage(
|
|
37476
|
+
_params.raw ? { ...coreSendMessageParams, raw: true } : {
|
|
37477
|
+
...coreSendMessageParams,
|
|
37478
|
+
raw: false,
|
|
37479
|
+
walletProvider: _params.walletProvider
|
|
37480
|
+
}
|
|
37481
|
+
);
|
|
37482
|
+
if (!txResult2.ok) {
|
|
37483
|
+
if (isLeverageYieldCreateIntentError(txResult2.error)) {
|
|
37484
|
+
return { ok: false, error: txResult2.error };
|
|
37485
|
+
}
|
|
37486
|
+
return { ok: false, error: intentCreationFailed("leverageYield", txResult2.error, baseCtx) };
|
|
37487
|
+
}
|
|
37488
|
+
return {
|
|
37489
|
+
ok: true,
|
|
37490
|
+
value: {
|
|
37491
|
+
tx: txResult2.value,
|
|
37492
|
+
intent: { ...intent2, feeAmount: feeAmount2 },
|
|
37493
|
+
relayData: { address: creatorHubWalletAddress, payload: data2 }
|
|
37494
|
+
}
|
|
37495
|
+
};
|
|
37496
|
+
}
|
|
37497
|
+
if (isHubChainKeyType(params.srcChainKey) && isSonicChainKeyType(params.srcChainKey)) {
|
|
37498
|
+
const coreSonicParams = {
|
|
37499
|
+
createIntentParams: params,
|
|
37500
|
+
creatorHubWalletAddress,
|
|
37501
|
+
solverConfig: this.config.solver,
|
|
37502
|
+
fee: partnerFee,
|
|
37503
|
+
hubProvider: this.hubProvider
|
|
37504
|
+
};
|
|
37505
|
+
const [txResult2, intent2, feeAmount2, data2] = await SonicSpokeService.createSwapIntent(
|
|
37506
|
+
_params.raw ? { ...coreSonicParams, raw: true } : {
|
|
37507
|
+
...coreSonicParams,
|
|
37508
|
+
raw: false,
|
|
37509
|
+
walletProvider: _params.walletProvider
|
|
37510
|
+
}
|
|
37511
|
+
);
|
|
37512
|
+
return {
|
|
37513
|
+
ok: true,
|
|
37514
|
+
value: {
|
|
37515
|
+
tx: txResult2,
|
|
37516
|
+
intent: { ...intent2, feeAmount: feeAmount2 },
|
|
37517
|
+
relayData: { address: intent2.creator, payload: data2 }
|
|
37518
|
+
}
|
|
37519
|
+
};
|
|
37520
|
+
}
|
|
37521
|
+
const [data, intent, feeAmount] = EvmSolverService.constructCreateIntentData(
|
|
37522
|
+
{
|
|
37523
|
+
...params,
|
|
37524
|
+
srcAddress: walletAddress
|
|
37525
|
+
},
|
|
37526
|
+
creatorHubWalletAddress,
|
|
37527
|
+
this.config,
|
|
37528
|
+
partnerFee
|
|
37529
|
+
);
|
|
37530
|
+
const coreDepositParams = {
|
|
37531
|
+
srcChainKey: params.srcChainKey,
|
|
37532
|
+
srcAddress: walletAddress,
|
|
37533
|
+
to: creatorHubWalletAddress,
|
|
37534
|
+
token: params.inputToken,
|
|
37535
|
+
amount: params.inputAmount,
|
|
37536
|
+
data,
|
|
37537
|
+
skipSimulation
|
|
37538
|
+
};
|
|
37539
|
+
const txResult = await this.spoke.deposit(
|
|
37540
|
+
_params.raw ? {
|
|
37541
|
+
...coreDepositParams,
|
|
37542
|
+
raw: true
|
|
37543
|
+
} : {
|
|
37544
|
+
...coreDepositParams,
|
|
37545
|
+
raw: false,
|
|
37546
|
+
walletProvider: _params.walletProvider
|
|
37547
|
+
}
|
|
37548
|
+
);
|
|
37549
|
+
if (!txResult.ok) {
|
|
37550
|
+
if (isLeverageYieldCreateIntentError(txResult.error)) {
|
|
37551
|
+
return { ok: false, error: txResult.error };
|
|
37552
|
+
}
|
|
37553
|
+
return {
|
|
37554
|
+
ok: false,
|
|
37555
|
+
error: intentCreationFailed("leverageYield", txResult.error, baseCtx)
|
|
37556
|
+
};
|
|
37557
|
+
}
|
|
37558
|
+
return {
|
|
37559
|
+
ok: true,
|
|
37560
|
+
value: {
|
|
37561
|
+
tx: txResult.value,
|
|
37562
|
+
intent: { ...intent, feeAmount },
|
|
37563
|
+
relayData: { address: intent.creator, payload: data }
|
|
37564
|
+
}
|
|
37565
|
+
};
|
|
37566
|
+
} catch (error) {
|
|
37567
|
+
if (isLeverageYieldCreateIntentError(error)) return { ok: false, error };
|
|
37568
|
+
return {
|
|
37569
|
+
ok: false,
|
|
37570
|
+
error: intentCreationFailed("leverageYield", error, baseCtx)
|
|
37571
|
+
};
|
|
37572
|
+
}
|
|
37573
|
+
}
|
|
37574
|
+
/**
|
|
37575
|
+
* Executes a full end-to-end leverage-yield vault swap (deposit or withdraw).
|
|
37576
|
+
* Leverage-yield copy of the swap domain's `swap()` orchestrator:
|
|
37577
|
+
* 1. Calls {@link LeverageYieldService.createVaultIntent} to submit the intent
|
|
37578
|
+
* transaction on the source spoke chain.
|
|
37579
|
+
* 2. Verifies the spoke transaction landed on-chain.
|
|
37580
|
+
* 3. For non-hub source chains: submits the spoke tx to the relayer and waits for the
|
|
37581
|
+
* relay packet to land on the hub (Sonic). Skipped when `srcChainKey` is the hub.
|
|
37582
|
+
* 4. Notifies the solver, triggering it to fill the intent.
|
|
37583
|
+
*
|
|
37584
|
+
* Spread a {@link LeverageYieldSwapPayload} from `deposit` / `withdraw` into this method
|
|
37585
|
+
* alongside the wallet provider: `vaultSwap({ ...payload, walletProvider })`.
|
|
37586
|
+
*
|
|
37587
|
+
* @returns A `Result<VaultSwapResponse, LeverageYieldSwapError>`. On success:
|
|
37588
|
+
* - `solverExecutionResponse` — solver acknowledgement (`{ answer: 'OK', intent_hash }`).
|
|
37589
|
+
* - `intent` — the on-chain intent object that was created.
|
|
37590
|
+
* - `intentDeliveryInfo` — source/destination chain keys, tx hashes, and user addresses.
|
|
37591
|
+
*
|
|
37592
|
+
* On failure `result.error` carries one of the create-intent codes plus
|
|
37593
|
+
* `TX_VERIFICATION_FAILED`, `TX_SUBMIT_FAILED`, `RELAY_TIMEOUT`, `RELAY_FAILED`,
|
|
37594
|
+
* `EXECUTION_FAILED`, `EXTERNAL_API_ERROR` or `UNKNOWN`.
|
|
37595
|
+
*/
|
|
37596
|
+
async vaultSwap(_params) {
|
|
37597
|
+
const { params } = _params;
|
|
37598
|
+
const srcChainKey = params.srcChainKey;
|
|
37599
|
+
const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "vaultSwap" };
|
|
37600
|
+
try {
|
|
37601
|
+
const timeout = _params.timeout;
|
|
37602
|
+
const createIntentResult = await this.createVaultIntent(_params);
|
|
37603
|
+
if (!createIntentResult.ok) {
|
|
37604
|
+
return { ok: false, error: createIntentResult.error };
|
|
37605
|
+
}
|
|
37606
|
+
const { tx: spokeTxHash, intent, relayData } = createIntentResult.value;
|
|
37607
|
+
const verifyTxHashResult = await this.spoke.verifyTxHash({
|
|
37608
|
+
txHash: spokeTxHash,
|
|
37609
|
+
chainKey: srcChainKey
|
|
37610
|
+
});
|
|
37611
|
+
if (!verifyTxHashResult.ok) {
|
|
37612
|
+
return {
|
|
37613
|
+
ok: false,
|
|
37614
|
+
error: verifyFailed("leverageYield", verifyTxHashResult.error, baseCtx)
|
|
37615
|
+
};
|
|
37616
|
+
}
|
|
37617
|
+
let dstIntentTxHash;
|
|
37618
|
+
if (isHubChainKeyType(srcChainKey)) {
|
|
37619
|
+
dstIntentTxHash = spokeTxHash;
|
|
37620
|
+
} else {
|
|
37621
|
+
const packet = await relayTxAndWaitPacket({
|
|
37622
|
+
srcTxHash: spokeTxHash,
|
|
37623
|
+
data: relayData,
|
|
37624
|
+
chainKey: srcChainKey,
|
|
37625
|
+
relayerApiEndpoint: this.config.relay.relayerApiEndpoint,
|
|
37626
|
+
timeout
|
|
37627
|
+
});
|
|
37628
|
+
if (!packet.ok) {
|
|
37629
|
+
return {
|
|
37630
|
+
ok: false,
|
|
37631
|
+
error: mapRelayFailure(packet.error, { feature: "leverageYield", ...baseCtx })
|
|
37632
|
+
};
|
|
37633
|
+
}
|
|
37634
|
+
dstIntentTxHash = packet.value.dst_tx_hash;
|
|
37635
|
+
}
|
|
37636
|
+
const postExecResult = await this.notifySolver({
|
|
37637
|
+
intent_tx_hash: dstIntentTxHash
|
|
37638
|
+
});
|
|
37639
|
+
if (!postExecResult.ok) {
|
|
37640
|
+
return { ok: false, error: postExecResult.error };
|
|
37641
|
+
}
|
|
37642
|
+
return {
|
|
37643
|
+
ok: true,
|
|
37644
|
+
value: {
|
|
37645
|
+
solverExecutionResponse: postExecResult.value,
|
|
37646
|
+
intent,
|
|
37647
|
+
intentDeliveryInfo: {
|
|
37648
|
+
srcChainKey,
|
|
37649
|
+
srcTxHash: spokeTxHash,
|
|
37650
|
+
srcAddress: params.srcAddress,
|
|
37651
|
+
dstChainKey: params.dstChainKey,
|
|
37652
|
+
dstTxHash: dstIntentTxHash,
|
|
37653
|
+
dstAddress: params.dstAddress
|
|
37654
|
+
}
|
|
37655
|
+
}
|
|
37656
|
+
};
|
|
37657
|
+
} catch (error) {
|
|
37658
|
+
if (isLeverageYieldSwapError(error)) return { ok: false, error };
|
|
37659
|
+
return {
|
|
37660
|
+
ok: false,
|
|
37661
|
+
error: unknownFailed("leverageYield", error, baseCtx)
|
|
37662
|
+
};
|
|
37663
|
+
}
|
|
37664
|
+
}
|
|
37665
|
+
/**
|
|
37666
|
+
* Notifies the solver that the vault intent landed on the hub, triggering it to fill.
|
|
37667
|
+
* Leverage-yield copy of the swap domain's `postExecution` — emits only
|
|
37668
|
+
* `EXECUTION_FAILED` / `EXTERNAL_API_ERROR` / `UNKNOWN` (relay/verify codes appear only
|
|
37669
|
+
* on {@link LeverageYieldService.vaultSwap}, which owns the verify + relay steps).
|
|
37670
|
+
*
|
|
37671
|
+
* Called automatically by {@link LeverageYieldService.vaultSwap} after the relay packet
|
|
37672
|
+
* lands on the hub. Public so callers who created the intent via
|
|
37673
|
+
* {@link LeverageYieldService.createVaultIntent} and relayed it themselves can finish the
|
|
37674
|
+
* flow manually.
|
|
37675
|
+
*
|
|
37676
|
+
* @param request - `{ intent_tx_hash }` — the hub-chain (Sonic) tx hash where the intent
|
|
37677
|
+
* was registered (the relay packet's `dst_tx_hash`, or the spoke tx hash for hub-sourced
|
|
37678
|
+
* intents).
|
|
37679
|
+
*/
|
|
37680
|
+
async notifySolver(request) {
|
|
37681
|
+
try {
|
|
37682
|
+
const result = await SolverApiService.postExecution(request, this.config.solver, this.config.logger);
|
|
37683
|
+
if (result.ok) return result;
|
|
37684
|
+
const detail = result.error?.detail ?? {
|
|
37685
|
+
code: -999,
|
|
37686
|
+
// SolverIntentErrorCode.UNKNOWN
|
|
37687
|
+
message: "Solver returned malformed error response"
|
|
37688
|
+
};
|
|
37689
|
+
return {
|
|
37690
|
+
ok: false,
|
|
37691
|
+
error: new SodaxError("EXTERNAL_API_ERROR", detail.message, {
|
|
37692
|
+
feature: "leverageYield",
|
|
37693
|
+
context: {
|
|
37694
|
+
phase: "postExecution",
|
|
37695
|
+
api: "solver",
|
|
37696
|
+
solverCode: detail.code,
|
|
37697
|
+
solverDetail: detail
|
|
37698
|
+
}
|
|
37699
|
+
})
|
|
37700
|
+
};
|
|
37701
|
+
} catch (error) {
|
|
37702
|
+
if (isLeverageYieldPostExecutionError(error)) return { ok: false, error };
|
|
37703
|
+
return { ok: false, error: executionFailed("leverageYield", error, { phase: "postExecution" }) };
|
|
37704
|
+
}
|
|
37705
|
+
}
|
|
37706
|
+
/**
|
|
37707
|
+
* Approves the vault's underlying asset to the leverage vault on Sonic. For callers
|
|
37708
|
+
* interacting with the vault directly on the hub — the swap-style {@link
|
|
37709
|
+
* LeverageYieldService.deposit} flow handles its own approvals.
|
|
37710
|
+
*/
|
|
37711
|
+
async approve(params) {
|
|
37712
|
+
const baseCtx = { action: "approve" };
|
|
37713
|
+
try {
|
|
37714
|
+
leverageYieldInvariant(params.amount > 0n, "Amount must be greater than 0", { ...baseCtx, field: "amount" });
|
|
37715
|
+
leverageYieldInvariant(params.vault.length > 0, "Vault address is required", { ...baseCtx, field: "vault" });
|
|
37716
|
+
const assetResult = await this.getAsset(params.vault);
|
|
37717
|
+
if (!assetResult.ok) {
|
|
37718
|
+
return { ok: false, error: approveFailed("leverageYield", assetResult.error, baseCtx) };
|
|
37719
|
+
}
|
|
37720
|
+
const from = await params.walletProvider.getWalletAddress();
|
|
37721
|
+
const baseApprove = {
|
|
37722
|
+
token: assetResult.value,
|
|
37723
|
+
amount: params.amount,
|
|
37724
|
+
from,
|
|
37725
|
+
spender: params.vault
|
|
37726
|
+
};
|
|
37727
|
+
if (params.raw) {
|
|
37728
|
+
const tx2 = await Erc20Service.approve({ ...baseApprove, raw: true });
|
|
37729
|
+
return { ok: true, value: tx2 };
|
|
37730
|
+
}
|
|
37731
|
+
const tx = await Erc20Service.approve({
|
|
37732
|
+
...baseApprove,
|
|
37733
|
+
raw: false,
|
|
37734
|
+
walletProvider: params.walletProvider
|
|
37735
|
+
});
|
|
37736
|
+
return { ok: true, value: tx };
|
|
37737
|
+
} catch (error) {
|
|
37738
|
+
if (isLeverageYieldApproveError(error)) return { ok: false, error };
|
|
37739
|
+
return { ok: false, error: approveFailed("leverageYield", error, baseCtx) };
|
|
37740
|
+
}
|
|
37741
|
+
}
|
|
37742
|
+
/**
|
|
37743
|
+
* Reads on-chain allowance of the vault's underlying asset for `owner → vault`. Returns
|
|
37744
|
+
* `true` when the allowance covers `amount`. Use before a direct
|
|
37745
|
+
* {@link LeverageYieldService.deposit}.
|
|
37746
|
+
*/
|
|
37747
|
+
async isAllowanceValid(params) {
|
|
37748
|
+
const baseCtx = { action: "allowanceCheck" };
|
|
37749
|
+
try {
|
|
37750
|
+
leverageYieldInvariant(params.amount > 0n, "Amount must be greater than 0", { ...baseCtx, field: "amount" });
|
|
37751
|
+
const assetResult = await this.getAsset(params.vault);
|
|
37752
|
+
if (!assetResult.ok) {
|
|
37753
|
+
return { ok: false, error: allowanceCheckFailed("leverageYield", assetResult.error, baseCtx) };
|
|
37754
|
+
}
|
|
37755
|
+
const allowance = await this.hubProvider.publicClient.readContract({
|
|
37756
|
+
address: assetResult.value,
|
|
37757
|
+
abi: erc20Abi$1,
|
|
37758
|
+
functionName: "allowance",
|
|
37759
|
+
args: [params.owner, params.vault]
|
|
37760
|
+
});
|
|
37761
|
+
return { ok: true, value: allowance >= params.amount };
|
|
37762
|
+
} catch (error) {
|
|
37763
|
+
if (isLeverageYieldAllowanceCheckError(error)) return { ok: false, error };
|
|
37764
|
+
return { ok: false, error: allowanceCheckFailed("leverageYield", error, baseCtx) };
|
|
37765
|
+
}
|
|
37766
|
+
}
|
|
37767
|
+
// ─── Reads ──────────────────────────────────────────────────────────────
|
|
37768
|
+
/** ERC-4626 `asset()` of the vault — the sodaWEETH-style underlying. */
|
|
37769
|
+
async getAsset(vault) {
|
|
37770
|
+
try {
|
|
37771
|
+
const value = await this.hubProvider.publicClient.readContract({
|
|
37772
|
+
address: vault,
|
|
37773
|
+
abi: leverageYieldVaultAbi,
|
|
37774
|
+
functionName: "asset"
|
|
37775
|
+
});
|
|
37776
|
+
return { ok: true, value };
|
|
37777
|
+
} catch (error) {
|
|
37778
|
+
if (isLeverageYieldLookupError(error)) return { ok: false, error };
|
|
37779
|
+
return { ok: false, error: lookupFailed("leverageYield", "getAsset", error) };
|
|
37780
|
+
}
|
|
37781
|
+
}
|
|
37782
|
+
/** Reads the vault's leveraged position snapshot via the non-standard `getPositionDetails`. */
|
|
37783
|
+
async getPosition(vault) {
|
|
37784
|
+
try {
|
|
37785
|
+
const [collateral, debt, ltv, healthFactor, idleAsset] = await this.hubProvider.publicClient.readContract({
|
|
37786
|
+
address: vault,
|
|
37787
|
+
abi: leverageYieldVaultAbi,
|
|
37788
|
+
functionName: "getPositionDetails"
|
|
37789
|
+
});
|
|
37790
|
+
return { ok: true, value: { collateral, debt, ltv, healthFactor, idleAsset } };
|
|
37791
|
+
} catch (error) {
|
|
37792
|
+
if (isLeverageYieldLookupError(error)) return { ok: false, error };
|
|
37793
|
+
return { ok: false, error: lookupFailed("leverageYield", "getPosition", error) };
|
|
37794
|
+
}
|
|
37795
|
+
}
|
|
37796
|
+
/**
|
|
37797
|
+
* Computes the steady-state APR of a leverage-yield vault from the AAVE supply/borrow
|
|
37798
|
+
* rates of its asset and borrowToken, scaled by the vault's target leverage. Matches the
|
|
37799
|
+
* convention used by leveraged-LSD vaults (Origami, Gearbox, etc.) — assumes constant
|
|
37800
|
+
* LTV at `targetLTV` and constant AAVE rates.
|
|
37801
|
+
*
|
|
37802
|
+
* Returns raw fields in RAY (1e27, AAVE's native rate scale) plus the leverage multiplier
|
|
37803
|
+
* in WAD (1e18). See {@link LeverageYieldApr} for the formula and caveats.
|
|
37804
|
+
*/
|
|
37805
|
+
async getApr(vault) {
|
|
37806
|
+
try {
|
|
37807
|
+
const [pool, asset, borrowToken, targetLtvBps] = await Promise.all([
|
|
37808
|
+
this.hubProvider.publicClient.readContract({
|
|
37809
|
+
address: vault,
|
|
37810
|
+
abi: leverageYieldVaultAbi,
|
|
37811
|
+
functionName: "pool"
|
|
37812
|
+
}),
|
|
37813
|
+
this.hubProvider.publicClient.readContract({
|
|
37814
|
+
address: vault,
|
|
37815
|
+
abi: leverageYieldVaultAbi,
|
|
37816
|
+
functionName: "asset"
|
|
37817
|
+
}),
|
|
37818
|
+
this.hubProvider.publicClient.readContract({
|
|
37819
|
+
address: vault,
|
|
37820
|
+
abi: leverageYieldVaultAbi,
|
|
37821
|
+
functionName: "borrowToken"
|
|
37822
|
+
}),
|
|
37823
|
+
this.hubProvider.publicClient.readContract({
|
|
37824
|
+
address: vault,
|
|
37825
|
+
abi: leverageYieldVaultAbi,
|
|
37826
|
+
functionName: "targetLTV"
|
|
37827
|
+
})
|
|
37828
|
+
]);
|
|
37829
|
+
const [assetReserve, borrowReserve] = await Promise.all([
|
|
37830
|
+
this.hubProvider.publicClient.readContract({
|
|
37831
|
+
address: pool,
|
|
37832
|
+
abi: poolAbi,
|
|
37833
|
+
functionName: "getReserveData",
|
|
37834
|
+
args: [asset]
|
|
37835
|
+
}),
|
|
37836
|
+
this.hubProvider.publicClient.readContract({
|
|
37837
|
+
address: pool,
|
|
37838
|
+
abi: poolAbi,
|
|
37839
|
+
functionName: "getReserveData",
|
|
37840
|
+
args: [borrowToken]
|
|
37841
|
+
})
|
|
37842
|
+
]);
|
|
37843
|
+
const supplyAprRay = assetReserve.currentLiquidityRate;
|
|
37844
|
+
const borrowAprRay = borrowReserve.currentVariableBorrowRate;
|
|
37845
|
+
const BPS = 10000n;
|
|
37846
|
+
const WAD2 = 1000000000000000000n;
|
|
37847
|
+
leverageYieldInvariant(targetLtvBps < BPS, `targetLTV (${targetLtvBps}) must be < 100% (10_000 bps)`, {
|
|
37848
|
+
method: "getApr",
|
|
37849
|
+
field: "targetLtvBps"
|
|
37850
|
+
});
|
|
37851
|
+
const leverageMultiplierWad = targetLtvBps * WAD2 / (BPS - targetLtvBps);
|
|
37852
|
+
const spreadRay = supplyAprRay - borrowAprRay;
|
|
37853
|
+
const netAprRay = supplyAprRay + spreadRay * leverageMultiplierWad / WAD2;
|
|
37854
|
+
return {
|
|
37855
|
+
ok: true,
|
|
37856
|
+
value: { supplyAprRay, borrowAprRay, targetLtvBps, leverageMultiplierWad, netAprRay }
|
|
37857
|
+
};
|
|
37858
|
+
} catch (error) {
|
|
37859
|
+
if (isLeverageYieldLookupError(error)) return { ok: false, error };
|
|
37860
|
+
return { ok: false, error: lookupFailed("leverageYield", "getApr", error) };
|
|
37861
|
+
}
|
|
37862
|
+
}
|
|
37863
|
+
/**
|
|
37864
|
+
* Off-chain LSD staking-APR for the vault's underlying asset. Looks the vault up in the
|
|
37865
|
+
* registry, hits DefiLlama's per-pool chart endpoint for the configured `poolId`, and on
|
|
37866
|
+
* any fetch failure returns the registry's hardcoded `fallbackAprPct` with `stale: true`.
|
|
37867
|
+
*
|
|
37868
|
+
* Always resolves to `{ ok: true, ... }` for a known vault — the fallback path replaces
|
|
37869
|
+
* the error, since a missing LSD APR shouldn't break the parent call. Returns
|
|
37870
|
+
* `{ aprRay: 0n, stale: true, label: 'no LSD source' }` for vaults without an
|
|
37871
|
+
* `lsdSource` configured (non-LSD strategies); callers can treat that as "skip LSD".
|
|
37872
|
+
*/
|
|
37873
|
+
async getLsdApr(vault) {
|
|
37874
|
+
try {
|
|
37875
|
+
const cfg = this.getVaultByAddress(vault);
|
|
37876
|
+
const source = cfg?.lsdSource;
|
|
37877
|
+
if (!source) {
|
|
37878
|
+
return { ok: true, value: { aprRay: 0n, label: "no LSD source", stale: true } };
|
|
37879
|
+
}
|
|
37880
|
+
try {
|
|
37881
|
+
const aprPct = await fetchDefillamaApr(source.poolId);
|
|
37882
|
+
return { ok: true, value: { aprRay: pctToRay(aprPct), label: source.label, stale: false } };
|
|
37883
|
+
} catch (fetchError) {
|
|
37884
|
+
this.config.logger.warn("[leverageYield] DefiLlama APR fetch failed; using fallbackAprPct", {
|
|
37885
|
+
vault,
|
|
37886
|
+
poolId: source.poolId,
|
|
37887
|
+
fallbackAprPct: source.fallbackAprPct,
|
|
37888
|
+
error: fetchError instanceof Error ? fetchError.message : String(fetchError)
|
|
37889
|
+
});
|
|
37890
|
+
return {
|
|
37891
|
+
ok: true,
|
|
37892
|
+
value: { aprRay: pctToRay(source.fallbackAprPct), label: `${source.label} (fallback)`, stale: true }
|
|
37893
|
+
};
|
|
37894
|
+
}
|
|
37895
|
+
} catch (error) {
|
|
37896
|
+
if (isLeverageYieldLookupError(error)) return { ok: false, error };
|
|
37897
|
+
return { ok: false, error: lookupFailed("leverageYield", "getLsdApr", error) };
|
|
37898
|
+
}
|
|
37899
|
+
}
|
|
37900
|
+
/**
|
|
37901
|
+
* Combined view of {@link getApr} + {@link getLsdApr}: re-applies the vault's leverage
|
|
37902
|
+
* formula with the LSD's native staking yield folded into the supply side, exposing the
|
|
37903
|
+
* **effective** net APR that LSD-backed strategies actually earn. The AAVE-only
|
|
37904
|
+
* `netAprRay` is preserved on the return value for callers who want to display both.
|
|
37905
|
+
*
|
|
37906
|
+
* effectiveSupply = supplyAprRay + lsdApr.aprRay
|
|
37907
|
+
* effectiveNet = effectiveSupply + leverage × (effectiveSupply − borrowAprRay)
|
|
37908
|
+
*
|
|
37909
|
+
* Fetches AAVE rates and the LSD APR in parallel for one round-trip's worth of latency.
|
|
37910
|
+
*/
|
|
37911
|
+
async getEffectiveApr(vault) {
|
|
37912
|
+
try {
|
|
37913
|
+
const [aprResult, lsdResult] = await Promise.all([this.getApr(vault), this.getLsdApr(vault)]);
|
|
37914
|
+
if (!aprResult.ok) return aprResult;
|
|
37915
|
+
if (!lsdResult.ok) return lsdResult;
|
|
37916
|
+
const apr = aprResult.value;
|
|
37917
|
+
const lsd = lsdResult.value;
|
|
37918
|
+
const effectiveSupplyAprRay = apr.supplyAprRay + lsd.aprRay;
|
|
37919
|
+
const spreadRay = effectiveSupplyAprRay - apr.borrowAprRay;
|
|
37920
|
+
const WAD2 = 1000000000000000000n;
|
|
37921
|
+
const effectiveNetAprRay = effectiveSupplyAprRay + spreadRay * apr.leverageMultiplierWad / WAD2;
|
|
37922
|
+
return {
|
|
37923
|
+
ok: true,
|
|
37924
|
+
value: { ...apr, lsdApr: lsd, effectiveSupplyAprRay, effectiveNetAprRay }
|
|
37925
|
+
};
|
|
37926
|
+
} catch (error) {
|
|
37927
|
+
if (isLeverageYieldLookupError(error)) return { ok: false, error };
|
|
37928
|
+
return { ok: false, error: lookupFailed("leverageYield", "getEffectiveApr", error) };
|
|
37929
|
+
}
|
|
37930
|
+
}
|
|
37931
|
+
/** Synchronously withdrawable assets for `owner` (clamped against leverage HF floor). */
|
|
37932
|
+
async getMaxWithdraw(vault, owner) {
|
|
37933
|
+
const inner = await Erc4626Service.getMaxWithdraw(vault, owner, this.hubProvider.publicClient);
|
|
37934
|
+
if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "getMaxWithdraw", inner.error) };
|
|
37935
|
+
return { ok: true, value: inner.value };
|
|
37936
|
+
}
|
|
37937
|
+
/** Total underlying assets currently held by the vault (vault-asset units, 18 decimals) — TVL. */
|
|
37938
|
+
async getTotalAssets(vault) {
|
|
37939
|
+
const inner = await Erc4626Service.getTotalAssets(vault, this.hubProvider.publicClient);
|
|
37940
|
+
if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "getTotalAssets", inner.error) };
|
|
37941
|
+
return { ok: true, value: inner.value };
|
|
37942
|
+
}
|
|
37943
|
+
/** Shares minted for a given asset deposit. */
|
|
37944
|
+
async previewDeposit(vault, assets) {
|
|
37945
|
+
const inner = await Erc4626Service.previewDeposit(vault, assets, this.hubProvider.publicClient);
|
|
37946
|
+
if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "previewDeposit", inner.error) };
|
|
37947
|
+
return { ok: true, value: inner.value };
|
|
37948
|
+
}
|
|
37949
|
+
/** Shares burned for a given asset withdrawal. */
|
|
37950
|
+
async previewWithdraw(vault, assets) {
|
|
37951
|
+
const inner = await Erc4626Service.previewWithdraw(vault, assets, this.hubProvider.publicClient);
|
|
37952
|
+
if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "previewWithdraw", inner.error) };
|
|
37953
|
+
return { ok: true, value: inner.value };
|
|
37954
|
+
}
|
|
37955
|
+
/** Assets received for a given share redemption. */
|
|
37956
|
+
async previewRedeem(vault, shares) {
|
|
37957
|
+
const inner = await Erc4626Service.previewRedeem(vault, shares, this.hubProvider.publicClient);
|
|
37958
|
+
if (!inner.ok) return { ok: false, error: lookupFailed("leverageYield", "previewRedeem", inner.error) };
|
|
37959
|
+
return { ok: true, value: inner.value };
|
|
37960
|
+
}
|
|
37961
|
+
/** Vault shares held by `owner`. */
|
|
37962
|
+
async getShareBalance(vault, owner) {
|
|
37963
|
+
try {
|
|
37964
|
+
const value = await this.hubProvider.publicClient.readContract({
|
|
37965
|
+
address: vault,
|
|
37966
|
+
abi: erc20Abi$1,
|
|
37967
|
+
functionName: "balanceOf",
|
|
37968
|
+
args: [owner]
|
|
37969
|
+
});
|
|
37970
|
+
return { ok: true, value };
|
|
37971
|
+
} catch (error) {
|
|
37972
|
+
if (isLeverageYieldLookupError(error)) return { ok: false, error };
|
|
37973
|
+
return { ok: false, error: lookupFailed("leverageYield", "getShareBalance", error) };
|
|
37974
|
+
}
|
|
37975
|
+
}
|
|
37976
|
+
/**
|
|
37977
|
+
* Convenience: resolves the user's hub wallet from `(srcChainKey, srcAddress)` and
|
|
37978
|
+
* returns its on-chain `maxWithdraw`, less {@link MAX_WITHDRAW_DUST_BUFFER}. The trim
|
|
37979
|
+
* keeps the value safe for an asset-denominated ERC-4626 `withdraw` — the raw
|
|
37980
|
+
* `maxWithdraw` can trip the round-up that asks for one more share than the user holds.
|
|
37981
|
+
*/
|
|
37982
|
+
async getMaxWithdrawForUser(vault, srcChainKey, srcAddress) {
|
|
37983
|
+
try {
|
|
37984
|
+
const hubWallet = await this.hubProvider.getUserHubWalletAddress(srcAddress, srcChainKey);
|
|
37985
|
+
const maxWithdrawResult = await this.getMaxWithdraw(vault, hubWallet);
|
|
37986
|
+
if (!maxWithdrawResult.ok) return maxWithdrawResult;
|
|
37987
|
+
const buffered = maxWithdrawResult.value > MAX_WITHDRAW_DUST_BUFFER ? maxWithdrawResult.value - MAX_WITHDRAW_DUST_BUFFER : 0n;
|
|
37988
|
+
return { ok: true, value: buffered };
|
|
37989
|
+
} catch (error) {
|
|
37990
|
+
if (isLeverageYieldLookupError(error)) return { ok: false, error };
|
|
37991
|
+
return { ok: false, error: lookupFailed("leverageYield", "getMaxWithdrawForUser", error, { srcChainKey }) };
|
|
37992
|
+
}
|
|
37993
|
+
}
|
|
37994
|
+
/**
|
|
37995
|
+
* Convenience: resolves the user's hub wallet from `(srcChainKey, srcAddress)` and
|
|
37996
|
+
* returns its on-chain share balance.
|
|
37997
|
+
*/
|
|
37998
|
+
async getShareBalanceForUser(vault, srcChainKey, srcAddress) {
|
|
37999
|
+
try {
|
|
38000
|
+
const hubWallet = await this.hubProvider.getUserHubWalletAddress(srcAddress, srcChainKey);
|
|
38001
|
+
return await this.getShareBalance(vault, hubWallet);
|
|
38002
|
+
} catch (error) {
|
|
38003
|
+
if (isLeverageYieldLookupError(error)) return { ok: false, error };
|
|
38004
|
+
return { ok: false, error: lookupFailed("leverageYield", "getShareBalanceForUser", error, { srcChainKey }) };
|
|
38005
|
+
}
|
|
38006
|
+
}
|
|
38007
|
+
};
|
|
38008
|
+
|
|
36837
38009
|
// src/shared/entities/Sodax.ts
|
|
36838
38010
|
var Sodax = class {
|
|
36839
38011
|
instanceConfig;
|
|
@@ -36855,6 +38027,8 @@ var Sodax = class {
|
|
|
36855
38027
|
// Recovery service for withdrawing stuck hub-wallet assets back to a spoke chain
|
|
36856
38028
|
dex;
|
|
36857
38029
|
// Dex service enabling DEX operations
|
|
38030
|
+
leverageYield;
|
|
38031
|
+
// Leverage-yield service: cross-chain deposits / withdrawals into ERC-4626 leverage vaults on Sonic
|
|
36858
38032
|
config;
|
|
36859
38033
|
// Config service enabling configuration data fetching from the backend API or fallbacking to default values
|
|
36860
38034
|
hubProvider;
|
|
@@ -36862,9 +38036,10 @@ var Sodax = class {
|
|
|
36862
38036
|
spoke;
|
|
36863
38037
|
// spoke service enabling spoke chain operations
|
|
36864
38038
|
constructor(config) {
|
|
38039
|
+
const logger = resolveLogger(config?.logger);
|
|
36865
38040
|
this.instanceConfig = config ? mergeSodaxConfig(sodaxConfig, config) : sodaxConfig;
|
|
36866
|
-
this.backendApi = new BackendApiService(this.instanceConfig.api);
|
|
36867
|
-
this.config = new ConfigService({ api: this.backendApi, config: this.instanceConfig, userConfig: config });
|
|
38041
|
+
this.backendApi = new BackendApiService(this.instanceConfig.api, logger);
|
|
38042
|
+
this.config = new ConfigService({ api: this.backendApi, config: this.instanceConfig, userConfig: config, logger });
|
|
36868
38043
|
this.hubProvider = new EvmHubProvider({ config: this.config });
|
|
36869
38044
|
this.spoke = new SpokeService({ config: this.config, hubProvider: this.hubProvider });
|
|
36870
38045
|
this.swaps = new SwapService({
|
|
@@ -36899,6 +38074,11 @@ var Sodax = class {
|
|
|
36899
38074
|
config: this.config,
|
|
36900
38075
|
spoke: this.spoke
|
|
36901
38076
|
});
|
|
38077
|
+
this.leverageYield = new LeverageYieldService({
|
|
38078
|
+
hubProvider: this.hubProvider,
|
|
38079
|
+
config: this.config,
|
|
38080
|
+
spoke: this.spoke
|
|
38081
|
+
});
|
|
36902
38082
|
}
|
|
36903
38083
|
/**
|
|
36904
38084
|
* Initializes the Sodax instance with dynamic configuration.
|
|
@@ -36939,4 +38119,4 @@ var isPartnerError = isCodeMember(PARTNER_CODES);
|
|
|
36939
38119
|
(*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
36940
38120
|
*/
|
|
36941
38121
|
|
|
36942
|
-
export { ALLOWANCE_CHECK_CODES, APPROVE_CODES, AssetService, BITCOIN_CHAIN_KEYS, BITCOIN_CHAIN_KEYS_SET, BTC_WALLET_ADDRESS_TYPES, BackendApiService, BalnSwapService, BigIntToHex, BigNumberZeroDecimal, BitcoinSpokeService, BnUSDMigrationService, BridgeService, CHAIN_KEYS, CONFIG_VERSION, CREATE_INTENT_CODES, ChainKeys, ChainTypeArr, ClService, ConfigService, CustomSorobanServer, CustomStellarAccount, DEFAULT_BACKEND_API_ENDPOINT, DEFAULT_BACKEND_API_HEADERS, DEFAULT_BACKEND_API_TIMEOUT, DEFAULT_DEADLINE_OFFSET, DEFAULT_MAX_RETRY, DEFAULT_RELAYER_API_ENDPOINT, DEFAULT_RELAY_TX_TIMEOUT, DEFAULT_RETRY_DELAY_MS, DexService, EVM_CHAIN_ID_TO_KEY, EVM_CHAIN_KEYS, EVM_CHAIN_KEYS_SET, EVM_SPOKE_ONLY_CHAIN_KEYS, EVM_SPOKE_ONLY_CHAIN_KEYS_SET, Erc20Service, Erc4626Service, EvmAssetManagerService, EvmHubProvider, EvmSolverService, EvmSpokeService, EvmVaultTokenService, FEE_PERCENTAGE_SCALE, GAS_ESTIMATION_CODES, HALF_RAY, HALF_WAD, HUB_CHAIN_KEY, HttpRelayError, HubVaultSymbols, ICON_CHAIN_KEYS, ICON_CHAIN_KEYS_SET, ICON_TX_RESULT_WAIT_MAX_RETRY, INJECTIVE_CHAIN_KEYS, INJECTIVE_CHAIN_KEYS_SET, INTENT_CHAIN_IDS, IconSpokeService, IcxMigrationService, Injective20Token, InjectiveSpokeService, IntentCreatedEventAbi, IntentDataType, IntentFilledEventAbi, IntentRelayChainIdToChainKey, IntentsAbi, LOOKUP_CODES, LTV_PRECISION, LendingPoolService, LockupMultiplier, LockupPeriod, MAX_UINT256, MigrationService, MintPositionEventAbi, MoneyMarketDataService, MoneyMarketService, NEAR_CHAIN_KEYS, NEAR_CHAIN_KEYS_SET, NEAR_DEFAULT_GAS, NearSpokeService, PartnerFeeClaimService, PartnerService, Permit2Service, ProtocolIntentsAbi, RAY, RAY_DECIMALS, RELAY_ERROR_CODES, RadfiApiError, RadfiProvider, RecoveryService, RelayChainIdMap, SECONDS_PER_YEAR, SODAX_ERROR_CODES, SODAX_FEATURES, SOLANA_CHAIN_KEYS, SOLANA_CHAIN_KEYS_SET, SONIC_CHAIN_KEYS, SONIC_CHAIN_KEYS_SET, STACKS_CHAIN_KEYS, STACKS_CHAIN_KEYS_SET, STELLAR_CHAIN_KEYS, STELLAR_CHAIN_KEYS_SET, SUI_CHAIN_KEYS, SUI_CHAIN_KEYS_SET, SodaTokens, Sodax, SodaxError, SolanaSpokeService, SolverApiService, SolverIntentErrorCode, SolverIntentStatusCode, SonicSpokeService, SpokeService, StacksSpokeService, StakingLogic, StakingService, StatATokenAddresses, StellarSpokeService, SuiSpokeService, SupportedMigrationTokens, SwapService, USD_DECIMALS, UiPoolDataProviderService, VAULT_TOKEN_DECIMALS, WAD, WAD_RAY_RATIO, WEI_DECIMALS, adjustAmountByFee, allowanceCheckFailed, apiConfig, approveFailed, arbitrumSupportedTokens, assetManagerAbi, avalancheSupportedTokens, balnSwapAbi, baseChainInfo, baseSupportedTokens, binomialApproximatedRayPow, bitcoinSupportedTokens, bnUSDLegacySpokeChainIds, bnUSDLegacyTokens, bridgeConfig, bridgeInvariant, bscSupportedTokens, calculateAllReserveIncentives, calculateAllUserIncentives, calculateAvailableBorrowsMarketReferenceCurrency, calculateCompoundedInterest, calculateCompoundedRate, calculateFeeAmount, calculateHealthFactorFromBalances, calculateHealthFactorFromBalancesBigUnits, calculateLinearInterest, calculatePercentageFeeAmount, clPoolAbi, clPoolManagerAbi, clPositionManagerAbi, clQuoterAbi, clRouterAbi, clTickLensAbi, concentratedLiquidityConfig, connectionAbi, convertTransactionInstructionToRaw, createInvariant, deepMerge, defaultHookAbi, detectBitcoinAddressType, dexConfig, dexInvariant, dexPools, encodeAddress, encodeBtcPayloadToBytes, encodeContractCalls, erc20Abi, erc4626Abi, estimateBitcoinTxSize, ethereumSupportedTokens, executionFailed, formatBasisPoints, formatEModeCategory, formatEModes, formatPercentage, formatReserve, formatReserveUSD, formatReserves, formatReservesAndIncentives, formatUserSummary, formatUserSummaryAndIncentives, gasEstimationFailed, getAllLegacybnUSDTokens, getAndFormatReserveEModes, getAssetManagerIdl, getAssetManagerProgram, getChainKeyFromRelayChainId, getChainType, getCompoundedBalance, getConcentratedLiquidityConfig, getConnectionIdl, getConnectionProgram, getEvmChainKeyByChainId, getEvmViemChain, getIconAddressBytes, getIntentRelayChainId, getLinearBalance, getMarketReferenceCurrencyAndUsdBalance, getPacket, getProvider, getRandomBytes, getReserveNormalizedIncome, getReservesEModes, getSolanaAddressBytes, getSolverConfig, getSupportedSolverTokens, getTransactionPackets, getbnUSDToken, hexToBigInt, hexToSolanaAddress, hubConfig, hyper, hyperevmSupportedTokens, iconSupportedTokens, injectiveSupportedTokens, intentCreationFailed, isBalnMigrateParams, isBitcoinChainKey, isBitcoinChainKeyType, isBitcoinWalletProviderType, isBridgeAllowanceCheckError, isBridgeApproveError, isBridgeCreateIntentError, isBridgeError, isBridgeLookupError, isBridgeOrchestrationError, isCodeMember, isDexError, isEvmChainKey, isEvmChainKeyType, isEvmSpokeChainConfig, isEvmSpokeOnlyChainKey, isEvmSpokeOnlyChainKeyType, isEvmWalletProviderType, isFeatureError, isHubChainKey, isHubChainKeyType, isIconAddress, isIconChainKey, isIconChainKeyType, isIcxCreateRevertMigrationParams, isIcxMigrateParams, isInjectiveChainKey, isInjectiveChainKeyType, isJsonRpcPayloadResponse, isLegacybnUSDChainId, isLegacybnUSDToken, isMigrateOrchestrationError, isMigrationAllowanceCheckError, isMigrationApproveError, isMigrationCreateIntentError, isMigrationError, isMigrationLookupError, isMoneyMarketAllowanceCheckError, isMoneyMarketApproveError, isMoneyMarketCreateIntentError, isMoneyMarketError, isMoneyMarketGasEstimationError, isMoneyMarketOrchestrationError, isNativeToken, isNearChainKey, isNearChainKeyType, isNewbnUSDChainId, isNewbnUSDToken, isOptionalBitcoinWalletProviderType, isOptionalEvmWalletProviderType, isOptionalStellarWalletProviderType, isPartnerError, isPartnerFeeAmount, isPartnerFeePercentage, isPostExecutionError, isRawDestinationParams, isRecoveryError, isResponseAddressType, isResponseSigningType, isRevertMigrationOrchestrationError, isSodaxError, isSolanaChainKey, isSolanaChainKeyType, isSolanaNativeToken, isSonicChainKey, isSonicChainKeyType, isSpokeApproveParamsEvmSpoke, isSpokeApproveParamsHub, isSpokeApproveParamsStellar, isSpokeChainKey, isSpokeIsAllowanceValidParamsEvmSpoke, isSpokeIsAllowanceValidParamsHub, isSpokeIsAllowanceValidParamsStellar, isStacksChainKey, isStacksChainKeyType, isStakeOrchestrationError, isStakingAllowanceCheckError, isStakingApproveError, isStakingCreateIntentError, isStakingError, isStakingInfoFetchError, isStakingOrchestrationError, isStellarChainKey, isStellarChainKeyType, isStellarWalletProviderType, isSubmitSwapTxResponse, isSubmitSwapTxStatusResponse, isSuiChainKey, isSuiChainKeyType, isSupportedBitcoinAddressType, isSwapCreateIntentError, isSwapError, isSwapSupportedToken, isUndefinedOrValidWalletProviderForChainKey, isUnifiedBnUSDMigrateParams, isValidWalletProviderForChainKey, kaiaSupportedTokens, lightlinkSupportedTokens, lookupFailed, mapRelayFailure, mergeSodaxConfig, messageOf, migrationInvariant, mintPositionParamsAbi, mmInvariant, modifyLiquidityParamsAbi, moneyMarketConfig, moneyMarketReserveAssets, moneyMarketSupportedTokens, nativeToUSD, nearSupportedTokens, newbnUSDSpokeChainIds, normalize, normalizeBN, normalizePsbtToBase64, normalizedToUsd, optimismSupportedTokens, pancakeSwapInfinityDefaultHookAbi, pancakeSwapInfinityPoolManagerAbi, pancakeSwapInfinityPositionManagerAbi, parseToStroops, parseTokenArrayFromJson, partnerInvariant, permit2Abi, polygonSupportedTokens, poolAbi, poolKeyAbi, randomUint256, rayDiv, rayMul, rayPow, rayToWad, recoveryInvariant, redbellySupportedTokens, relayConfig, relayTxAndWaitPacket, requestAddress, requestJsonRpc, requestSigning, retry, reverseEncodeAddress, serializeAddressData, sleep, sodaxConfig, sodaxInvariant, solanaSupportedTokens, solverConfig, sonicSupportedTokens, sonicWalletFactoryAbi, spokeAssetManagerAbi, spokeChainConfig, spokeChainKeysSet, stacksSupportedTokens, stakedSodaAbi, stakingInvariant, stakingRouterAbi, stataTokenFactoryAbi, stellarSupportedTokens, submitTransaction, suiSupportedTokens, supportedSpokeChains, supportedTokensByChain, swapExactInSingleParamsAbi, swapInvariant, swapSupportedTokens, swapsConfig, uiPoolDataAbi, universalRouterAbi, unknownFailed, valueToBigNumber, valueToZDBigNumber, variableDebtTokenAbi, vaultTokenAbi, verifyFailed, wadToRay, waitForStacksTransaction, waitForTransactionReceipt, waitUntilIntentExecuted, walletFactoryAbi, wrappedSonicAbi };
|
|
38122
|
+
export { ALLOWANCE_CHECK_CODES, APPROVE_CODES, AssetService, BITCOIN_CHAIN_KEYS, BITCOIN_CHAIN_KEYS_SET, BTC_WALLET_ADDRESS_TYPES, BackendApiService, BalnSwapService, BigIntToHex, BigNumberZeroDecimal, BitcoinSpokeService, BnUSDMigrationService, BridgeService, CHAIN_KEYS, CONFIG_VERSION, CREATE_INTENT_CODES, ChainKeys, ChainTypeArr, ClService, ConfigService, CustomSorobanServer, CustomStellarAccount, DEFAULT_BACKEND_API_ENDPOINT, DEFAULT_BACKEND_API_HEADERS, DEFAULT_BACKEND_API_TIMEOUT, DEFAULT_DEADLINE_OFFSET, DEFAULT_MAX_RETRY, DEFAULT_RELAYER_API_ENDPOINT, DEFAULT_RELAY_TX_TIMEOUT, DEFAULT_RETRY_DELAY_MS, DexService, EVM_CHAIN_ID_TO_KEY, EVM_CHAIN_KEYS, EVM_CHAIN_KEYS_SET, EVM_SPOKE_ONLY_CHAIN_KEYS, EVM_SPOKE_ONLY_CHAIN_KEYS_SET, Erc20Service, Erc4626Service, EvmAssetManagerService, EvmHubProvider, EvmSolverService, EvmSpokeService, EvmVaultTokenService, FEE_PERCENTAGE_SCALE, GAS_ESTIMATION_CODES, HALF_RAY, HALF_WAD, HUB_CHAIN_KEY, HttpRelayError, HubVaultSymbols, ICON_CHAIN_KEYS, ICON_CHAIN_KEYS_SET, ICON_TX_RESULT_WAIT_MAX_RETRY, INJECTIVE_CHAIN_KEYS, INJECTIVE_CHAIN_KEYS_SET, INTENT_CHAIN_IDS, IconSpokeService, IcxMigrationService, Injective20Token, InjectiveSpokeService, IntentCreatedEventAbi, IntentDataType, IntentFilledEventAbi, IntentRelayChainIdToChainKey, IntentsAbi, LOOKUP_CODES, LTV_PRECISION, LendingPoolService, LeverageYieldService, LockupMultiplier, LockupPeriod, LsodaSymbols, LsodaTokens, MAX_UINT256, MigrationService, MintPositionEventAbi, MoneyMarketDataService, MoneyMarketService, NEAR_CHAIN_KEYS, NEAR_CHAIN_KEYS_SET, NEAR_DEFAULT_GAS, NEAR_STORAGE_DEPOSIT, NearSpokeService, PartnerFeeClaimService, PartnerService, Permit2Service, ProtocolIntentsAbi, RAY, RAY_DECIMALS, RELAY_ERROR_CODES, RadfiApiError, RadfiProvider, RecoveryService, RelayChainIdMap, SECONDS_PER_YEAR, SODAX_ERROR_CODES, SODAX_FEATURES, SOLANA_CHAIN_KEYS, SOLANA_CHAIN_KEYS_SET, SONIC_CHAIN_KEYS, SONIC_CHAIN_KEYS_SET, STACKS_CHAIN_KEYS, STACKS_CHAIN_KEYS_SET, STELLAR_CHAIN_KEYS, STELLAR_CHAIN_KEYS_SET, SUI_CHAIN_KEYS, SUI_CHAIN_KEYS_SET, SodaTokens, Sodax, SodaxError, SolanaSpokeService, SolverApiService, SolverIntentErrorCode, SolverIntentStatusCode, SonicSpokeService, SpokeService, StacksSpokeService, StakingLogic, StakingService, StatATokenAddresses, StellarSpokeService, SuiSpokeService, SupportedMigrationTokens, SwapService, USD_DECIMALS, UiPoolDataProviderService, VAULT_TOKEN_DECIMALS, WAD, WAD_RAY_RATIO, WEI_DECIMALS, adjustAmountByFee, allowanceCheckFailed, apiConfig, approveFailed, arbitrumSupportedTokens, assetManagerAbi, avalancheSupportedTokens, balnSwapAbi, baseChainInfo, baseSupportedTokens, binomialApproximatedRayPow, bitcoinSupportedTokens, bnUSDLegacySpokeChainIds, bnUSDLegacyTokens, bridgeConfig, bridgeInvariant, bscSupportedTokens, calcOpReturnOutputVbytes, calculateAllReserveIncentives, calculateAllUserIncentives, calculateAvailableBorrowsMarketReferenceCurrency, calculateCompoundedInterest, calculateCompoundedRate, calculateFeeAmount, calculateHealthFactorFromBalances, calculateHealthFactorFromBalancesBigUnits, calculateLinearInterest, calculatePercentageFeeAmount, clPoolAbi, clPoolManagerAbi, clPositionManagerAbi, clQuoterAbi, clRouterAbi, clTickLensAbi, concentratedLiquidityConfig, connectionAbi, consoleLogger, convertTransactionInstructionToRaw, createInvariant, deepMerge, defaultHookAbi, detectBitcoinAddressType, dexConfig, dexInvariant, dexPools, encodeAddress, encodeBtcPayloadToBytes, encodeContractCalls, erc20Abi, erc4626Abi, estimateBitcoinTxSize, ethereumSupportedTokens, executionFailed, formatBasisPoints, formatEModeCategory, formatEModes, formatPercentage, formatReserve, formatReserveUSD, formatReserves, formatReservesAndIncentives, formatUserSummary, formatUserSummaryAndIncentives, gasEstimationFailed, getAllLegacybnUSDTokens, getAndFormatReserveEModes, getAssetManagerIdl, getAssetManagerProgram, getChainKeyFromRelayChainId, getChainType, getCompoundedBalance, getConcentratedLiquidityConfig, getConnectionIdl, getConnectionProgram, getEvmChainKeyByChainId, getEvmViemChain, getIconAddressBytes, getIntentRelayChainId, getLinearBalance, getMarketReferenceCurrencyAndUsdBalance, getPacket, getProvider, getRandomBytes, getReserveNormalizedIncome, getReservesEModes, getSolanaAddressBytes, getSolverConfig, getSupportedSolverTokens, getTransactionPackets, getbnUSDToken, hexToBigInt, hexToSolanaAddress, hubConfig, hyper, hyperevmSupportedTokens, iconSupportedTokens, injectiveSupportedTokens, intentCreationFailed, isBalnMigrateParams, isBitcoinChainKey, isBitcoinChainKeyType, isBitcoinWalletProviderType, isBridgeAllowanceCheckError, isBridgeApproveError, isBridgeCreateIntentError, isBridgeError, isBridgeLookupError, isBridgeOrchestrationError, isCodeMember, isDexError, isEvmChainKey, isEvmChainKeyType, isEvmSpokeChainConfig, isEvmSpokeOnlyChainKey, isEvmSpokeOnlyChainKeyType, isEvmWalletProviderType, isFeatureError, isHubChainKey, isHubChainKeyType, isIconAddress, isIconChainKey, isIconChainKeyType, isIcxCreateRevertMigrationParams, isIcxMigrateParams, isInjectiveChainKey, isInjectiveChainKeyType, isJsonRpcPayloadResponse, isLegacybnUSDChainId, isLegacybnUSDToken, isLeverageYieldAllowanceCheckError, isLeverageYieldApproveError, isLeverageYieldCreateIntentError, isLeverageYieldError, isLeverageYieldLookupError, isLeverageYieldPostExecutionError, isLeverageYieldSwapError, isMigrateOrchestrationError, isMigrationAllowanceCheckError, isMigrationApproveError, isMigrationCreateIntentError, isMigrationError, isMigrationLookupError, isMoneyMarketAllowanceCheckError, isMoneyMarketApproveError, isMoneyMarketCreateIntentError, isMoneyMarketError, isMoneyMarketGasEstimationError, isMoneyMarketOrchestrationError, isNativeToken, isNearChainKey, isNearChainKeyType, isNewbnUSDChainId, isNewbnUSDToken, isOptionalBitcoinWalletProviderType, isOptionalEvmWalletProviderType, isOptionalStellarWalletProviderType, isPartnerError, isPartnerFeeAmount, isPartnerFeePercentage, isPostExecutionError, isRawDestinationParams, isRecoveryError, isResponseAddressType, isResponseSigningType, isRevertMigrationOrchestrationError, isSodaxError, isSolanaChainKey, isSolanaChainKeyType, isSolanaNativeToken, isSonicChainKey, isSonicChainKeyType, isSpokeApproveParamsEvmSpoke, isSpokeApproveParamsHub, isSpokeApproveParamsStellar, isSpokeChainKey, isSpokeIsAllowanceValidParamsEvmSpoke, isSpokeIsAllowanceValidParamsHub, isSpokeIsAllowanceValidParamsStellar, isStacksChainKey, isStacksChainKeyType, isStakeOrchestrationError, isStakingAllowanceCheckError, isStakingApproveError, isStakingCreateIntentError, isStakingError, isStakingInfoFetchError, isStakingOrchestrationError, isStellarChainKey, isStellarChainKeyType, isStellarWalletProviderType, isSubmitSwapTxResponse, isSubmitSwapTxStatusResponse, isSuiChainKey, isSuiChainKeyType, isSupportedBitcoinAddressType, isSwapCreateIntentError, isSwapError, isSwapSupportedToken, isUndefinedOrValidWalletProviderForChainKey, isUnifiedBnUSDMigrateParams, isValidWalletProviderForChainKey, kaiaSupportedTokens, leverageYieldConfig, leverageYieldInvariant, leverageYieldVaults, lightlinkSupportedTokens, lookupFailed, mapRelayFailure, mergeSodaxConfig, messageOf, migrationInvariant, mintPositionParamsAbi, mmInvariant, modifyLiquidityParamsAbi, moneyMarketConfig, moneyMarketReserveAssets, moneyMarketSupportedTokens, nativeToUSD, nearSupportedTokens, newbnUSDSpokeChainIds, normalize, normalizeBN, normalizePsbtToBase64, normalizeSignatureToBase64, normalizedToUsd, optimismSupportedTokens, pancakeSwapInfinityDefaultHookAbi, pancakeSwapInfinityPoolManagerAbi, pancakeSwapInfinityPositionManagerAbi, parseToStroops, parseTokenArrayFromJson, partnerInvariant, permit2Abi, polygonSupportedTokens, poolAbi, poolKeyAbi, randomUint256, rayDiv, rayMul, rayPow, rayToWad, recoveryInvariant, redbellySupportedTokens, relayConfig, relayTxAndWaitPacket, requestAddress, requestJsonRpc, requestSigning, resolveLogger, retry, reverseEncodeAddress, serializeAddressData, silentLogger, sleep, sodaxConfig, sodaxInvariant, solanaSupportedTokens, solverConfig, sonicSupportedTokens, sonicWalletFactoryAbi, spokeAssetManagerAbi, spokeChainConfig, spokeChainKeysSet, stacksSupportedTokens, stakedSodaAbi, stakingInvariant, stakingRouterAbi, stataTokenFactoryAbi, stellarSupportedTokens, submitTransaction, suiSupportedTokens, supportedSpokeChains, supportedTokensByChain, swapExactInSingleParamsAbi, swapInvariant, swapSupportedTokens, swapsConfig, uiPoolDataAbi, universalRouterAbi, unknownFailed, usesBip322MessageSigning, valueToBigNumber, valueToZDBigNumber, variableDebtTokenAbi, vaultTokenAbi, verifyFailed, wadToRay, waitForStacksTransaction, waitForTransactionReceipt, waitUntilIntentExecuted, walletFactoryAbi, wrappedSonicAbi };
|