@ape.swap/bonds-sdk 5.1.49-test.2 → 5.1.49-test.4
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/suiCallbacks.d.ts +2 -0
- package/dist/config/constants/suiCallbacks.js +17 -0
- package/dist/config/constants/suiCallbacks.js.map +1 -0
- 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 +2 -0
- package/dist/state/useSDKConfig.js +6 -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 +133 -57
- 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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useBondsList.js","sources":["../../../src/state/bonds/useBondsList.ts"],"sourcesContent":["import { QueryClient, useQuery, useQueryClient, UseQueryResult } from '@tanstack/react-query'\nimport { QUERY_KEYS } from '../../config/constants/queryKeys'\nimport axios from 'axios'\nimport { BillsConfig
|
|
1
|
+
{"version":3,"file":"useBondsList.js","sources":["../../../src/state/bonds/useBondsList.ts"],"sourcesContent":["import { QueryClient, useQuery, useQueryClient, UseQueryResult } from '@tanstack/react-query'\nimport { QUERY_KEYS } from '../../config/constants/queryKeys'\nimport axios from 'axios'\nimport { BillsConfig } from '@ape.swap/apeswap-lists'\nimport { SDKProps } from '../useSDKConfig'\n\nexport default function useBondsList(): UseQueryResult<BillsConfig[]> {\n const queryClient = useQueryClient()\n return useQuery({\n queryKey: [QUERY_KEYS.BONDS_LIST],\n queryFn: () => getBondsList(queryClient),\n staleTime: Infinity,\n refetchInterval: 300000, // 5 min\n refetchOnWindowFocus: false,\n })\n}\n\nexport const getBondsList = async (queryClient: QueryClient): Promise<BillsConfig[]> => {\n const { urls, customBranch } = queryClient?.getQueryData([QUERY_KEYS.SDK_CONFIG]) as SDKProps\n const realTimeApiURL = urls['realTimeApi']\n\n const response = await axios.get(`${realTimeApiURL}/utils/bonds${customBranch ? `?branch=${customBranch}` : ''}`)\n return response.data\n //\n // try {\n // const response = await axios.get(`${realTimeApiURL}/utils/bonds${customBranch ? `?branch=${customBranch}` : ''}`)\n // // TODO remove this fallback, from now on bonds should be fetched from list repo 'feat/sui-aptos' branch. Also remove try-catch\n //\n // // Always include static Aptos + discovered Sui configs alongside API bonds\n // const apiData: BillsConfig[] = response.data ?? []\n // const nonSuiApiData = apiData.filter((b) => b.chainId !== ChainId.SUI)\n // const aptosBonds = apiData.some((b) => b.chainId === ChainId.APTOS) ? [] : getAptosBondsList()\n // const suiBonds = await discoverSuiBonds(suiTreasuryAddresses)\n // return [...nonSuiApiData, ...aptosBonds, ...suiBonds]\n // } catch (e) {\n // reportError({\n // apiUrl,\n // error: e,\n // extraInfo: { type: 'getBondsList', e },\n // })\n // const suiBonds = await discoverSuiBonds(suiTreasuryAddresses)\n // return [...getAptosBondsList(), ...suiBonds]\n // }\n}\n"],"names":[],"mappings":";;;;AAMc,SAAU,YAAY,GAAA;AAClC,IAAA,MAAM,WAAW,GAAG,cAAc,EAAE;AACpC,IAAA,OAAO,QAAQ,CAAC;AACd,QAAA,QAAQ,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC;AACjC,QAAA,OAAO,EAAE,MAAM,YAAY,CAAC,WAAW,CAAC;AACxC,QAAA,SAAS,EAAE,QAAQ;QACnB,eAAe,EAAE,MAAM;AACvB,QAAA,oBAAoB,EAAE,KAAK;AAC5B,KAAA,CAAC;AACJ;MAEa,YAAY,GAAG,OAAO,WAAwB,KAA4B;AACrF,IAAA,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,WAAW,EAAE,YAAY,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAa;AAC7F,IAAA,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC;IAE1C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAA,EAAG,cAAc,CAAA,YAAA,EAAe,YAAY,GAAG,CAAA,QAAA,EAAW,YAAY,CAAA,CAAE,GAAG,EAAE,CAAA,CAAE,CAAC;IACjH,OAAO,QAAQ,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;AAqBtB;;;;"}
|
|
@@ -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;;;;"}
|
|
@@ -18,8 +18,10 @@ export interface SDKPropsDTO {
|
|
|
18
18
|
customBranch?: string;
|
|
19
19
|
highlightedBond?: string;
|
|
20
20
|
customRPCS?: Partial<Record<ChainId, string[]>>;
|
|
21
|
+
openSuiConnectModal?: () => void;
|
|
21
22
|
aptosAddress?: string;
|
|
22
23
|
suiAddress?: string;
|
|
24
|
+
suiTreasuryAddresses?: string[];
|
|
23
25
|
}
|
|
24
26
|
export interface SDKProps {
|
|
25
27
|
referenceId: string;
|
|
@@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query';
|
|
|
3
3
|
import { QUERY_KEYS } from '../config/constants/queryKeys.js';
|
|
4
4
|
import { ChainId } from '@ape.swap/apeswap-lists';
|
|
5
5
|
import { setCustomRPCS } from '../config/constants/networks.js';
|
|
6
|
+
import { setSuiConnectModalOpener } from '../config/constants/suiCallbacks.js';
|
|
6
7
|
|
|
7
8
|
// Prod URLS. Do not make changes here
|
|
8
9
|
const defaultUrls = {
|
|
@@ -43,6 +44,11 @@ const useSDKConfig = (config) => {
|
|
|
43
44
|
setCustomRPCS(config.customRPCS);
|
|
44
45
|
}
|
|
45
46
|
}, [config?.customRPCS]);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (config?.openSuiConnectModal) {
|
|
49
|
+
setSuiConnectModalOpener(config.openSuiConnectModal);
|
|
50
|
+
}
|
|
51
|
+
}, [config?.openSuiConnectModal]);
|
|
46
52
|
const { data } = useQuery({
|
|
47
53
|
queryKey: [QUERY_KEYS.SDK_CONFIG],
|
|
48
54
|
queryFn: () => {
|
|
@@ -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":"
|
|
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'\nimport { setSuiConnectModalOpener } from '../config/constants/suiCallbacks'\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 openSuiConnectModal?: () => void\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 useEffect(() => {\n if (config?.openSuiConnectModal) {\n setSuiConnectModalOpener(config.openSuiConnectModal)\n }\n }, [config?.openSuiConnectModal])\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":";;;;;;;AAOA;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;AAmDM,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;IAExB,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,MAAM,EAAE,mBAAmB,EAAE;AAC/B,YAAA,wBAAwB,CAAC,MAAM,CAAC,mBAAmB,CAAC;QACtD;AACF,IAAA,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAEjC,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,80 @@ 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
|
+
import { openSuiConnectModal } from '../../config/constants/suiCallbacks.js';
|
|
34
35
|
import { useQueryClient } from '@tanstack/react-query';
|
|
35
36
|
import { QUERY_KEYS } from '../../config/constants/queryKeys.js';
|
|
36
37
|
import axios from 'axios';
|
|
37
38
|
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Helper: extract the bill_id from a confirmed Sui deposit transaction.
|
|
41
|
+
// Logs the full tx block so the bill_id can be located manually if the
|
|
42
|
+
// automatic extraction fails.
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
const extractSuiBillId = async (digest, suiClient) => {
|
|
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' && 'objectType' in change && change.objectType?.includes(bondNftType));
|
|
59
|
+
console.log('[SUI AFTER-PURCHASE] Created BondNFT objectChange:', createdNft);
|
|
60
|
+
if (createdNft && 'objectId' in createdNft) {
|
|
61
|
+
const nftObjectId = createdNft.objectId;
|
|
62
|
+
console.log('[SUI AFTER-PURCHASE] BondNFT objectId:', nftObjectId);
|
|
63
|
+
try {
|
|
64
|
+
const nftObj = await suiClient.getObject({
|
|
65
|
+
id: nftObjectId,
|
|
66
|
+
options: { showContent: true },
|
|
67
|
+
});
|
|
68
|
+
console.log('[SUI AFTER-PURCHASE] BondNFT full object:', nftObj);
|
|
69
|
+
if (nftObj.data?.content?.dataType === 'moveObject') {
|
|
70
|
+
const fields = nftObj.data.content.fields;
|
|
71
|
+
console.log('[SUI AFTER-PURCHASE] BondNFT fields:', fields);
|
|
72
|
+
const billId = String(fields?.bill_id ?? '');
|
|
73
|
+
if (billId && billId !== 'undefined' && billId !== '') {
|
|
74
|
+
console.log('[SUI AFTER-PURCHASE] ✅ Extracted bill_id from BondNFT object:', billId);
|
|
75
|
+
return billId;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
console.warn('[SUI AFTER-PURCHASE] Failed to read BondNFT object:', nftObjectId, e);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// ── Strategy 2: look for bill_id in emitted Move events ────────────────
|
|
84
|
+
if (txBlock.events && txBlock.events.length > 0) {
|
|
85
|
+
for (const event of txBlock.events) {
|
|
86
|
+
console.log('[SUI AFTER-PURCHASE] Event type:', event.type, 'parsedJson:', event.parsedJson);
|
|
87
|
+
const eventData = event.parsedJson;
|
|
88
|
+
if (eventData?.bill_id !== undefined) {
|
|
89
|
+
const billId = String(eventData.bill_id);
|
|
90
|
+
console.log('[SUI AFTER-PURCHASE] ✅ Extracted bill_id from event:', event.type, billId);
|
|
91
|
+
return billId;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// ── Strategy 3: log all object changes for manual inspection ──────────
|
|
96
|
+
if (txBlock.objectChanges) {
|
|
97
|
+
for (const change of txBlock.objectChanges) {
|
|
98
|
+
console.log('[SUI AFTER-PURCHASE] objectChange entry:', change);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
console.warn('[SUI AFTER-PURCHASE] ⚠️ Could not extract bill_id automatically from digest:', digest, '— check the logs above to find it manually.');
|
|
102
|
+
// Signal that the tx succeeded but we don't have a bill ID yet.
|
|
103
|
+
// ModalHandler will fall back to a query-refresh-based flow.
|
|
104
|
+
return `digest:${digest}`;
|
|
105
|
+
};
|
|
38
106
|
const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, setBillId, }) => {
|
|
39
107
|
const SDKConfig = useSDKConfig();
|
|
40
108
|
const queryClient = useQueryClient();
|
|
@@ -122,7 +190,7 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
122
190
|
.times(new BigNumber(10).pow(principalDecimals))
|
|
123
191
|
.integerValue(BigNumber.ROUND_FLOOR)
|
|
124
192
|
.toFixed(0);
|
|
125
|
-
const market = bondData.contractAddress[bondData.chainId]
|
|
193
|
+
const market = bondData.contractAddress[bondData.chainId];
|
|
126
194
|
// Read fresh bond price from chain to avoid stale cache after previous purchases
|
|
127
195
|
const freshTruePrice = await readFreshTrueBondPrice(market);
|
|
128
196
|
const atomicMaxPrice = new BigNumber(freshTruePrice.toString())
|
|
@@ -157,13 +225,16 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
157
225
|
[principalCoin] = tx.splitCoins(tx.object(userCoins.data[0].coinObjectId), [tx.pure.u64(atomicAmount)]);
|
|
158
226
|
}
|
|
159
227
|
}
|
|
228
|
+
if (!market || !bondData?.suiTreasuryId || !bondData?.billNnftAddress?.[ChainId.SUI]) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
160
231
|
tx.moveCall({
|
|
161
232
|
target: SUI_DEPOSIT_FUNCTION,
|
|
162
233
|
typeArguments: [payoutCoinType, principalCoinType],
|
|
163
234
|
arguments: [
|
|
164
235
|
tx.object(market),
|
|
165
|
-
tx.object(bondData.suiTreasuryId
|
|
166
|
-
tx.object(
|
|
236
|
+
tx.object(bondData.suiTreasuryId),
|
|
237
|
+
tx.object(bondData.billNnftAddress[ChainId.SUI]),
|
|
167
238
|
principalCoin,
|
|
168
239
|
tx.pure.u64(atomicMaxPrice),
|
|
169
240
|
tx.pure.address(suiAccount),
|
|
@@ -186,13 +257,17 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
186
257
|
const suiClient = getSuiClient();
|
|
187
258
|
await suiClient.waitForTransaction({ digest });
|
|
188
259
|
await verifySuiTxSuccess(digest);
|
|
260
|
+
// Extract the bill_id from the confirmed transaction.
|
|
261
|
+
// extractSuiBillId logs the full tx block so you can inspect the raw data
|
|
262
|
+
// in case automatic extraction fails.
|
|
263
|
+
const billId = await extractSuiBillId(digest, suiClient);
|
|
264
|
+
console.log('[SUI AFTER-PURCHASE] handleBuyCallback billId:', billId);
|
|
189
265
|
// Invalidate bonds data so next purchase uses fresh pricing
|
|
190
266
|
await queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.BONDS_DATA] });
|
|
191
267
|
// Sui's indexer has a short lag — getOwnedObjects may not return the
|
|
192
268
|
// new BondNFT immediately. Schedule re-invalidations so the Your Bonds
|
|
193
269
|
// view picks up the new bond once the indexer catches up.
|
|
194
270
|
setTimeout(() => queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.USER_BONDS] }), 3000);
|
|
195
|
-
setTimeout(() => queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.USER_BONDS] }), 8000);
|
|
196
271
|
track({
|
|
197
272
|
event: 'bond',
|
|
198
273
|
chain: bondChain,
|
|
@@ -207,9 +282,7 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
207
282
|
},
|
|
208
283
|
});
|
|
209
284
|
addToastSuccess(digest, bondChain);
|
|
210
|
-
|
|
211
|
-
// the frontend will pick it up on the next query refresh.
|
|
212
|
-
setBillId?.('');
|
|
285
|
+
setBillId?.(billId);
|
|
213
286
|
}
|
|
214
287
|
catch (error) {
|
|
215
288
|
console.error('[SUI DEBUG] Error during Sui bond purchase:', error);
|
|
@@ -247,47 +320,47 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
247
320
|
.integerValue(BigNumber.ROUND_FLOOR)
|
|
248
321
|
.toFixed(0);
|
|
249
322
|
// 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
|
-
}
|
|
323
|
+
// if (IS_SUI_MAINNET) {
|
|
324
|
+
// Mainnet: swap via Aftermath DEX aggregator
|
|
325
|
+
const txResponse = await axios.post(AFTERMATH_TX_API_URL, {
|
|
326
|
+
walletAddress: suiAccount,
|
|
327
|
+
completeRoute: aftermathQuote,
|
|
328
|
+
slippage: slippage / 100,
|
|
329
|
+
});
|
|
330
|
+
const swapTxBytes = txResponse.data;
|
|
331
|
+
if (!swapTxBytes)
|
|
332
|
+
throw new Error('Aftermath returned no transaction data');
|
|
333
|
+
const swapTx = Transaction.from(swapTxBytes);
|
|
334
|
+
const swapResponse = await signAndExecuteTransaction({ transaction: swapTx });
|
|
335
|
+
const swapDigest = swapResponse?.digest;
|
|
336
|
+
if (!swapDigest)
|
|
337
|
+
throw new Error('No tx digest returned for swap');
|
|
338
|
+
await suiClient.waitForTransaction({ digest: swapDigest });
|
|
339
|
+
// } else {
|
|
340
|
+
// // Testnet: mint principal tokens via test_principal_token::mint
|
|
341
|
+
// // No DEX aggregator supports Sui testnet or custom test tokens.
|
|
342
|
+
// const mintTx = new Transaction()
|
|
343
|
+
// mintTx.moveCall({
|
|
344
|
+
// target: SUI_MINT_PRINCIPAL_FUNCTION,
|
|
345
|
+
// arguments: [
|
|
346
|
+
// mintTx.object(SUI_PRINCIPAL_TOKEN_ADMIN_TESTNET),
|
|
347
|
+
// mintTx.pure.u64(depositAmountAtomic),
|
|
348
|
+
// mintTx.pure.address(suiAccount),
|
|
349
|
+
// ],
|
|
350
|
+
// })
|
|
351
|
+
//
|
|
352
|
+
// mintTx.setSender(suiAccount)
|
|
353
|
+
// mintTx.setGasBudget(50_000_000)
|
|
354
|
+
// const builtMint = await mintTx.build({ client: suiClient })
|
|
355
|
+
// const prebuiltMint = Transaction.from(builtMint)
|
|
356
|
+
//
|
|
357
|
+
// const mintResponse = await signAndExecuteTransaction({ transaction: prebuiltMint })
|
|
358
|
+
// const mintDigest = mintResponse?.digest
|
|
359
|
+
// if (!mintDigest) throw new Error('No tx digest returned for testnet mint')
|
|
360
|
+
// await suiClient.waitForTransaction({ digest: mintDigest })
|
|
361
|
+
// }
|
|
289
362
|
// TX2: Deposit into bond with principal tokens
|
|
290
|
-
const market = bondData.contractAddress[
|
|
363
|
+
const market = bondData.contractAddress[ChainId.SUI];
|
|
291
364
|
// Read fresh bond price from chain to avoid stale cache
|
|
292
365
|
const freshTruePrice = await readFreshTrueBondPrice(market);
|
|
293
366
|
const atomicMaxPrice = new BigNumber(freshTruePrice.toString())
|
|
@@ -322,13 +395,16 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
322
395
|
]);
|
|
323
396
|
}
|
|
324
397
|
}
|
|
398
|
+
if (!market || !bondData?.suiTreasuryId || !bondData?.billNnftAddress?.[ChainId.SUI]) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
325
401
|
tx.moveCall({
|
|
326
402
|
target: SUI_DEPOSIT_FUNCTION,
|
|
327
403
|
typeArguments: [payoutCoinType, principalCoinType],
|
|
328
404
|
arguments: [
|
|
329
405
|
tx.object(market),
|
|
330
|
-
tx.object(bondData.suiTreasuryId
|
|
331
|
-
tx.object(
|
|
406
|
+
tx.object(bondData.suiTreasuryId),
|
|
407
|
+
tx.object(bondData.billNnftAddress[ChainId.SUI]),
|
|
332
408
|
principalCoin,
|
|
333
409
|
tx.pure.u64(atomicMaxPrice),
|
|
334
410
|
tx.pure.address(suiAccount),
|
|
@@ -345,11 +421,15 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
345
421
|
throw new Error('No tx digest returned for deposit');
|
|
346
422
|
await suiClient.waitForTransaction({ digest: depositDigest });
|
|
347
423
|
await verifySuiTxSuccess(depositDigest);
|
|
424
|
+
// Extract the bill_id from the confirmed deposit transaction.
|
|
425
|
+
// extractSuiBillId logs the full tx block so you can inspect the raw data
|
|
426
|
+
// in case automatic extraction fails.
|
|
427
|
+
const billId = await extractSuiBillId(depositDigest, suiClient);
|
|
428
|
+
console.log('[SUI AFTER-PURCHASE] handleZapCallback billId:', billId);
|
|
348
429
|
// Invalidate bonds data so next purchase uses fresh pricing
|
|
349
430
|
await queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.BONDS_DATA] });
|
|
350
431
|
// Sui indexer lag — schedule delayed re-invalidations for user bonds
|
|
351
432
|
setTimeout(() => queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.USER_BONDS] }), 3000);
|
|
352
|
-
setTimeout(() => queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.USER_BONDS] }), 8000);
|
|
353
433
|
track({
|
|
354
434
|
event: 'zap',
|
|
355
435
|
chain: bondChain,
|
|
@@ -374,7 +454,7 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
374
454
|
},
|
|
375
455
|
});
|
|
376
456
|
addToastSuccess(depositDigest, bondChain);
|
|
377
|
-
setBillId?.(
|
|
457
|
+
setBillId?.(billId);
|
|
378
458
|
}
|
|
379
459
|
catch (error) {
|
|
380
460
|
console.error('Error during Sui zap bond purchase:', error);
|
|
@@ -438,11 +518,7 @@ const BuyComponentSui = ({ onDismiss, bondAddress, bondChain, isProjectView, set
|
|
|
438
518
|
mt: '10px',
|
|
439
519
|
borderRadius: 'normal',
|
|
440
520
|
p: '2px 10px',
|
|
441
|
-
}, children: jsx(Text, { sx: { fontSize: '12px', fontWeight: 400, display: 'flex', alignItems: 'center', gap: '10px' }, children: jsx(SafeHTMLComponent, { html: bondData?.warningCard }) }) })), jsx(Flex, { className: "modaltable-container button-container", children: jsx(Flex, { className: "button-container buy", children: !suiAccount ? (jsx(Button, { className: "action-button", onClick:
|
|
442
|
-
// Sui dapp-kit ConnectModal is managed by the provider —
|
|
443
|
-
// consumers should wrap the app in SuiWalletProvider.
|
|
444
|
-
// This button is a fallback prompt.
|
|
445
|
-
}, sx: { width: '100%', fontSize: ['14px', '14px', '14px', '16px'] }, children: "Connect to Sui" })) : (jsx(Button, { className: "action-button", load: load, disabled: !canBuy, onClick: handleBuy, sx: { width: '100%', fontSize: ['14px', '14px', '14px', '16px'] }, children: SDKConfig.blockSales
|
|
521
|
+
}, children: jsx(Text, { sx: { fontSize: '12px', fontWeight: 400, display: 'flex', alignItems: 'center', gap: '10px' }, children: jsx(SafeHTMLComponent, { html: bondData?.warningCard }) }) })), jsx(Flex, { className: "modaltable-container button-container", children: jsx(Flex, { className: "button-container buy", children: !suiAccount ? (jsx(Button, { className: "action-button", onClick: openSuiConnectModal, sx: { width: '100%', fontSize: ['14px', '14px', '14px', '16px'] }, children: "Connect to Sui" })) : (jsx(Button, { className: "action-button", load: load, disabled: !canBuy, onClick: handleBuy, sx: { width: '100%', fontSize: ['14px', '14px', '14px', '16px'] }, children: SDKConfig.blockSales
|
|
446
522
|
? 'Complete KYC to Buy'
|
|
447
523
|
: zapError
|
|
448
524
|
? 'Swap quote failed'
|