@ape.swap/bonds-sdk 5.1.49-test.2 → 5.1.49-test.3
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/config/constants/chains.js +1 -1
- package/dist/config/constants/chains.js.map +1 -1
- package/dist/config/constants/suiZapTokens.js +19 -7
- package/dist/config/constants/suiZapTokens.js.map +1 -1
- package/dist/constants/suiConstants.d.ts +1 -7
- package/dist/constants/suiConstants.js +6 -34
- package/dist/constants/suiConstants.js.map +1 -1
- package/dist/state/bonds/discoverSuiBonds.d.ts +6 -0
- package/dist/state/bonds/fetchBondsDataSui.js +38 -11
- package/dist/state/bonds/fetchBondsDataSui.js.map +1 -1
- package/dist/state/bonds/useBondsData.js +17 -9
- package/dist/state/bonds/useBondsData.js.map +1 -1
- package/dist/state/bonds/useBondsList.js +22 -22
- package/dist/state/bonds/useBondsList.js.map +1 -1
- package/dist/state/tokenPrices/useTokenPrices.js +1 -13
- package/dist/state/tokenPrices/useTokenPrices.js.map +1 -1
- package/dist/state/useSDKConfig.d.ts +1 -0
- package/dist/state/useSDKConfig.js.map +1 -1
- package/dist/state/zap/useSuiZapQuote.js +5 -28
- package/dist/state/zap/useSuiZapQuote.js.map +1 -1
- package/dist/utils/suiHelpers.d.ts +1 -1
- package/dist/utils/suiHelpers.js +5 -5
- package/dist/utils/suiHelpers.js.map +1 -1
- package/dist/views/BuyBond/BuyComponentSui.js +134 -50
- package/dist/views/BuyBond/BuyComponentSui.js.map +1 -1
- package/dist/views/BuyBond/utils.js +3 -0
- package/dist/views/BuyBond/utils.js.map +1 -1
- package/dist/views/YourBonds/components/UserBondRow/UserBondRowSui.js +2 -2
- package/dist/views/YourBonds/components/UserBondRow/UserBondRowSui.js.map +1 -1
- package/dist/views/YourBondsModal/components/Actions/ActionsSui.js +2 -2
- package/dist/views/YourBondsModal/components/Actions/ActionsSui.js.map +1 -1
- package/dist/views/YourBondsModal/components/TransferBondModal/TransferActionSui.d.ts +9 -0
- package/dist/views/YourBondsModal/components/TransferBondModal/TransferActionSui.js +71 -0
- package/dist/views/YourBondsModal/components/TransferBondModal/TransferActionSui.js.map +1 -0
- package/dist/views/YourBondsModal/components/TransferBondModal/index.js +2 -1
- package/dist/views/YourBondsModal/components/TransferBondModal/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/state/bonds/aptosBondsConfig.js +0 -183
- package/dist/state/bonds/aptosBondsConfig.js.map +0 -1
- package/dist/state/bonds/suiBondsConfig.d.ts +0 -4
- package/dist/state/bonds/suiBondsConfig.js +0 -227
- package/dist/state/bonds/suiBondsConfig.js.map +0 -1
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { useQuery } from '@tanstack/react-query';
|
|
2
2
|
import axios from 'axios';
|
|
3
|
-
import { ChainId } from '@ape.swap/apeswap-lists';
|
|
4
3
|
import { QUERY_KEYS } from '../../config/constants/queryKeys.js';
|
|
5
4
|
import { useSDKConfig } from '../useSDKConfig.js';
|
|
6
5
|
import { reportError } from '../../utils/reportError.js';
|
|
7
|
-
import { getSuiFallbackPrices } from '../bonds/suiBondsConfig.js';
|
|
8
6
|
|
|
9
7
|
function useTokenPrices() {
|
|
10
8
|
const SDKConfig = useSDKConfig();
|
|
@@ -21,17 +19,7 @@ function useTokenPrices() {
|
|
|
21
19
|
const getTokenPrices = async (priceApi, apiv2) => {
|
|
22
20
|
try {
|
|
23
21
|
const response = await axios.get(`${priceApi}/realtime/prices`);
|
|
24
|
-
|
|
25
|
-
// Merge fallback prices for Sui tokens not returned by price-api (e.g. testnet tokens)
|
|
26
|
-
const suiKey = ChainId.SUI;
|
|
27
|
-
const suiFallback = getSuiFallbackPrices();
|
|
28
|
-
const suiApiPrices = data[suiKey] ?? [];
|
|
29
|
-
const suiApiAddresses = new Set(suiApiPrices.map((p) => p.tokenAddress.toLowerCase()));
|
|
30
|
-
const missingSuiPrices = suiFallback.filter((p) => !suiApiAddresses.has(p.tokenAddress.toLowerCase()));
|
|
31
|
-
if (missingSuiPrices.length > 0) {
|
|
32
|
-
data[suiKey] = [...suiApiPrices, ...missingSuiPrices];
|
|
33
|
-
}
|
|
34
|
-
return data;
|
|
22
|
+
return response.data;
|
|
35
23
|
}
|
|
36
24
|
catch (error) {
|
|
37
25
|
reportError({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTokenPrices.js","sources":["../../../src/state/tokenPrices/useTokenPrices.ts"],"sourcesContent":["import { useQuery, UseQueryResult } from '@tanstack/react-query'\nimport axios from 'axios'\nimport { ChainId } from '@ape.swap/apeswap-lists'\nimport { QUERY_KEYS } from '../../config/constants/queryKeys'\nimport { useSDKConfig } from '../useSDKConfig'\nimport { reportError } from '../../utils/reportError'\
|
|
1
|
+
{"version":3,"file":"useTokenPrices.js","sources":["../../../src/state/tokenPrices/useTokenPrices.ts"],"sourcesContent":["import { useQuery, UseQueryResult } from '@tanstack/react-query'\nimport axios from 'axios'\nimport { ChainId } from '@ape.swap/apeswap-lists'\nimport { QUERY_KEYS } from '../../config/constants/queryKeys'\nimport { useSDKConfig } from '../useSDKConfig'\nimport { reportError } from '../../utils/reportError'\n\nexport interface TokenPrices {\n chainId: ChainId\n chainName: string\n tokenAddress: string\n name: string\n symbol: string\n price: number\n priceSource: string\n updatedAt: number\n secondsAgoUpdated: number\n error?: string\n}\n\nexport default function useTokenPrices(): UseQueryResult<Partial<Record<ChainId, TokenPrices[]>>> {\n const SDKConfig = useSDKConfig()\n const priceApi = SDKConfig?.urls?.priceApi\n const apiv2 = SDKConfig?.urls?.apiV2\n return useQuery({\n queryKey: [QUERY_KEYS.TOKEN_PRICES],\n queryFn: () => getTokenPrices(priceApi, apiv2),\n refetchInterval: 30000, // 30 sec\n refetchOnMount: false,\n refetchOnWindowFocus: false,\n })\n}\n\nexport const getTokenPrices = async (\n priceApi: string,\n apiv2: string,\n): Promise<Partial<Record<ChainId, TokenPrices[]>>> => {\n try {\n const response = await axios.get(`${priceApi}/realtime/prices`)\n return response.data\n } catch (error) {\n reportError({\n apiUrl: apiv2,\n error,\n extraInfo: { type: 'getTokenPrices', error },\n })\n throw new Error('Error getting tokens')\n }\n}\n"],"names":[],"mappings":";;;;;;AAoBc,SAAU,cAAc,GAAA;AACpC,IAAA,MAAM,SAAS,GAAG,YAAY,EAAE;AAChC,IAAA,MAAM,QAAQ,GAAG,SAAS,EAAE,IAAI,EAAE,QAAQ;AAC1C,IAAA,MAAM,KAAK,GAAG,SAAS,EAAE,IAAI,EAAE,KAAK;AACpC,IAAA,OAAO,QAAQ,CAAC;AACd,QAAA,QAAQ,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;QACnC,OAAO,EAAE,MAAM,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC;QAC9C,eAAe,EAAE,KAAK;AACtB,QAAA,cAAc,EAAE,KAAK;AACrB,QAAA,oBAAoB,EAAE,KAAK;AAC5B,KAAA,CAAC;AACJ;AAEO,MAAM,cAAc,GAAG,OAC5B,QAAgB,EAChB,KAAa,KACuC;AACpD,IAAA,IAAI;QACF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAA,EAAG,QAAQ,CAAA,gBAAA,CAAkB,CAAC;QAC/D,OAAO,QAAQ,CAAC,IAAI;IACtB;IAAE,OAAO,KAAK,EAAE;AACd,QAAA,WAAW,CAAC;AACV,YAAA,MAAM,EAAE,KAAK;YACb,KAAK;AACL,YAAA,SAAS,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE;AAC7C,SAAA,CAAC;AACF,QAAA,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;IACzC;AACF;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSDKConfig.js","sources":["../../src/state/useSDKConfig.ts"],"sourcesContent":["import { useEffect } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { QUERY_KEYS } from '../config/constants/queryKeys'\nimport { ChainId } from '@ape.swap/apeswap-lists'\nimport { setCustomRPCS } from '../config/constants/networks'\n\n// Prod URLS. Do not make changes here\nconst defaultUrls = {\n apiV2: 'https://api.ape.bond',\n realTimeApi: 'https://realtime-api.ape.bond',\n mainUrl: 'https://ape.bond',\n priceApi: 'https://price-api.ape.bond',\n}\n\n// Staging URLS.\nconst stagingUrls = {\n apiV2: 'https://staging-api.ape.bond',\n realTimeApi: 'https://realtime-api-staging.ape.bond',\n mainUrl: 'https://staging.ape.bond',\n priceApi: 'https://price-api.ape.bond',\n}\n\nexport interface SDKPropsDTO {\n referenceId: string\n chains: number[]\n hotBondChains?: number[]\n connector?: 'rainbowkit' | 'appkit' | 'default'\n useHotBonds?: boolean\n useTiers?: boolean\n useTGEBonds?: boolean\n useCardsView?: boolean\n showLowValueBonds?: boolean\n bondPartner?: string\n namingPreference?: 'Discount' | 'Bonus'\n urls?: Partial<Record<URLKeys, string>>\n theme?: any\n highestCompatibleVersion?: string\n blockSales?: boolean\n customBranch?: string\n highlightedBond?: string\n customRPCS?: Partial<Record<ChainId, string[]>>\n aptosAddress?: string\n suiAddress?: string\n}\n\nexport interface SDKProps {\n referenceId: string\n chains: number[]\n hotBondChains: number[]\n connector?: 'rainbowkit' | 'appkit' | 'default'\n useHotBonds: boolean\n useTiers: boolean\n useTGEBonds: boolean\n showLowValueBonds: boolean\n bondPartner?: string\n namingPreference: 'Discount' | 'Bonus'\n urls: Record<URLKeys, string>\n theme?: any\n highestCompatibleVersion?: string\n evmAddress?: string\n solAddress?: string\n aptosAddress?: string\n suiAddress?: string\n useCardsView?: boolean\n blockSales?: boolean\n customBranch?: string\n highlightedBond?: string\n}\n\nexport const useSDKConfig = (config?: SDKPropsDTO): SDKProps => {\n const urls = process.env.NODE_ENV === 'production' ? defaultUrls : stagingUrls\n\n const initialData: SDKProps = {\n referenceId: '',\n chains: [],\n hotBondChains: [ChainId.BSC, ChainId.MATIC],\n useHotBonds: true,\n connector: 'default',\n useTGEBonds: false,\n showLowValueBonds: false,\n bondPartner: undefined,\n namingPreference: 'Bonus',\n useCardsView: false,\n blockSales: false,\n customBranch: '',\n ...config,\n useTiers: config?.namingPreference === 'Discount' ? false : (config?.useTiers ?? false), // for the time being we'll assume discount preference does not want to useTiers\n urls: { ...urls, ...config?.urls },\n highestCompatibleVersion: '2.2.0',\n }\n\n useEffect(() => {\n if (config?.customRPCS) {\n setCustomRPCS(config.customRPCS)\n }\n }, [config?.customRPCS])\n\n const { data } = useQuery({\n queryKey: [QUERY_KEYS.SDK_CONFIG],\n queryFn: () => {\n throw new Error('Just a hotfix for latest versions of react-query that make queryFn a required prop')\n },\n initialData,\n })\n return data as SDKProps\n}\n\nexport type URLKeys = 'apiV2' | 'realTimeApi' | 'mainUrl' | 'priceApi'\n\nexport const useURLByEnvironment = (key: URLKeys) => {\n const config = useSDKConfig()\n return config?.urls?.[key] as string\n}\n"],"names":[],"mappings":";;;;;;AAMA;AACA,MAAM,WAAW,GAAG;AAClB,IAAA,KAAK,EAAE,sBAAsB;AAC7B,IAAA,WAAW,EAAE,+BAA+B;AAC5C,IAAA,OAAO,EAAE,kBAAkB;AAC3B,IAAA,QAAQ,EAAE,4BAA4B;CACvC;AAED;AACA,MAAM,WAAW,GAAG;AAClB,IAAA,KAAK,EAAE,8BAA8B;AACrC,IAAA,WAAW,EAAE,uCAAuC;AACpD,IAAA,OAAO,EAAE,0BAA0B;AACnC,IAAA,QAAQ,EAAE,4BAA4B;CACvC;
|
|
1
|
+
{"version":3,"file":"useSDKConfig.js","sources":["../../src/state/useSDKConfig.ts"],"sourcesContent":["import { useEffect } from 'react'\nimport { useQuery } from '@tanstack/react-query'\nimport { QUERY_KEYS } from '../config/constants/queryKeys'\nimport { ChainId } from '@ape.swap/apeswap-lists'\nimport { setCustomRPCS } from '../config/constants/networks'\n\n// Prod URLS. Do not make changes here\nconst defaultUrls = {\n apiV2: 'https://api.ape.bond',\n realTimeApi: 'https://realtime-api.ape.bond',\n mainUrl: 'https://ape.bond',\n priceApi: 'https://price-api.ape.bond',\n}\n\n// Staging URLS.\nconst stagingUrls = {\n apiV2: 'https://staging-api.ape.bond',\n realTimeApi: 'https://realtime-api-staging.ape.bond',\n mainUrl: 'https://staging.ape.bond',\n priceApi: 'https://price-api.ape.bond',\n}\n\nexport interface SDKPropsDTO {\n referenceId: string\n chains: number[]\n hotBondChains?: number[]\n connector?: 'rainbowkit' | 'appkit' | 'default'\n useHotBonds?: boolean\n useTiers?: boolean\n useTGEBonds?: boolean\n useCardsView?: boolean\n showLowValueBonds?: boolean\n bondPartner?: string\n namingPreference?: 'Discount' | 'Bonus'\n urls?: Partial<Record<URLKeys, string>>\n theme?: any\n highestCompatibleVersion?: string\n blockSales?: boolean\n customBranch?: string\n highlightedBond?: string\n customRPCS?: Partial<Record<ChainId, string[]>>\n aptosAddress?: string\n suiAddress?: string\n suiTreasuryAddresses?: string[]\n}\n\nexport interface SDKProps {\n referenceId: string\n chains: number[]\n hotBondChains: number[]\n connector?: 'rainbowkit' | 'appkit' | 'default'\n useHotBonds: boolean\n useTiers: boolean\n useTGEBonds: boolean\n showLowValueBonds: boolean\n bondPartner?: string\n namingPreference: 'Discount' | 'Bonus'\n urls: Record<URLKeys, string>\n theme?: any\n highestCompatibleVersion?: string\n evmAddress?: string\n solAddress?: string\n aptosAddress?: string\n suiAddress?: string\n useCardsView?: boolean\n blockSales?: boolean\n customBranch?: string\n highlightedBond?: string\n}\n\nexport const useSDKConfig = (config?: SDKPropsDTO): SDKProps => {\n const urls = process.env.NODE_ENV === 'production' ? defaultUrls : stagingUrls\n\n const initialData: SDKProps = {\n referenceId: '',\n chains: [],\n hotBondChains: [ChainId.BSC, ChainId.MATIC],\n useHotBonds: true,\n connector: 'default',\n useTGEBonds: false,\n showLowValueBonds: false,\n bondPartner: undefined,\n namingPreference: 'Bonus',\n useCardsView: false,\n blockSales: false,\n customBranch: '',\n ...config,\n useTiers: config?.namingPreference === 'Discount' ? false : (config?.useTiers ?? false), // for the time being we'll assume discount preference does not want to useTiers\n urls: { ...urls, ...config?.urls },\n highestCompatibleVersion: '2.2.0',\n }\n\n useEffect(() => {\n if (config?.customRPCS) {\n setCustomRPCS(config.customRPCS)\n }\n }, [config?.customRPCS])\n\n const { data } = useQuery({\n queryKey: [QUERY_KEYS.SDK_CONFIG],\n queryFn: () => {\n throw new Error('Just a hotfix for latest versions of react-query that make queryFn a required prop')\n },\n initialData,\n })\n return data as SDKProps\n}\n\nexport type URLKeys = 'apiV2' | 'realTimeApi' | 'mainUrl' | 'priceApi'\n\nexport const useURLByEnvironment = (key: URLKeys) => {\n const config = useSDKConfig()\n return config?.urls?.[key] as string\n}\n"],"names":[],"mappings":";;;;;;AAMA;AACA,MAAM,WAAW,GAAG;AAClB,IAAA,KAAK,EAAE,sBAAsB;AAC7B,IAAA,WAAW,EAAE,+BAA+B;AAC5C,IAAA,OAAO,EAAE,kBAAkB;AAC3B,IAAA,QAAQ,EAAE,4BAA4B;CACvC;AAED;AACA,MAAM,WAAW,GAAG;AAClB,IAAA,KAAK,EAAE,8BAA8B;AACrC,IAAA,WAAW,EAAE,uCAAuC;AACpD,IAAA,OAAO,EAAE,0BAA0B;AACnC,IAAA,QAAQ,EAAE,4BAA4B;CACvC;AAkDM,MAAM,YAAY,GAAG,CAAC,MAAoB,KAAc;AAC7D,IAAA,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,GAAG,WAAW,GAAG,WAAW;AAE9E,IAAA,MAAM,WAAW,GAAa;AAC5B,QAAA,WAAW,EAAE,EAAE;AACf,QAAA,MAAM,EAAE,EAAE;QACV,aAAa,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC;AAC3C,QAAA,WAAW,EAAE,IAAI;AACjB,QAAA,SAAS,EAAE,SAAS;AACpB,QAAA,WAAW,EAAE,KAAK;AAClB,QAAA,iBAAiB,EAAE,KAAK;AACxB,QAAA,WAAW,EAAE,SAAS;AACtB,QAAA,gBAAgB,EAAE,OAAO;AACzB,QAAA,YAAY,EAAE,KAAK;AACnB,QAAA,UAAU,EAAE,KAAK;AACjB,QAAA,YAAY,EAAE,EAAE;AAChB,QAAA,GAAG,MAAM;QACT,QAAQ,EAAE,MAAM,EAAE,gBAAgB,KAAK,UAAU,GAAG,KAAK,IAAI,MAAM,EAAE,QAAQ,IAAI,KAAK,CAAC;QACvF,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,EAAE,IAAI,EAAE;AAClC,QAAA,wBAAwB,EAAE,OAAO;KAClC;IAED,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,MAAM,EAAE,UAAU,EAAE;AACtB,YAAA,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC;QAClC;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAExB,IAAA,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;AACxB,QAAA,QAAQ,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;QACjC,OAAO,EAAE,MAAK;AACZ,YAAA,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC;QACvG,CAAC;QACD,WAAW;AACZ,KAAA,CAAC;AACF,IAAA,OAAO,IAAgB;AACzB;AAIO,MAAM,mBAAmB,GAAG,CAAC,GAAY,KAAI;AAClD,IAAA,MAAM,MAAM,GAAG,YAAY,EAAE;AAC7B,IAAA,OAAO,MAAM,EAAE,IAAI,GAAG,GAAG,CAAW;AACtC;;;;"}
|
|
@@ -5,8 +5,7 @@ import { useQuery } from '@tanstack/react-query';
|
|
|
5
5
|
import { QUERY_KEYS } from '../../config/constants/queryKeys.js';
|
|
6
6
|
import useDebounce from '../../hooks/useDebounce.js';
|
|
7
7
|
import axios from 'axios';
|
|
8
|
-
import
|
|
9
|
-
import { getSuiFallbackPrices } from '../bonds/suiBondsConfig.js';
|
|
8
|
+
import '../../constants/suiConstants.js';
|
|
10
9
|
|
|
11
10
|
// =============================================================================
|
|
12
11
|
// useSuiZapQuote — Aftermath Finance DEX aggregator quote for Sui zap
|
|
@@ -54,28 +53,6 @@ const useSuiZapQuote = (typedValue, inputToken, bond, account, slippage = 0.5) =
|
|
|
54
53
|
};
|
|
55
54
|
}, [inputTokenAddress, principalTokenAddress, inputAmountAtomic, account]);
|
|
56
55
|
// -------------------------------------------------------------------------
|
|
57
|
-
// Testnet mock: calculate quote from fallback prices (no DEX available)
|
|
58
|
-
// -------------------------------------------------------------------------
|
|
59
|
-
const testnetMockQuote = useMemo(() => {
|
|
60
|
-
if (IS_SUI_MAINNET || !queryParams)
|
|
61
|
-
return null;
|
|
62
|
-
const fallbackPrices = getSuiFallbackPrices();
|
|
63
|
-
const inputPrice = fallbackPrices.find((p) => p.tokenAddress.toLowerCase() === queryParams.coinInType.toLowerCase())?.price;
|
|
64
|
-
const outputPrice = fallbackPrices.find((p) => p.tokenAddress.toLowerCase() === queryParams.coinOutType.toLowerCase())?.price;
|
|
65
|
-
if (!inputPrice || !outputPrice || outputPrice === 0)
|
|
66
|
-
return null;
|
|
67
|
-
const inputHuman = new BigNumber(queryParams.coinInAmount).div(new BigNumber(10).pow(inputDecimals));
|
|
68
|
-
const outputHuman = inputHuman.times(inputPrice).div(outputPrice);
|
|
69
|
-
const outputAtomic = outputHuman.times(new BigNumber(10).pow(principalDecimals)).integerValue(BigNumber.ROUND_FLOOR);
|
|
70
|
-
return {
|
|
71
|
-
routes: [],
|
|
72
|
-
coinIn: { type: queryParams.coinInType, amount: queryParams.coinInAmount, tradeFee: '0' },
|
|
73
|
-
coinOut: { type: queryParams.coinOutType, amount: outputAtomic.toFixed(0), tradeFee: '0' },
|
|
74
|
-
spotPrice: inputPrice / outputPrice,
|
|
75
|
-
netTradeFeePercentage: 0,
|
|
76
|
-
};
|
|
77
|
-
}, [queryParams, inputDecimals, principalDecimals]);
|
|
78
|
-
// -------------------------------------------------------------------------
|
|
79
56
|
// Mainnet: fetch real quote from Aftermath
|
|
80
57
|
// -------------------------------------------------------------------------
|
|
81
58
|
const fetchAftermathQuote = async () => {
|
|
@@ -91,13 +68,13 @@ const useSuiZapQuote = (typedValue, inputToken, bond, account, slippage = 0.5) =
|
|
|
91
68
|
queryKey: [QUERY_KEYS.ZAP_TOKEN_QUOTE, 'aftermath-sui', queryParams],
|
|
92
69
|
queryFn: fetchAftermathQuote,
|
|
93
70
|
refetchInterval: 60000,
|
|
94
|
-
enabled:
|
|
71
|
+
enabled: !!queryParams,
|
|
95
72
|
retry: 1,
|
|
96
73
|
staleTime: 30000,
|
|
97
74
|
});
|
|
98
75
|
// Use testnet mock on testnet, real quote on mainnet
|
|
99
|
-
const activeQuote =
|
|
100
|
-
const zapError =
|
|
76
|
+
const activeQuote = quoteData ?? null;
|
|
77
|
+
const zapError = !!error;
|
|
101
78
|
// Convert amounts to human-readable
|
|
102
79
|
const estimatedDepositAmount = activeQuote?.coinOut?.amount
|
|
103
80
|
? new BigNumber(parseAftermathAmount(activeQuote.coinOut.amount))
|
|
@@ -111,7 +88,7 @@ const useSuiZapQuote = (typedValue, inputToken, bond, account, slippage = 0.5) =
|
|
|
111
88
|
.times(1 - slippage / 100)
|
|
112
89
|
.toFixed(principalDecimals)
|
|
113
90
|
: '0';
|
|
114
|
-
const zapLoading =
|
|
91
|
+
const zapLoading = isLoading || isFetching ;
|
|
115
92
|
return [zapLoading, activeQuote, estimatedDepositAmount, zapError, minimumDepositAmount];
|
|
116
93
|
};
|
|
117
94
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSuiZapQuote.js","sources":["../../../src/state/zap/useSuiZapQuote.ts"],"sourcesContent":["// =============================================================================\n// useSuiZapQuote — Aftermath Finance DEX aggregator quote for Sui zap\n// =============================================================================\n//\n// Mainnet: fetches a swap quote from Aftermath Finance (Sui DEX aggregator)\n// when the user selects an input token different from the bond's principal token.\n//\n// Testnet: no DEX aggregator supports Sui testnet or our custom test tokens.\n// Returns a mock quote calculated from fallback prices so the full zap UI and\n// two-TX flow (mint → deposit) can be tested end-to-end.\n//\n// Aftermath API: POST https://aftermath.finance/api/router/trade-route\n\nimport { useMemo } from 'react'\nimport BigNumber from 'bignumber.js'\nimport { ChainId } from '@ape.swap/apeswap-lists'\nimport { useQuery } from '@tanstack/react-query'\nimport { QUERY_KEYS } from '../../config/constants/queryKeys'\nimport { BondsData } from '../../types/bonds'\nimport useDebounce from '../../hooks/useDebounce'\nimport axios from 'axios'\nimport type { SuiZapToken } from '../../config/constants/suiZapTokens'\nimport { IS_SUI_MAINNET } from '../../constants/suiConstants'\nimport { getSuiFallbackPrices } from '../bonds/suiBondsConfig'\n\nconst AFTERMATH_API_URL = 'https://aftermath.finance/api/router/trade-route'\nconst AFTERMATH_TX_API_URL = 'https://aftermath.finance/api/router/transactions/trade'\n\ninterface AftermathCoinInfo {\n type: string\n amount: string // atomic units with BigInt \"n\" suffix, e.g. \"963906n\"\n tradeFee: string\n}\n\nexport interface AftermathTradeRoute {\n routes: Array<{\n paths: Array<Record<string, unknown>>\n portion: string\n coinIn: AftermathCoinInfo\n coinOut: AftermathCoinInfo\n spotPrice: number\n }>\n coinIn: AftermathCoinInfo\n coinOut: AftermathCoinInfo\n spotPrice: number\n netTradeFeePercentage: number\n}\n\n/** Parse Aftermath amount strings — they may have a trailing \"n\" (BigInt notation) */\nconst parseAftermathAmount = (amount: string): string => {\n return amount.replace(/n$/, '')\n}\n\nconst useSuiZapQuote = (\n typedValue: string,\n inputToken: SuiZapToken | undefined,\n bond: BondsData | undefined,\n account?: string,\n slippage = 0.5,\n): [\n loading: boolean,\n response: AftermathTradeRoute | null,\n depositAmount: string,\n error: boolean,\n minimumDepositAmount: string,\n] => {\n const debouncedInput = useDebounce(typedValue, 400)\n\n const principalTokenAddress = bond?.lpToken?.address?.[ChainId.SUI]\n const inputTokenAddress = inputToken?.address\n\n // Aftermath uses atomic units — convert from human-readable\n const inputDecimals = inputToken?.decimals ?? 9\n const inputAmountAtomic = useMemo(() => {\n const val = new BigNumber(debouncedInput ?? '0')\n if (val.isNaN() || val.lte(0)) return '0'\n return val.times(new BigNumber(10).pow(inputDecimals)).integerValue(BigNumber.ROUND_FLOOR).toFixed(0)\n }, [debouncedInput, inputDecimals])\n\n const principalDecimals = bond?.lpToken?.decimals?.[ChainId.SUI] ?? 6\n\n const queryParams = useMemo(() => {\n if (\n !inputTokenAddress ||\n !principalTokenAddress ||\n inputAmountAtomic === '0' ||\n !account ||\n inputTokenAddress.toLowerCase() === principalTokenAddress.toLowerCase()\n ) {\n return null\n }\n\n return {\n coinInType: inputTokenAddress,\n coinOutType: principalTokenAddress,\n coinInAmount: inputAmountAtomic,\n }\n }, [inputTokenAddress, principalTokenAddress, inputAmountAtomic, account])\n\n // -------------------------------------------------------------------------\n // Testnet mock: calculate quote from fallback prices (no DEX available)\n // -------------------------------------------------------------------------\n const testnetMockQuote = useMemo((): AftermathTradeRoute | null => {\n if (IS_SUI_MAINNET || !queryParams) return null\n\n const fallbackPrices = getSuiFallbackPrices()\n const inputPrice = fallbackPrices.find(\n (p) => p.tokenAddress.toLowerCase() === queryParams.coinInType.toLowerCase(),\n )?.price\n const outputPrice = fallbackPrices.find(\n (p) => p.tokenAddress.toLowerCase() === queryParams.coinOutType.toLowerCase(),\n )?.price\n\n if (!inputPrice || !outputPrice || outputPrice === 0) return null\n\n const inputHuman = new BigNumber(queryParams.coinInAmount).div(new BigNumber(10).pow(inputDecimals))\n const outputHuman = inputHuman.times(inputPrice).div(outputPrice)\n const outputAtomic = outputHuman.times(new BigNumber(10).pow(principalDecimals)).integerValue(BigNumber.ROUND_FLOOR)\n\n return {\n routes: [],\n coinIn: { type: queryParams.coinInType, amount: queryParams.coinInAmount, tradeFee: '0' },\n coinOut: { type: queryParams.coinOutType, amount: outputAtomic.toFixed(0), tradeFee: '0' },\n spotPrice: inputPrice / outputPrice,\n netTradeFeePercentage: 0,\n }\n }, [queryParams, inputDecimals, principalDecimals])\n\n // -------------------------------------------------------------------------\n // Mainnet: fetch real quote from Aftermath\n // -------------------------------------------------------------------------\n const fetchAftermathQuote = async (): Promise<AftermathTradeRoute | null> => {\n if (!queryParams) return null\n\n const response = await axios.post<AftermathTradeRoute>(AFTERMATH_API_URL, queryParams)\n const data = response.data\n if (!data?.coinOut?.amount) return null\n return data\n }\n\n const {\n data: quoteData,\n isLoading,\n isFetching,\n error,\n } = useQuery({\n queryKey: [QUERY_KEYS.ZAP_TOKEN_QUOTE, 'aftermath-sui', queryParams],\n queryFn: fetchAftermathQuote,\n refetchInterval: 60000,\n enabled: IS_SUI_MAINNET && !!queryParams,\n retry: 1,\n staleTime: 30000,\n })\n\n // Use testnet mock on testnet, real quote on mainnet\n const activeQuote = IS_SUI_MAINNET ? (quoteData ?? null) : testnetMockQuote\n const zapError = IS_SUI_MAINNET ? !!error : false\n\n // Convert amounts to human-readable\n const estimatedDepositAmount = activeQuote?.coinOut?.amount\n ? new BigNumber(parseAftermathAmount(activeQuote.coinOut.amount))\n .div(new BigNumber(10).pow(principalDecimals))\n .toFixed(principalDecimals)\n : '0'\n\n // Apply slippage for minimum deposit amount\n const minimumDepositAmount = activeQuote?.coinOut?.amount\n ? new BigNumber(parseAftermathAmount(activeQuote.coinOut.amount))\n .div(new BigNumber(10).pow(principalDecimals))\n .times(1 - slippage / 100)\n .toFixed(principalDecimals)\n : '0'\n\n const zapLoading = IS_SUI_MAINNET ? isLoading || isFetching : false\n\n return [zapLoading, activeQuote, estimatedDepositAmount, zapError, minimumDepositAmount]\n}\n\nexport { AFTERMATH_TX_API_URL }\n\nexport default useSuiZapQuote\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useSuiZapQuote.js","sources":["../../../src/state/zap/useSuiZapQuote.ts"],"sourcesContent":["// =============================================================================\n// useSuiZapQuote — Aftermath Finance DEX aggregator quote for Sui zap\n// =============================================================================\n//\n// Mainnet: fetches a swap quote from Aftermath Finance (Sui DEX aggregator)\n// when the user selects an input token different from the bond's principal token.\n//\n// Testnet: no DEX aggregator supports Sui testnet or our custom test tokens.\n// Returns a mock quote calculated from fallback prices so the full zap UI and\n// two-TX flow (mint → deposit) can be tested end-to-end.\n//\n// Aftermath API: POST https://aftermath.finance/api/router/trade-route\n\nimport { useMemo } from 'react'\nimport BigNumber from 'bignumber.js'\nimport { ChainId } from '@ape.swap/apeswap-lists'\nimport { useQuery } from '@tanstack/react-query'\nimport { QUERY_KEYS } from '../../config/constants/queryKeys'\nimport { BondsData } from '../../types/bonds'\nimport useDebounce from '../../hooks/useDebounce'\nimport axios from 'axios'\nimport type { SuiZapToken } from '../../config/constants/suiZapTokens'\nimport { IS_SUI_MAINNET } from '../../constants/suiConstants'\n\nconst AFTERMATH_API_URL = 'https://aftermath.finance/api/router/trade-route'\nconst AFTERMATH_TX_API_URL = 'https://aftermath.finance/api/router/transactions/trade'\n\ninterface AftermathCoinInfo {\n type: string\n amount: string // atomic units with BigInt \"n\" suffix, e.g. \"963906n\"\n tradeFee: string\n}\n\nexport interface AftermathTradeRoute {\n routes: Array<{\n paths: Array<Record<string, unknown>>\n portion: string\n coinIn: AftermathCoinInfo\n coinOut: AftermathCoinInfo\n spotPrice: number\n }>\n coinIn: AftermathCoinInfo\n coinOut: AftermathCoinInfo\n spotPrice: number\n netTradeFeePercentage: number\n}\n\n/** Parse Aftermath amount strings — they may have a trailing \"n\" (BigInt notation) */\nconst parseAftermathAmount = (amount: string): string => {\n return amount.replace(/n$/, '')\n}\n\nconst useSuiZapQuote = (\n typedValue: string,\n inputToken: SuiZapToken | undefined,\n bond: BondsData | undefined,\n account?: string,\n slippage = 0.5,\n): [\n loading: boolean,\n response: AftermathTradeRoute | null,\n depositAmount: string,\n error: boolean,\n minimumDepositAmount: string,\n] => {\n const debouncedInput = useDebounce(typedValue, 400)\n\n const principalTokenAddress = bond?.lpToken?.address?.[ChainId.SUI]\n const inputTokenAddress = inputToken?.address\n\n // Aftermath uses atomic units — convert from human-readable\n const inputDecimals = inputToken?.decimals ?? 9\n const inputAmountAtomic = useMemo(() => {\n const val = new BigNumber(debouncedInput ?? '0')\n if (val.isNaN() || val.lte(0)) return '0'\n return val.times(new BigNumber(10).pow(inputDecimals)).integerValue(BigNumber.ROUND_FLOOR).toFixed(0)\n }, [debouncedInput, inputDecimals])\n\n const principalDecimals = bond?.lpToken?.decimals?.[ChainId.SUI] ?? 6\n\n const queryParams = useMemo(() => {\n if (\n !inputTokenAddress ||\n !principalTokenAddress ||\n inputAmountAtomic === '0' ||\n !account ||\n inputTokenAddress.toLowerCase() === principalTokenAddress.toLowerCase()\n ) {\n return null\n }\n\n return {\n coinInType: inputTokenAddress,\n coinOutType: principalTokenAddress,\n coinInAmount: inputAmountAtomic,\n }\n }, [inputTokenAddress, principalTokenAddress, inputAmountAtomic, account])\n\n // -------------------------------------------------------------------------\n // Mainnet: fetch real quote from Aftermath\n // -------------------------------------------------------------------------\n const fetchAftermathQuote = async (): Promise<AftermathTradeRoute | null> => {\n if (!queryParams) return null\n\n const response = await axios.post<AftermathTradeRoute>(AFTERMATH_API_URL, queryParams)\n const data = response.data\n if (!data?.coinOut?.amount) return null\n return data\n }\n\n const {\n data: quoteData,\n isLoading,\n isFetching,\n error,\n } = useQuery({\n queryKey: [QUERY_KEYS.ZAP_TOKEN_QUOTE, 'aftermath-sui', queryParams],\n queryFn: fetchAftermathQuote,\n refetchInterval: 60000,\n enabled: IS_SUI_MAINNET && !!queryParams,\n retry: 1,\n staleTime: 30000,\n })\n\n // Use testnet mock on testnet, real quote on mainnet\n const activeQuote = quoteData ?? null\n const zapError = !!error\n\n // Convert amounts to human-readable\n const estimatedDepositAmount = activeQuote?.coinOut?.amount\n ? new BigNumber(parseAftermathAmount(activeQuote.coinOut.amount))\n .div(new BigNumber(10).pow(principalDecimals))\n .toFixed(principalDecimals)\n : '0'\n\n // Apply slippage for minimum deposit amount\n const minimumDepositAmount = activeQuote?.coinOut?.amount\n ? new BigNumber(parseAftermathAmount(activeQuote.coinOut.amount))\n .div(new BigNumber(10).pow(principalDecimals))\n .times(1 - slippage / 100)\n .toFixed(principalDecimals)\n : '0'\n\n const zapLoading = IS_SUI_MAINNET ? isLoading || isFetching : false\n\n return [zapLoading, activeQuote, estimatedDepositAmount, zapError, minimumDepositAmount]\n}\n\nexport { AFTERMATH_TX_API_URL }\n\nexport default useSuiZapQuote\n"],"names":[],"mappings":"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"}
|
|
@@ -2,5 +2,5 @@ import { SuiClient } from '@mysten/sui/client';
|
|
|
2
2
|
export declare const getSuiClient: () => SuiClient;
|
|
3
3
|
export declare const toAtomicUnits: (amount: string | number, decimals: number) => string;
|
|
4
4
|
export declare const fromAtomicUnits: (amount: string | number, decimals: number) => number;
|
|
5
|
-
export declare const readFreshTrueBondPrice: (marketObjectId
|
|
5
|
+
export declare const readFreshTrueBondPrice: (marketObjectId?: string) => Promise<bigint>;
|
|
6
6
|
export declare const verifySuiTxSuccess: (digest: string) => Promise<void>;
|
package/dist/utils/suiHelpers.js
CHANGED
|
@@ -45,14 +45,16 @@ const valueOfToken = (fromDec, toDec, amount) => {
|
|
|
45
45
|
return amount / pow10bi(fromDec - toDec);
|
|
46
46
|
};
|
|
47
47
|
const readFreshTrueBondPrice = async (marketObjectId) => {
|
|
48
|
+
if (!marketObjectId) {
|
|
49
|
+
throw new Error('marketObjectId is required');
|
|
50
|
+
}
|
|
48
51
|
const client = getSuiClient();
|
|
49
52
|
const obj = await client.getObject({ id: marketObjectId, options: { showContent: true } });
|
|
50
53
|
if (!obj.data?.content || obj.data.content.dataType !== 'moveObject') {
|
|
51
54
|
throw new Error(`[Sui] Could not read BondMarket ${marketObjectId}`);
|
|
52
55
|
}
|
|
53
56
|
const f = obj.data.content.fields;
|
|
54
|
-
const terms = f.terms?.fields ??
|
|
55
|
-
f.terms;
|
|
57
|
+
const terms = f.terms?.fields ?? f.terms;
|
|
56
58
|
const totalDebt = BigInt(String(f.total_debt ?? '0'));
|
|
57
59
|
const payoutInitialSupply = BigInt(String(f.payout_token_initial_supply ?? '0'));
|
|
58
60
|
const controlVariable = BigInt(String(terms.control_variable ?? '0'));
|
|
@@ -75,9 +77,7 @@ const readFreshTrueBondPrice = async (marketObjectId) => {
|
|
|
75
77
|
const currentDebtPayout = valueOfToken(principalDecimals, payoutDecimals, currentDebtU64);
|
|
76
78
|
const payoutScale = pow10bi(payoutDecimals);
|
|
77
79
|
const principalScale = pow10bi(principalDecimals);
|
|
78
|
-
const debtRatio = payoutInitialSupply > 0n
|
|
79
|
-
? (currentDebtPayout * payoutScale) / payoutInitialSupply
|
|
80
|
-
: 0n;
|
|
80
|
+
const debtRatio = payoutInitialSupply > 0n ? (currentDebtPayout * payoutScale) / payoutInitialSupply : 0n;
|
|
81
81
|
const basePrice = (controlVariable * debtRatio * principalScale) / PRICE_DECIMALS;
|
|
82
82
|
const price = basePrice < minimumPrice ? minimumPrice : basePrice;
|
|
83
83
|
// calculate_true_price (includes fee)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"suiHelpers.js","sources":["../../src/utils/suiHelpers.ts"],"sourcesContent":["import { SuiClient } from '@mysten/sui/client'\nimport BigNumber from 'bignumber.js'\nimport { SUI_FULLNODE_URL } from '../constants/suiConstants'\n\n// ---------------------------------------------------------------------------\n// Sui client — lazy singleton\n// ---------------------------------------------------------------------------\nlet _suiClient: SuiClient | undefined\n\nexport const getSuiClient = (): SuiClient => {\n if (_suiClient) return _suiClient\n _suiClient = new SuiClient({ url: SUI_FULLNODE_URL })\n return _suiClient\n}\n\n// ---------------------------------------------------------------------------\n// Unit conversion\n// ---------------------------------------------------------------------------\n// User inputs live in \"whole tokens\" (e.g. \"1.5 SUI\"). The Sui SDK\n// serialises numeric function arguments from strings, so we convert to\n// atomic units and return a stringified BigInt.\nexport const toAtomicUnits = (amount: string | number, decimals: number): string => {\n if (amount === '' || amount == null) return '0'\n const bn = new BigNumber(amount).times(new BigNumber(10).pow(decimals))\n // Floor so we never over-spend what the user typed.\n return bn.integerValue(BigNumber.ROUND_FLOOR).toFixed(0)\n}\n\n// Atomic → human-readable.\nexport const fromAtomicUnits = (amount: string | number, decimals: number): number => {\n if (amount === '' || amount == null) return 0\n return new BigNumber(amount).div(new BigNumber(10).pow(decimals)).toNumber()\n}\n\n// ---------------------------------------------------------------------------\n// Fresh bond price reader — reads the BondMarket object on-chain and\n// computes the current true_price using the same bond_math formulas as\n// the Move contract. Returns the u64 value (scaled 1e8).\n// ---------------------------------------------------------------------------\n\nconst PRICE_DECIMALS = 100_000_000n // 1e8\nconst PERCENTAGE_BASE = 1_000_000n // 1e6\n\nconst pow10bi = (n: number): bigint => 10n ** BigInt(n)\n\nconst valueOfToken = (fromDec: number, toDec: number, amount: bigint): bigint => {\n if (toDec >= fromDec) return amount * pow10bi(toDec - fromDec)\n return amount / pow10bi(fromDec - toDec)\n}\n\nexport const readFreshTrueBondPrice = async (marketObjectId
|
|
1
|
+
{"version":3,"file":"suiHelpers.js","sources":["../../src/utils/suiHelpers.ts"],"sourcesContent":["import { SuiClient } from '@mysten/sui/client'\nimport BigNumber from 'bignumber.js'\nimport { SUI_FULLNODE_URL } from '../constants/suiConstants'\n\n// ---------------------------------------------------------------------------\n// Sui client — lazy singleton\n// ---------------------------------------------------------------------------\nlet _suiClient: SuiClient | undefined\n\nexport const getSuiClient = (): SuiClient => {\n if (_suiClient) return _suiClient\n _suiClient = new SuiClient({ url: SUI_FULLNODE_URL })\n return _suiClient\n}\n\n// ---------------------------------------------------------------------------\n// Unit conversion\n// ---------------------------------------------------------------------------\n// User inputs live in \"whole tokens\" (e.g. \"1.5 SUI\"). The Sui SDK\n// serialises numeric function arguments from strings, so we convert to\n// atomic units and return a stringified BigInt.\nexport const toAtomicUnits = (amount: string | number, decimals: number): string => {\n if (amount === '' || amount == null) return '0'\n const bn = new BigNumber(amount).times(new BigNumber(10).pow(decimals))\n // Floor so we never over-spend what the user typed.\n return bn.integerValue(BigNumber.ROUND_FLOOR).toFixed(0)\n}\n\n// Atomic → human-readable.\nexport const fromAtomicUnits = (amount: string | number, decimals: number): number => {\n if (amount === '' || amount == null) return 0\n return new BigNumber(amount).div(new BigNumber(10).pow(decimals)).toNumber()\n}\n\n// ---------------------------------------------------------------------------\n// Fresh bond price reader — reads the BondMarket object on-chain and\n// computes the current true_price using the same bond_math formulas as\n// the Move contract. Returns the u64 value (scaled 1e8).\n// ---------------------------------------------------------------------------\n\nconst PRICE_DECIMALS = 100_000_000n // 1e8\nconst PERCENTAGE_BASE = 1_000_000n // 1e6\n\nconst pow10bi = (n: number): bigint => 10n ** BigInt(n)\n\nconst valueOfToken = (fromDec: number, toDec: number, amount: bigint): bigint => {\n if (toDec >= fromDec) return amount * pow10bi(toDec - fromDec)\n return amount / pow10bi(fromDec - toDec)\n}\n\nexport const readFreshTrueBondPrice = async (marketObjectId?: string): Promise<bigint> => {\n if (!marketObjectId) {\n throw new Error('marketObjectId is required')\n }\n\n const client = getSuiClient()\n const obj = await client.getObject({ id: marketObjectId, options: { showContent: true } })\n\n if (!obj.data?.content || obj.data.content.dataType !== 'moveObject') {\n throw new Error(`[Sui] Could not read BondMarket ${marketObjectId}`)\n }\n\n const f = obj.data.content.fields as Record<string, unknown>\n const terms =\n ((f.terms as Record<string, unknown>)?.fields as Record<string, unknown>) ?? (f.terms as Record<string, unknown>)\n\n const totalDebt = BigInt(String(f.total_debt ?? '0'))\n const payoutInitialSupply = BigInt(String(f.payout_token_initial_supply ?? '0'))\n const controlVariable = BigInt(String(terms.control_variable ?? '0'))\n const minimumPrice = BigInt(String(terms.minimum_price ?? '0'))\n const vestingTerm = BigInt(String(terms.vesting_term ?? '1'))\n const lastDecay = BigInt(String(f.last_decay ?? '0'))\n const feeInPrincipal = BigInt(String(f.fee_in_principal ?? '0'))\n const payoutDecimals = Number(f.payout_decimals ?? 9)\n const principalDecimals = Number(f.principal_decimals ?? 9)\n\n // Decay debt client-side (same as contract's decay_debt)\n const nowSeconds = BigInt(Math.floor(Date.now() / 1000))\n let currentDebt = totalDebt\n if (nowSeconds > lastDecay && vestingTerm > 0n) {\n const elapsed = nowSeconds - lastDecay\n const decay = (totalDebt * elapsed) / vestingTerm\n currentDebt = totalDebt > decay ? totalDebt - decay : 0n\n }\n\n // calculate_price — contract casts total_debt (u128) to u64 via `as u64`\n const currentDebtU64 = currentDebt & 0xffffffffffffffffn\n const currentDebtPayout = valueOfToken(principalDecimals, payoutDecimals, currentDebtU64)\n const payoutScale = pow10bi(payoutDecimals)\n const principalScale = pow10bi(principalDecimals)\n\n const debtRatio = payoutInitialSupply > 0n ? (currentDebtPayout * payoutScale) / payoutInitialSupply : 0n\n const basePrice = (controlVariable * debtRatio * principalScale) / PRICE_DECIMALS\n\n const price = basePrice < minimumPrice ? minimumPrice : basePrice\n\n // calculate_true_price (includes fee)\n const denominator = PERCENTAGE_BASE - feeInPrincipal\n const truePrice = denominator > 0n ? (price * PERCENTAGE_BASE) / denominator : price\n\n return truePrice\n}\n\n// ---------------------------------------------------------------------------\n// TX status verification — Sui returns digests for failed TXs too.\n// Call this after waitForTransaction to ensure the TX actually succeeded.\n// ---------------------------------------------------------------------------\n\nexport const verifySuiTxSuccess = async (digest: string): Promise<void> => {\n const client = getSuiClient()\n const txBlock = await client.getTransactionBlock({\n digest,\n options: { showEffects: true },\n })\n const status = txBlock.effects?.status\n if (status?.status !== 'success') {\n const errorMsg = status?.error ?? 'Transaction failed on-chain'\n throw new Error(`Transaction failed: ${errorMsg}`)\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -29,12 +29,82 @@ import Flex from '../../components/uikit-sdk/Flex/index.js';
|
|
|
29
29
|
import Text from '../../components/uikit-sdk/Text/index.js';
|
|
30
30
|
import Button from '../../components/uikit-sdk/Button/Button.js';
|
|
31
31
|
import SafeHTMLComponent from '../../components/SafeHTMLComponent/index.js';
|
|
32
|
-
import {
|
|
32
|
+
import { SUI_DEPOSIT_FUNCTION, SUI_PACKAGE_ID } from '../../constants/suiConstants.js';
|
|
33
33
|
import { getSuiClient, readFreshTrueBondPrice, verifySuiTxSuccess } from '../../utils/suiHelpers.js';
|
|
34
34
|
import { useQueryClient } from '@tanstack/react-query';
|
|
35
35
|
import { QUERY_KEYS } from '../../config/constants/queryKeys.js';
|
|
36
36
|
import axios from 'axios';
|
|
37
37
|
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Helper: extract the bill_id from a confirmed Sui deposit transaction.
|
|
40
|
+
// Logs the full tx block so the bill_id can be located manually if the
|
|
41
|
+
// automatic extraction fails.
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
const extractSuiBillId = async (digest) => {
|
|
44
|
+
const suiClient = getSuiClient();
|
|
45
|
+
const txBlock = await suiClient.getTransactionBlock({
|
|
46
|
+
digest,
|
|
47
|
+
options: {
|
|
48
|
+
showEffects: true,
|
|
49
|
+
showObjectChanges: true,
|
|
50
|
+
showEvents: true,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
console.log('[SUI AFTER-PURCHASE] Full tx block for digest', digest, txBlock);
|
|
54
|
+
console.log('[SUI AFTER-PURCHASE] objectChanges:', txBlock.objectChanges);
|
|
55
|
+
console.log('[SUI AFTER-PURCHASE] events:', txBlock.events);
|
|
56
|
+
// ── Strategy 1: find the created BondNFT in objectChanges ──────────────
|
|
57
|
+
const bondNftType = `${SUI_PACKAGE_ID}::bond_nft::BondNFT`;
|
|
58
|
+
const createdNft = txBlock.objectChanges?.find((change) => change.type === 'created' &&
|
|
59
|
+
'objectType' in change &&
|
|
60
|
+
change.objectType?.includes(bondNftType));
|
|
61
|
+
console.log('[SUI AFTER-PURCHASE] Created BondNFT objectChange:', createdNft);
|
|
62
|
+
if (createdNft && 'objectId' in createdNft) {
|
|
63
|
+
const nftObjectId = createdNft.objectId;
|
|
64
|
+
console.log('[SUI AFTER-PURCHASE] BondNFT objectId:', nftObjectId);
|
|
65
|
+
try {
|
|
66
|
+
const nftObj = await suiClient.getObject({
|
|
67
|
+
id: nftObjectId,
|
|
68
|
+
options: { showContent: true },
|
|
69
|
+
});
|
|
70
|
+
console.log('[SUI AFTER-PURCHASE] BondNFT full object:', nftObj);
|
|
71
|
+
if (nftObj.data?.content?.dataType === 'moveObject') {
|
|
72
|
+
const fields = nftObj.data.content.fields;
|
|
73
|
+
console.log('[SUI AFTER-PURCHASE] BondNFT fields:', fields);
|
|
74
|
+
const billId = String(fields?.bill_id ?? '');
|
|
75
|
+
if (billId && billId !== 'undefined' && billId !== '') {
|
|
76
|
+
console.log('[SUI AFTER-PURCHASE] ✅ Extracted bill_id from BondNFT object:', billId);
|
|
77
|
+
return billId;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (e) {
|
|
82
|
+
console.warn('[SUI AFTER-PURCHASE] Failed to read BondNFT object:', nftObjectId, e);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// ── Strategy 2: look for bill_id in emitted Move events ────────────────
|
|
86
|
+
if (txBlock.events && txBlock.events.length > 0) {
|
|
87
|
+
for (const event of txBlock.events) {
|
|
88
|
+
console.log('[SUI AFTER-PURCHASE] Event type:', event.type, 'parsedJson:', event.parsedJson);
|
|
89
|
+
const eventData = event.parsedJson;
|
|
90
|
+
if (eventData?.bill_id !== undefined) {
|
|
91
|
+
const billId = String(eventData.bill_id);
|
|
92
|
+
console.log('[SUI AFTER-PURCHASE] ✅ Extracted bill_id from event:', event.type, billId);
|
|
93
|
+
return billId;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// ── Strategy 3: log all object changes for manual inspection ──────────
|
|
98
|
+
if (txBlock.objectChanges) {
|
|
99
|
+
for (const change of txBlock.objectChanges) {
|
|
100
|
+
console.log('[SUI AFTER-PURCHASE] objectChange entry:', change);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
console.warn('[SUI AFTER-PURCHASE] ⚠️ Could not extract bill_id automatically from digest:', digest, '— check the logs above to find it manually.');
|
|
104
|
+
// Signal that the tx succeeded but we don't have a bill ID yet.
|
|
105
|
+
// ModalHandler will fall back to a query-refresh-based flow.
|
|
106
|
+
return `digest:${digest}`;
|
|
107
|
+
};
|
|
38
108
|
const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, setBillId, }) => {
|
|
39
109
|
const SDKConfig = useSDKConfig();
|
|
40
110
|
const queryClient = useQueryClient();
|
|
@@ -122,7 +192,7 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
122
192
|
.times(new BigNumber(10).pow(principalDecimals))
|
|
123
193
|
.integerValue(BigNumber.ROUND_FLOOR)
|
|
124
194
|
.toFixed(0);
|
|
125
|
-
const market = bondData.contractAddress[bondData.chainId]
|
|
195
|
+
const market = bondData.contractAddress[bondData.chainId];
|
|
126
196
|
// Read fresh bond price from chain to avoid stale cache after previous purchases
|
|
127
197
|
const freshTruePrice = await readFreshTrueBondPrice(market);
|
|
128
198
|
const atomicMaxPrice = new BigNumber(freshTruePrice.toString())
|
|
@@ -157,13 +227,16 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
157
227
|
[principalCoin] = tx.splitCoins(tx.object(userCoins.data[0].coinObjectId), [tx.pure.u64(atomicAmount)]);
|
|
158
228
|
}
|
|
159
229
|
}
|
|
230
|
+
if (!market || !bondData?.suiTreasuryId || !bondData?.billNnftAddress?.[ChainId.SUI]) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
160
233
|
tx.moveCall({
|
|
161
234
|
target: SUI_DEPOSIT_FUNCTION,
|
|
162
235
|
typeArguments: [payoutCoinType, principalCoinType],
|
|
163
236
|
arguments: [
|
|
164
237
|
tx.object(market),
|
|
165
|
-
tx.object(bondData.suiTreasuryId
|
|
166
|
-
tx.object(
|
|
238
|
+
tx.object(bondData.suiTreasuryId),
|
|
239
|
+
tx.object(bondData.billNnftAddress[ChainId.SUI]),
|
|
167
240
|
principalCoin,
|
|
168
241
|
tx.pure.u64(atomicMaxPrice),
|
|
169
242
|
tx.pure.address(suiAccount),
|
|
@@ -186,6 +259,11 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
186
259
|
const suiClient = getSuiClient();
|
|
187
260
|
await suiClient.waitForTransaction({ digest });
|
|
188
261
|
await verifySuiTxSuccess(digest);
|
|
262
|
+
// Extract the bill_id from the confirmed transaction.
|
|
263
|
+
// extractSuiBillId logs the full tx block so you can inspect the raw data
|
|
264
|
+
// in case automatic extraction fails.
|
|
265
|
+
const billId = await extractSuiBillId(digest);
|
|
266
|
+
console.log('[SUI AFTER-PURCHASE] handleBuyCallback billId:', billId);
|
|
189
267
|
// Invalidate bonds data so next purchase uses fresh pricing
|
|
190
268
|
await queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.BONDS_DATA] });
|
|
191
269
|
// Sui's indexer has a short lag — getOwnedObjects may not return the
|
|
@@ -207,9 +285,7 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
207
285
|
},
|
|
208
286
|
});
|
|
209
287
|
addToastSuccess(digest, bondChain);
|
|
210
|
-
|
|
211
|
-
// the frontend will pick it up on the next query refresh.
|
|
212
|
-
setBillId?.('');
|
|
288
|
+
setBillId?.(billId);
|
|
213
289
|
}
|
|
214
290
|
catch (error) {
|
|
215
291
|
console.error('[SUI DEBUG] Error during Sui bond purchase:', error);
|
|
@@ -247,47 +323,47 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
247
323
|
.integerValue(BigNumber.ROUND_FLOOR)
|
|
248
324
|
.toFixed(0);
|
|
249
325
|
// TX1: Acquire principal tokens
|
|
250
|
-
if (IS_SUI_MAINNET) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
326
|
+
// if (IS_SUI_MAINNET) {
|
|
327
|
+
// Mainnet: swap via Aftermath DEX aggregator
|
|
328
|
+
const txResponse = await axios.post(AFTERMATH_TX_API_URL, {
|
|
329
|
+
walletAddress: suiAccount,
|
|
330
|
+
completeRoute: aftermathQuote,
|
|
331
|
+
slippage: slippage / 100,
|
|
332
|
+
});
|
|
333
|
+
const swapTxBytes = txResponse.data;
|
|
334
|
+
if (!swapTxBytes)
|
|
335
|
+
throw new Error('Aftermath returned no transaction data');
|
|
336
|
+
const swapTx = Transaction.from(swapTxBytes);
|
|
337
|
+
const swapResponse = await signAndExecuteTransaction({ transaction: swapTx });
|
|
338
|
+
const swapDigest = swapResponse?.digest;
|
|
339
|
+
if (!swapDigest)
|
|
340
|
+
throw new Error('No tx digest returned for swap');
|
|
341
|
+
await suiClient.waitForTransaction({ digest: swapDigest });
|
|
342
|
+
// } else {
|
|
343
|
+
// // Testnet: mint principal tokens via test_principal_token::mint
|
|
344
|
+
// // No DEX aggregator supports Sui testnet or custom test tokens.
|
|
345
|
+
// const mintTx = new Transaction()
|
|
346
|
+
// mintTx.moveCall({
|
|
347
|
+
// target: SUI_MINT_PRINCIPAL_FUNCTION,
|
|
348
|
+
// arguments: [
|
|
349
|
+
// mintTx.object(SUI_PRINCIPAL_TOKEN_ADMIN_TESTNET),
|
|
350
|
+
// mintTx.pure.u64(depositAmountAtomic),
|
|
351
|
+
// mintTx.pure.address(suiAccount),
|
|
352
|
+
// ],
|
|
353
|
+
// })
|
|
354
|
+
//
|
|
355
|
+
// mintTx.setSender(suiAccount)
|
|
356
|
+
// mintTx.setGasBudget(50_000_000)
|
|
357
|
+
// const builtMint = await mintTx.build({ client: suiClient })
|
|
358
|
+
// const prebuiltMint = Transaction.from(builtMint)
|
|
359
|
+
//
|
|
360
|
+
// const mintResponse = await signAndExecuteTransaction({ transaction: prebuiltMint })
|
|
361
|
+
// const mintDigest = mintResponse?.digest
|
|
362
|
+
// if (!mintDigest) throw new Error('No tx digest returned for testnet mint')
|
|
363
|
+
// await suiClient.waitForTransaction({ digest: mintDigest })
|
|
364
|
+
// }
|
|
289
365
|
// TX2: Deposit into bond with principal tokens
|
|
290
|
-
const market = bondData.contractAddress[
|
|
366
|
+
const market = bondData.contractAddress[ChainId.SUI];
|
|
291
367
|
// Read fresh bond price from chain to avoid stale cache
|
|
292
368
|
const freshTruePrice = await readFreshTrueBondPrice(market);
|
|
293
369
|
const atomicMaxPrice = new BigNumber(freshTruePrice.toString())
|
|
@@ -322,13 +398,16 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
322
398
|
]);
|
|
323
399
|
}
|
|
324
400
|
}
|
|
401
|
+
if (!market || !bondData?.suiTreasuryId || !bondData?.billNnftAddress?.[ChainId.SUI]) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
325
404
|
tx.moveCall({
|
|
326
405
|
target: SUI_DEPOSIT_FUNCTION,
|
|
327
406
|
typeArguments: [payoutCoinType, principalCoinType],
|
|
328
407
|
arguments: [
|
|
329
408
|
tx.object(market),
|
|
330
|
-
tx.object(bondData.suiTreasuryId
|
|
331
|
-
tx.object(
|
|
409
|
+
tx.object(bondData.suiTreasuryId),
|
|
410
|
+
tx.object(bondData.billNnftAddress[ChainId.SUI]),
|
|
332
411
|
principalCoin,
|
|
333
412
|
tx.pure.u64(atomicMaxPrice),
|
|
334
413
|
tx.pure.address(suiAccount),
|
|
@@ -345,6 +424,11 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
345
424
|
throw new Error('No tx digest returned for deposit');
|
|
346
425
|
await suiClient.waitForTransaction({ digest: depositDigest });
|
|
347
426
|
await verifySuiTxSuccess(depositDigest);
|
|
427
|
+
// Extract the bill_id from the confirmed deposit transaction.
|
|
428
|
+
// extractSuiBillId logs the full tx block so you can inspect the raw data
|
|
429
|
+
// in case automatic extraction fails.
|
|
430
|
+
const billId = await extractSuiBillId(depositDigest);
|
|
431
|
+
console.log('[SUI AFTER-PURCHASE] handleZapCallback billId:', billId);
|
|
348
432
|
// Invalidate bonds data so next purchase uses fresh pricing
|
|
349
433
|
await queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.BONDS_DATA] });
|
|
350
434
|
// Sui indexer lag — schedule delayed re-invalidations for user bonds
|
|
@@ -374,7 +458,7 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
374
458
|
},
|
|
375
459
|
});
|
|
376
460
|
addToastSuccess(depositDigest, bondChain);
|
|
377
|
-
setBillId?.(
|
|
461
|
+
setBillId?.(billId);
|
|
378
462
|
}
|
|
379
463
|
catch (error) {
|
|
380
464
|
console.error('Error during Sui zap bond purchase:', error);
|