@sodax/sdk 2.0.0-rc.16 → 2.0.0-rc.18

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 CHANGED
@@ -2641,6 +2641,8 @@ var RelayChainIdMap = {
2641
2641
  };
2642
2642
  var INTENT_CHAIN_IDS = Object.values(RelayChainIdMap);
2643
2643
  var IntentRelayChainIdToChainKey = Object.fromEntries(Object.entries(RelayChainIdMap).map(([chainKey, chainId]) => [chainId, chainKey]));
2644
+ var CHAIN_LOGO_BASE_URL = "https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/assets/chain";
2645
+ var chainLogo = (key) => `${CHAIN_LOGO_BASE_URL}/${key}.png`;
2644
2646
  var baseChainInfo = {
2645
2647
  [ChainKeys.SONIC_MAINNET]: {
2646
2648
  name: "Sonic",
@@ -2648,6 +2650,7 @@ var baseChainInfo = {
2648
2650
  type: "EVM",
2649
2651
  chainId: 146,
2650
2652
  mainnet: true,
2653
+ logo: chainLogo(ChainKeys.SONIC_MAINNET),
2651
2654
  explorer: {
2652
2655
  baseUrl: "https://sonicscan.org/",
2653
2656
  txUrl: "https://sonicscan.org/tx/",
@@ -2661,6 +2664,7 @@ var baseChainInfo = {
2661
2664
  type: "SOLANA",
2662
2665
  chainId: "solana",
2663
2666
  mainnet: true,
2667
+ logo: chainLogo(ChainKeys.SOLANA_MAINNET),
2664
2668
  explorer: {
2665
2669
  baseUrl: "https://solscan.io/",
2666
2670
  txUrl: "https://solscan.io/tx/",
@@ -2674,6 +2678,7 @@ var baseChainInfo = {
2674
2678
  type: "EVM",
2675
2679
  chainId: 43114,
2676
2680
  mainnet: true,
2681
+ logo: chainLogo(ChainKeys.AVALANCHE_MAINNET),
2677
2682
  explorer: {
2678
2683
  baseUrl: "https://snowtrace.io/",
2679
2684
  txUrl: "https://snowtrace.io/tx/",
@@ -2687,6 +2692,7 @@ var baseChainInfo = {
2687
2692
  type: "EVM",
2688
2693
  chainId: 42161,
2689
2694
  mainnet: true,
2695
+ logo: chainLogo(ChainKeys.ARBITRUM_MAINNET),
2690
2696
  explorer: {
2691
2697
  baseUrl: "https://arbiscan.io/",
2692
2698
  txUrl: "https://arbiscan.io/tx/",
@@ -2700,6 +2706,7 @@ var baseChainInfo = {
2700
2706
  type: "EVM",
2701
2707
  chainId: 8453,
2702
2708
  mainnet: true,
2709
+ logo: chainLogo(ChainKeys.BASE_MAINNET),
2703
2710
  explorer: {
2704
2711
  baseUrl: "https://basescan.org/",
2705
2712
  txUrl: "https://basescan.org/tx/",
@@ -2713,6 +2720,7 @@ var baseChainInfo = {
2713
2720
  type: "EVM",
2714
2721
  chainId: 10,
2715
2722
  mainnet: true,
2723
+ logo: chainLogo(ChainKeys.OPTIMISM_MAINNET),
2716
2724
  explorer: {
2717
2725
  baseUrl: "https://optimistic.etherscan.io/",
2718
2726
  txUrl: "https://optimistic.etherscan.io/tx/",
@@ -2726,6 +2734,7 @@ var baseChainInfo = {
2726
2734
  type: "EVM",
2727
2735
  chainId: 56,
2728
2736
  mainnet: true,
2737
+ logo: chainLogo(ChainKeys.BSC_MAINNET),
2729
2738
  explorer: {
2730
2739
  baseUrl: "https://bscscan.com/",
2731
2740
  txUrl: "https://bscscan.com/tx/",
@@ -2739,6 +2748,7 @@ var baseChainInfo = {
2739
2748
  type: "EVM",
2740
2749
  chainId: 137,
2741
2750
  mainnet: true,
2751
+ logo: chainLogo(ChainKeys.POLYGON_MAINNET),
2742
2752
  explorer: {
2743
2753
  baseUrl: "https://polygonscan.com/",
2744
2754
  txUrl: "https://polygonscan.com/tx/",
@@ -2752,6 +2762,7 @@ var baseChainInfo = {
2752
2762
  type: "EVM",
2753
2763
  chainId: 999,
2754
2764
  mainnet: true,
2765
+ logo: chainLogo(ChainKeys.HYPEREVM_MAINNET),
2755
2766
  explorer: {
2756
2767
  baseUrl: "https://hyperevmscan.io/",
2757
2768
  txUrl: "https://hyperevmscan.io/tx/",
@@ -2765,6 +2776,7 @@ var baseChainInfo = {
2765
2776
  type: "EVM",
2766
2777
  chainId: 1890,
2767
2778
  mainnet: true,
2779
+ logo: chainLogo(ChainKeys.LIGHTLINK_MAINNET),
2768
2780
  explorer: {
2769
2781
  baseUrl: "https://phoenix.lightlink.io/",
2770
2782
  txUrl: "https://phoenix.lightlink.io/tx/",
@@ -2778,6 +2790,7 @@ var baseChainInfo = {
2778
2790
  type: "INJECTIVE",
2779
2791
  chainId: "injective-1",
2780
2792
  mainnet: true,
2793
+ logo: chainLogo(ChainKeys.INJECTIVE_MAINNET),
2781
2794
  explorer: {
2782
2795
  baseUrl: "https://www.mintscan.io/injective/",
2783
2796
  txUrl: "https://www.mintscan.io/injective/tx/",
@@ -2791,6 +2804,7 @@ var baseChainInfo = {
2791
2804
  type: "STELLAR",
2792
2805
  chainId: "stellar",
2793
2806
  mainnet: true,
2807
+ logo: chainLogo(ChainKeys.STELLAR_MAINNET),
2794
2808
  explorer: {
2795
2809
  baseUrl: "https://stellar.expert/explorer/public/",
2796
2810
  txUrl: "https://stellar.expert/explorer/public/tx/",
@@ -2804,6 +2818,7 @@ var baseChainInfo = {
2804
2818
  type: "SUI",
2805
2819
  chainId: "sui",
2806
2820
  mainnet: true,
2821
+ logo: chainLogo(ChainKeys.SUI_MAINNET),
2807
2822
  explorer: {
2808
2823
  baseUrl: "https://suivision.xyz/",
2809
2824
  txUrl: "https://suivision.xyz/txblock/",
@@ -2817,6 +2832,7 @@ var baseChainInfo = {
2817
2832
  type: "ICON",
2818
2833
  chainId: "0x1.icon",
2819
2834
  mainnet: true,
2835
+ logo: chainLogo(ChainKeys.ICON_MAINNET),
2820
2836
  explorer: {
2821
2837
  baseUrl: "https://tracker.icon.community/",
2822
2838
  txUrl: "https://tracker.icon.community/transaction/",
@@ -2830,6 +2846,7 @@ var baseChainInfo = {
2830
2846
  type: "NEAR",
2831
2847
  chainId: "near",
2832
2848
  mainnet: true,
2849
+ logo: chainLogo(ChainKeys.NEAR_MAINNET),
2833
2850
  explorer: {
2834
2851
  baseUrl: "https://nearblocks.io/",
2835
2852
  txUrl: "https://nearblocks.io/txns/",
@@ -2843,6 +2860,7 @@ var baseChainInfo = {
2843
2860
  type: "EVM",
2844
2861
  chainId: 1,
2845
2862
  mainnet: true,
2863
+ logo: chainLogo(ChainKeys.ETHEREUM_MAINNET),
2846
2864
  explorer: {
2847
2865
  baseUrl: "https://etherscan.io/",
2848
2866
  txUrl: "https://etherscan.io/tx/",
@@ -2856,6 +2874,7 @@ var baseChainInfo = {
2856
2874
  type: "BITCOIN",
2857
2875
  chainId: "bitcoin",
2858
2876
  mainnet: true,
2877
+ logo: chainLogo(ChainKeys.BITCOIN_MAINNET),
2859
2878
  explorer: {
2860
2879
  baseUrl: "https://mempool.space/",
2861
2880
  txUrl: "https://mempool.space/tx/",
@@ -2869,6 +2888,7 @@ var baseChainInfo = {
2869
2888
  type: "EVM",
2870
2889
  chainId: 151,
2871
2890
  mainnet: true,
2891
+ logo: chainLogo(ChainKeys.REDBELLY_MAINNET),
2872
2892
  explorer: {
2873
2893
  baseUrl: "https://redbelly.routescan.io/",
2874
2894
  txUrl: "https://redbelly.routescan.io/tx/",
@@ -2882,6 +2902,7 @@ var baseChainInfo = {
2882
2902
  type: "EVM",
2883
2903
  chainId: 8217,
2884
2904
  mainnet: true,
2905
+ logo: chainLogo(ChainKeys.KAIA_MAINNET),
2885
2906
  explorer: {
2886
2907
  baseUrl: "https://klaytnfinder.io/",
2887
2908
  txUrl: "https://klaytnfinder.io/tx/",
@@ -2895,6 +2916,7 @@ var baseChainInfo = {
2895
2916
  type: "STACKS",
2896
2917
  chainId: "stacks",
2897
2918
  mainnet: true,
2919
+ logo: chainLogo(ChainKeys.STACKS_MAINNET),
2898
2920
  explorer: {
2899
2921
  baseUrl: "https://explorer.hiro.so/",
2900
2922
  txUrl: "https://explorer.hiro.so/txid/",
@@ -3886,8 +3908,11 @@ var swapSupportedTokens = {
3886
3908
  spokeChainConfig[ChainKeys.SUI_MAINNET].supportedTokens.WAL,
3887
3909
  spokeChainConfig[ChainKeys.SUI_MAINNET].supportedTokens.NAVX
3888
3910
  ],
3889
- // Injective is currently staging-only — see stagingSwapSupportedTokens
3890
- [ChainKeys.INJECTIVE_MAINNET]: [],
3911
+ [ChainKeys.INJECTIVE_MAINNET]: [
3912
+ spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.INJ,
3913
+ spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.bnUSD,
3914
+ spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.USDC
3915
+ ],
3891
3916
  [ChainKeys.NEAR_MAINNET]: [
3892
3917
  spokeChainConfig[ChainKeys.NEAR_MAINNET].supportedTokens.NEAR,
3893
3918
  spokeChainConfig[ChainKeys.NEAR_MAINNET].supportedTokens.bnUSD,
@@ -3976,12 +4001,7 @@ var stagingSwapSupportedTokens = {
3976
4001
  [ChainKeys.ICON_MAINNET]: [],
3977
4002
  [ChainKeys.STELLAR_MAINNET]: [],
3978
4003
  [ChainKeys.SUI_MAINNET]: [spokeChainConfig[ChainKeys.SUI_MAINNET].supportedTokens.USDT],
3979
- [ChainKeys.INJECTIVE_MAINNET]: [
3980
- spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.INJ,
3981
- spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.bnUSD,
3982
- spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.USDC
3983
- // spokeChainConfig[ChainKeys.INJECTIVE_MAINNET].supportedTokens.SODA, // NOTE: not in solver wiki
3984
- ],
4004
+ [ChainKeys.INJECTIVE_MAINNET]: [],
3985
4005
  [ChainKeys.NEAR_MAINNET]: [],
3986
4006
  [ChainKeys.BITCOIN_MAINNET]: [],
3987
4007
  [ChainKeys.ETHEREUM_MAINNET]: [
@@ -4087,6 +4107,31 @@ function usesBip322MessageSigning(addressType) {
4087
4107
  var BTC_WALLET_ADDRESS_TYPES = ["taproot", "segwit"];
4088
4108
  var BTC_ADDRESS_TYPES = ["P2PKH", "P2SH", "P2WPKH", "P2TR"];
4089
4109
 
4110
+ // ../types/dist/hooks/hooks.js
4111
+ var HookKind = {
4112
+ /** Deposits delivered USDC into the recipient's HyperCore perps account (HyperEVM). */
4113
+ HYPERCORE_DEPOSIT: "hyperCoreDeposit"
4114
+ };
4115
+ var spokeHooks = {
4116
+ [ChainKeys.HYPEREVM_MAINNET]: [
4117
+ {
4118
+ kind: HookKind.HYPERCORE_DEPOSIT,
4119
+ address: "0xc79224a4DEE653C9a26572B941149d95a88432c4",
4120
+ supportedTokens: [spokeChainConfig[ChainKeys.HYPEREVM_MAINNET].supportedTokens.USDC.address]
4121
+ // USDC on HyperEVM
4122
+ }
4123
+ ]
4124
+ };
4125
+ var getSpokeHook = (chainKey, kind) => spokeHooks[chainKey]?.find((h) => h.kind === kind);
4126
+ var getSpokeHooks = (chainKey) => spokeHooks[chainKey] ?? [];
4127
+ var isHookSupportedToken = (chainKey, kind, token) => {
4128
+ const hook = getSpokeHook(chainKey, kind);
4129
+ if (!hook) {
4130
+ return false;
4131
+ }
4132
+ return !hook.supportedTokens || hook.supportedTokens.some((t) => t.toLowerCase() === token.toLowerCase());
4133
+ };
4134
+
4090
4135
  // ../types/dist/utils/utils.js
4091
4136
  function isHubChainKey(chainId) {
4092
4137
  return chainId === HUB_CHAIN_KEY;
@@ -4201,7 +4246,7 @@ function isValidWalletProviderForChainKey(chainKey, walletProvider) {
4201
4246
  }
4202
4247
 
4203
4248
  // ../types/dist/index.js
4204
- var CONFIG_VERSION = 214;
4249
+ var CONFIG_VERSION = 216;
4205
4250
  function isEvmSpokeChainConfig(value) {
4206
4251
  return typeof value === "object" && value !== null && value.chain.type === "EVM" && value.chain.key !== HUB_CHAIN_KEY;
4207
4252
  }
@@ -10604,6 +10649,144 @@ var ProtocolIntentsAbi = [
10604
10649
  }
10605
10650
  ],
10606
10651
  stateMutability: "view"
10652
+ },
10653
+ {
10654
+ type: "function",
10655
+ name: "cancelIntent",
10656
+ inputs: [
10657
+ {
10658
+ name: "fromToken",
10659
+ type: "address",
10660
+ internalType: "address"
10661
+ },
10662
+ {
10663
+ name: "toToken",
10664
+ type: "address",
10665
+ internalType: "address"
10666
+ }
10667
+ ],
10668
+ outputs: [],
10669
+ stateMutability: "nonpayable"
10670
+ },
10671
+ {
10672
+ type: "function",
10673
+ name: "getUserIntent",
10674
+ inputs: [
10675
+ {
10676
+ name: "user",
10677
+ type: "address",
10678
+ internalType: "address"
10679
+ },
10680
+ {
10681
+ name: "fromToken",
10682
+ type: "address",
10683
+ internalType: "address"
10684
+ },
10685
+ {
10686
+ name: "toToken",
10687
+ type: "address",
10688
+ internalType: "address"
10689
+ }
10690
+ ],
10691
+ outputs: [
10692
+ {
10693
+ name: "intentHash",
10694
+ type: "bytes32",
10695
+ internalType: "bytes32"
10696
+ }
10697
+ ],
10698
+ stateMutability: "view"
10699
+ },
10700
+ {
10701
+ type: "function",
10702
+ name: "getIntentDetails",
10703
+ inputs: [
10704
+ {
10705
+ name: "intentHash",
10706
+ type: "bytes32",
10707
+ internalType: "bytes32"
10708
+ }
10709
+ ],
10710
+ outputs: [
10711
+ {
10712
+ name: "intent",
10713
+ type: "tuple",
10714
+ internalType: "struct Intents.Intent",
10715
+ components: [
10716
+ {
10717
+ name: "intentId",
10718
+ type: "uint256",
10719
+ internalType: "uint256"
10720
+ },
10721
+ {
10722
+ name: "creator",
10723
+ type: "address",
10724
+ internalType: "address"
10725
+ },
10726
+ {
10727
+ name: "inputToken",
10728
+ type: "address",
10729
+ internalType: "address"
10730
+ },
10731
+ {
10732
+ name: "outputToken",
10733
+ type: "address",
10734
+ internalType: "address"
10735
+ },
10736
+ {
10737
+ name: "inputAmount",
10738
+ type: "uint256",
10739
+ internalType: "uint256"
10740
+ },
10741
+ {
10742
+ name: "minOutputAmount",
10743
+ type: "uint256",
10744
+ internalType: "uint256"
10745
+ },
10746
+ {
10747
+ name: "deadline",
10748
+ type: "uint256",
10749
+ internalType: "uint256"
10750
+ },
10751
+ {
10752
+ name: "allowPartialFill",
10753
+ type: "bool",
10754
+ internalType: "bool"
10755
+ },
10756
+ {
10757
+ name: "srcChain",
10758
+ type: "uint256",
10759
+ internalType: "uint256"
10760
+ },
10761
+ {
10762
+ name: "dstChain",
10763
+ type: "uint256",
10764
+ internalType: "uint256"
10765
+ },
10766
+ {
10767
+ name: "srcAddress",
10768
+ type: "bytes",
10769
+ internalType: "bytes"
10770
+ },
10771
+ {
10772
+ name: "dstAddress",
10773
+ type: "bytes",
10774
+ internalType: "bytes"
10775
+ },
10776
+ {
10777
+ name: "solver",
10778
+ type: "address",
10779
+ internalType: "address"
10780
+ },
10781
+ {
10782
+ name: "data",
10783
+ type: "bytes",
10784
+ internalType: "bytes"
10785
+ }
10786
+ ]
10787
+ }
10788
+ ],
10789
+ stateMutability: "view"
10607
10790
  }
10608
10791
  ];
10609
10792
 
@@ -13511,6 +13694,68 @@ function resolveLogger(option) {
13511
13694
  return option;
13512
13695
  }
13513
13696
 
13697
+ // src/shared/analytics.ts
13698
+ var noopAnalytics = {
13699
+ isEnabled: () => false,
13700
+ emit: () => {
13701
+ },
13702
+ trackResult: (_feature, _action, run) => run()
13703
+ };
13704
+ var LEVEL_RANK = { basic: 0, detailed: 1 };
13705
+ function normalizeFeatures(features) {
13706
+ if (features === void 0) return null;
13707
+ const map = /* @__PURE__ */ new Map();
13708
+ if (Array.isArray(features)) {
13709
+ for (const feature of features) map.set(feature, true);
13710
+ } else {
13711
+ for (const [feature, scope] of Object.entries(features)) {
13712
+ if (scope === true) map.set(feature, true);
13713
+ else if (scope) map.set(feature, new Set(scope.actions));
13714
+ }
13715
+ }
13716
+ return map;
13717
+ }
13718
+ function resolveAnalytics(option) {
13719
+ if (!option) return noopAnalytics;
13720
+ const { tracker, level: configuredLevel = "basic", features } = option;
13721
+ const maxRank = LEVEL_RANK[configuredLevel];
13722
+ const allow = normalizeFeatures(features);
13723
+ const isEnabled = (feature, action, level = "basic") => {
13724
+ if (LEVEL_RANK[level] > maxRank) return false;
13725
+ if (allow === null) return true;
13726
+ const scope = allow.get(feature);
13727
+ if (scope === void 0) return false;
13728
+ if (scope === true) return true;
13729
+ if (action === void 0) return scope.size > 0;
13730
+ return scope.has(action);
13731
+ };
13732
+ const emit = (feature, action, phase, build, level = "basic") => {
13733
+ if (!isEnabled(feature, action, level)) return;
13734
+ try {
13735
+ tracker({ feature, action, phase, level, data: build?.() });
13736
+ } catch {
13737
+ }
13738
+ };
13739
+ const trackResult = async (feature, action, run, data) => {
13740
+ emit(feature, action, "start", data?.start);
13741
+ try {
13742
+ const result = await run();
13743
+ if (result.ok) {
13744
+ const build = data?.success;
13745
+ emit(feature, action, "success", build ? () => build(result.value) : void 0);
13746
+ } else {
13747
+ const build = data?.failure;
13748
+ emit(feature, action, "failure", build ? () => build(result.error) : void 0);
13749
+ }
13750
+ return result;
13751
+ } catch (error) {
13752
+ emit(feature, action, "failure", () => ({ error: error instanceof Error ? error.message : String(error) }));
13753
+ throw error;
13754
+ }
13755
+ };
13756
+ return { isEnabled, emit, trackResult };
13757
+ }
13758
+
13514
13759
  // src/shared/config/ConfigService.ts
13515
13760
  var ConfigService = class {
13516
13761
  sodax;
@@ -13521,6 +13766,12 @@ var ConfigService = class {
13521
13766
  * {@link initialize}'s dynamic-config swap never clobbers it. Read by services via `config.logger`.
13522
13767
  */
13523
13768
  logger;
13769
+ /**
13770
+ * Analytics emitter. Resolved once at construction and kept independent of {@link sodax} so that
13771
+ * {@link initialize}'s dynamic-config swap never clobbers it. Read by services via `config.analytics`;
13772
+ * disabled (no-op) unless the consumer passed an `analytics` config to `new Sodax(...)`.
13773
+ */
13774
+ analytics;
13524
13775
  /**
13525
13776
  * Global partner fee. Resolved once at construction and kept independent of {@link sodax} so that
13526
13777
  * {@link initialize}'s dynamic-config swap never clobbers it. The backend never supplies it — it is
@@ -13538,11 +13789,12 @@ var ConfigService = class {
13538
13789
  stakedATokenAddressesSet;
13539
13790
  chainToSupportedTokenAddressMap;
13540
13791
  hubAssetToXTokenMap;
13541
- constructor({ api, config, userConfig, logger, fee }) {
13792
+ constructor({ api, config, userConfig, logger, analytics, fee }) {
13542
13793
  this.api = api;
13543
13794
  this.sodax = config;
13544
13795
  this.userConfig = userConfig;
13545
13796
  this.logger = logger ?? resolveLogger(void 0);
13797
+ this.analytics = analytics ?? noopAnalytics;
13546
13798
  this.fee = fee;
13547
13799
  this.loadSodaxConfigDataStructures(config);
13548
13800
  }
@@ -13593,6 +13845,16 @@ var ConfigService = class {
13593
13845
  getOriginalAssetAddress(chainId, hubAsset) {
13594
13846
  return this.hubAssetToXTokenMap.get(hubAsset.toLowerCase())?.address;
13595
13847
  }
13848
+ /**
13849
+ * Resolves the {@link XToken} descriptor (hub asset, vault, decimals) for a hub-asset address.
13850
+ *
13851
+ * Useful when a caller holds a hub asset directly on Sonic that has no spoke-token entry under
13852
+ * the hub chain — e.g. a partner BTC fee held as the BTC hub asset, which only exists as a spoke
13853
+ * token on Bitcoin. Returns `undefined` when the address is not a known hub asset.
13854
+ */
13855
+ getXTokenFromHubAsset(hubAsset) {
13856
+ return this.hubAssetToXTokenMap.get(hubAsset.toLowerCase());
13857
+ }
13596
13858
  getSpokeTokenFromOriginalAssetAddress(chainId, originalAssetAddress) {
13597
13859
  return this.supportedTokensPerChain.get(chainId)?.find((token) => token.address.toLowerCase() === originalAssetAddress.toLowerCase());
13598
13860
  }
@@ -21852,9 +22114,147 @@ var NearSpokeService = class {
21852
22114
 
21853
22115
  // src/shared/types/intent-types.ts
21854
22116
  var IntentDataType = /* @__PURE__ */ ((IntentDataType2) => {
22117
+ IntentDataType2[IntentDataType2["ARRAY"] = 0] = "ARRAY";
21855
22118
  IntentDataType2[IntentDataType2["FEE"] = 1] = "FEE";
22119
+ IntentDataType2[IntentDataType2["HOOK"] = 2] = "HOOK";
22120
+ IntentDataType2[IntentDataType2["DELIVERY"] = 3] = "DELIVERY";
21856
22121
  return IntentDataType2;
21857
22122
  })(IntentDataType || {});
22123
+ var HOOK_DELIVERY_ABI = {
22124
+ // HyperCoreDepositHook expects `abi.encode(address)` — the HyperCore account to credit.
22125
+ [HookKind.HYPERCORE_DEPOSIT]: [{ name: "recipient", type: "address" }]
22126
+ };
22127
+ var HookService = class _HookService {
22128
+ constructor() {
22129
+ }
22130
+ /**
22131
+ * Encodes a hook's `deliveryData` payload. One common entry point for all hooks — the encoding is
22132
+ * selected by {@link HookRequest.kind} and uses that hook's schema from {@link HOOK_DELIVERY_ABI}.
22133
+ *
22134
+ * @param request - The hook selection (and any hook-specific params).
22135
+ * @param recipient - The end recipient the hook should credit (the intent's `dstAddress`).
22136
+ */
22137
+ static encodeDeliveryData(request, recipient) {
22138
+ switch (request.kind) {
22139
+ case HookKind.HYPERCORE_DEPOSIT:
22140
+ return viem.encodeAbiParameters(HOOK_DELIVERY_ABI[HookKind.HYPERCORE_DEPOSIT], [recipient]);
22141
+ }
22142
+ throw new Error(
22143
+ `[HookService.encodeDeliveryData] Unsupported delivery hook kind: ${request.kind}`
22144
+ );
22145
+ }
22146
+ /**
22147
+ * Resolves a high-level {@link HookRequest} to the on-chain delivery pair: the deployed hook address
22148
+ * (becomes the intent's `dstAddress`) and the encoded payload the hook expects (`deliveryData`).
22149
+ * Bundling lookup + codec here guarantees the address and its payload schema can never drift.
22150
+ *
22151
+ * @param chainKey - Destination spoke chain (must have the requested hook deployed).
22152
+ * @param request - The hook selection (and any hook-specific params).
22153
+ * @param recipient - The end recipient the hook should credit (the intent's `dstAddress`).
22154
+ */
22155
+ static resolveDeliveryHook(chainKey, request, recipient) {
22156
+ const hook = getSpokeHook(chainKey, request.kind);
22157
+ invariant(hook, `No '${request.kind}' delivery hook is deployed on chain ${chainKey}`);
22158
+ return { dstAddress: hook.address, deliveryData: _HookService.encodeDeliveryData(request, recipient) };
22159
+ }
22160
+ /**
22161
+ * Resolves the effective delivery target for an intent. When {@link CreateIntentParams.hook} is set,
22162
+ * routes the output through that registered hook (overriding `dstAddress` and deriving `deliveryData`);
22163
+ * otherwise returns the caller's `dstAddress` and low-level `deliveryData` unchanged. Centralised so
22164
+ * both the hub and Sonic intent constructors apply hooks identically.
22165
+ *
22166
+ * @returns `{ dstAddress, deliveryData }` — the address to deliver to and the payload to forward.
22167
+ */
22168
+ static resolveDelivery(params) {
22169
+ if (!params.hook) {
22170
+ return { dstAddress: params.dstAddress, deliveryData: params.deliveryData };
22171
+ }
22172
+ return _HookService.resolveDeliveryHook(params.dstChainKey, params.hook, params.dstAddress);
22173
+ }
22174
+ };
22175
+ var ARRAY_DATA_ABI = [
22176
+ {
22177
+ type: "tuple",
22178
+ components: [
22179
+ {
22180
+ name: "data",
22181
+ type: "tuple[]",
22182
+ components: [
22183
+ { name: "dataType", type: "uint8" },
22184
+ { name: "data", type: "bytes" }
22185
+ ]
22186
+ }
22187
+ ]
22188
+ }
22189
+ ];
22190
+ var IntentDataService = class _IntentDataService {
22191
+ constructor() {
22192
+ }
22193
+ /**
22194
+ * Folds a partner-fee envelope and an optional delivery payload into the final `Intent.data`:
22195
+ * - Neither → `'0x'`.
22196
+ * - Exactly one → that single packed `[uint8 type, bytes payload]` envelope (byte-identical to a
22197
+ * bare fee envelope, so a fee-only intent's `data` is unchanged and stays decode-stable).
22198
+ * - Both → a `TYPE_ARRAY` envelope wrapping `[FEE, DELIVERY]` entries.
22199
+ *
22200
+ * @param feeEnvelope - The packed fee envelope from `EvmSolverService.createIntentFeeData` (`'0x'` if no fee).
22201
+ * @param deliveryData - Opaque delivery payload (e.g. from `HookService.encodeDeliveryData`), or `undefined`.
22202
+ */
22203
+ static composeIntentData(feeEnvelope, deliveryData) {
22204
+ const entries = [];
22205
+ if (feeEnvelope !== "0x") {
22206
+ entries.push({ type: 1 /* FEE */, data: `0x${feeEnvelope.slice(4)}` });
22207
+ }
22208
+ if (deliveryData && deliveryData !== "0x") {
22209
+ entries.push({ type: 3 /* DELIVERY */, data: deliveryData });
22210
+ }
22211
+ return _IntentDataService.encodeIntentData(entries);
22212
+ }
22213
+ /**
22214
+ * Encodes a list of typed `IntentData` entries into the `Intent.data` bytes the contract decodes.
22215
+ * Empty → `'0x'`; single → a packed `[uint8 type, bytes payload]` envelope; multiple → a `TYPE_ARRAY`
22216
+ * envelope wrapping the entries as `ArrayData { DataEntry[] }`.
22217
+ */
22218
+ static encodeIntentData(entries) {
22219
+ if (entries.length === 0) {
22220
+ return "0x";
22221
+ }
22222
+ const [first] = entries;
22223
+ if (first && entries.length === 1) {
22224
+ return viem.encodePacked(["uint8", "bytes"], [first.type, first.data]);
22225
+ }
22226
+ const encodedArray = viem.encodeAbiParameters(ARRAY_DATA_ABI, [
22227
+ { data: entries.map((e) => ({ dataType: e.type, data: e.data })) }
22228
+ ]);
22229
+ return viem.encodePacked(["uint8", "bytes"], [0 /* ARRAY */, encodedArray]);
22230
+ }
22231
+ /**
22232
+ * Extracts the raw `FeeData` payload (`abi.encode(uint256 fee, address receiver)`) from an intent's
22233
+ * `data`, unwrapping whichever envelope shape it uses. Returns `undefined` when there is no fee:
22234
+ * empty `data`, a delivery-only envelope, or an unknown type byte (logged). Used by
22235
+ * `EvmSolverService.decodeIntentFeeAmount` to recover fees regardless of delivery data.
22236
+ */
22237
+ static extractFeePayload(data) {
22238
+ if (data === "0x" || data.length <= 2) {
22239
+ return void 0;
22240
+ }
22241
+ const typeByte = Number.parseInt(data.slice(2, 4), 16);
22242
+ if (typeByte === 1 /* FEE */) {
22243
+ return `0x${data.slice(4)}`;
22244
+ }
22245
+ if (typeByte === 0 /* ARRAY */) {
22246
+ const [arrayData] = viem.decodeAbiParameters(ARRAY_DATA_ABI, `0x${data.slice(4)}`);
22247
+ return arrayData.data.find((e) => e.dataType === 1 /* FEE */)?.data;
22248
+ }
22249
+ if (typeByte === 3 /* DELIVERY */) {
22250
+ return void 0;
22251
+ }
22252
+ console.error(
22253
+ `[IntentDataService.extractFeePayload] Unknown IntentData type byte: ${typeByte}. Gracefully returning no fee.`
22254
+ );
22255
+ return void 0;
22256
+ }
22257
+ };
21858
22258
  var IntentCreatedEventAbi = viem.getAbiItem({ abi: IntentsAbi, name: "IntentCreated" });
21859
22259
  var IntentFilledEventAbi = viem.getAbiItem({ abi: IntentsAbi, name: "IntentFilled" });
21860
22260
  var MintPositionEventAbi = viem.getAbiItem({ abi: infinitySdk.CLPositionManagerAbi, name: "MintPosition" });
@@ -21893,7 +22293,9 @@ var EvmSolverService = class _EvmSolverService {
21893
22293
  outputToken,
21894
22294
  `hub asset not found for spoke chain token (intent.outputToken): ${createIntentParams.outputToken}`
21895
22295
  );
21896
- const [feeData, feeAmount] = _EvmSolverService.createIntentFeeData(fee, createIntentParams.inputAmount);
22296
+ const { dstAddress, deliveryData } = HookService.resolveDelivery(createIntentParams);
22297
+ const [feeEnvelope, feeAmount] = _EvmSolverService.createIntentFeeData(fee, createIntentParams.inputAmount);
22298
+ const intentData = IntentDataService.composeIntentData(feeEnvelope, deliveryData);
21897
22299
  const calls = [];
21898
22300
  const intentsContract = config.solver.intentsContract;
21899
22301
  const intent = {
@@ -21908,10 +22310,10 @@ var EvmSolverService = class _EvmSolverService {
21908
22310
  srcChain: getIntentRelayChainId(createIntentParams.srcChainKey),
21909
22311
  dstChain: getIntentRelayChainId(createIntentParams.dstChainKey),
21910
22312
  srcAddress: encodeAddress(createIntentParams.srcChainKey, createIntentParams.srcAddress),
21911
- dstAddress: encodeAddress(createIntentParams.dstChainKey, createIntentParams.dstAddress),
22313
+ dstAddress: encodeAddress(createIntentParams.dstChainKey, dstAddress),
21912
22314
  solver: createIntentParams.solver ?? "0x0000000000000000000000000000000000000000",
21913
- data: feeData
21914
- // fee amount will be deducted from the input amount
22315
+ data: intentData
22316
+ // fee amount will be deducted from the input amount; may also carry delivery data
21915
22317
  };
21916
22318
  calls.push(Erc20Service.encodeApprove(intent.inputToken, intentsContract, createIntentParams.inputAmount));
21917
22319
  calls.push(_EvmSolverService.encodeCreateIntent(intent, intentsContract));
@@ -21972,29 +22374,25 @@ var EvmSolverService = class _EvmSolverService {
21972
22374
  /**
21973
22375
  * Recovers the partner fee amount embedded in an intent's `data` field.
21974
22376
  *
21975
- * Exact inverse of {@link createIntentFeeData}: `'0x'` means no fee (`0n`); otherwise the first
21976
- * byte is the {@link IntentDataType} tag (from the `encodePacked(['uint8','bytes'], …)` envelope)
21977
- * and the remainder is the ABI-encoded `(uint256 fee, address receiver)` struct.
22377
+ * Inverse of {@link createIntentFeeData}: returns the encoded fee, regardless of whether the `data`
22378
+ * is a bare fee envelope or a multi-entry envelope that also carries delivery data. The envelope
22379
+ * parsing lives in {@link IntentDataService.extractFeePayload}; this method just decodes the fee struct.
21978
22380
  *
21979
22381
  * @param data - The intent's `data` field (`'0x'` when no fee was configured).
21980
- * @returns The fee amount in the input token's smallest unit (`0n` when no fee data is present, or
21981
- * when the leading type byte is not {@link IntentDataType.FEE} — in which case it logs and degrades to `0n`).
22382
+ * @returns The fee amount in the input token's smallest unit (`0n` when no fee is present).
21982
22383
  */
21983
22384
  static decodeIntentFeeAmount(data) {
21984
- if (data === "0x" || data.length <= 2) {
21985
- return 0n;
21986
- }
21987
- const typeByte = Number.parseInt(data.slice(2, 4), 16);
21988
- if (typeByte !== 1 /* FEE */) {
21989
- console.error(`[decodeIntentFeeAmount] Unknown IntentData type byte: ${typeByte}. Gracefully returning 0n.`);
21990
- return 0n;
21991
- }
22385
+ const feePayload = IntentDataService.extractFeePayload(data);
22386
+ return feePayload ? _EvmSolverService.decodeFeePayload(feePayload) : 0n;
22387
+ }
22388
+ /** Decodes a raw `FeeData` payload (`abi.encode(uint256 fee, address receiver)`) to its fee amount. */
22389
+ static decodeFeePayload(payload) {
21992
22390
  const [feeAmount] = viem.decodeAbiParameters(
21993
22391
  [
21994
22392
  { name: "fee", type: "uint256" },
21995
22393
  { name: "receiver", type: "address" }
21996
22394
  ],
21997
- `0x${data.slice(4)}`
22395
+ payload
21998
22396
  );
21999
22397
  return feeAmount;
22000
22398
  }
@@ -22360,7 +22758,9 @@ var SonicSpokeService = class {
22360
22758
  outputToken,
22361
22759
  `hub asset not found for spoke chain token (intent.outputToken): ${createIntentParams.outputToken}`
22362
22760
  );
22363
- const [feeData, feeAmount] = EvmSolverService.createIntentFeeData(fee, createIntentParams.inputAmount);
22761
+ const { dstAddress, deliveryData } = HookService.resolveDelivery(createIntentParams);
22762
+ const [feeEnvelope, feeAmount] = EvmSolverService.createIntentFeeData(fee, createIntentParams.inputAmount);
22763
+ const intentData = IntentDataService.composeIntentData(feeEnvelope, deliveryData);
22364
22764
  const intentsContract = solverConfig2.intentsContract;
22365
22765
  const intent = {
22366
22766
  intentId: randomUint256(),
@@ -22374,10 +22774,10 @@ var SonicSpokeService = class {
22374
22774
  srcChain: getIntentRelayChainId(createIntentParams.srcChainKey),
22375
22775
  dstChain: getIntentRelayChainId(createIntentParams.dstChainKey),
22376
22776
  srcAddress: encodeAddress(createIntentParams.srcChainKey, createIntentParams.srcAddress),
22377
- dstAddress: encodeAddress(createIntentParams.dstChainKey, createIntentParams.dstAddress),
22777
+ dstAddress: encodeAddress(createIntentParams.dstChainKey, dstAddress),
22378
22778
  solver: createIntentParams.solver ?? "0x0000000000000000000000000000000000000000",
22379
- data: feeData
22380
- // fee amount will be deducted from the input amount
22779
+ data: intentData
22780
+ // fee amount will be deducted from the input amount; may also carry delivery data
22381
22781
  };
22382
22782
  const txData = EvmSolverService.encodeCreateIntent(intent, intentsContract);
22383
22783
  const rawTx = {
@@ -26242,64 +26642,88 @@ var SwapService = class {
26242
26642
  const { params } = _params;
26243
26643
  const srcChainKey = params.srcChainKey;
26244
26644
  const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey };
26245
- try {
26246
- const timeout = _params.timeout;
26247
- const createIntentResult = await this.createIntent(_params);
26248
- if (!createIntentResult.ok) {
26249
- return { ok: false, error: createIntentResult.error };
26250
- }
26251
- const { tx: spokeTxHash, intent, relayData } = createIntentResult.value;
26252
- const verifyTxHashResult = await this.spoke.verifyTxHash({
26253
- txHash: spokeTxHash,
26254
- chainKey: srcChainKey
26255
- });
26256
- if (!verifyTxHashResult.ok) {
26257
- return { ok: false, error: verifyFailed("swap", verifyTxHashResult.error, { ...baseCtx, action: "swap" }) };
26258
- }
26259
- let dstIntentTxHash;
26260
- if (isHubChainKeyType(srcChainKey)) {
26261
- dstIntentTxHash = spokeTxHash;
26262
- } else {
26263
- const packet = await relayTxAndWaitPacket({
26264
- srcTxHash: spokeTxHash,
26265
- data: relayData,
26266
- chainKey: srcChainKey,
26267
- relayerApiEndpoint: this.relayerApiEndpoint,
26268
- timeout
26269
- });
26270
- if (!packet.ok) {
26271
- return { ok: false, error: mapRelayFailure(packet.error, { feature: "swap", action: "swap", ...baseCtx }) };
26272
- }
26273
- dstIntentTxHash = packet.value.dst_tx_hash;
26274
- }
26275
- const postExecResult = await this.postExecution({
26276
- intent_tx_hash: dstIntentTxHash
26277
- });
26278
- if (!postExecResult.ok) {
26279
- return { ok: false, error: postExecResult.error };
26280
- }
26281
- return {
26282
- ok: true,
26283
- value: {
26284
- solverExecutionResponse: postExecResult.value,
26285
- intent,
26286
- intentDeliveryInfo: {
26287
- srcChainKey,
26288
- srcTxHash: spokeTxHash,
26289
- srcAddress: params.srcAddress,
26290
- dstChainKey: params.dstChainKey,
26291
- dstTxHash: dstIntentTxHash,
26292
- dstAddress: params.dstAddress
26645
+ return this.config.analytics.trackResult(
26646
+ "swap",
26647
+ "swap",
26648
+ async () => {
26649
+ try {
26650
+ const timeout = _params.timeout;
26651
+ const createIntentResult = await this.createIntent(_params);
26652
+ if (!createIntentResult.ok) {
26653
+ return { ok: false, error: createIntentResult.error };
26654
+ }
26655
+ const { tx: spokeTxHash, intent, relayData } = createIntentResult.value;
26656
+ const verifyTxHashResult = await this.spoke.verifyTxHash({
26657
+ txHash: spokeTxHash,
26658
+ chainKey: srcChainKey
26659
+ });
26660
+ if (!verifyTxHashResult.ok) {
26661
+ return { ok: false, error: verifyFailed("swap", verifyTxHashResult.error, { ...baseCtx, action: "swap" }) };
26662
+ }
26663
+ let dstIntentTxHash;
26664
+ if (isHubChainKeyType(srcChainKey)) {
26665
+ dstIntentTxHash = spokeTxHash;
26666
+ } else {
26667
+ const packet = await relayTxAndWaitPacket({
26668
+ srcTxHash: spokeTxHash,
26669
+ data: relayData,
26670
+ chainKey: srcChainKey,
26671
+ relayerApiEndpoint: this.relayerApiEndpoint,
26672
+ timeout
26673
+ });
26674
+ if (!packet.ok) {
26675
+ return {
26676
+ ok: false,
26677
+ error: mapRelayFailure(packet.error, { feature: "swap", action: "swap", ...baseCtx })
26678
+ };
26679
+ }
26680
+ dstIntentTxHash = packet.value.dst_tx_hash;
26293
26681
  }
26682
+ const postExecResult = await this.postExecution({
26683
+ intent_tx_hash: dstIntentTxHash
26684
+ });
26685
+ if (!postExecResult.ok) {
26686
+ return { ok: false, error: postExecResult.error };
26687
+ }
26688
+ return {
26689
+ ok: true,
26690
+ value: {
26691
+ solverExecutionResponse: postExecResult.value,
26692
+ intent,
26693
+ intentDeliveryInfo: {
26694
+ srcChainKey,
26695
+ srcTxHash: spokeTxHash,
26696
+ srcAddress: params.srcAddress,
26697
+ dstChainKey: params.dstChainKey,
26698
+ dstTxHash: dstIntentTxHash,
26699
+ dstAddress: params.dstAddress
26700
+ }
26701
+ }
26702
+ };
26703
+ } catch (error) {
26704
+ if (isSwapError(error)) return { ok: false, error };
26705
+ return {
26706
+ ok: false,
26707
+ error: unknownFailed("swap", error, { ...baseCtx, action: "swap" })
26708
+ };
26294
26709
  }
26295
- };
26296
- } catch (error) {
26297
- if (isSwapError(error)) return { ok: false, error };
26298
- return {
26299
- ok: false,
26300
- error: unknownFailed("swap", error, { ...baseCtx, action: "swap" })
26301
- };
26302
- }
26710
+ },
26711
+ {
26712
+ start: () => ({
26713
+ srcChainKey,
26714
+ dstChainKey: params.dstChainKey,
26715
+ srcAddress: params.srcAddress,
26716
+ dstAddress: params.dstAddress
26717
+ }),
26718
+ success: (value) => ({
26719
+ srcChainKey,
26720
+ dstChainKey: params.dstChainKey,
26721
+ srcTxHash: value.intentDeliveryInfo.srcTxHash,
26722
+ dstTxHash: value.intentDeliveryInfo.dstTxHash
26723
+ }),
26724
+ failure: (error) => ({ code: error.code })
26725
+ }
26726
+ );
26303
26727
  }
26304
26728
  /**
26305
26729
  * Checks whether the relevant spender contract is already approved to spend the input token amount.
@@ -28345,72 +28769,94 @@ var MigrationService = class {
28345
28769
  * }
28346
28770
  */
28347
28771
  async migratebnUSD(_params) {
28348
- const { params, timeout } = _params;
28349
- const baseCtx = {
28350
- srcChainKey: params.srcChainKey,
28351
- dstChainKey: params.dstChainKey,
28352
- action: "migratebnUSD"
28353
- };
28354
- try {
28355
- const intentResult = await this.createMigratebnUSDIntent(_params);
28356
- if (!intentResult.ok) return { ok: false, error: intentResult.error };
28357
- const { tx: spokeTxHash, relayData: extraData } = intentResult.value;
28358
- const verifyTxHashResult = await this.spoke.verifyTxHash({
28359
- txHash: spokeTxHash,
28360
- chainKey: params.srcChainKey
28361
- });
28362
- if (!verifyTxHashResult.ok) {
28363
- return {
28364
- ok: false,
28365
- error: verifyFailed("migration", verifyTxHashResult.error, baseCtx)
28366
- };
28367
- }
28368
- const packetResult = await relayTxAndWaitPacket({
28369
- srcTxHash: spokeTxHash,
28370
- data: extraData,
28371
- chainKey: params.srcChainKey,
28372
- relayerApiEndpoint: this.relayerApiEndpoint,
28373
- timeout
28374
- });
28375
- if (!packetResult.ok) {
28376
- return {
28377
- ok: false,
28378
- error: mapRelayFailure(packetResult.error, {
28379
- feature: "migration",
28380
- action: baseCtx.action,
28381
- srcChainKey: baseCtx.srcChainKey,
28382
- dstChainKey: baseCtx.dstChainKey
28383
- })
28772
+ return this.config.analytics.trackResult(
28773
+ "migration",
28774
+ "migratebnUSD",
28775
+ async () => {
28776
+ const { params, timeout } = _params;
28777
+ const baseCtx = {
28778
+ srcChainKey: params.srcChainKey,
28779
+ dstChainKey: params.dstChainKey,
28780
+ action: "migratebnUSD"
28384
28781
  };
28385
- }
28386
- if (!(params.srcChainKey === ChainKeys.SONIC_MAINNET || params.dstChainKey === ChainKeys.SONIC_MAINNET)) {
28387
- const execResult = await waitUntilIntentExecuted({
28388
- intentRelayChainId: getIntentRelayChainId(ChainKeys.SONIC_MAINNET).toString(),
28389
- srcTxHash: packetResult.value.dst_tx_hash,
28390
- timeout,
28391
- apiUrl: this.relayerApiEndpoint
28392
- });
28393
- if (!execResult.ok) {
28782
+ try {
28783
+ const intentResult = await this.createMigratebnUSDIntent(_params);
28784
+ if (!intentResult.ok) return { ok: false, error: intentResult.error };
28785
+ const { tx: spokeTxHash, relayData: extraData } = intentResult.value;
28786
+ const verifyTxHashResult = await this.spoke.verifyTxHash({
28787
+ txHash: spokeTxHash,
28788
+ chainKey: params.srcChainKey
28789
+ });
28790
+ if (!verifyTxHashResult.ok) {
28791
+ return {
28792
+ ok: false,
28793
+ error: verifyFailed("migration", verifyTxHashResult.error, baseCtx)
28794
+ };
28795
+ }
28796
+ const packetResult = await relayTxAndWaitPacket({
28797
+ srcTxHash: spokeTxHash,
28798
+ data: extraData,
28799
+ chainKey: params.srcChainKey,
28800
+ relayerApiEndpoint: this.relayerApiEndpoint,
28801
+ timeout
28802
+ });
28803
+ if (!packetResult.ok) {
28804
+ return {
28805
+ ok: false,
28806
+ error: mapRelayFailure(packetResult.error, {
28807
+ feature: "migration",
28808
+ action: baseCtx.action,
28809
+ srcChainKey: baseCtx.srcChainKey,
28810
+ dstChainKey: baseCtx.dstChainKey
28811
+ })
28812
+ };
28813
+ }
28814
+ if (!(params.srcChainKey === ChainKeys.SONIC_MAINNET || params.dstChainKey === ChainKeys.SONIC_MAINNET)) {
28815
+ const execResult = await waitUntilIntentExecuted({
28816
+ intentRelayChainId: getIntentRelayChainId(ChainKeys.SONIC_MAINNET).toString(),
28817
+ srcTxHash: packetResult.value.dst_tx_hash,
28818
+ timeout,
28819
+ apiUrl: this.relayerApiEndpoint
28820
+ });
28821
+ if (!execResult.ok) {
28822
+ return {
28823
+ ok: false,
28824
+ error: mapRelayFailure(execResult.error, {
28825
+ feature: "migration",
28826
+ action: baseCtx.action,
28827
+ srcChainKey: baseCtx.srcChainKey,
28828
+ dstChainKey: baseCtx.dstChainKey,
28829
+ phase: "destinationExecution"
28830
+ })
28831
+ };
28832
+ }
28833
+ }
28834
+ return { ok: true, value: { srcChainTxHash: spokeTxHash, dstChainTxHash: packetResult.value.dst_tx_hash } };
28835
+ } catch (error) {
28836
+ if (isMigrateOrchestrationError(error)) return { ok: false, error };
28394
28837
  return {
28395
28838
  ok: false,
28396
- error: mapRelayFailure(execResult.error, {
28397
- feature: "migration",
28398
- action: baseCtx.action,
28399
- srcChainKey: baseCtx.srcChainKey,
28400
- dstChainKey: baseCtx.dstChainKey,
28401
- phase: "destinationExecution"
28402
- })
28839
+ error: executionFailed("migration", error, baseCtx)
28403
28840
  };
28404
28841
  }
28842
+ },
28843
+ {
28844
+ start: () => ({
28845
+ srcChainKey: _params.params.srcChainKey,
28846
+ dstChainKey: _params.params.dstChainKey,
28847
+ srcAddress: _params.params.srcAddress,
28848
+ dstAddress: _params.params.dstAddress,
28849
+ srcbnUSD: _params.params.srcbnUSD,
28850
+ dstbnUSD: _params.params.dstbnUSD,
28851
+ amount: _params.params.amount
28852
+ }),
28853
+ success: (value) => ({
28854
+ srcChainTxHash: value.srcChainTxHash,
28855
+ dstChainTxHash: value.dstChainTxHash
28856
+ }),
28857
+ failure: (error) => ({ code: error.code })
28405
28858
  }
28406
- return { ok: true, value: { srcChainTxHash: spokeTxHash, dstChainTxHash: packetResult.value.dst_tx_hash } };
28407
- } catch (error) {
28408
- if (isMigrateOrchestrationError(error)) return { ok: false, error };
28409
- return {
28410
- ok: false,
28411
- error: executionFailed("migration", error, baseCtx)
28412
- };
28413
- }
28859
+ );
28414
28860
  }
28415
28861
  /**
28416
28862
  * Migrates ICX or wICX tokens from ICON to SODA on the hub chain (Sonic), including relay.
@@ -28425,37 +28871,57 @@ var MigrationService = class {
28425
28871
  * check fails, the deposit reverts, or the relay times out.
28426
28872
  */
28427
28873
  async migrateIcxToSoda(_params) {
28428
- const { timeout } = _params;
28429
- const baseCtx = { srcChainKey: _params.params.srcChainKey, action: "migrateIcxToSoda" };
28430
- try {
28431
- const txResult = await this.createMigrateIcxToSodaIntent(_params);
28432
- if (!txResult.ok) return { ok: false, error: txResult.error };
28433
- const { tx, relayData } = txResult.value;
28434
- const packetResult = await relayTxAndWaitPacket({
28435
- srcTxHash: tx,
28436
- data: relayData,
28437
- chainKey: _params.params.srcChainKey,
28438
- relayerApiEndpoint: this.relayerApiEndpoint,
28439
- timeout
28440
- });
28441
- if (!packetResult.ok) {
28442
- return {
28443
- ok: false,
28444
- error: mapRelayFailure(packetResult.error, {
28445
- feature: "migration",
28446
- action: baseCtx.action,
28447
- srcChainKey: baseCtx.srcChainKey
28448
- })
28449
- };
28874
+ return this.config.analytics.trackResult(
28875
+ "migration",
28876
+ "migrateIcxToSoda",
28877
+ async () => {
28878
+ const { timeout } = _params;
28879
+ const baseCtx = { srcChainKey: _params.params.srcChainKey, action: "migrateIcxToSoda" };
28880
+ try {
28881
+ const txResult = await this.createMigrateIcxToSodaIntent(_params);
28882
+ if (!txResult.ok) return { ok: false, error: txResult.error };
28883
+ const { tx, relayData } = txResult.value;
28884
+ const packetResult = await relayTxAndWaitPacket({
28885
+ srcTxHash: tx,
28886
+ data: relayData,
28887
+ chainKey: _params.params.srcChainKey,
28888
+ relayerApiEndpoint: this.relayerApiEndpoint,
28889
+ timeout
28890
+ });
28891
+ if (!packetResult.ok) {
28892
+ return {
28893
+ ok: false,
28894
+ error: mapRelayFailure(packetResult.error, {
28895
+ feature: "migration",
28896
+ action: baseCtx.action,
28897
+ srcChainKey: baseCtx.srcChainKey
28898
+ })
28899
+ };
28900
+ }
28901
+ return { ok: true, value: { srcChainTxHash: tx, dstChainTxHash: packetResult.value.dst_tx_hash } };
28902
+ } catch (error) {
28903
+ if (isMigrateOrchestrationError(error)) return { ok: false, error };
28904
+ return {
28905
+ ok: false,
28906
+ error: executionFailed("migration", error, baseCtx)
28907
+ };
28908
+ }
28909
+ },
28910
+ {
28911
+ start: () => ({
28912
+ srcChainKey: _params.params.srcChainKey,
28913
+ srcAddress: _params.params.srcAddress,
28914
+ dstAddress: _params.params.dstAddress,
28915
+ address: _params.params.address,
28916
+ amount: _params.params.amount
28917
+ }),
28918
+ success: (value) => ({
28919
+ srcChainTxHash: value.srcChainTxHash,
28920
+ dstChainTxHash: value.dstChainTxHash
28921
+ }),
28922
+ failure: (error) => ({ code: error.code })
28450
28923
  }
28451
- return { ok: true, value: { srcChainTxHash: tx, dstChainTxHash: packetResult.value.dst_tx_hash } };
28452
- } catch (error) {
28453
- if (isMigrateOrchestrationError(error)) return { ok: false, error };
28454
- return {
28455
- ok: false,
28456
- error: executionFailed("migration", error, baseCtx)
28457
- };
28458
- }
28924
+ );
28459
28925
  }
28460
28926
  /**
28461
28927
  * Reverts a previous ICX→SODA migration by swapping SODA back to wICX on the hub and
@@ -28473,37 +28939,56 @@ var MigrationService = class {
28473
28939
  * Sonic deposit transaction and `dstChainTxHash` is the hub-side packet receipt.
28474
28940
  */
28475
28941
  async revertMigrateSodaToIcx(_params) {
28476
- const { timeout } = _params;
28477
- const baseCtx = { srcChainKey: ChainKeys.SONIC_MAINNET, action: "revertMigrateSodaToIcx" };
28478
- try {
28479
- const txResult = await this.createRevertSodaToIcxMigrationIntent(_params);
28480
- if (!txResult.ok) return { ok: false, error: txResult.error };
28481
- const { tx, relayData } = txResult.value;
28482
- const packetResult = await relayTxAndWaitPacket({
28483
- srcTxHash: tx,
28484
- data: relayData,
28485
- chainKey: ChainKeys.SONIC_MAINNET,
28486
- relayerApiEndpoint: this.relayerApiEndpoint,
28487
- timeout
28488
- });
28489
- if (!packetResult.ok) {
28490
- return {
28491
- ok: false,
28492
- error: mapRelayFailure(packetResult.error, {
28493
- feature: "migration",
28494
- action: baseCtx.action,
28495
- srcChainKey: baseCtx.srcChainKey
28496
- })
28497
- };
28942
+ return this.config.analytics.trackResult(
28943
+ "migration",
28944
+ "revertMigrateSodaToIcx",
28945
+ async () => {
28946
+ const { timeout } = _params;
28947
+ const baseCtx = { srcChainKey: ChainKeys.SONIC_MAINNET, action: "revertMigrateSodaToIcx" };
28948
+ try {
28949
+ const txResult = await this.createRevertSodaToIcxMigrationIntent(_params);
28950
+ if (!txResult.ok) return { ok: false, error: txResult.error };
28951
+ const { tx, relayData } = txResult.value;
28952
+ const packetResult = await relayTxAndWaitPacket({
28953
+ srcTxHash: tx,
28954
+ data: relayData,
28955
+ chainKey: ChainKeys.SONIC_MAINNET,
28956
+ relayerApiEndpoint: this.relayerApiEndpoint,
28957
+ timeout
28958
+ });
28959
+ if (!packetResult.ok) {
28960
+ return {
28961
+ ok: false,
28962
+ error: mapRelayFailure(packetResult.error, {
28963
+ feature: "migration",
28964
+ action: baseCtx.action,
28965
+ srcChainKey: baseCtx.srcChainKey
28966
+ })
28967
+ };
28968
+ }
28969
+ return { ok: true, value: { srcChainTxHash: tx, dstChainTxHash: packetResult.value.dst_tx_hash } };
28970
+ } catch (error) {
28971
+ if (isRevertMigrationOrchestrationError(error)) return { ok: false, error };
28972
+ return {
28973
+ ok: false,
28974
+ error: executionFailed("migration", error, baseCtx)
28975
+ };
28976
+ }
28977
+ },
28978
+ {
28979
+ start: () => ({
28980
+ srcChainKey: _params.params.srcChainKey,
28981
+ srcAddress: _params.params.srcAddress,
28982
+ dstAddress: _params.params.dstAddress,
28983
+ amount: _params.params.amount
28984
+ }),
28985
+ success: (value) => ({
28986
+ srcChainTxHash: value.srcChainTxHash,
28987
+ dstChainTxHash: value.dstChainTxHash
28988
+ }),
28989
+ failure: (error) => ({ code: error.code })
28498
28990
  }
28499
- return { ok: true, value: { srcChainTxHash: tx, dstChainTxHash: packetResult.value.dst_tx_hash } };
28500
- } catch (error) {
28501
- if (isRevertMigrationOrchestrationError(error)) return { ok: false, error };
28502
- return {
28503
- ok: false,
28504
- error: executionFailed("migration", error, baseCtx)
28505
- };
28506
- }
28991
+ );
28507
28992
  }
28508
28993
  /**
28509
28994
  * Migrates BALN tokens from ICON to SODA on the hub chain (Sonic), including relay.
@@ -28520,37 +29005,58 @@ var MigrationService = class {
28520
29005
  * ICON deposit transaction and `dstChainTxHash` is the hub-side packet receipt.
28521
29006
  */
28522
29007
  async migrateBaln(_params) {
28523
- const { timeout } = _params;
28524
- const baseCtx = { srcChainKey: ChainKeys.ICON_MAINNET, action: "migrateBaln" };
28525
- try {
28526
- const txResult = await this.createMigrateBalnIntent(_params);
28527
- if (!txResult.ok) return { ok: false, error: txResult.error };
28528
- const { tx, relayData } = txResult.value;
28529
- const packetResult = await relayTxAndWaitPacket({
28530
- srcTxHash: tx,
28531
- data: relayData,
28532
- chainKey: ChainKeys.ICON_MAINNET,
28533
- relayerApiEndpoint: this.relayerApiEndpoint,
28534
- timeout
28535
- });
28536
- if (!packetResult.ok) {
28537
- return {
28538
- ok: false,
28539
- error: mapRelayFailure(packetResult.error, {
28540
- feature: "migration",
28541
- action: baseCtx.action,
28542
- srcChainKey: baseCtx.srcChainKey
28543
- })
28544
- };
29008
+ return this.config.analytics.trackResult(
29009
+ "migration",
29010
+ "migrateBaln",
29011
+ async () => {
29012
+ const { timeout } = _params;
29013
+ const baseCtx = { srcChainKey: ChainKeys.ICON_MAINNET, action: "migrateBaln" };
29014
+ try {
29015
+ const txResult = await this.createMigrateBalnIntent(_params);
29016
+ if (!txResult.ok) return { ok: false, error: txResult.error };
29017
+ const { tx, relayData } = txResult.value;
29018
+ const packetResult = await relayTxAndWaitPacket({
29019
+ srcTxHash: tx,
29020
+ data: relayData,
29021
+ chainKey: ChainKeys.ICON_MAINNET,
29022
+ relayerApiEndpoint: this.relayerApiEndpoint,
29023
+ timeout
29024
+ });
29025
+ if (!packetResult.ok) {
29026
+ return {
29027
+ ok: false,
29028
+ error: mapRelayFailure(packetResult.error, {
29029
+ feature: "migration",
29030
+ action: baseCtx.action,
29031
+ srcChainKey: baseCtx.srcChainKey
29032
+ })
29033
+ };
29034
+ }
29035
+ return { ok: true, value: { srcChainTxHash: tx, dstChainTxHash: packetResult.value.dst_tx_hash } };
29036
+ } catch (error) {
29037
+ if (isMigrateOrchestrationError(error)) return { ok: false, error };
29038
+ return {
29039
+ ok: false,
29040
+ error: executionFailed("migration", error, baseCtx)
29041
+ };
29042
+ }
29043
+ },
29044
+ {
29045
+ start: () => ({
29046
+ srcChainKey: _params.params.srcChainKey,
29047
+ srcAddress: _params.params.srcAddress,
29048
+ dstAddress: _params.params.dstAddress,
29049
+ amount: _params.params.amount,
29050
+ lockupPeriod: _params.params.lockupPeriod,
29051
+ stake: _params.params.stake
29052
+ }),
29053
+ success: (value) => ({
29054
+ srcChainTxHash: value.srcChainTxHash,
29055
+ dstChainTxHash: value.dstChainTxHash
29056
+ }),
29057
+ failure: (error) => ({ code: error.code })
28545
29058
  }
28546
- return { ok: true, value: { srcChainTxHash: tx, dstChainTxHash: packetResult.value.dst_tx_hash } };
28547
- } catch (error) {
28548
- if (isMigrateOrchestrationError(error)) return { ok: false, error };
28549
- return {
28550
- ok: false,
28551
- error: executionFailed("migration", error, baseCtx)
28552
- };
28553
- }
29059
+ );
28554
29060
  }
28555
29061
  /**
28556
29062
  * Builds and submits the spoke-side deposit for a BALN→SODA migration without relaying.
@@ -29604,49 +30110,71 @@ var BridgeService = class {
29604
30110
  * }
29605
30111
  */
29606
30112
  async bridge(_params) {
29607
- const { params, timeout } = _params;
29608
- const baseCtx = { srcChainKey: params.srcChainKey, dstChainKey: params.dstChainKey };
29609
- try {
29610
- const txResult = await this.createBridgeIntent(_params);
29611
- if (!txResult.ok) return { ok: false, error: txResult.error };
29612
- const verifyTxHashResult = await this.spoke.verifyTxHash({
29613
- txHash: txResult.value.tx,
29614
- chainKey: params.srcChainKey
29615
- });
29616
- if (!verifyTxHashResult.ok) {
29617
- return {
29618
- ok: false,
29619
- error: verifyFailed("bridge", verifyTxHashResult.error, baseCtx)
29620
- };
30113
+ return this.config.analytics.trackResult(
30114
+ "bridge",
30115
+ "bridge",
30116
+ async () => {
30117
+ const { params, timeout } = _params;
30118
+ const baseCtx = { srcChainKey: params.srcChainKey, dstChainKey: params.dstChainKey };
30119
+ try {
30120
+ const txResult = await this.createBridgeIntent(_params);
30121
+ if (!txResult.ok) return { ok: false, error: txResult.error };
30122
+ const verifyTxHashResult = await this.spoke.verifyTxHash({
30123
+ txHash: txResult.value.tx,
30124
+ chainKey: params.srcChainKey
30125
+ });
30126
+ if (!verifyTxHashResult.ok) {
30127
+ return {
30128
+ ok: false,
30129
+ error: verifyFailed("bridge", verifyTxHashResult.error, baseCtx)
30130
+ };
30131
+ }
30132
+ const packetResult = await relayTxAndWaitPacket({
30133
+ srcTxHash: txResult.value.tx,
30134
+ data: txResult.value.relayData,
30135
+ chainKey: params.srcChainKey,
30136
+ relayerApiEndpoint: this.config.relay.relayerApiEndpoint,
30137
+ timeout
30138
+ });
30139
+ if (!packetResult.ok)
30140
+ return {
30141
+ ok: false,
30142
+ error: mapRelayFailure(packetResult.error, {
30143
+ feature: "bridge",
30144
+ action: "bridge",
30145
+ srcChainKey: baseCtx.srcChainKey,
30146
+ dstChainKey: baseCtx.dstChainKey
30147
+ })
30148
+ };
30149
+ return {
30150
+ ok: true,
30151
+ value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: packetResult.value.dst_tx_hash }
30152
+ };
30153
+ } catch (error) {
30154
+ if (isBridgeOrchestrationError(error)) return { ok: false, error };
30155
+ return {
30156
+ ok: false,
30157
+ error: executionFailed("bridge", error, baseCtx)
30158
+ };
30159
+ }
30160
+ },
30161
+ {
30162
+ start: () => ({
30163
+ srcChainKey: _params.params.srcChainKey,
30164
+ dstChainKey: _params.params.dstChainKey,
30165
+ srcToken: _params.params.srcToken,
30166
+ dstToken: _params.params.dstToken,
30167
+ amount: _params.params.amount,
30168
+ srcAddress: _params.params.srcAddress,
30169
+ recipient: _params.params.recipient
30170
+ }),
30171
+ success: (value) => ({
30172
+ srcChainTxHash: value.srcChainTxHash,
30173
+ dstChainTxHash: value.dstChainTxHash
30174
+ }),
30175
+ failure: (error) => ({ code: error.code })
29621
30176
  }
29622
- const packetResult = await relayTxAndWaitPacket({
29623
- srcTxHash: txResult.value.tx,
29624
- data: txResult.value.relayData,
29625
- chainKey: params.srcChainKey,
29626
- relayerApiEndpoint: this.config.relay.relayerApiEndpoint,
29627
- timeout
29628
- });
29629
- if (!packetResult.ok)
29630
- return {
29631
- ok: false,
29632
- error: mapRelayFailure(packetResult.error, {
29633
- feature: "bridge",
29634
- action: "bridge",
29635
- srcChainKey: baseCtx.srcChainKey,
29636
- dstChainKey: baseCtx.dstChainKey
29637
- })
29638
- };
29639
- return {
29640
- ok: true,
29641
- value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: packetResult.value.dst_tx_hash }
29642
- };
29643
- } catch (error) {
29644
- if (isBridgeOrchestrationError(error)) return { ok: false, error };
29645
- return {
29646
- ok: false,
29647
- error: executionFailed("bridge", error, baseCtx)
29648
- };
29649
- }
30177
+ );
29650
30178
  }
29651
30179
  /**
29652
30180
  * Submits the spoke-side deposit transaction that initiates a bridge transfer,
@@ -29675,8 +30203,8 @@ var BridgeService = class {
29675
30203
  const baseCtx = { srcChainKey: params.srcChainKey, dstChainKey: params.dstChainKey };
29676
30204
  try {
29677
30205
  bridgeInvariant(params.amount > 0n, "Amount must be greater than 0", { ...baseCtx, field: "amount" });
29678
- const srcToken = this.config.getSpokeTokenFromOriginalAssetAddress(params.srcChainKey, params.srcToken);
29679
- const dstToken = this.config.getSpokeTokenFromOriginalAssetAddress(params.dstChainKey, params.dstToken);
30206
+ const srcToken = this.resolveBridgeEndpointToken(params.srcChainKey, params.srcToken);
30207
+ const dstToken = this.resolveBridgeEndpointToken(params.dstChainKey, params.dstToken);
29680
30208
  bridgeInvariant(srcToken, `Unsupported spoke chain (${params.srcChainKey}) token: ${params.srcToken}`, {
29681
30209
  ...baseCtx,
29682
30210
  field: "srcToken"
@@ -29744,6 +30272,20 @@ var BridgeService = class {
29744
30272
  };
29745
30273
  }
29746
30274
  }
30275
+ /**
30276
+ * Resolves a bridge endpoint's {@link XToken} descriptor from a chain key + token address.
30277
+ *
30278
+ * Spoke endpoints (and hub-native tokens such as USDC/WETH/S whose on-chain address equals their
30279
+ * hub asset) resolve by original asset address. On the hub a caller may instead hold a hub asset
30280
+ * that has no spoke-token entry under the hub chain — e.g. a partner BTC fee held as the BTC hub
30281
+ * asset, whose only spoke-token entry lives on Bitcoin. Resolve those by hub-asset address so the
30282
+ * Sonic-sourced "withdraw directly" bridge can find the matching vault/decimals.
30283
+ */
30284
+ resolveBridgeEndpointToken(chainKey, token) {
30285
+ const spokeToken = this.config.getSpokeTokenFromOriginalAssetAddress(chainKey, token);
30286
+ if (spokeToken) return spokeToken;
30287
+ return isHubChainKeyType(chainKey) ? this.config.getXTokenFromHubAsset(token) : void 0;
30288
+ }
29747
30289
  /**
29748
30290
  * Encodes the hub-side execution payload for a bridge operation.
29749
30291
  *
@@ -30626,52 +31168,71 @@ var StakingService = class {
30626
31168
  * @returns `{ ok: true, value: { srcChainTxHash, dstChainTxHash } }` on success.
30627
31169
  */
30628
31170
  async stake(_params) {
30629
- const { params, timeout } = _params;
30630
- const baseCtx = { srcChainKey: params.srcChainKey, action: "stake" };
30631
- try {
30632
- const txResult = await this.createStakeIntent(_params);
30633
- if (!txResult.ok) return { ok: false, error: txResult.error };
30634
- const verifyTxHashResult = await this.spoke.verifyTxHash({
30635
- txHash: txResult.value.tx,
30636
- chainKey: params.srcChainKey
30637
- });
30638
- if (!verifyTxHashResult.ok) {
30639
- return {
30640
- ok: false,
30641
- error: verifyFailed("staking", verifyTxHashResult.error, baseCtx)
30642
- };
30643
- }
30644
- let hubTxHash;
30645
- if (!isHubChainKeyType(params.srcChainKey)) {
30646
- const packetResult = await relayTxAndWaitPacket({
30647
- srcTxHash: txResult.value.tx,
30648
- data: txResult.value.relayData,
30649
- chainKey: params.srcChainKey,
30650
- relayerApiEndpoint: this.relayerApiEndpoint,
30651
- timeout
30652
- });
30653
- if (!packetResult.ok) {
31171
+ return this.config.analytics.trackResult(
31172
+ "staking",
31173
+ "stake",
31174
+ async () => {
31175
+ const { params, timeout } = _params;
31176
+ const baseCtx = { srcChainKey: params.srcChainKey, action: "stake" };
31177
+ try {
31178
+ const txResult = await this.createStakeIntent(_params);
31179
+ if (!txResult.ok) return { ok: false, error: txResult.error };
31180
+ const verifyTxHashResult = await this.spoke.verifyTxHash({
31181
+ txHash: txResult.value.tx,
31182
+ chainKey: params.srcChainKey
31183
+ });
31184
+ if (!verifyTxHashResult.ok) {
31185
+ return {
31186
+ ok: false,
31187
+ error: verifyFailed("staking", verifyTxHashResult.error, baseCtx)
31188
+ };
31189
+ }
31190
+ let hubTxHash;
31191
+ if (!isHubChainKeyType(params.srcChainKey)) {
31192
+ const packetResult = await relayTxAndWaitPacket({
31193
+ srcTxHash: txResult.value.tx,
31194
+ data: txResult.value.relayData,
31195
+ chainKey: params.srcChainKey,
31196
+ relayerApiEndpoint: this.relayerApiEndpoint,
31197
+ timeout
31198
+ });
31199
+ if (!packetResult.ok) {
31200
+ return {
31201
+ ok: false,
31202
+ error: mapRelayFailure(packetResult.error, {
31203
+ feature: "staking",
31204
+ action: baseCtx.action,
31205
+ srcChainKey: baseCtx.srcChainKey
31206
+ })
31207
+ };
31208
+ }
31209
+ hubTxHash = packetResult.value.dst_tx_hash;
31210
+ } else {
31211
+ hubTxHash = txResult.value.tx;
31212
+ }
31213
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
31214
+ } catch (error) {
31215
+ if (isStakeOrchestrationError(error)) return { ok: false, error };
30654
31216
  return {
30655
31217
  ok: false,
30656
- error: mapRelayFailure(packetResult.error, {
30657
- feature: "staking",
30658
- action: baseCtx.action,
30659
- srcChainKey: baseCtx.srcChainKey
30660
- })
31218
+ error: executionFailed("staking", error, baseCtx)
30661
31219
  };
30662
31220
  }
30663
- hubTxHash = packetResult.value.dst_tx_hash;
30664
- } else {
30665
- hubTxHash = txResult.value.tx;
31221
+ },
31222
+ {
31223
+ start: () => ({
31224
+ srcChainKey: _params.params.srcChainKey,
31225
+ srcAddress: _params.params.srcAddress,
31226
+ amount: _params.params.amount,
31227
+ minReceive: _params.params.minReceive
31228
+ }),
31229
+ success: (value) => ({
31230
+ srcChainTxHash: value.srcChainTxHash,
31231
+ dstChainTxHash: value.dstChainTxHash
31232
+ }),
31233
+ failure: (error) => ({ code: error.code })
30666
31234
  }
30667
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
30668
- } catch (error) {
30669
- if (isStakeOrchestrationError(error)) return { ok: false, error };
30670
- return {
30671
- ok: false,
30672
- error: executionFailed("staking", error, baseCtx)
30673
- };
30674
- }
31235
+ );
30675
31236
  }
30676
31237
  /**
30677
31238
  * Submits the stake transaction on the spoke chain without relaying to the hub.
@@ -30776,42 +31337,60 @@ var StakingService = class {
30776
31337
  * @returns `{ ok: true, value: { srcChainTxHash, dstChainTxHash } }` on success.
30777
31338
  */
30778
31339
  async unstake(_params) {
30779
- const { params, timeout } = _params;
30780
- const baseCtx = { srcChainKey: params.srcChainKey, action: "unstake" };
30781
- try {
30782
- const txResult = await this.createUnstakeIntent(_params);
30783
- if (!txResult.ok) return { ok: false, error: txResult.error };
30784
- let hubTxHash;
30785
- if (!isHubChainKeyType(params.srcChainKey)) {
30786
- const packetResult = await relayTxAndWaitPacket({
30787
- srcTxHash: txResult.value.tx,
30788
- data: txResult.value.relayData,
30789
- chainKey: params.srcChainKey,
30790
- relayerApiEndpoint: this.relayerApiEndpoint,
30791
- timeout
30792
- });
30793
- if (!packetResult.ok) {
31340
+ return this.config.analytics.trackResult(
31341
+ "staking",
31342
+ "unstake",
31343
+ async () => {
31344
+ const { params, timeout } = _params;
31345
+ const baseCtx = { srcChainKey: params.srcChainKey, action: "unstake" };
31346
+ try {
31347
+ const txResult = await this.createUnstakeIntent(_params);
31348
+ if (!txResult.ok) return { ok: false, error: txResult.error };
31349
+ let hubTxHash;
31350
+ if (!isHubChainKeyType(params.srcChainKey)) {
31351
+ const packetResult = await relayTxAndWaitPacket({
31352
+ srcTxHash: txResult.value.tx,
31353
+ data: txResult.value.relayData,
31354
+ chainKey: params.srcChainKey,
31355
+ relayerApiEndpoint: this.relayerApiEndpoint,
31356
+ timeout
31357
+ });
31358
+ if (!packetResult.ok) {
31359
+ return {
31360
+ ok: false,
31361
+ error: mapRelayFailure(packetResult.error, {
31362
+ feature: "staking",
31363
+ action: baseCtx.action,
31364
+ srcChainKey: baseCtx.srcChainKey
31365
+ })
31366
+ };
31367
+ }
31368
+ hubTxHash = packetResult.value.dst_tx_hash;
31369
+ } else {
31370
+ hubTxHash = txResult.value.tx;
31371
+ }
31372
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
31373
+ } catch (error) {
31374
+ if (isStakingOrchestrationError(error)) return { ok: false, error };
30794
31375
  return {
30795
31376
  ok: false,
30796
- error: mapRelayFailure(packetResult.error, {
30797
- feature: "staking",
30798
- action: baseCtx.action,
30799
- srcChainKey: baseCtx.srcChainKey
30800
- })
31377
+ error: executionFailed("staking", error, baseCtx)
30801
31378
  };
30802
31379
  }
30803
- hubTxHash = packetResult.value.dst_tx_hash;
30804
- } else {
30805
- hubTxHash = txResult.value.tx;
31380
+ },
31381
+ {
31382
+ start: () => ({
31383
+ srcChainKey: _params.params.srcChainKey,
31384
+ srcAddress: _params.params.srcAddress,
31385
+ amount: _params.params.amount
31386
+ }),
31387
+ success: (value) => ({
31388
+ srcChainTxHash: value.srcChainTxHash,
31389
+ dstChainTxHash: value.dstChainTxHash
31390
+ }),
31391
+ failure: (error) => ({ code: error.code })
30806
31392
  }
30807
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
30808
- } catch (error) {
30809
- if (isStakingOrchestrationError(error)) return { ok: false, error };
30810
- return {
30811
- ok: false,
30812
- error: executionFailed("staking", error, baseCtx)
30813
- };
30814
- }
31393
+ );
30815
31394
  }
30816
31395
  /**
30817
31396
  * Submits the unstake transaction on the spoke chain without relaying to the hub.
@@ -30907,42 +31486,61 @@ var StakingService = class {
30907
31486
  * @returns `{ ok: true, value: { srcChainTxHash, dstChainTxHash } }` on success.
30908
31487
  */
30909
31488
  async instantUnstake(_params) {
30910
- const { params, timeout } = _params;
30911
- const baseCtx = { srcChainKey: params.srcChainKey, action: "instantUnstake" };
30912
- try {
30913
- const txResult = await this.createInstantUnstakeIntent(_params);
30914
- if (!txResult.ok) return { ok: false, error: txResult.error };
30915
- let hubTxHash;
30916
- if (!isHubChainKeyType(params.srcChainKey)) {
30917
- const packetResult = await relayTxAndWaitPacket({
30918
- srcTxHash: txResult.value.tx,
30919
- data: txResult.value.relayData,
30920
- chainKey: params.srcChainKey,
30921
- relayerApiEndpoint: this.relayerApiEndpoint,
30922
- timeout
30923
- });
30924
- if (!packetResult.ok) {
31489
+ return this.config.analytics.trackResult(
31490
+ "staking",
31491
+ "instantUnstake",
31492
+ async () => {
31493
+ const { params, timeout } = _params;
31494
+ const baseCtx = { srcChainKey: params.srcChainKey, action: "instantUnstake" };
31495
+ try {
31496
+ const txResult = await this.createInstantUnstakeIntent(_params);
31497
+ if (!txResult.ok) return { ok: false, error: txResult.error };
31498
+ let hubTxHash;
31499
+ if (!isHubChainKeyType(params.srcChainKey)) {
31500
+ const packetResult = await relayTxAndWaitPacket({
31501
+ srcTxHash: txResult.value.tx,
31502
+ data: txResult.value.relayData,
31503
+ chainKey: params.srcChainKey,
31504
+ relayerApiEndpoint: this.relayerApiEndpoint,
31505
+ timeout
31506
+ });
31507
+ if (!packetResult.ok) {
31508
+ return {
31509
+ ok: false,
31510
+ error: mapRelayFailure(packetResult.error, {
31511
+ feature: "staking",
31512
+ action: baseCtx.action,
31513
+ srcChainKey: baseCtx.srcChainKey
31514
+ })
31515
+ };
31516
+ }
31517
+ hubTxHash = packetResult.value.dst_tx_hash;
31518
+ } else {
31519
+ hubTxHash = txResult.value.tx;
31520
+ }
31521
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
31522
+ } catch (error) {
31523
+ if (isStakingOrchestrationError(error)) return { ok: false, error };
30925
31524
  return {
30926
31525
  ok: false,
30927
- error: mapRelayFailure(packetResult.error, {
30928
- feature: "staking",
30929
- action: baseCtx.action,
30930
- srcChainKey: baseCtx.srcChainKey
30931
- })
31526
+ error: executionFailed("staking", error, baseCtx)
30932
31527
  };
30933
31528
  }
30934
- hubTxHash = packetResult.value.dst_tx_hash;
30935
- } else {
30936
- hubTxHash = txResult.value.tx;
31529
+ },
31530
+ {
31531
+ start: () => ({
31532
+ srcChainKey: _params.params.srcChainKey,
31533
+ srcAddress: _params.params.srcAddress,
31534
+ amount: _params.params.amount,
31535
+ minAmount: _params.params.minAmount
31536
+ }),
31537
+ success: (value) => ({
31538
+ srcChainTxHash: value.srcChainTxHash,
31539
+ dstChainTxHash: value.dstChainTxHash
31540
+ }),
31541
+ failure: (error) => ({ code: error.code })
30937
31542
  }
30938
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
30939
- } catch (error) {
30940
- if (isStakingOrchestrationError(error)) return { ok: false, error };
30941
- return {
30942
- ok: false,
30943
- error: executionFailed("staking", error, baseCtx)
30944
- };
30945
- }
31543
+ );
30946
31544
  }
30947
31545
  /**
30948
31546
  * Submits the instant-unstake transaction on the spoke chain without relaying to the hub.
@@ -31050,42 +31648,61 @@ var StakingService = class {
31050
31648
  * @returns `{ ok: true, value: { srcChainTxHash, dstChainTxHash } }` on success.
31051
31649
  */
31052
31650
  async claim(_params) {
31053
- const { params, timeout } = _params;
31054
- const baseCtx = { srcChainKey: params.srcChainKey, action: "claim" };
31055
- try {
31056
- const txResult = await this.createClaimIntent(_params);
31057
- if (!txResult.ok) return { ok: false, error: txResult.error };
31058
- let hubTxHash;
31059
- if (!isHubChainKeyType(params.srcChainKey)) {
31060
- const packetResult = await relayTxAndWaitPacket({
31061
- srcTxHash: txResult.value.tx,
31062
- data: txResult.value.relayData,
31063
- chainKey: params.srcChainKey,
31064
- relayerApiEndpoint: this.relayerApiEndpoint,
31065
- timeout
31066
- });
31067
- if (!packetResult.ok) {
31651
+ return this.config.analytics.trackResult(
31652
+ "staking",
31653
+ "claim",
31654
+ async () => {
31655
+ const { params, timeout } = _params;
31656
+ const baseCtx = { srcChainKey: params.srcChainKey, action: "claim" };
31657
+ try {
31658
+ const txResult = await this.createClaimIntent(_params);
31659
+ if (!txResult.ok) return { ok: false, error: txResult.error };
31660
+ let hubTxHash;
31661
+ if (!isHubChainKeyType(params.srcChainKey)) {
31662
+ const packetResult = await relayTxAndWaitPacket({
31663
+ srcTxHash: txResult.value.tx,
31664
+ data: txResult.value.relayData,
31665
+ chainKey: params.srcChainKey,
31666
+ relayerApiEndpoint: this.relayerApiEndpoint,
31667
+ timeout
31668
+ });
31669
+ if (!packetResult.ok) {
31670
+ return {
31671
+ ok: false,
31672
+ error: mapRelayFailure(packetResult.error, {
31673
+ feature: "staking",
31674
+ action: baseCtx.action,
31675
+ srcChainKey: baseCtx.srcChainKey
31676
+ })
31677
+ };
31678
+ }
31679
+ hubTxHash = packetResult.value.dst_tx_hash;
31680
+ } else {
31681
+ hubTxHash = txResult.value.tx;
31682
+ }
31683
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
31684
+ } catch (error) {
31685
+ if (isStakingOrchestrationError(error)) return { ok: false, error };
31068
31686
  return {
31069
31687
  ok: false,
31070
- error: mapRelayFailure(packetResult.error, {
31071
- feature: "staking",
31072
- action: baseCtx.action,
31073
- srcChainKey: baseCtx.srcChainKey
31074
- })
31688
+ error: executionFailed("staking", error, baseCtx)
31075
31689
  };
31076
31690
  }
31077
- hubTxHash = packetResult.value.dst_tx_hash;
31078
- } else {
31079
- hubTxHash = txResult.value.tx;
31691
+ },
31692
+ {
31693
+ start: () => ({
31694
+ srcChainKey: _params.params.srcChainKey,
31695
+ srcAddress: _params.params.srcAddress,
31696
+ requestId: _params.params.requestId,
31697
+ amount: _params.params.amount
31698
+ }),
31699
+ success: (value) => ({
31700
+ srcChainTxHash: value.srcChainTxHash,
31701
+ dstChainTxHash: value.dstChainTxHash
31702
+ }),
31703
+ failure: (error) => ({ code: error.code })
31080
31704
  }
31081
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
31082
- } catch (error) {
31083
- if (isStakingOrchestrationError(error)) return { ok: false, error };
31084
- return {
31085
- ok: false,
31086
- error: executionFailed("staking", error, baseCtx)
31087
- };
31088
- }
31705
+ );
31089
31706
  }
31090
31707
  /**
31091
31708
  * Submits the claim transaction on the spoke chain without relaying to the hub.
@@ -31199,42 +31816,60 @@ var StakingService = class {
31199
31816
  * @returns `{ ok: true, value: { srcChainTxHash, dstChainTxHash } }` on success.
31200
31817
  */
31201
31818
  async cancelUnstake(_params) {
31202
- const { params, timeout } = _params;
31203
- const baseCtx = { srcChainKey: params.srcChainKey, action: "cancelUnstake" };
31204
- try {
31205
- const txResult = await this.createCancelUnstakeIntent(_params);
31206
- if (!txResult.ok) return { ok: false, error: txResult.error };
31207
- let hubTxHash;
31208
- if (!isHubChainKeyType(params.srcChainKey)) {
31209
- const packetResult = await relayTxAndWaitPacket({
31210
- srcTxHash: txResult.value.tx,
31211
- data: txResult.value.relayData,
31212
- chainKey: params.srcChainKey,
31213
- relayerApiEndpoint: this.relayerApiEndpoint,
31214
- timeout
31215
- });
31216
- if (!packetResult.ok) {
31819
+ return this.config.analytics.trackResult(
31820
+ "staking",
31821
+ "cancelUnstake",
31822
+ async () => {
31823
+ const { params, timeout } = _params;
31824
+ const baseCtx = { srcChainKey: params.srcChainKey, action: "cancelUnstake" };
31825
+ try {
31826
+ const txResult = await this.createCancelUnstakeIntent(_params);
31827
+ if (!txResult.ok) return { ok: false, error: txResult.error };
31828
+ let hubTxHash;
31829
+ if (!isHubChainKeyType(params.srcChainKey)) {
31830
+ const packetResult = await relayTxAndWaitPacket({
31831
+ srcTxHash: txResult.value.tx,
31832
+ data: txResult.value.relayData,
31833
+ chainKey: params.srcChainKey,
31834
+ relayerApiEndpoint: this.relayerApiEndpoint,
31835
+ timeout
31836
+ });
31837
+ if (!packetResult.ok) {
31838
+ return {
31839
+ ok: false,
31840
+ error: mapRelayFailure(packetResult.error, {
31841
+ feature: "staking",
31842
+ action: baseCtx.action,
31843
+ srcChainKey: baseCtx.srcChainKey
31844
+ })
31845
+ };
31846
+ }
31847
+ hubTxHash = packetResult.value.dst_tx_hash;
31848
+ } else {
31849
+ hubTxHash = txResult.value.tx;
31850
+ }
31851
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
31852
+ } catch (error) {
31853
+ if (isStakingOrchestrationError(error)) return { ok: false, error };
31217
31854
  return {
31218
31855
  ok: false,
31219
- error: mapRelayFailure(packetResult.error, {
31220
- feature: "staking",
31221
- action: baseCtx.action,
31222
- srcChainKey: baseCtx.srcChainKey
31223
- })
31856
+ error: executionFailed("staking", error, baseCtx)
31224
31857
  };
31225
31858
  }
31226
- hubTxHash = packetResult.value.dst_tx_hash;
31227
- } else {
31228
- hubTxHash = txResult.value.tx;
31859
+ },
31860
+ {
31861
+ start: () => ({
31862
+ srcChainKey: _params.params.srcChainKey,
31863
+ srcAddress: _params.params.srcAddress,
31864
+ requestId: _params.params.requestId
31865
+ }),
31866
+ success: (value) => ({
31867
+ srcChainTxHash: value.srcChainTxHash,
31868
+ dstChainTxHash: value.dstChainTxHash
31869
+ }),
31870
+ failure: (error) => ({ code: error.code })
31229
31871
  }
31230
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
31231
- } catch (error) {
31232
- if (isStakingOrchestrationError(error)) return { ok: false, error };
31233
- return {
31234
- ok: false,
31235
- error: executionFailed("staking", error, baseCtx)
31236
- };
31237
- }
31872
+ );
31238
31873
  }
31239
31874
  /**
31240
31875
  * Submits the cancel-unstake transaction on the spoke chain without relaying to the hub.
@@ -32608,34 +33243,56 @@ var ClService = class _ClService {
32608
33243
  * `dstChainTxHash` (hub) once the packet has been confirmed.
32609
33244
  */
32610
33245
  async supplyLiquidity(_params) {
32611
- const { params, timeout } = _params;
32612
- try {
32613
- const txResult = await this.executeSupplyLiquidity(_params);
32614
- if (!txResult.ok) {
32615
- return txResult;
32616
- }
32617
- let hubTxHash;
32618
- if (!isHubChainKeyType(params.srcChainKey)) {
32619
- const packetResult = await relayTxAndWaitPacket({
32620
- srcTxHash: txResult.value.tx,
32621
- data: txResult.value.relayData,
32622
- chainKey: params.srcChainKey,
32623
- relayerApiEndpoint: this.relayerApiEndpoint,
32624
- timeout
32625
- });
32626
- if (!packetResult.ok) return packetResult;
32627
- hubTxHash = packetResult.value.dst_tx_hash;
32628
- } else {
32629
- hubTxHash = txResult.value.tx;
33246
+ return this.config.analytics.trackResult(
33247
+ "dex",
33248
+ "supplyLiquidity",
33249
+ async () => {
33250
+ const { params, timeout } = _params;
33251
+ try {
33252
+ const txResult = await this.executeSupplyLiquidity(_params);
33253
+ if (!txResult.ok) {
33254
+ return txResult;
33255
+ }
33256
+ let hubTxHash;
33257
+ if (!isHubChainKeyType(params.srcChainKey)) {
33258
+ const packetResult = await relayTxAndWaitPacket({
33259
+ srcTxHash: txResult.value.tx,
33260
+ data: txResult.value.relayData,
33261
+ chainKey: params.srcChainKey,
33262
+ relayerApiEndpoint: this.relayerApiEndpoint,
33263
+ timeout
33264
+ });
33265
+ if (!packetResult.ok) return packetResult;
33266
+ hubTxHash = packetResult.value.dst_tx_hash;
33267
+ } else {
33268
+ hubTxHash = txResult.value.tx;
33269
+ }
33270
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
33271
+ } catch (error) {
33272
+ this.config.logger.error("supplyLiquidity error", error);
33273
+ return {
33274
+ ok: false,
33275
+ error
33276
+ };
33277
+ }
33278
+ },
33279
+ {
33280
+ start: () => ({
33281
+ srcChainKey: _params.params.srcChainKey,
33282
+ srcAddress: _params.params.srcAddress,
33283
+ currency0: _params.params.poolKey.currency0,
33284
+ currency1: _params.params.poolKey.currency1,
33285
+ fee: _params.params.poolKey.fee,
33286
+ tickLower: _params.params.tickLower,
33287
+ tickUpper: _params.params.tickUpper,
33288
+ liquidity: _params.params.liquidity,
33289
+ amount0Max: _params.params.amount0Max,
33290
+ amount1Max: _params.params.amount1Max
33291
+ }),
33292
+ success: (value) => ({ srcChainTxHash: value.srcChainTxHash, dstChainTxHash: value.dstChainTxHash }),
33293
+ failure: (error) => ({ code: isSodaxError(error) ? error.code : void 0 })
32630
33294
  }
32631
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
32632
- } catch (error) {
32633
- this.config.logger.error("supplyLiquidity error", error);
32634
- return {
32635
- ok: false,
32636
- error
32637
- };
32638
- }
33295
+ );
32639
33296
  }
32640
33297
  /**
32641
33298
  * Add liquidity to an existing position and wait for the cross-chain relay to complete.
@@ -32650,33 +33307,56 @@ var ClService = class _ClService {
32650
33307
  * `dstChainTxHash` (hub) once the packet has been confirmed.
32651
33308
  */
32652
33309
  async increaseLiquidity(_params) {
32653
- const { params, timeout } = _params;
32654
- try {
32655
- const txResult = await this.executeIncreaseLiquidity(_params);
32656
- if (!txResult.ok) {
32657
- return txResult;
32658
- }
32659
- let hubTxHash;
32660
- if (!isHubChainKeyType(params.srcChainKey)) {
32661
- const packetResult = await relayTxAndWaitPacket({
32662
- srcTxHash: txResult.value.tx,
32663
- data: txResult.value.relayData,
32664
- chainKey: params.srcChainKey,
32665
- relayerApiEndpoint: this.relayerApiEndpoint,
32666
- timeout
32667
- });
32668
- if (!packetResult.ok) return packetResult;
32669
- hubTxHash = packetResult.value.dst_tx_hash;
32670
- } else {
32671
- hubTxHash = txResult.value.tx;
33310
+ return this.config.analytics.trackResult(
33311
+ "dex",
33312
+ "increaseLiquidity",
33313
+ async () => {
33314
+ const { params, timeout } = _params;
33315
+ try {
33316
+ const txResult = await this.executeIncreaseLiquidity(_params);
33317
+ if (!txResult.ok) {
33318
+ return txResult;
33319
+ }
33320
+ let hubTxHash;
33321
+ if (!isHubChainKeyType(params.srcChainKey)) {
33322
+ const packetResult = await relayTxAndWaitPacket({
33323
+ srcTxHash: txResult.value.tx,
33324
+ data: txResult.value.relayData,
33325
+ chainKey: params.srcChainKey,
33326
+ relayerApiEndpoint: this.relayerApiEndpoint,
33327
+ timeout
33328
+ });
33329
+ if (!packetResult.ok) return packetResult;
33330
+ hubTxHash = packetResult.value.dst_tx_hash;
33331
+ } else {
33332
+ hubTxHash = txResult.value.tx;
33333
+ }
33334
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
33335
+ } catch (error) {
33336
+ return {
33337
+ ok: false,
33338
+ error
33339
+ };
33340
+ }
33341
+ },
33342
+ {
33343
+ start: () => ({
33344
+ srcChainKey: _params.params.srcChainKey,
33345
+ srcAddress: _params.params.srcAddress,
33346
+ currency0: _params.params.poolKey.currency0,
33347
+ currency1: _params.params.poolKey.currency1,
33348
+ fee: _params.params.poolKey.fee,
33349
+ tokenId: _params.params.tokenId,
33350
+ tickLower: _params.params.tickLower,
33351
+ tickUpper: _params.params.tickUpper,
33352
+ liquidity: _params.params.liquidity,
33353
+ amount0Max: _params.params.amount0Max,
33354
+ amount1Max: _params.params.amount1Max
33355
+ }),
33356
+ success: (value) => ({ srcChainTxHash: value.srcChainTxHash, dstChainTxHash: value.dstChainTxHash }),
33357
+ failure: (error) => ({ code: isSodaxError(error) ? error.code : void 0 })
32672
33358
  }
32673
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
32674
- } catch (error) {
32675
- return {
32676
- ok: false,
32677
- error
32678
- };
32679
- }
33359
+ );
32680
33360
  }
32681
33361
  /**
32682
33362
  * Remove liquidity from an existing position and wait for the cross-chain relay to complete.
@@ -32691,33 +33371,54 @@ var ClService = class _ClService {
32691
33371
  * `dstChainTxHash` (hub) once the packet has been confirmed.
32692
33372
  */
32693
33373
  async decreaseLiquidity(_params) {
32694
- const { params, timeout } = _params;
32695
- try {
32696
- const txResult = await this.executeDecreaseLiquidity(_params);
32697
- if (!txResult.ok) {
32698
- return txResult;
32699
- }
32700
- let hubTxHash;
32701
- if (!isHubChainKeyType(params.srcChainKey)) {
32702
- const packetResult = await relayTxAndWaitPacket({
32703
- srcTxHash: txResult.value.tx,
32704
- data: txResult.value.relayData,
32705
- chainKey: params.srcChainKey,
32706
- relayerApiEndpoint: this.relayerApiEndpoint,
32707
- timeout
32708
- });
32709
- if (!packetResult.ok) return packetResult;
32710
- hubTxHash = packetResult.value.dst_tx_hash;
32711
- } else {
32712
- hubTxHash = txResult.value.tx;
33374
+ return this.config.analytics.trackResult(
33375
+ "dex",
33376
+ "decreaseLiquidity",
33377
+ async () => {
33378
+ const { params, timeout } = _params;
33379
+ try {
33380
+ const txResult = await this.executeDecreaseLiquidity(_params);
33381
+ if (!txResult.ok) {
33382
+ return txResult;
33383
+ }
33384
+ let hubTxHash;
33385
+ if (!isHubChainKeyType(params.srcChainKey)) {
33386
+ const packetResult = await relayTxAndWaitPacket({
33387
+ srcTxHash: txResult.value.tx,
33388
+ data: txResult.value.relayData,
33389
+ chainKey: params.srcChainKey,
33390
+ relayerApiEndpoint: this.relayerApiEndpoint,
33391
+ timeout
33392
+ });
33393
+ if (!packetResult.ok) return packetResult;
33394
+ hubTxHash = packetResult.value.dst_tx_hash;
33395
+ } else {
33396
+ hubTxHash = txResult.value.tx;
33397
+ }
33398
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
33399
+ } catch (error) {
33400
+ return {
33401
+ ok: false,
33402
+ error
33403
+ };
33404
+ }
33405
+ },
33406
+ {
33407
+ start: () => ({
33408
+ srcChainKey: _params.params.srcChainKey,
33409
+ srcAddress: _params.params.srcAddress,
33410
+ currency0: _params.params.poolKey.currency0,
33411
+ currency1: _params.params.poolKey.currency1,
33412
+ fee: _params.params.poolKey.fee,
33413
+ tokenId: _params.params.tokenId,
33414
+ liquidity: _params.params.liquidity,
33415
+ amount0Min: _params.params.amount0Min,
33416
+ amount1Min: _params.params.amount1Min
33417
+ }),
33418
+ success: (value) => ({ srcChainTxHash: value.srcChainTxHash, dstChainTxHash: value.dstChainTxHash }),
33419
+ failure: (error) => ({ code: isSodaxError(error) ? error.code : void 0 })
32713
33420
  }
32714
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
32715
- } catch (error) {
32716
- return {
32717
- ok: false,
32718
- error
32719
- };
32720
- }
33421
+ );
32721
33422
  }
32722
33423
  /**
32723
33424
  * Fetch the reward configuration stored in the pool's hook contract.
@@ -32869,34 +33570,54 @@ var ClService = class _ClService {
32869
33570
  * `dstChainTxHash` (hub) once the packet has been confirmed.
32870
33571
  */
32871
33572
  async claimRewards(_params) {
32872
- const { params, timeout } = _params;
32873
- try {
32874
- const txResult = await this.executeClaimRewards(_params);
32875
- if (!txResult.ok) {
32876
- return txResult;
32877
- }
32878
- let hubTxHash;
32879
- if (!isHubChainKeyType(params.srcChainKey)) {
32880
- const packetResult = await relayTxAndWaitPacket({
32881
- srcTxHash: txResult.value.tx,
32882
- data: txResult.value.relayData,
32883
- chainKey: params.srcChainKey,
32884
- relayerApiEndpoint: this.relayerApiEndpoint,
32885
- timeout
32886
- });
32887
- if (!packetResult.ok) return packetResult;
32888
- hubTxHash = packetResult.value.dst_tx_hash;
32889
- } else {
32890
- hubTxHash = txResult.value.tx;
33573
+ return this.config.analytics.trackResult(
33574
+ "dex",
33575
+ "claimRewards",
33576
+ async () => {
33577
+ const { params, timeout } = _params;
33578
+ try {
33579
+ const txResult = await this.executeClaimRewards(_params);
33580
+ if (!txResult.ok) {
33581
+ return txResult;
33582
+ }
33583
+ let hubTxHash;
33584
+ if (!isHubChainKeyType(params.srcChainKey)) {
33585
+ const packetResult = await relayTxAndWaitPacket({
33586
+ srcTxHash: txResult.value.tx,
33587
+ data: txResult.value.relayData,
33588
+ chainKey: params.srcChainKey,
33589
+ relayerApiEndpoint: this.relayerApiEndpoint,
33590
+ timeout
33591
+ });
33592
+ if (!packetResult.ok) return packetResult;
33593
+ hubTxHash = packetResult.value.dst_tx_hash;
33594
+ } else {
33595
+ hubTxHash = txResult.value.tx;
33596
+ }
33597
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
33598
+ } catch (error) {
33599
+ this.config.logger.error("claimRewards error", error);
33600
+ return {
33601
+ ok: false,
33602
+ error
33603
+ };
33604
+ }
33605
+ },
33606
+ {
33607
+ start: () => ({
33608
+ srcChainKey: _params.params.srcChainKey,
33609
+ srcAddress: _params.params.srcAddress,
33610
+ currency0: _params.params.poolKey.currency0,
33611
+ currency1: _params.params.poolKey.currency1,
33612
+ fee: _params.params.poolKey.fee,
33613
+ tokenId: _params.params.tokenId,
33614
+ tickLower: _params.params.tickLower,
33615
+ tickUpper: _params.params.tickUpper
33616
+ }),
33617
+ success: (value) => ({ srcChainTxHash: value.srcChainTxHash, dstChainTxHash: value.dstChainTxHash }),
33618
+ failure: (error) => ({ code: isSodaxError(error) ? error.code : void 0 })
32891
33619
  }
32892
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: hubTxHash } };
32893
- } catch (error) {
32894
- this.config.logger.error("claimRewards error", error);
32895
- return {
32896
- ok: false,
32897
- error
32898
- };
32899
- }
33620
+ );
32900
33621
  }
32901
33622
  /**
32902
33623
  * Return the list of configured concentrated-liquidity pool keys for the SODAX DEX.
@@ -35819,50 +36540,68 @@ var MoneyMarketService = class _MoneyMarketService {
35819
36540
  * @returns A pair of transaction hashes — `srcChainTxHash` (spoke) and `dstChainTxHash` (hub).
35820
36541
  */
35821
36542
  async supply(_params) {
35822
- const { params, timeout = DEFAULT_RELAY_TX_TIMEOUT } = _params;
35823
- const srcChainKey = params.srcChainKey;
35824
- const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "supply" };
35825
- try {
35826
- const txResult = await this.createSupplyIntent(_params);
35827
- if (!txResult.ok) return { ok: false, error: txResult.error };
35828
- const verify = await this.spoke.verifyTxHash({ txHash: txResult.value.tx, chainKey: srcChainKey });
35829
- if (!verify.ok) {
35830
- return {
35831
- ok: false,
35832
- error: verifyFailed("moneyMarket", verify.error, baseCtx)
35833
- };
35834
- }
35835
- if (isHubChainKeyType(srcChainKey)) {
35836
- return {
35837
- ok: true,
35838
- value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
35839
- };
36543
+ return this.config.analytics.trackResult(
36544
+ "moneyMarket",
36545
+ "supply",
36546
+ async () => {
36547
+ const { params, timeout = DEFAULT_RELAY_TX_TIMEOUT } = _params;
36548
+ const srcChainKey = params.srcChainKey;
36549
+ const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "supply" };
36550
+ try {
36551
+ const txResult = await this.createSupplyIntent(_params);
36552
+ if (!txResult.ok) return { ok: false, error: txResult.error };
36553
+ const verify = await this.spoke.verifyTxHash({ txHash: txResult.value.tx, chainKey: srcChainKey });
36554
+ if (!verify.ok) {
36555
+ return {
36556
+ ok: false,
36557
+ error: verifyFailed("moneyMarket", verify.error, baseCtx)
36558
+ };
36559
+ }
36560
+ if (isHubChainKeyType(srcChainKey)) {
36561
+ return {
36562
+ ok: true,
36563
+ value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
36564
+ };
36565
+ }
36566
+ const packet = await relayTxAndWaitPacket({
36567
+ srcTxHash: txResult.value.tx,
36568
+ data: txResult.value.relayData,
36569
+ chainKey: srcChainKey,
36570
+ relayerApiEndpoint: this.relayerApiEndpoint,
36571
+ timeout
36572
+ });
36573
+ if (!packet.ok)
36574
+ return {
36575
+ ok: false,
36576
+ error: mapRelayFailure(packet.error, {
36577
+ feature: "moneyMarket",
36578
+ action: baseCtx.action,
36579
+ srcChainKey: baseCtx.srcChainKey,
36580
+ dstChainKey: baseCtx.dstChainKey
36581
+ })
36582
+ };
36583
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: packet.value.dst_tx_hash } };
36584
+ } catch (error) {
36585
+ if (isMoneyMarketOrchestrationError(error)) return { ok: false, error };
36586
+ return {
36587
+ ok: false,
36588
+ error: executionFailed("moneyMarket", error, { ...baseCtx, phase: "intentCreation" })
36589
+ };
36590
+ }
36591
+ },
36592
+ {
36593
+ start: () => ({
36594
+ srcChainKey: _params.params.srcChainKey,
36595
+ srcAddress: _params.params.srcAddress,
36596
+ dstChainKey: _params.params.dstChainKey,
36597
+ dstAddress: _params.params.dstAddress,
36598
+ token: _params.params.token,
36599
+ amount: _params.params.amount
36600
+ }),
36601
+ success: (value) => ({ srcChainTxHash: value.srcChainTxHash, dstChainTxHash: value.dstChainTxHash }),
36602
+ failure: (error) => ({ code: error.code })
35840
36603
  }
35841
- const packet = await relayTxAndWaitPacket({
35842
- srcTxHash: txResult.value.tx,
35843
- data: txResult.value.relayData,
35844
- chainKey: srcChainKey,
35845
- relayerApiEndpoint: this.relayerApiEndpoint,
35846
- timeout
35847
- });
35848
- if (!packet.ok)
35849
- return {
35850
- ok: false,
35851
- error: mapRelayFailure(packet.error, {
35852
- feature: "moneyMarket",
35853
- action: baseCtx.action,
35854
- srcChainKey: baseCtx.srcChainKey,
35855
- dstChainKey: baseCtx.dstChainKey
35856
- })
35857
- };
35858
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: packet.value.dst_tx_hash } };
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
- }
36604
+ );
35866
36605
  }
35867
36606
  /**
35868
36607
  * Build and optionally broadcast the spoke-side supply transaction without waiting for the
@@ -35979,58 +36718,76 @@ var MoneyMarketService = class _MoneyMarketService {
35979
36718
  * `dstChainTxHash` (hub delivery or relay destination).
35980
36719
  */
35981
36720
  async borrow(_params) {
35982
- const { params, timeout = DEFAULT_RELAY_TX_TIMEOUT } = _params;
35983
- const srcChainKey = params.srcChainKey;
35984
- const hubChainId = this.hubProvider.chainConfig.chain.key;
35985
- const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "borrow" };
35986
- try {
35987
- const txResult = await this.createBorrowIntent(_params);
35988
- if (!txResult.ok) return { ok: false, error: txResult.error };
35989
- const verify = await this.spoke.verifyTxHash({ txHash: txResult.value.tx, chainKey: srcChainKey });
35990
- if (!verify.ok) {
35991
- return {
35992
- ok: false,
35993
- error: verifyFailed("moneyMarket", verify.error, baseCtx)
35994
- };
35995
- }
35996
- const needsRelay = srcChainKey !== hubChainId || params.dstChainKey != null && params.dstAddress != null && params.dstChainKey !== hubChainId;
35997
- if (!needsRelay) {
35998
- return {
35999
- ok: true,
36000
- value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
36001
- };
36002
- }
36003
- const relayIdentity = this.buildRelayIdentity(srcChainKey, txResult.value.tx, txResult.value.relayData);
36004
- const packet = await relayTxAndWaitPacket({
36005
- ...relayIdentity,
36006
- chainKey: srcChainKey,
36007
- relayerApiEndpoint: this.relayerApiEndpoint,
36008
- timeout
36009
- });
36010
- if (!packet.ok)
36011
- return {
36012
- ok: false,
36013
- error: mapRelayFailure(packet.error, {
36014
- feature: "moneyMarket",
36015
- action: baseCtx.action,
36016
- srcChainKey: baseCtx.srcChainKey,
36017
- dstChainKey: baseCtx.dstChainKey
36018
- })
36019
- };
36020
- return {
36021
- ok: true,
36022
- value: {
36023
- srcChainTxHash: relayIdentity.pollTxHash ?? txResult.value.tx,
36024
- dstChainTxHash: packet.value.dst_tx_hash
36721
+ return this.config.analytics.trackResult(
36722
+ "moneyMarket",
36723
+ "borrow",
36724
+ async () => {
36725
+ const { params, timeout = DEFAULT_RELAY_TX_TIMEOUT } = _params;
36726
+ const srcChainKey = params.srcChainKey;
36727
+ const hubChainId = this.hubProvider.chainConfig.chain.key;
36728
+ const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "borrow" };
36729
+ try {
36730
+ const txResult = await this.createBorrowIntent(_params);
36731
+ if (!txResult.ok) return { ok: false, error: txResult.error };
36732
+ const verify = await this.spoke.verifyTxHash({ txHash: txResult.value.tx, chainKey: srcChainKey });
36733
+ if (!verify.ok) {
36734
+ return {
36735
+ ok: false,
36736
+ error: verifyFailed("moneyMarket", verify.error, baseCtx)
36737
+ };
36738
+ }
36739
+ const needsRelay = srcChainKey !== hubChainId || params.dstChainKey != null && params.dstAddress != null && params.dstChainKey !== hubChainId;
36740
+ if (!needsRelay) {
36741
+ return {
36742
+ ok: true,
36743
+ value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
36744
+ };
36745
+ }
36746
+ const relayIdentity = this.buildRelayIdentity(srcChainKey, txResult.value.tx, txResult.value.relayData);
36747
+ const packet = await relayTxAndWaitPacket({
36748
+ ...relayIdentity,
36749
+ chainKey: srcChainKey,
36750
+ relayerApiEndpoint: this.relayerApiEndpoint,
36751
+ timeout
36752
+ });
36753
+ if (!packet.ok)
36754
+ return {
36755
+ ok: false,
36756
+ error: mapRelayFailure(packet.error, {
36757
+ feature: "moneyMarket",
36758
+ action: baseCtx.action,
36759
+ srcChainKey: baseCtx.srcChainKey,
36760
+ dstChainKey: baseCtx.dstChainKey
36761
+ })
36762
+ };
36763
+ return {
36764
+ ok: true,
36765
+ value: {
36766
+ srcChainTxHash: relayIdentity.pollTxHash ?? txResult.value.tx,
36767
+ dstChainTxHash: packet.value.dst_tx_hash
36768
+ }
36769
+ };
36770
+ } catch (error) {
36771
+ if (isMoneyMarketOrchestrationError(error)) return { ok: false, error };
36772
+ return {
36773
+ ok: false,
36774
+ error: executionFailed("moneyMarket", error, { ...baseCtx, phase: "intentCreation" })
36775
+ };
36025
36776
  }
36026
- };
36027
- } catch (error) {
36028
- if (isMoneyMarketOrchestrationError(error)) return { ok: false, error };
36029
- return {
36030
- ok: false,
36031
- error: executionFailed("moneyMarket", error, { ...baseCtx, phase: "intentCreation" })
36032
- };
36033
- }
36777
+ },
36778
+ {
36779
+ start: () => ({
36780
+ srcChainKey: _params.params.srcChainKey,
36781
+ srcAddress: _params.params.srcAddress,
36782
+ dstChainKey: _params.params.dstChainKey,
36783
+ dstAddress: _params.params.dstAddress,
36784
+ token: _params.params.token,
36785
+ amount: _params.params.amount
36786
+ }),
36787
+ success: (value) => ({ srcChainTxHash: value.srcChainTxHash, dstChainTxHash: value.dstChainTxHash }),
36788
+ failure: (error) => ({ code: error.code })
36789
+ }
36790
+ );
36034
36791
  }
36035
36792
  /**
36036
36793
  * Build and optionally broadcast the spoke-side borrow message without waiting for the
@@ -36128,59 +36885,77 @@ var MoneyMarketService = class _MoneyMarketService {
36128
36885
  * `dstChainTxHash` (hub or relay destination).
36129
36886
  */
36130
36887
  async withdraw(_params) {
36131
- const { params, timeout = DEFAULT_RELAY_TX_TIMEOUT } = _params;
36132
- const srcChainKey = params.srcChainKey;
36133
- const hubChainId = this.hubProvider.chainConfig.chain.key;
36134
- const walletRouter = this.hubProvider.chainConfig.addresses.walletRouter;
36135
- const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "withdraw" };
36136
- try {
36137
- const txResult = await this.createWithdrawIntent(_params);
36138
- if (!txResult.ok) return { ok: false, error: txResult.error };
36139
- const verify = await this.spoke.verifyTxHash({ txHash: txResult.value.tx, chainKey: srcChainKey });
36140
- if (!verify.ok) {
36141
- return {
36142
- ok: false,
36143
- error: verifyFailed("moneyMarket", verify.error, baseCtx)
36144
- };
36145
- }
36146
- const needsRelay = srcChainKey !== hubChainId || params.dstChainKey != null && params.dstAddress != null && params.dstChainKey !== hubChainId && params.dstAddress !== walletRouter;
36147
- if (!needsRelay) {
36148
- return {
36149
- ok: true,
36150
- value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
36151
- };
36152
- }
36153
- const relayIdentity = this.buildRelayIdentity(srcChainKey, txResult.value.tx, txResult.value.relayData);
36154
- const packet = await relayTxAndWaitPacket({
36155
- ...relayIdentity,
36156
- chainKey: srcChainKey,
36157
- relayerApiEndpoint: this.relayerApiEndpoint,
36158
- timeout
36159
- });
36160
- if (!packet.ok)
36161
- return {
36162
- ok: false,
36163
- error: mapRelayFailure(packet.error, {
36164
- feature: "moneyMarket",
36165
- action: baseCtx.action,
36166
- srcChainKey: baseCtx.srcChainKey,
36167
- dstChainKey: baseCtx.dstChainKey
36168
- })
36169
- };
36170
- return {
36171
- ok: true,
36172
- value: {
36173
- srcChainTxHash: relayIdentity.pollTxHash ?? txResult.value.tx,
36174
- dstChainTxHash: packet.value.dst_tx_hash
36888
+ return this.config.analytics.trackResult(
36889
+ "moneyMarket",
36890
+ "withdraw",
36891
+ async () => {
36892
+ const { params, timeout = DEFAULT_RELAY_TX_TIMEOUT } = _params;
36893
+ const srcChainKey = params.srcChainKey;
36894
+ const hubChainId = this.hubProvider.chainConfig.chain.key;
36895
+ const walletRouter = this.hubProvider.chainConfig.addresses.walletRouter;
36896
+ const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "withdraw" };
36897
+ try {
36898
+ const txResult = await this.createWithdrawIntent(_params);
36899
+ if (!txResult.ok) return { ok: false, error: txResult.error };
36900
+ const verify = await this.spoke.verifyTxHash({ txHash: txResult.value.tx, chainKey: srcChainKey });
36901
+ if (!verify.ok) {
36902
+ return {
36903
+ ok: false,
36904
+ error: verifyFailed("moneyMarket", verify.error, baseCtx)
36905
+ };
36906
+ }
36907
+ const needsRelay = srcChainKey !== hubChainId || params.dstChainKey != null && params.dstAddress != null && params.dstChainKey !== hubChainId && params.dstAddress !== walletRouter;
36908
+ if (!needsRelay) {
36909
+ return {
36910
+ ok: true,
36911
+ value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
36912
+ };
36913
+ }
36914
+ const relayIdentity = this.buildRelayIdentity(srcChainKey, txResult.value.tx, txResult.value.relayData);
36915
+ const packet = await relayTxAndWaitPacket({
36916
+ ...relayIdentity,
36917
+ chainKey: srcChainKey,
36918
+ relayerApiEndpoint: this.relayerApiEndpoint,
36919
+ timeout
36920
+ });
36921
+ if (!packet.ok)
36922
+ return {
36923
+ ok: false,
36924
+ error: mapRelayFailure(packet.error, {
36925
+ feature: "moneyMarket",
36926
+ action: baseCtx.action,
36927
+ srcChainKey: baseCtx.srcChainKey,
36928
+ dstChainKey: baseCtx.dstChainKey
36929
+ })
36930
+ };
36931
+ return {
36932
+ ok: true,
36933
+ value: {
36934
+ srcChainTxHash: relayIdentity.pollTxHash ?? txResult.value.tx,
36935
+ dstChainTxHash: packet.value.dst_tx_hash
36936
+ }
36937
+ };
36938
+ } catch (error) {
36939
+ if (isMoneyMarketOrchestrationError(error)) return { ok: false, error };
36940
+ return {
36941
+ ok: false,
36942
+ error: executionFailed("moneyMarket", error, { ...baseCtx, phase: "intentCreation" })
36943
+ };
36175
36944
  }
36176
- };
36177
- } catch (error) {
36178
- if (isMoneyMarketOrchestrationError(error)) return { ok: false, error };
36179
- return {
36180
- ok: false,
36181
- error: executionFailed("moneyMarket", error, { ...baseCtx, phase: "intentCreation" })
36182
- };
36183
- }
36945
+ },
36946
+ {
36947
+ start: () => ({
36948
+ srcChainKey: _params.params.srcChainKey,
36949
+ srcAddress: _params.params.srcAddress,
36950
+ dstChainKey: _params.params.dstChainKey,
36951
+ dstAddress: _params.params.dstAddress,
36952
+ token: _params.params.token,
36953
+ amount: _params.params.amount
36954
+ }),
36955
+ success: (value) => ({ srcChainTxHash: value.srcChainTxHash, dstChainTxHash: value.dstChainTxHash }),
36956
+ failure: (error) => ({ code: error.code })
36957
+ }
36958
+ );
36184
36959
  }
36185
36960
  /**
36186
36961
  * Build and optionally broadcast the spoke-side withdraw message without waiting for the
@@ -36276,50 +37051,68 @@ var MoneyMarketService = class _MoneyMarketService {
36276
37051
  * @returns A pair of transaction hashes — `srcChainTxHash` (spoke) and `dstChainTxHash` (hub).
36277
37052
  */
36278
37053
  async repay(_params) {
36279
- const { params, timeout = DEFAULT_RELAY_TX_TIMEOUT } = _params;
36280
- const srcChainKey = params.srcChainKey;
36281
- const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "repay" };
36282
- try {
36283
- const txResult = await this.createRepayIntent(_params);
36284
- if (!txResult.ok) return { ok: false, error: txResult.error };
36285
- const verify = await this.spoke.verifyTxHash({ txHash: txResult.value.tx, chainKey: srcChainKey });
36286
- if (!verify.ok) {
36287
- return {
36288
- ok: false,
36289
- error: verifyFailed("moneyMarket", verify.error, baseCtx)
36290
- };
36291
- }
36292
- if (isHubChainKeyType(srcChainKey)) {
36293
- return {
36294
- ok: true,
36295
- value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
36296
- };
37054
+ return this.config.analytics.trackResult(
37055
+ "moneyMarket",
37056
+ "repay",
37057
+ async () => {
37058
+ const { params, timeout = DEFAULT_RELAY_TX_TIMEOUT } = _params;
37059
+ const srcChainKey = params.srcChainKey;
37060
+ const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "repay" };
37061
+ try {
37062
+ const txResult = await this.createRepayIntent(_params);
37063
+ if (!txResult.ok) return { ok: false, error: txResult.error };
37064
+ const verify = await this.spoke.verifyTxHash({ txHash: txResult.value.tx, chainKey: srcChainKey });
37065
+ if (!verify.ok) {
37066
+ return {
37067
+ ok: false,
37068
+ error: verifyFailed("moneyMarket", verify.error, baseCtx)
37069
+ };
37070
+ }
37071
+ if (isHubChainKeyType(srcChainKey)) {
37072
+ return {
37073
+ ok: true,
37074
+ value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: txResult.value.tx }
37075
+ };
37076
+ }
37077
+ const packet = await relayTxAndWaitPacket({
37078
+ srcTxHash: txResult.value.tx,
37079
+ data: txResult.value.relayData,
37080
+ chainKey: srcChainKey,
37081
+ relayerApiEndpoint: this.relayerApiEndpoint,
37082
+ timeout
37083
+ });
37084
+ if (!packet.ok)
37085
+ return {
37086
+ ok: false,
37087
+ error: mapRelayFailure(packet.error, {
37088
+ feature: "moneyMarket",
37089
+ action: baseCtx.action,
37090
+ srcChainKey: baseCtx.srcChainKey,
37091
+ dstChainKey: baseCtx.dstChainKey
37092
+ })
37093
+ };
37094
+ return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: packet.value.dst_tx_hash } };
37095
+ } catch (error) {
37096
+ if (isMoneyMarketOrchestrationError(error)) return { ok: false, error };
37097
+ return {
37098
+ ok: false,
37099
+ error: executionFailed("moneyMarket", error, { ...baseCtx, phase: "intentCreation" })
37100
+ };
37101
+ }
37102
+ },
37103
+ {
37104
+ start: () => ({
37105
+ srcChainKey: _params.params.srcChainKey,
37106
+ srcAddress: _params.params.srcAddress,
37107
+ dstChainKey: _params.params.dstChainKey,
37108
+ dstAddress: _params.params.dstAddress,
37109
+ token: _params.params.token,
37110
+ amount: _params.params.amount
37111
+ }),
37112
+ success: (value) => ({ srcChainTxHash: value.srcChainTxHash, dstChainTxHash: value.dstChainTxHash }),
37113
+ failure: (error) => ({ code: error.code })
36297
37114
  }
36298
- const packet = await relayTxAndWaitPacket({
36299
- srcTxHash: txResult.value.tx,
36300
- data: txResult.value.relayData,
36301
- chainKey: srcChainKey,
36302
- relayerApiEndpoint: this.relayerApiEndpoint,
36303
- timeout
36304
- });
36305
- if (!packet.ok)
36306
- return {
36307
- ok: false,
36308
- error: mapRelayFailure(packet.error, {
36309
- feature: "moneyMarket",
36310
- action: baseCtx.action,
36311
- srcChainKey: baseCtx.srcChainKey,
36312
- dstChainKey: baseCtx.dstChainKey
36313
- })
36314
- };
36315
- return { ok: true, value: { srcChainTxHash: txResult.value.tx, dstChainTxHash: packet.value.dst_tx_hash } };
36316
- } catch (error) {
36317
- if (isMoneyMarketOrchestrationError(error)) return { ok: false, error };
36318
- return {
36319
- ok: false,
36320
- error: executionFailed("moneyMarket", error, { ...baseCtx, phase: "intentCreation" })
36321
- };
36322
- }
37115
+ );
36323
37116
  }
36324
37117
  /**
36325
37118
  * Build and optionally broadcast the spoke-side repay transaction without waiting for the
@@ -37020,50 +37813,67 @@ var PartnerFeeClaimService = class {
37020
37813
  * unsigned raw transaction (`raw: true`). Returns an error on failure.
37021
37814
  */
37022
37815
  async setSwapPreference(_params) {
37023
- const { params, walletProvider, raw } = _params;
37024
- try {
37025
- invariant(isHubChainKeyType(params.srcChainKey), "PartnerFeeClaimService only supports Sonic spoke provider");
37026
- invariant(this.protocolIntentsContract, "protocolIntentsContract is not configured in solver config");
37027
- const outputToken = params.dstChainKey !== this.hubProvider.chainConfig.chain.key ? this.hubProvider.config.getSpokeTokenFromOriginalAssetAddress(params.dstChainKey, params.outputToken)?.hubAsset : params.outputToken;
37028
- invariant(
37029
- outputToken,
37030
- `hub asset not found for spoke chain token (params.outputToken): ${params.outputToken} with chain key: ${params.dstChainKey}`
37031
- );
37032
- const rawTx = {
37033
- from: params.srcAddress,
37034
- to: this.protocolIntentsContract,
37035
- value: 0n,
37036
- data: viem.encodeFunctionData({
37037
- abi: ProtocolIntentsAbi,
37038
- functionName: "setAutoSwapPreferences",
37039
- args: [
37816
+ return this.config.analytics.trackResult(
37817
+ "partner",
37818
+ "setSwapPreference",
37819
+ async () => {
37820
+ const { params, walletProvider, raw } = _params;
37821
+ try {
37822
+ invariant(isHubChainKeyType(params.srcChainKey), "PartnerFeeClaimService only supports Sonic spoke provider");
37823
+ invariant(this.protocolIntentsContract, "protocolIntentsContract is not configured in solver config");
37824
+ const outputToken = params.dstChainKey !== this.hubProvider.chainConfig.chain.key ? this.hubProvider.config.getSpokeTokenFromOriginalAssetAddress(params.dstChainKey, params.outputToken)?.hubAsset : params.outputToken;
37825
+ invariant(
37040
37826
  outputToken,
37041
- BigInt(getIntentRelayChainId(params.dstChainKey)),
37042
- encodeAddress(params.dstChainKey, params.dstAddress)
37043
- ]
37044
- })
37045
- };
37046
- if (raw) {
37047
- return {
37048
- ok: true,
37049
- value: rawTx
37050
- };
37827
+ `hub asset not found for spoke chain token (params.outputToken): ${params.outputToken} with chain key: ${params.dstChainKey}`
37828
+ );
37829
+ const rawTx = {
37830
+ from: params.srcAddress,
37831
+ to: this.protocolIntentsContract,
37832
+ value: 0n,
37833
+ data: viem.encodeFunctionData({
37834
+ abi: ProtocolIntentsAbi,
37835
+ functionName: "setAutoSwapPreferences",
37836
+ args: [
37837
+ outputToken,
37838
+ BigInt(getIntentRelayChainId(params.dstChainKey)),
37839
+ encodeAddress(params.dstChainKey, params.dstAddress)
37840
+ ]
37841
+ })
37842
+ };
37843
+ if (raw) {
37844
+ return {
37845
+ ok: true,
37846
+ value: rawTx
37847
+ };
37848
+ }
37849
+ invariant(
37850
+ isEvmWalletProviderType(walletProvider),
37851
+ "PartnerFeeClaimService only supports Evm (sonic) wallet provider"
37852
+ );
37853
+ const txHash = await walletProvider.sendTransaction(rawTx);
37854
+ return {
37855
+ ok: true,
37856
+ value: txHash
37857
+ };
37858
+ } catch (error) {
37859
+ return {
37860
+ ok: false,
37861
+ error
37862
+ };
37863
+ }
37864
+ },
37865
+ {
37866
+ start: () => ({
37867
+ srcChainKey: _params.params.srcChainKey,
37868
+ srcAddress: _params.params.srcAddress,
37869
+ outputToken: _params.params.outputToken,
37870
+ dstChainKey: _params.params.dstChainKey,
37871
+ dstAddress: _params.params.dstAddress
37872
+ }),
37873
+ success: (value) => ({ txHash: value }),
37874
+ failure: (error) => ({ code: isSodaxError(error) ? error.code : void 0 })
37051
37875
  }
37052
- invariant(
37053
- isEvmWalletProviderType(walletProvider),
37054
- "PartnerFeeClaimService only supports Evm (sonic) wallet provider"
37055
- );
37056
- const txHash = await walletProvider.sendTransaction(rawTx);
37057
- return {
37058
- ok: true,
37059
- value: txHash
37060
- };
37061
- } catch (error) {
37062
- return {
37063
- ok: false,
37064
- error
37065
- };
37066
- }
37876
+ );
37067
37877
  }
37068
37878
  /**
37069
37879
  * Checks whether a hub-chain ERC-20 token is already approved for the ProtocolIntents contract.
@@ -37175,6 +37985,11 @@ var PartnerFeeClaimService = class {
37175
37985
  * This is the low-level building block. Use `swap` for the full flow that also waits for
37176
37986
  * the solver to execute the intent.
37177
37987
  *
37988
+ * Guards against same-token intents: if the configured output token equals `fromToken` the solver
37989
+ * cannot fill the swap, so the call is rejected with `VALIDATION_FAILED` before any transaction is
37990
+ * built. The guard fails closed — if the preference lookup fails the call returns that error rather
37991
+ * than submitting an intent that may become unfillable.
37992
+ *
37178
37993
  * @param _params - Action descriptor containing:
37179
37994
  * - `params.srcChainKey` — must be the hub chain key (Sonic).
37180
37995
  * - `params.srcAddress` — partner's EVM address; also used as the intent creator.
@@ -37198,6 +38013,25 @@ var PartnerFeeClaimService = class {
37198
38013
  this.config.solver.protocolIntentsContract,
37199
38014
  "protocolIntentsContract is not configured in solver config"
37200
38015
  );
38016
+ const prefs = await this.getAutoSwapPreferences(params.srcAddress);
38017
+ if (!prefs.ok) return prefs;
38018
+ if (prefs.value.outputToken.toLowerCase() === params.fromToken.toLowerCase()) {
38019
+ return {
38020
+ ok: false,
38021
+ error: new SodaxError(
38022
+ "VALIDATION_FAILED",
38023
+ "Auto-swap output token equals the fee token; the solver cannot swap a token into itself. Withdraw the fee token directly (bridge/transfer) or change the swap preference before claiming.",
38024
+ {
38025
+ feature: "partner",
38026
+ context: {
38027
+ action: "createIntentAutoSwap",
38028
+ fromToken: params.fromToken,
38029
+ outputToken: prefs.value.outputToken
38030
+ }
38031
+ }
38032
+ )
38033
+ };
38034
+ }
37201
38035
  const minOutputAmount = 0n;
37202
38036
  const rawTx = {
37203
38037
  from: params.srcAddress,
@@ -37245,47 +38079,218 @@ var PartnerFeeClaimService = class {
37245
38079
  *
37246
38080
  * On failure the `error` is tagged:
37247
38081
  * - `WAIT_INTENT_AUTO_SWAP_FAILED` — transaction was submitted but receipt polling failed.
37248
- * - Error from `createIntentAutoSwap` — if the initial submission failed.
38082
+ * - Error from `createIntentAutoSwap` — if the initial submission failed, including
38083
+ * `VALIDATION_FAILED` when the output token equals the fee token (same-token guard) or the
38084
+ * preference lookup that backs the guard fails.
37249
38085
  * - Error from `SolverApiService.postExecution` — if the solver notification failed.
37250
38086
  */
37251
38087
  async swap(_params) {
37252
- try {
37253
- const txHash = await this.createIntentAutoSwap(_params);
37254
- if (!txHash.ok) {
37255
- return txHash;
38088
+ return this.config.analytics.trackResult(
38089
+ "partner",
38090
+ "swap",
38091
+ async () => {
38092
+ try {
38093
+ const txHash = await this.createIntentAutoSwap(_params);
38094
+ if (!txHash.ok) {
38095
+ return txHash;
38096
+ }
38097
+ let intentTxHash;
38098
+ try {
38099
+ const receipt = await this.hubProvider.publicClient.waitForTransactionReceipt({ hash: txHash.value });
38100
+ intentTxHash = receipt.transactionHash;
38101
+ } catch (error) {
38102
+ return {
38103
+ ok: false,
38104
+ error: new SodaxError(
38105
+ "EXECUTION_FAILED",
38106
+ error instanceof Error ? error.message : "waitIntentAutoSwap failed",
38107
+ { feature: "partner", cause: error, context: { action: "waitAutoSwap", phase: "execution" } }
38108
+ )
38109
+ };
38110
+ }
38111
+ const solverExecutionResponse = await SolverApiService.postExecution(
38112
+ { intent_tx_hash: intentTxHash },
38113
+ this.config.solver,
38114
+ this.config.logger
38115
+ );
38116
+ if (!solverExecutionResponse.ok) {
38117
+ return solverExecutionResponse;
38118
+ }
38119
+ return {
38120
+ ok: true,
38121
+ value: {
38122
+ srcTxHash: txHash.value,
38123
+ solverExecutionResponse: solverExecutionResponse.value,
38124
+ intentTxHash
38125
+ }
38126
+ };
38127
+ } catch (error) {
38128
+ return { ok: false, error };
38129
+ }
38130
+ },
38131
+ {
38132
+ start: () => ({
38133
+ srcChainKey: _params.params.srcChainKey,
38134
+ srcAddress: _params.params.srcAddress,
38135
+ fromToken: _params.params.fromToken,
38136
+ amount: _params.params.amount
38137
+ }),
38138
+ success: (value) => ({
38139
+ srcTxHash: value.srcTxHash,
38140
+ intentTxHash: value.intentTxHash
38141
+ }),
38142
+ failure: (error) => ({ code: isSodaxError(error) ? error.code : void 0 })
37256
38143
  }
37257
- let intentTxHash;
37258
- try {
37259
- const receipt = await this.hubProvider.publicClient.waitForTransactionReceipt({ hash: txHash.value });
37260
- intentTxHash = receipt.transactionHash;
37261
- } catch (error) {
38144
+ );
38145
+ }
38146
+ /**
38147
+ * Cancels a partner fee-claim auto-swap intent and refunds the input token to the partner.
38148
+ *
38149
+ * This targets the ProtocolIntents contract's own `cancelIntent(fromToken, toToken)`, which is
38150
+ * the only authorized cancel path for partner auto-swap intents: the intent's `creator` is the
38151
+ * ProtocolIntents contract (not the partner), so the generic `SwapService.cancelIntent` reverts
38152
+ * with `Unauthorized()`. ProtocolIntents looks up the caller's intent for the token pair, cancels
38153
+ * it in the main intents contract (as the creator), and transfers the locked `inputAmount` back
38154
+ * to the partner (`msg.sender`).
38155
+ *
38156
+ * Use this to recover funds stuck in an unfillable intent — most commonly a same-token claim
38157
+ * (`fromToken === toToken`) the solver refused to fill (see the guard in {@link swap}).
38158
+ *
38159
+ * @param _params - Action descriptor containing:
38160
+ * - `params.srcChainKey` — must be the hub chain key (Sonic).
38161
+ * - `params.srcAddress` — the partner's EVM address; must match the intent's owner.
38162
+ * - `params.fromToken` — the stuck intent's input (fee) token, hub-chain address.
38163
+ * - `params.toToken` — the stuck intent's output token, hub-chain address.
38164
+ * - `raw` — when `true`, returns the unsigned transaction object instead of submitting it.
38165
+ * - `walletProvider` — required when `raw` is `false`; must be an EVM wallet provider.
38166
+ * @returns A `Result` containing the submitted transaction hash (`raw: false`) or the unsigned
38167
+ * raw transaction (`raw: true`).
38168
+ */
38169
+ async cancelIntent(_params) {
38170
+ return this.config.analytics.trackResult(
38171
+ "partner",
38172
+ "cancelIntent",
38173
+ async () => {
38174
+ const { params } = _params;
38175
+ try {
38176
+ invariant(isHubChainKeyType(params.srcChainKey), "PartnerFeeClaimService only supports Hub srcChainKey");
38177
+ invariant(
38178
+ isOptionalEvmWalletProviderType(_params.walletProvider),
38179
+ "PartnerFeeClaimService only supports Evm wallet provider"
38180
+ );
38181
+ invariant(this.protocolIntentsContract, "protocolIntentsContract is not configured in solver config");
38182
+ const rawTx = {
38183
+ from: params.srcAddress,
38184
+ to: this.protocolIntentsContract,
38185
+ value: 0n,
38186
+ data: viem.encodeFunctionData({
38187
+ abi: ProtocolIntentsAbi,
38188
+ functionName: "cancelIntent",
38189
+ args: [params.fromToken, params.toToken]
38190
+ })
38191
+ };
38192
+ if (_params.raw) {
38193
+ return {
38194
+ ok: true,
38195
+ value: rawTx
38196
+ };
38197
+ }
38198
+ const txHash = await _params.walletProvider.sendTransaction(rawTx);
38199
+ return {
38200
+ ok: true,
38201
+ value: txHash
38202
+ };
38203
+ } catch (error) {
38204
+ return { ok: false, error };
38205
+ }
38206
+ },
38207
+ {
38208
+ start: () => ({
38209
+ srcChainKey: _params.params.srcChainKey,
38210
+ srcAddress: _params.params.srcAddress,
38211
+ fromToken: _params.params.fromToken,
38212
+ toToken: _params.params.toToken
38213
+ }),
38214
+ success: (value) => ({ txHash: value }),
38215
+ failure: (error) => ({ code: isSodaxError(error) ? error.code : void 0 })
38216
+ }
38217
+ );
38218
+ }
38219
+ /**
38220
+ * Returns the stored intent hash for a partner's `(user, fromToken, toToken)` token pair.
38221
+ *
38222
+ * A non-zero hash means an auto-swap intent currently exists for that pair (e.g. an unfilled
38223
+ * same-token claim) and can be cancelled via {@link cancelIntent}. A zero hash
38224
+ * (`0x000…0`) means there is no open intent for the pair.
38225
+ *
38226
+ * @param params.user - The partner's EVM address on Sonic.
38227
+ * @param params.fromToken - Input (fee) token, hub-chain address.
38228
+ * @param params.toToken - Output token, hub-chain address.
38229
+ * @returns A `Result` containing the intent hash, or an `Error` tagged `LOOKUP_FAILED`.
38230
+ */
38231
+ async getUserIntent({ user, fromToken, toToken }) {
38232
+ try {
38233
+ invariant(this.protocolIntentsContract, "protocolIntentsContract is not configured in solver config");
38234
+ const intentHash = await this.hubProvider.publicClient.readContract({
38235
+ address: this.protocolIntentsContract,
38236
+ abi: ProtocolIntentsAbi,
38237
+ functionName: "getUserIntent",
38238
+ args: [user, fromToken, toToken]
38239
+ });
38240
+ return { ok: true, value: intentHash };
38241
+ } catch (error) {
38242
+ return { ok: false, error: lookupFailed("partner", "getUserIntent", error) };
38243
+ }
38244
+ }
38245
+ /**
38246
+ * Reads the full {@link Intent} details for a stored intent hash from the ProtocolIntents contract.
38247
+ *
38248
+ * Useful for displaying a stuck intent before cancelling it — e.g. the locked `inputAmount` and
38249
+ * `inputToken`. Pair with {@link getUserIntent} to resolve the hash from a token pair.
38250
+ *
38251
+ * @param intentHash - The intent hash (from {@link getUserIntent}).
38252
+ * @returns A `Result` containing the `Intent`, or an `Error` tagged `LOOKUP_FAILED`.
38253
+ */
38254
+ async getIntentDetails(intentHash) {
38255
+ try {
38256
+ invariant(this.protocolIntentsContract, "protocolIntentsContract is not configured in solver config");
38257
+ const intent = await this.hubProvider.publicClient.readContract({
38258
+ address: this.protocolIntentsContract,
38259
+ abi: ProtocolIntentsAbi,
38260
+ functionName: "getIntentDetails",
38261
+ args: [intentHash]
38262
+ });
38263
+ if (!this.config.isValidIntentRelayChainId(intent.srcChain) || !this.config.isValidIntentRelayChainId(intent.dstChain)) {
37262
38264
  return {
37263
38265
  ok: false,
37264
- error: new SodaxError(
37265
- "EXECUTION_FAILED",
37266
- error instanceof Error ? error.message : "waitIntentAutoSwap failed",
37267
- { feature: "partner", cause: error, context: { action: "waitAutoSwap", phase: "execution" } }
38266
+ error: lookupFailed(
38267
+ "partner",
38268
+ "getIntentDetails",
38269
+ new Error(`Invalid intent relay chain id: ${intent.srcChain} or ${intent.dstChain}`)
37268
38270
  )
37269
38271
  };
37270
38272
  }
37271
- const solverExecutionResponse = await SolverApiService.postExecution(
37272
- { intent_tx_hash: intentTxHash },
37273
- this.config.solver,
37274
- this.config.logger
37275
- );
37276
- if (!solverExecutionResponse.ok) {
37277
- return solverExecutionResponse;
37278
- }
37279
38273
  return {
37280
38274
  ok: true,
37281
38275
  value: {
37282
- srcTxHash: txHash.value,
37283
- solverExecutionResponse: solverExecutionResponse.value,
37284
- intentTxHash
38276
+ intentId: intent.intentId,
38277
+ creator: intent.creator,
38278
+ inputToken: intent.inputToken,
38279
+ outputToken: intent.outputToken,
38280
+ inputAmount: intent.inputAmount,
38281
+ minOutputAmount: intent.minOutputAmount,
38282
+ deadline: intent.deadline,
38283
+ allowPartialFill: intent.allowPartialFill,
38284
+ srcChain: intent.srcChain,
38285
+ dstChain: intent.dstChain,
38286
+ srcAddress: intent.srcAddress,
38287
+ dstAddress: intent.dstAddress,
38288
+ solver: intent.solver,
38289
+ data: intent.data
37285
38290
  }
37286
38291
  };
37287
38292
  } catch (error) {
37288
- return { ok: false, error };
38293
+ return { ok: false, error: lookupFailed("partner", "getIntentDetails", error) };
37289
38294
  }
37290
38295
  }
37291
38296
  };
@@ -37420,42 +38425,62 @@ var RecoveryService = class {
37420
38425
  * transaction object when `raw: true`, or the broadcast transaction hash when `raw: false`.
37421
38426
  */
37422
38427
  async withdrawHubAsset(_params) {
37423
- const { params } = _params;
37424
- try {
37425
- const hubWallet = await this.hubProvider.getUserHubWalletAddress(params.srcAddress, params.srcChainKey);
37426
- const payload = EvmAssetManagerService.withdrawAssetData(
37427
- {
37428
- token: params.token,
37429
- to: encodeAddress(params.srcChainKey, params.srcAddress),
37430
- amount: params.amount
37431
- },
37432
- this.hubProvider,
37433
- params.srcChainKey
37434
- );
37435
- const coreParams = {
37436
- srcChainKey: params.srcChainKey,
37437
- srcAddress: params.srcAddress,
37438
- dstChainKey: this.hubProvider.chainConfig.chain.key,
37439
- dstAddress: hubWallet,
37440
- payload
37441
- };
37442
- const sendMessageParams = _params.raw ? { ...coreParams, raw: true } : { ...coreParams, raw: false, walletProvider: _params.walletProvider };
37443
- const txResult = await this.spoke.sendMessage(sendMessageParams);
37444
- if (!txResult.ok) return txResult;
37445
- return {
37446
- ok: true,
37447
- value: txResult.value
37448
- };
37449
- } catch (error) {
37450
- return {
37451
- ok: false,
37452
- error: new SodaxError("EXECUTION_FAILED", error instanceof Error ? error.message : "withdrawHubAsset failed", {
37453
- feature: "recovery",
37454
- cause: error,
37455
- context: { action: "withdrawHubAsset", phase: "execution" }
37456
- })
37457
- };
37458
- }
38428
+ return this.config.analytics.trackResult(
38429
+ "recovery",
38430
+ "withdrawHubAsset",
38431
+ async () => {
38432
+ const { params } = _params;
38433
+ try {
38434
+ const hubWallet = await this.hubProvider.getUserHubWalletAddress(params.srcAddress, params.srcChainKey);
38435
+ const payload = EvmAssetManagerService.withdrawAssetData(
38436
+ {
38437
+ token: params.token,
38438
+ to: encodeAddress(params.srcChainKey, params.srcAddress),
38439
+ amount: params.amount
38440
+ },
38441
+ this.hubProvider,
38442
+ params.srcChainKey
38443
+ );
38444
+ const coreParams = {
38445
+ srcChainKey: params.srcChainKey,
38446
+ srcAddress: params.srcAddress,
38447
+ dstChainKey: this.hubProvider.chainConfig.chain.key,
38448
+ dstAddress: hubWallet,
38449
+ payload
38450
+ };
38451
+ const sendMessageParams = _params.raw ? { ...coreParams, raw: true } : {
38452
+ ...coreParams,
38453
+ raw: false,
38454
+ walletProvider: _params.walletProvider
38455
+ };
38456
+ const txResult = await this.spoke.sendMessage(sendMessageParams);
38457
+ if (!txResult.ok) return txResult;
38458
+ return {
38459
+ ok: true,
38460
+ value: txResult.value
38461
+ };
38462
+ } catch (error) {
38463
+ return {
38464
+ ok: false,
38465
+ error: new SodaxError(
38466
+ "EXECUTION_FAILED",
38467
+ error instanceof Error ? error.message : "withdrawHubAsset failed",
38468
+ { feature: "recovery", cause: error, context: { action: "withdrawHubAsset", phase: "execution" } }
38469
+ )
38470
+ };
38471
+ }
38472
+ },
38473
+ {
38474
+ start: () => ({
38475
+ srcChainKey: _params.params.srcChainKey,
38476
+ srcAddress: _params.params.srcAddress,
38477
+ token: _params.params.token,
38478
+ amount: _params.params.amount
38479
+ }),
38480
+ success: (value) => ({ txHash: typeof value === "string" ? value : void 0 }),
38481
+ failure: (error) => ({ code: isSodaxError(error) ? error.code : void 0 })
38482
+ }
38483
+ );
37459
38484
  }
37460
38485
  };
37461
38486
 
@@ -37915,70 +38940,93 @@ var LeverageYieldService = class {
37915
38940
  const { params } = _params;
37916
38941
  const srcChainKey = params.srcChainKey;
37917
38942
  const baseCtx = { srcChainKey, dstChainKey: params.dstChainKey, action: "vaultSwap" };
37918
- try {
37919
- const timeout = _params.timeout;
37920
- const createIntentResult = await this.createVaultIntent(_params);
37921
- if (!createIntentResult.ok) {
37922
- return { ok: false, error: createIntentResult.error };
37923
- }
37924
- const { tx: spokeTxHash, intent, relayData } = createIntentResult.value;
37925
- const verifyTxHashResult = await this.spoke.verifyTxHash({
37926
- txHash: spokeTxHash,
37927
- chainKey: srcChainKey
37928
- });
37929
- if (!verifyTxHashResult.ok) {
37930
- return {
37931
- ok: false,
37932
- error: verifyFailed("leverageYield", verifyTxHashResult.error, baseCtx)
37933
- };
37934
- }
37935
- let dstIntentTxHash;
37936
- if (isHubChainKeyType(srcChainKey)) {
37937
- dstIntentTxHash = spokeTxHash;
37938
- } else {
37939
- const packet = await relayTxAndWaitPacket({
37940
- srcTxHash: spokeTxHash,
37941
- data: relayData,
37942
- chainKey: srcChainKey,
37943
- relayerApiEndpoint: this.config.relay.relayerApiEndpoint,
37944
- timeout
37945
- });
37946
- if (!packet.ok) {
38943
+ return this.config.analytics.trackResult(
38944
+ "leverageYield",
38945
+ "vaultSwap",
38946
+ async () => {
38947
+ try {
38948
+ const timeout = _params.timeout;
38949
+ const createIntentResult = await this.createVaultIntent(_params);
38950
+ if (!createIntentResult.ok) {
38951
+ return { ok: false, error: createIntentResult.error };
38952
+ }
38953
+ const { tx: spokeTxHash, intent, relayData } = createIntentResult.value;
38954
+ const verifyTxHashResult = await this.spoke.verifyTxHash({
38955
+ txHash: spokeTxHash,
38956
+ chainKey: srcChainKey
38957
+ });
38958
+ if (!verifyTxHashResult.ok) {
38959
+ return {
38960
+ ok: false,
38961
+ error: verifyFailed("leverageYield", verifyTxHashResult.error, baseCtx)
38962
+ };
38963
+ }
38964
+ let dstIntentTxHash;
38965
+ if (isHubChainKeyType(srcChainKey)) {
38966
+ dstIntentTxHash = spokeTxHash;
38967
+ } else {
38968
+ const packet = await relayTxAndWaitPacket({
38969
+ srcTxHash: spokeTxHash,
38970
+ data: relayData,
38971
+ chainKey: srcChainKey,
38972
+ relayerApiEndpoint: this.config.relay.relayerApiEndpoint,
38973
+ timeout
38974
+ });
38975
+ if (!packet.ok) {
38976
+ return {
38977
+ ok: false,
38978
+ error: mapRelayFailure(packet.error, { feature: "leverageYield", ...baseCtx })
38979
+ };
38980
+ }
38981
+ dstIntentTxHash = packet.value.dst_tx_hash;
38982
+ }
38983
+ const postExecResult = await this.notifySolver({
38984
+ intent_tx_hash: dstIntentTxHash
38985
+ });
38986
+ if (!postExecResult.ok) {
38987
+ return { ok: false, error: postExecResult.error };
38988
+ }
38989
+ return {
38990
+ ok: true,
38991
+ value: {
38992
+ solverExecutionResponse: postExecResult.value,
38993
+ intent,
38994
+ intentDeliveryInfo: {
38995
+ srcChainKey,
38996
+ srcTxHash: spokeTxHash,
38997
+ srcAddress: params.srcAddress,
38998
+ dstChainKey: params.dstChainKey,
38999
+ dstTxHash: dstIntentTxHash,
39000
+ dstAddress: params.dstAddress
39001
+ }
39002
+ }
39003
+ };
39004
+ } catch (error) {
39005
+ if (isLeverageYieldSwapError(error)) return { ok: false, error };
37947
39006
  return {
37948
39007
  ok: false,
37949
- error: mapRelayFailure(packet.error, { feature: "leverageYield", ...baseCtx })
39008
+ error: unknownFailed("leverageYield", error, baseCtx)
37950
39009
  };
37951
39010
  }
37952
- dstIntentTxHash = packet.value.dst_tx_hash;
37953
- }
37954
- const postExecResult = await this.notifySolver({
37955
- intent_tx_hash: dstIntentTxHash
37956
- });
37957
- if (!postExecResult.ok) {
37958
- return { ok: false, error: postExecResult.error };
39011
+ },
39012
+ {
39013
+ start: () => ({
39014
+ srcChainKey: _params.params.srcChainKey,
39015
+ dstChainKey: _params.params.dstChainKey,
39016
+ srcAddress: _params.params.srcAddress,
39017
+ dstAddress: _params.params.dstAddress,
39018
+ inputToken: _params.params.inputToken,
39019
+ outputToken: _params.params.outputToken,
39020
+ inputAmount: _params.params.inputAmount
39021
+ }),
39022
+ success: (value) => ({
39023
+ intentId: value.intent.intentId,
39024
+ srcTxHash: value.intentDeliveryInfo.srcTxHash,
39025
+ dstTxHash: value.intentDeliveryInfo.dstTxHash
39026
+ }),
39027
+ failure: (error) => ({ code: error.code })
37959
39028
  }
37960
- return {
37961
- ok: true,
37962
- value: {
37963
- solverExecutionResponse: postExecResult.value,
37964
- intent,
37965
- intentDeliveryInfo: {
37966
- srcChainKey,
37967
- srcTxHash: spokeTxHash,
37968
- srcAddress: params.srcAddress,
37969
- dstChainKey: params.dstChainKey,
37970
- dstTxHash: dstIntentTxHash,
37971
- dstAddress: params.dstAddress
37972
- }
37973
- }
37974
- };
37975
- } catch (error) {
37976
- if (isLeverageYieldSwapError(error)) return { ok: false, error };
37977
- return {
37978
- ok: false,
37979
- error: unknownFailed("leverageYield", error, baseCtx)
37980
- };
37981
- }
39029
+ );
37982
39030
  }
37983
39031
  /**
37984
39032
  * Notifies the solver that the vault intent landed on the hub, triggering it to fill.
@@ -38355,6 +39403,7 @@ var Sodax = class {
38355
39403
  // spoke service enabling spoke chain operations
38356
39404
  constructor(options) {
38357
39405
  const logger = resolveLogger(options?.logger);
39406
+ const analytics = resolveAnalytics(options?.analytics);
38358
39407
  const fee = options?.fee;
38359
39408
  this.instanceConfig = options ? mergeSodaxConfig(sodaxConfig, options) : sodaxConfig;
38360
39409
  this.backendApi = new BackendApiService(this.instanceConfig.api, logger);
@@ -38363,6 +39412,7 @@ var Sodax = class {
38363
39412
  config: this.instanceConfig,
38364
39413
  userConfig: options,
38365
39414
  logger,
39415
+ analytics,
38366
39416
  fee
38367
39417
  });
38368
39418
  this.hubProvider = new EvmHubProvider({ config: this.config });
@@ -38458,6 +39508,7 @@ exports.BitcoinSpokeService = BitcoinSpokeService;
38458
39508
  exports.BnUSDMigrationService = BnUSDMigrationService;
38459
39509
  exports.BridgeService = BridgeService;
38460
39510
  exports.CHAIN_KEYS = CHAIN_KEYS;
39511
+ exports.CHAIN_LOGO_BASE_URL = CHAIN_LOGO_BASE_URL;
38461
39512
  exports.CONFIG_VERSION = CONFIG_VERSION;
38462
39513
  exports.CREATE_INTENT_CODES = CREATE_INTENT_CODES;
38463
39514
  exports.ChainKeys = ChainKeys;
@@ -38492,6 +39543,8 @@ exports.GAS_ESTIMATION_CODES = GAS_ESTIMATION_CODES;
38492
39543
  exports.HALF_RAY = HALF_RAY;
38493
39544
  exports.HALF_WAD = HALF_WAD;
38494
39545
  exports.HUB_CHAIN_KEY = HUB_CHAIN_KEY;
39546
+ exports.HookKind = HookKind;
39547
+ exports.HookService = HookService;
38495
39548
  exports.HttpRelayError = HttpRelayError;
38496
39549
  exports.HubVaultSymbols = HubVaultSymbols;
38497
39550
  exports.ICON_CHAIN_KEYS = ICON_CHAIN_KEYS;
@@ -38505,6 +39558,7 @@ exports.IcxMigrationService = IcxMigrationService;
38505
39558
  exports.Injective20Token = Injective20Token;
38506
39559
  exports.InjectiveSpokeService = InjectiveSpokeService;
38507
39560
  exports.IntentCreatedEventAbi = IntentCreatedEventAbi;
39561
+ exports.IntentDataService = IntentDataService;
38508
39562
  exports.IntentDataType = IntentDataType;
38509
39563
  exports.IntentFilledEventAbi = IntentFilledEventAbi;
38510
39564
  exports.IntentRelayChainIdToChainKey = IntentRelayChainIdToChainKey;
@@ -38659,6 +39713,8 @@ exports.getReserveNormalizedIncome = getReserveNormalizedIncome;
38659
39713
  exports.getReservesEModes = getReservesEModes;
38660
39714
  exports.getSolanaAddressBytes = getSolanaAddressBytes;
38661
39715
  exports.getSolverConfig = getSolverConfig;
39716
+ exports.getSpokeHook = getSpokeHook;
39717
+ exports.getSpokeHooks = getSpokeHooks;
38662
39718
  exports.getStagingSolverTokens = getStagingSolverTokens;
38663
39719
  exports.getSupportedSolverTokens = getSupportedSolverTokens;
38664
39720
  exports.getTransactionPackets = getTransactionPackets;
@@ -38690,6 +39746,7 @@ exports.isEvmSpokeOnlyChainKey = isEvmSpokeOnlyChainKey;
38690
39746
  exports.isEvmSpokeOnlyChainKeyType = isEvmSpokeOnlyChainKeyType;
38691
39747
  exports.isEvmWalletProviderType = isEvmWalletProviderType;
38692
39748
  exports.isFeatureError = isFeatureError;
39749
+ exports.isHookSupportedToken = isHookSupportedToken;
38693
39750
  exports.isHubChainKey = isHubChainKey;
38694
39751
  exports.isHubChainKeyType = isHubChainKeyType;
38695
39752
  exports.isIconAddress = isIconAddress;
@@ -38793,6 +39850,7 @@ exports.moneyMarketSupportedTokens = moneyMarketSupportedTokens;
38793
39850
  exports.nativeToUSD = nativeToUSD;
38794
39851
  exports.nearSupportedTokens = nearSupportedTokens;
38795
39852
  exports.newbnUSDSpokeChainIds = newbnUSDSpokeChainIds;
39853
+ exports.noopAnalytics = noopAnalytics;
38796
39854
  exports.normalize = normalize;
38797
39855
  exports.normalizeBN = normalizeBN;
38798
39856
  exports.normalizePsbtToBase64 = normalizePsbtToBase64;
@@ -38821,6 +39879,7 @@ exports.relayTxAndWaitPacket = relayTxAndWaitPacket;
38821
39879
  exports.requestAddress = requestAddress;
38822
39880
  exports.requestJsonRpc = requestJsonRpc;
38823
39881
  exports.requestSigning = requestSigning;
39882
+ exports.resolveAnalytics = resolveAnalytics;
38824
39883
  exports.resolveLogger = resolveLogger;
38825
39884
  exports.retry = retry;
38826
39885
  exports.reverseEncodeAddress = reverseEncodeAddress;
@@ -38836,6 +39895,7 @@ exports.sonicWalletFactoryAbi = sonicWalletFactoryAbi;
38836
39895
  exports.spokeAssetManagerAbi = spokeAssetManagerAbi;
38837
39896
  exports.spokeChainConfig = spokeChainConfig;
38838
39897
  exports.spokeChainKeysSet = spokeChainKeysSet;
39898
+ exports.spokeHooks = spokeHooks;
38839
39899
  exports.stacksSupportedTokens = stacksSupportedTokens;
38840
39900
  exports.stagingSwapSupportedTokens = stagingSwapSupportedTokens;
38841
39901
  exports.stakedSodaAbi = stakedSodaAbi;