@tbookdev/vault-react-sui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -0
- package/dist/index.cjs +511 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +404 -0
- package/dist/index.d.ts +404 -0
- package/dist/index.js +488 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @tbookdev/vault-react-sui
|
|
2
|
+
|
|
3
|
+
Headless React hooks and provider for TBook Sui vault integrations.
|
|
4
|
+
|
|
5
|
+
This package assumes your app already provides:
|
|
6
|
+
|
|
7
|
+
- `QueryClientProvider` from `@tanstack/react-query`
|
|
8
|
+
- `SuiClientProvider` and `WalletProvider` from `@mysten/dapp-kit`
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pnpm add @tbookdev/vault-react-sui @tbookdev/vault-sdk-sui
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Provider
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { TBookSuiVaultProvider } from "@tbookdev/vault-react-sui";
|
|
20
|
+
|
|
21
|
+
export function AppProviders({ children }: { children: React.ReactNode }) {
|
|
22
|
+
return (
|
|
23
|
+
<TBookSuiVaultProvider network="testnet" vaultId="rcusdp-sui">
|
|
24
|
+
{children}
|
|
25
|
+
</TBookSuiVaultProvider>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Hooks
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import {
|
|
34
|
+
useSuiDeposit,
|
|
35
|
+
useSuiTransactionHistory,
|
|
36
|
+
useSuiUsdcBalance,
|
|
37
|
+
useSuiVaultBalances,
|
|
38
|
+
useSuiVaultInfo,
|
|
39
|
+
} from "@tbookdev/vault-react-sui";
|
|
40
|
+
|
|
41
|
+
function VaultPanel() {
|
|
42
|
+
const vaultInfo = useSuiVaultInfo();
|
|
43
|
+
const balances = useSuiVaultBalances();
|
|
44
|
+
const usdc = useSuiUsdcBalance();
|
|
45
|
+
const history = useSuiTransactionHistory();
|
|
46
|
+
const deposit = useSuiDeposit();
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<button onClick={() => deposit.mutate({ amount: 100_000_000n })}>
|
|
50
|
+
Deposit 100 USDC
|
|
51
|
+
</button>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Transaction Builders
|
|
57
|
+
|
|
58
|
+
`local-sdk` builds Sui transaction bytes in the browser through
|
|
59
|
+
`@tbookdev/vault-sdk-sui`. It is the default on every network.
|
|
60
|
+
|
|
61
|
+
The API server base URL is selected from `network`, independent of
|
|
62
|
+
`txBuilderMode`: `testnet` points at the deployed sandbox Gateway API, while
|
|
63
|
+
`mainnet` stays empty until the production Gateway API is deployed.
|
|
64
|
+
If `gateway-api` is selected on a network without a configured Gateway API,
|
|
65
|
+
the write hook reports a configuration error only when it tries to build the
|
|
66
|
+
transaction through the API.
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
<TBookSuiVaultProvider network="testnet" txBuilderMode="local-sdk">
|
|
70
|
+
{children}
|
|
71
|
+
</TBookSuiVaultProvider>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`gateway-api` calls the selected TBook Gateway API to build unsigned transaction
|
|
75
|
+
bytes, then signs and executes them with the connected Sui wallet. Select it
|
|
76
|
+
explicitly when you want API-built transactions.
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<TBookSuiVaultProvider
|
|
80
|
+
network="testnet"
|
|
81
|
+
txBuilderMode="gateway-api"
|
|
82
|
+
>
|
|
83
|
+
{children}
|
|
84
|
+
</TBookSuiVaultProvider>
|
|
85
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var vaultSdkSui = require('@tbookdev/vault-sdk-sui');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var dappKit = require('@mysten/dapp-kit');
|
|
7
|
+
var reactQuery = require('@tanstack/react-query');
|
|
8
|
+
|
|
9
|
+
// src/provider.tsx
|
|
10
|
+
var DEFAULT_STALE_TIMES = {
|
|
11
|
+
vaultInfo: 3e4,
|
|
12
|
+
balances: 1e4,
|
|
13
|
+
history: 1e4,
|
|
14
|
+
usdcBalance: 1e4
|
|
15
|
+
};
|
|
16
|
+
var DEFAULT_REFETCH_INTERVALS = {
|
|
17
|
+
vaultInfo: 6e4,
|
|
18
|
+
balances: 3e4,
|
|
19
|
+
history: 3e4,
|
|
20
|
+
usdcBalance: 3e4
|
|
21
|
+
};
|
|
22
|
+
var DEFAULT_SUI_VAULT_ID = "rcusdp-sui";
|
|
23
|
+
var SUI_TESTNET_GATEWAY_API_BASE_URL = "https://1cm2fjkq6k.execute-api.ap-southeast-1.amazonaws.com/v1";
|
|
24
|
+
function defaultGatewayApiBaseUrl(network) {
|
|
25
|
+
return network === "testnet" ? SUI_TESTNET_GATEWAY_API_BASE_URL : void 0;
|
|
26
|
+
}
|
|
27
|
+
function stripTrailingSlash(url) {
|
|
28
|
+
return url.replace(/\/+$/, "");
|
|
29
|
+
}
|
|
30
|
+
function createSuiVaultConfig(input) {
|
|
31
|
+
const vaultId = input.vaultId ?? DEFAULT_SUI_VAULT_ID;
|
|
32
|
+
const txBuilderMode = input.txBuilderMode ?? "local-sdk";
|
|
33
|
+
const gatewayApiBaseUrl = input.gatewayApiBaseUrl ?? defaultGatewayApiBaseUrl(input.network);
|
|
34
|
+
if (txBuilderMode === "custom" && !input.customTxBuilder) {
|
|
35
|
+
throw new Error("customTxBuilder is required when txBuilderMode is custom");
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
network: input.network,
|
|
39
|
+
vaultId,
|
|
40
|
+
vault: vaultSdkSui.getSuiVaultConfig(vaultId, input.network),
|
|
41
|
+
txBuilderMode,
|
|
42
|
+
gatewayApiBaseUrl: gatewayApiBaseUrl ? stripTrailingSlash(gatewayApiBaseUrl) : void 0,
|
|
43
|
+
publishableKey: input.publishableKey,
|
|
44
|
+
customTxBuilder: input.customTxBuilder,
|
|
45
|
+
staleTimes: { ...DEFAULT_STALE_TIMES, ...input.staleTimes },
|
|
46
|
+
refetchIntervals: { ...DEFAULT_REFETCH_INTERVALS, ...input.refetchIntervals },
|
|
47
|
+
preflightChecks: input.preflightChecks ?? true
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
var TBookSuiVaultContext = react.createContext(null);
|
|
51
|
+
function TBookSuiVaultProvider({ children, ...input }) {
|
|
52
|
+
const value = react.useMemo(
|
|
53
|
+
() => createSuiVaultConfig(input),
|
|
54
|
+
[
|
|
55
|
+
input.network,
|
|
56
|
+
input.vaultId,
|
|
57
|
+
input.txBuilderMode,
|
|
58
|
+
input.gatewayApiBaseUrl,
|
|
59
|
+
input.publishableKey,
|
|
60
|
+
input.customTxBuilder,
|
|
61
|
+
input.preflightChecks,
|
|
62
|
+
input.staleTimes,
|
|
63
|
+
input.refetchIntervals
|
|
64
|
+
]
|
|
65
|
+
);
|
|
66
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TBookSuiVaultContext.Provider, { value, children });
|
|
67
|
+
}
|
|
68
|
+
function useTBookSuiVault() {
|
|
69
|
+
const ctx = react.useContext(TBookSuiVaultContext);
|
|
70
|
+
if (!ctx) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
"useTBookSuiVault must be used within a <TBookSuiVaultProvider>."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return ctx;
|
|
76
|
+
}
|
|
77
|
+
function parseDecimalAmount(value, decimals = vaultSdkSui.USDC_DECIMALS) {
|
|
78
|
+
const input = String(value).trim();
|
|
79
|
+
if (!/^\d+(\.\d+)?$/.test(input)) {
|
|
80
|
+
throw new Error(`Invalid decimal amount: ${value}`);
|
|
81
|
+
}
|
|
82
|
+
const [whole, fraction = ""] = input.split(".");
|
|
83
|
+
if (fraction.length > decimals) {
|
|
84
|
+
throw new Error(`Amount has more than ${decimals} decimal places: ${value}`);
|
|
85
|
+
}
|
|
86
|
+
const scale = 10n ** BigInt(decimals);
|
|
87
|
+
return BigInt(whole) * scale + BigInt(fraction.padEnd(decimals, "0") || "0");
|
|
88
|
+
}
|
|
89
|
+
function formatRawAmount(value, decimals = vaultSdkSui.USDC_DECIMALS) {
|
|
90
|
+
const raw = BigInt(value);
|
|
91
|
+
const scale = 10n ** BigInt(decimals);
|
|
92
|
+
const whole = raw / scale;
|
|
93
|
+
const fraction = (raw % scale).toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
94
|
+
return fraction ? `${whole}.${fraction}` : whole.toString();
|
|
95
|
+
}
|
|
96
|
+
function toRawAmount(value, decimals = vaultSdkSui.USDC_DECIMALS) {
|
|
97
|
+
return typeof value === "bigint" ? value : parseDecimalAmount(value, decimals);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// src/query-keys.ts
|
|
101
|
+
var ROOT = "tbook-sui";
|
|
102
|
+
var suiVaultQueryKeys = {
|
|
103
|
+
all: [ROOT],
|
|
104
|
+
vault: (network, vaultId) => [ROOT, "vault", network, vaultId],
|
|
105
|
+
vaultInfo: (network, vaultId) => [ROOT, "vault", network, vaultId, "info"],
|
|
106
|
+
balances: (network, vaultId, address) => [ROOT, "vault", network, vaultId, "balances", address],
|
|
107
|
+
history: (network, vaultId, address) => [ROOT, "vault", network, vaultId, "history", address],
|
|
108
|
+
usdcBalance: (network, address, coinType) => [ROOT, "wallet", network, address, "usdc", coinType]
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// src/errors.ts
|
|
112
|
+
var TBookSuiVaultReactError = class extends Error {
|
|
113
|
+
constructor(code, message) {
|
|
114
|
+
super(message);
|
|
115
|
+
this.code = code;
|
|
116
|
+
this.name = "TBookSuiVaultReactError";
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
function walletNotConnected() {
|
|
120
|
+
return new TBookSuiVaultReactError("WALLET_NOT_CONNECTED", "Wallet not connected");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// src/gateway-api.ts
|
|
124
|
+
var TBookSuiGatewayApiClient = class {
|
|
125
|
+
baseUrl;
|
|
126
|
+
apiKey;
|
|
127
|
+
fetcher;
|
|
128
|
+
constructor(options) {
|
|
129
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
130
|
+
this.apiKey = options.apiKey;
|
|
131
|
+
this.fetcher = options.fetcher ?? ((input, init) => globalThis.fetch(input, init));
|
|
132
|
+
}
|
|
133
|
+
buildDepositTx(vaultId, body) {
|
|
134
|
+
return this.post(`/vaults/${vaultId}/tx/deposit`, body);
|
|
135
|
+
}
|
|
136
|
+
buildRedeemTx(vaultId, body) {
|
|
137
|
+
return this.post(`/vaults/${vaultId}/tx/redeem`, body);
|
|
138
|
+
}
|
|
139
|
+
buildClaimTx(vaultId, body) {
|
|
140
|
+
return this.post(`/vaults/${vaultId}/tx/claim`, body);
|
|
141
|
+
}
|
|
142
|
+
buildCancelDepositTx(vaultId, body) {
|
|
143
|
+
return this.post(`/vaults/${vaultId}/tx/cancel-deposit`, body);
|
|
144
|
+
}
|
|
145
|
+
async confirmIntent(intentId, digest) {
|
|
146
|
+
return this.post(`/transactions/${intentId}/confirm`, { digest });
|
|
147
|
+
}
|
|
148
|
+
async post(endpoint, body) {
|
|
149
|
+
const response = await this.fetcher(`${this.baseUrl}${endpoint}`, {
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers: this.headers(),
|
|
152
|
+
body: JSON.stringify(body)
|
|
153
|
+
});
|
|
154
|
+
if (!response.ok) {
|
|
155
|
+
const error = await response.json().catch(() => void 0);
|
|
156
|
+
const message = error?.error?.message ?? error?.message ?? response.statusText ?? `HTTP ${response.status}`;
|
|
157
|
+
throw new TBookSuiVaultReactError("API_ERROR", message);
|
|
158
|
+
}
|
|
159
|
+
return response.json();
|
|
160
|
+
}
|
|
161
|
+
headers() {
|
|
162
|
+
return {
|
|
163
|
+
"Content-Type": "application/json",
|
|
164
|
+
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/vault-info.ts
|
|
170
|
+
function balanceValue(value) {
|
|
171
|
+
return BigInt(value?.value ?? value ?? "0");
|
|
172
|
+
}
|
|
173
|
+
function boolValue(value) {
|
|
174
|
+
return value === true || value === "true";
|
|
175
|
+
}
|
|
176
|
+
function fieldsFromMoveObject(obj, label) {
|
|
177
|
+
const content = obj.data?.content;
|
|
178
|
+
if (!content || content.dataType !== "moveObject") {
|
|
179
|
+
throw new Error(`Invalid ${label} object`);
|
|
180
|
+
}
|
|
181
|
+
return content.fields;
|
|
182
|
+
}
|
|
183
|
+
async function getSuiVaultInfo(client, cfg) {
|
|
184
|
+
const [vaultObj, depositStateObj] = await Promise.all([
|
|
185
|
+
client.getObject({ id: cfg.vaultObjectId, options: { showContent: true } }),
|
|
186
|
+
client.getObject({ id: cfg.depositSettlementStateId, options: { showContent: true } })
|
|
187
|
+
]);
|
|
188
|
+
const fields = fieldsFromMoveObject(vaultObj, "vault");
|
|
189
|
+
let depositSettlementActive = false;
|
|
190
|
+
try {
|
|
191
|
+
const depositStateFields = fieldsFromMoveObject(depositStateObj, "deposit settlement state");
|
|
192
|
+
depositSettlementActive = boolValue(depositStateFields.active);
|
|
193
|
+
} catch {
|
|
194
|
+
depositSettlementActive = false;
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
totalShares: BigInt(fields.total_shares ?? "0"),
|
|
198
|
+
pendingDeposit: balanceValue(fields.pending_deposit),
|
|
199
|
+
claimReserve: balanceValue(fields.claim_reserve),
|
|
200
|
+
rcusdpCustody: balanceValue(fields.rcusdp_custody),
|
|
201
|
+
pendingRedeemRcusdp: balanceValue(fields.pending_redeem_rcusdp),
|
|
202
|
+
reserveFund: balanceValue(fields.reserve_fund),
|
|
203
|
+
depositFeeBps: BigInt(fields.deposit_fee_bps ?? "0"),
|
|
204
|
+
mgmtFeeBps: BigInt(fields.mgmt_fee_bps ?? "0"),
|
|
205
|
+
redeemFeeBps: BigInt(fields.redeem_fee_bps ?? "0"),
|
|
206
|
+
withdrawFeeBps: BigInt(fields.withdraw_fee_bps ?? "0"),
|
|
207
|
+
cancelDepositFeeBps: BigInt(fields.cancel_deposit_fee_bps ?? "0"),
|
|
208
|
+
instantRedeemFeeBps: BigInt(fields.instant_redeem_fee_bps ?? "0"),
|
|
209
|
+
paused: boolValue(fields.paused),
|
|
210
|
+
version: BigInt(fields.version ?? "1"),
|
|
211
|
+
depositEnabled: !depositSettlementActive,
|
|
212
|
+
instantRedeemEnabled: boolValue(fields.instant_redeem_enabled),
|
|
213
|
+
withdrawRcusdpEnabled: boolValue(fields.withdraw_rcusdp_enabled),
|
|
214
|
+
cancelDepositEnabled: boolValue(fields.cancel_deposit_enabled),
|
|
215
|
+
redeemSettled: boolValue(fields.redeem_settled),
|
|
216
|
+
raw: fields
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/hooks/use-vault-config.ts
|
|
221
|
+
var useSuiVaultConfig = useTBookSuiVault;
|
|
222
|
+
function useSuiVaultInfo(options) {
|
|
223
|
+
const client = dappKit.useSuiClient();
|
|
224
|
+
const config = useTBookSuiVault();
|
|
225
|
+
return reactQuery.useQuery({
|
|
226
|
+
queryKey: suiVaultQueryKeys.vaultInfo(config.network, config.vaultId),
|
|
227
|
+
queryFn: () => getSuiVaultInfo(client, config.vault),
|
|
228
|
+
staleTime: config.staleTimes.vaultInfo,
|
|
229
|
+
refetchInterval: config.refetchIntervals.vaultInfo,
|
|
230
|
+
enabled: Boolean(config.vault.vaultObjectId) && (options?.enabled ?? true),
|
|
231
|
+
...options
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
function useSuiVaultBalances(options) {
|
|
235
|
+
const account = dappKit.useCurrentAccount();
|
|
236
|
+
const client = dappKit.useSuiClient();
|
|
237
|
+
const config = useTBookSuiVault();
|
|
238
|
+
return reactQuery.useQuery({
|
|
239
|
+
queryKey: suiVaultQueryKeys.balances(config.network, config.vaultId, account?.address ?? ""),
|
|
240
|
+
queryFn: async () => {
|
|
241
|
+
if (!account?.address) {
|
|
242
|
+
throw new Error("Wallet not connected");
|
|
243
|
+
}
|
|
244
|
+
return vaultSdkSui.getUserPosition(client, config.vault, account.address);
|
|
245
|
+
},
|
|
246
|
+
enabled: Boolean(account?.address) && (options?.enabled ?? true),
|
|
247
|
+
staleTime: config.staleTimes.balances,
|
|
248
|
+
refetchInterval: config.refetchIntervals.balances,
|
|
249
|
+
...options
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
function useSuiTransactionHistory(options) {
|
|
253
|
+
const account = dappKit.useCurrentAccount();
|
|
254
|
+
const client = dappKit.useSuiClient();
|
|
255
|
+
const config = useTBookSuiVault();
|
|
256
|
+
return reactQuery.useQuery({
|
|
257
|
+
queryKey: suiVaultQueryKeys.history(config.network, config.vaultId, account?.address ?? ""),
|
|
258
|
+
queryFn: async () => {
|
|
259
|
+
if (!account?.address) return [];
|
|
260
|
+
return vaultSdkSui.getUserRecords(client, config.vault, account.address);
|
|
261
|
+
},
|
|
262
|
+
enabled: Boolean(account?.address) && (options?.enabled ?? true),
|
|
263
|
+
staleTime: config.staleTimes.history,
|
|
264
|
+
refetchInterval: config.refetchIntervals.history,
|
|
265
|
+
...options
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
function useSuiUsdcBalance(options) {
|
|
269
|
+
const account = dappKit.useCurrentAccount();
|
|
270
|
+
const client = dappKit.useSuiClient();
|
|
271
|
+
const config = useTBookSuiVault();
|
|
272
|
+
const query = reactQuery.useQuery({
|
|
273
|
+
queryKey: suiVaultQueryKeys.usdcBalance(
|
|
274
|
+
config.network,
|
|
275
|
+
account?.address ?? "",
|
|
276
|
+
config.vault.usdcType
|
|
277
|
+
),
|
|
278
|
+
queryFn: async () => {
|
|
279
|
+
if (!account?.address) {
|
|
280
|
+
throw new Error("Wallet not connected");
|
|
281
|
+
}
|
|
282
|
+
return client.getBalance({ owner: account.address, coinType: config.vault.usdcType });
|
|
283
|
+
},
|
|
284
|
+
enabled: Boolean(account?.address) && (options?.enabled ?? true),
|
|
285
|
+
staleTime: config.staleTimes.usdcBalance,
|
|
286
|
+
refetchInterval: config.refetchIntervals.usdcBalance,
|
|
287
|
+
...options
|
|
288
|
+
});
|
|
289
|
+
const balance = BigInt(query.data?.totalBalance ?? "0");
|
|
290
|
+
return {
|
|
291
|
+
...query,
|
|
292
|
+
balance,
|
|
293
|
+
decimals: vaultSdkSui.USDC_DECIMALS,
|
|
294
|
+
formatted: formatRawAmount(balance, vaultSdkSui.USDC_DECIMALS)
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
function useRefreshSuiVaultData() {
|
|
298
|
+
const account = dappKit.useCurrentAccount();
|
|
299
|
+
const queryClient = reactQuery.useQueryClient();
|
|
300
|
+
const config = useTBookSuiVault();
|
|
301
|
+
return async () => {
|
|
302
|
+
await Promise.all([
|
|
303
|
+
queryClient.invalidateQueries({
|
|
304
|
+
queryKey: suiVaultQueryKeys.vault(config.network, config.vaultId)
|
|
305
|
+
}),
|
|
306
|
+
account?.address ? queryClient.invalidateQueries({
|
|
307
|
+
queryKey: suiVaultQueryKeys.balances(config.network, config.vaultId, account.address)
|
|
308
|
+
}) : Promise.resolve(),
|
|
309
|
+
account?.address ? queryClient.invalidateQueries({
|
|
310
|
+
queryKey: suiVaultQueryKeys.history(config.network, config.vaultId, account.address)
|
|
311
|
+
}) : Promise.resolve(),
|
|
312
|
+
account?.address ? queryClient.invalidateQueries({
|
|
313
|
+
queryKey: suiVaultQueryKeys.usdcBalance(
|
|
314
|
+
config.network,
|
|
315
|
+
account.address,
|
|
316
|
+
config.vault.usdcType
|
|
317
|
+
)
|
|
318
|
+
}) : Promise.resolve()
|
|
319
|
+
]);
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function redeemMode(params) {
|
|
323
|
+
if (params.mode) return params.mode;
|
|
324
|
+
return params.tokenType === "RCUSDP" ? "instant" : "queued";
|
|
325
|
+
}
|
|
326
|
+
async function executeTx(signAndExecuteTransaction, result) {
|
|
327
|
+
return signAndExecuteTransaction({ transaction: result.txBytesBase64 });
|
|
328
|
+
}
|
|
329
|
+
function gatewayClient(config) {
|
|
330
|
+
if (!config.gatewayApiBaseUrl) {
|
|
331
|
+
throw new TBookSuiVaultReactError(
|
|
332
|
+
"CONFIGURATION_ERROR",
|
|
333
|
+
"gatewayApiBaseUrl is required for gateway-api transaction building"
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
return new TBookSuiGatewayApiClient({
|
|
337
|
+
baseUrl: config.gatewayApiBaseUrl,
|
|
338
|
+
apiKey: config.publishableKey
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
function assertVaultCanDeposit(info) {
|
|
342
|
+
if (!info) return;
|
|
343
|
+
if (info.paused) throw new TBookSuiVaultReactError("VAULT_PAUSED", "Vault is paused");
|
|
344
|
+
if (!info.depositEnabled) {
|
|
345
|
+
throw new TBookSuiVaultReactError("SETTLEMENT_ACTIVE", "Deposits are temporarily unavailable");
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
function assertVaultCanRedeem(info) {
|
|
349
|
+
if (!info) return;
|
|
350
|
+
if (info.paused) throw new TBookSuiVaultReactError("VAULT_PAUSED", "Vault is paused");
|
|
351
|
+
}
|
|
352
|
+
function assertVaultCanCancel(info) {
|
|
353
|
+
if (!info) return;
|
|
354
|
+
if (info.paused) throw new TBookSuiVaultReactError("VAULT_PAUSED", "Vault is paused");
|
|
355
|
+
if (!info.cancelDepositEnabled) {
|
|
356
|
+
throw new TBookSuiVaultReactError("SETTLEMENT_ACTIVE", "Cancel deposit is unavailable");
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function useSuiDeposit() {
|
|
360
|
+
const account = dappKit.useCurrentAccount();
|
|
361
|
+
const client = dappKit.useSuiClient();
|
|
362
|
+
const config = useTBookSuiVault();
|
|
363
|
+
const { mutateAsync: signAndExecuteTransaction } = dappKit.useSignAndExecuteTransaction();
|
|
364
|
+
const refresh = useRefreshSuiVaultData();
|
|
365
|
+
const { data: vaultInfo } = useSuiVaultInfo({ enabled: config.preflightChecks });
|
|
366
|
+
return reactQuery.useMutation({
|
|
367
|
+
mutationFn: async ({ amount }) => {
|
|
368
|
+
if (!account?.address) throw walletNotConnected();
|
|
369
|
+
if (config.preflightChecks) assertVaultCanDeposit(vaultInfo);
|
|
370
|
+
const raw = toRawAmount(amount);
|
|
371
|
+
if (config.txBuilderMode === "gateway-api") {
|
|
372
|
+
const api = gatewayClient(config);
|
|
373
|
+
const response = await api.buildDepositTx(config.vaultId, {
|
|
374
|
+
user: account.address,
|
|
375
|
+
amount: formatRawAmount(raw)
|
|
376
|
+
});
|
|
377
|
+
const tx = await signAndExecuteTransaction({ transaction: response.transaction.data });
|
|
378
|
+
if (response.intentId && tx.digest) {
|
|
379
|
+
await api.confirmIntent(response.intentId, tx.digest);
|
|
380
|
+
}
|
|
381
|
+
return tx;
|
|
382
|
+
}
|
|
383
|
+
const result = config.txBuilderMode === "custom" ? await config.customTxBuilder?.buildDepositTx?.({ sender: account.address, amount: raw }) : await vaultSdkSui.buildDepositTx(client, config.vault, { sender: account.address, amount: raw });
|
|
384
|
+
if (!result) {
|
|
385
|
+
throw new TBookSuiVaultReactError("UNSUPPORTED_TX_BUILDER", "Deposit builder is not configured");
|
|
386
|
+
}
|
|
387
|
+
return executeTx(signAndExecuteTransaction, result);
|
|
388
|
+
},
|
|
389
|
+
onSuccess: refresh
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
function useSuiRedeem() {
|
|
393
|
+
const account = dappKit.useCurrentAccount();
|
|
394
|
+
const client = dappKit.useSuiClient();
|
|
395
|
+
const config = useTBookSuiVault();
|
|
396
|
+
const { mutateAsync: signAndExecuteTransaction } = dappKit.useSignAndExecuteTransaction();
|
|
397
|
+
const refresh = useRefreshSuiVaultData();
|
|
398
|
+
const { data: vaultInfo } = useSuiVaultInfo({ enabled: config.preflightChecks });
|
|
399
|
+
return reactQuery.useMutation({
|
|
400
|
+
mutationFn: async (params) => {
|
|
401
|
+
if (!account?.address) throw walletNotConnected();
|
|
402
|
+
if (config.preflightChecks) assertVaultCanRedeem(vaultInfo);
|
|
403
|
+
const mode = redeemMode(params);
|
|
404
|
+
const shares = toRawAmount(params.shares);
|
|
405
|
+
if (config.txBuilderMode === "gateway-api") {
|
|
406
|
+
const api = gatewayClient(config);
|
|
407
|
+
const response = await api.buildRedeemTx(config.vaultId, {
|
|
408
|
+
user: account.address,
|
|
409
|
+
shares: formatRawAmount(shares),
|
|
410
|
+
mode
|
|
411
|
+
});
|
|
412
|
+
const tx = await signAndExecuteTransaction({ transaction: response.transaction.data });
|
|
413
|
+
if (response.intentId && tx.digest) {
|
|
414
|
+
await api.confirmIntent(response.intentId, tx.digest);
|
|
415
|
+
}
|
|
416
|
+
return tx;
|
|
417
|
+
}
|
|
418
|
+
const result = config.txBuilderMode === "custom" ? mode === "instant" ? await config.customTxBuilder?.buildInstantRedeemTx?.({ sender: account.address, shares }) : await config.customTxBuilder?.buildQueueRedeemTx?.({ sender: account.address, shares }) : mode === "instant" ? await vaultSdkSui.buildInstantRedeemTx(client, config.vault, { sender: account.address, shares }) : await vaultSdkSui.buildQueueRedeemTx(client, config.vault, { sender: account.address, shares });
|
|
419
|
+
if (!result) {
|
|
420
|
+
throw new TBookSuiVaultReactError("UNSUPPORTED_TX_BUILDER", "Redeem builder is not configured");
|
|
421
|
+
}
|
|
422
|
+
return executeTx(signAndExecuteTransaction, result);
|
|
423
|
+
},
|
|
424
|
+
onSuccess: refresh
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
function useSuiClaim() {
|
|
428
|
+
const account = dappKit.useCurrentAccount();
|
|
429
|
+
const client = dappKit.useSuiClient();
|
|
430
|
+
const config = useTBookSuiVault();
|
|
431
|
+
const { mutateAsync: signAndExecuteTransaction } = dappKit.useSignAndExecuteTransaction();
|
|
432
|
+
const refresh = useRefreshSuiVaultData();
|
|
433
|
+
return reactQuery.useMutation({
|
|
434
|
+
mutationFn: async (params) => {
|
|
435
|
+
if (!account?.address) throw walletNotConnected();
|
|
436
|
+
const amount = params?.amount === void 0 ? void 0 : toRawAmount(params.amount);
|
|
437
|
+
if (config.txBuilderMode === "gateway-api") {
|
|
438
|
+
const api = gatewayClient(config);
|
|
439
|
+
const response = await api.buildClaimTx(config.vaultId, { user: account.address });
|
|
440
|
+
const tx = await signAndExecuteTransaction({ transaction: response.transaction.data });
|
|
441
|
+
if (response.intentId && tx.digest) {
|
|
442
|
+
await api.confirmIntent(response.intentId, tx.digest);
|
|
443
|
+
}
|
|
444
|
+
return tx;
|
|
445
|
+
}
|
|
446
|
+
const result = config.txBuilderMode === "custom" ? await config.customTxBuilder?.buildClaimTx?.({ sender: account.address, amount }) : await vaultSdkSui.buildClaimTx(client, config.vault, { sender: account.address, amount });
|
|
447
|
+
if (!result) {
|
|
448
|
+
throw new TBookSuiVaultReactError("UNSUPPORTED_TX_BUILDER", "Claim builder is not configured");
|
|
449
|
+
}
|
|
450
|
+
return executeTx(signAndExecuteTransaction, result);
|
|
451
|
+
},
|
|
452
|
+
onSuccess: refresh
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
function useSuiCancelDeposit() {
|
|
456
|
+
const account = dappKit.useCurrentAccount();
|
|
457
|
+
const client = dappKit.useSuiClient();
|
|
458
|
+
const config = useTBookSuiVault();
|
|
459
|
+
const { mutateAsync: signAndExecuteTransaction } = dappKit.useSignAndExecuteTransaction();
|
|
460
|
+
const refresh = useRefreshSuiVaultData();
|
|
461
|
+
const { data: vaultInfo } = useSuiVaultInfo({ enabled: config.preflightChecks });
|
|
462
|
+
return reactQuery.useMutation({
|
|
463
|
+
mutationFn: async ({ recordId }) => {
|
|
464
|
+
if (!account?.address) throw walletNotConnected();
|
|
465
|
+
if (config.preflightChecks) assertVaultCanCancel(vaultInfo);
|
|
466
|
+
if (config.txBuilderMode === "gateway-api") {
|
|
467
|
+
const api = gatewayClient(config);
|
|
468
|
+
const response = await api.buildCancelDepositTx(config.vaultId, {
|
|
469
|
+
user: account.address,
|
|
470
|
+
recordId: String(recordId)
|
|
471
|
+
});
|
|
472
|
+
const tx = await signAndExecuteTransaction({ transaction: response.transaction.data });
|
|
473
|
+
if (response.intentId && tx.digest) {
|
|
474
|
+
await api.confirmIntent(response.intentId, tx.digest);
|
|
475
|
+
}
|
|
476
|
+
return tx;
|
|
477
|
+
}
|
|
478
|
+
const result = config.txBuilderMode === "custom" ? await config.customTxBuilder?.buildCancelDepositTx?.({ sender: account.address, recordId }) : await vaultSdkSui.buildCancelDepositTx(client, config.vault, { sender: account.address, recordId });
|
|
479
|
+
if (!result) {
|
|
480
|
+
throw new TBookSuiVaultReactError("UNSUPPORTED_TX_BUILDER", "Cancel deposit builder is not configured");
|
|
481
|
+
}
|
|
482
|
+
return executeTx(signAndExecuteTransaction, result);
|
|
483
|
+
},
|
|
484
|
+
onSuccess: refresh
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
exports.DEFAULT_SUI_VAULT_ID = DEFAULT_SUI_VAULT_ID;
|
|
489
|
+
exports.SUI_TESTNET_GATEWAY_API_BASE_URL = SUI_TESTNET_GATEWAY_API_BASE_URL;
|
|
490
|
+
exports.TBookSuiGatewayApiClient = TBookSuiGatewayApiClient;
|
|
491
|
+
exports.TBookSuiVaultProvider = TBookSuiVaultProvider;
|
|
492
|
+
exports.TBookSuiVaultReactError = TBookSuiVaultReactError;
|
|
493
|
+
exports.createSuiVaultConfig = createSuiVaultConfig;
|
|
494
|
+
exports.formatRawAmount = formatRawAmount;
|
|
495
|
+
exports.getSuiVaultInfo = getSuiVaultInfo;
|
|
496
|
+
exports.parseDecimalAmount = parseDecimalAmount;
|
|
497
|
+
exports.suiVaultQueryKeys = suiVaultQueryKeys;
|
|
498
|
+
exports.toRawAmount = toRawAmount;
|
|
499
|
+
exports.useRefreshSuiVaultData = useRefreshSuiVaultData;
|
|
500
|
+
exports.useSuiCancelDeposit = useSuiCancelDeposit;
|
|
501
|
+
exports.useSuiClaim = useSuiClaim;
|
|
502
|
+
exports.useSuiDeposit = useSuiDeposit;
|
|
503
|
+
exports.useSuiRedeem = useSuiRedeem;
|
|
504
|
+
exports.useSuiTransactionHistory = useSuiTransactionHistory;
|
|
505
|
+
exports.useSuiUsdcBalance = useSuiUsdcBalance;
|
|
506
|
+
exports.useSuiVaultBalances = useSuiVaultBalances;
|
|
507
|
+
exports.useSuiVaultConfig = useSuiVaultConfig;
|
|
508
|
+
exports.useSuiVaultInfo = useSuiVaultInfo;
|
|
509
|
+
exports.useTBookSuiVault = useTBookSuiVault;
|
|
510
|
+
//# sourceMappingURL=index.cjs.map
|
|
511
|
+
//# sourceMappingURL=index.cjs.map
|