@swapkit/toolboxes 1.0.0-beta.15 → 1.0.0-beta.17

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.
@@ -13,6 +13,12 @@ import { Client, type Payment, Wallet, isValidAddress, xrpToDrops } from "xrpl";
13
13
 
14
14
  export type RippleWallet = Awaited<ReturnType<typeof getRippleToolbox>>;
15
15
 
16
+ export { hashes, type Transaction } from "xrpl";
17
+
18
+ const RIPPLE_ERROR_CODES = {
19
+ ACCOUNT_NOT_FOUND: 19,
20
+ } as const;
21
+
16
22
  // Note: Ripple seeds generate a single address, no derivation path/index support.
17
23
  function createSigner(phrase: string): ChainSigner<Transaction, { tx_blob: string; hash: string }> {
18
24
  const wallet = Wallet.fromMnemonic(phrase);
@@ -64,11 +70,7 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
64
70
  const addr = address || (await getAddress());
65
71
 
66
72
  try {
67
- await client.connect();
68
- const accountInfo = await client.request({
69
- command: "account_info",
70
- account: addr,
71
- });
73
+ const accountInfo = await client.request({ command: "account_info", account: addr });
72
74
 
73
75
  const balance = accountInfo.result.account_data.Balance;
74
76
 
@@ -81,7 +83,7 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
81
83
  ];
82
84
  } catch (error) {
83
85
  // empty account
84
- if ((error as any).data.error_code === 19) {
86
+ if ((error as any).data.error_code === RIPPLE_ERROR_CODES.ACCOUNT_NOT_FOUND) {
85
87
  return [
86
88
  AssetValue.from({
87
89
  chain: Chain.Ripple,
@@ -148,22 +150,15 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
148
150
 
149
151
  const broadcastTransaction = async (signedTxHex: string) => {
150
152
  const submitResult = await client.submitAndWait(signedTxHex);
151
- // Cast result to any to bypass potential type mismatches in xrpl.js definitions
152
- const result: any = submitResult.result;
153
+ const result = submitResult.result;
153
154
 
154
- // Check engine_result directly on result
155
- if (result.engine_result === "tesSUCCESS" || result.engine_result === "terQUEUED") {
156
- // Access hash from tx_json if available, otherwise fallback to result.hash
157
- return result.tx_json?.hash || result.hash;
155
+ if (result.validated) {
156
+ return result.hash;
158
157
  }
159
158
 
160
- const message = result.engine_result_message || "Unknown error";
161
- const code = result.engine_result || "Unknown code";
162
-
163
159
  throw new SwapKitError({
164
160
  errorKey: "toolbox_ripple_broadcast_error",
165
- info: { chain: Chain.Ripple, message, code, result },
166
- // Remove explicit message when using object format
161
+ info: { chain: Chain.Ripple },
167
162
  });
168
163
  };
169
164
 
@@ -177,9 +172,7 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
177
172
  return broadcastTransaction(signedTx.tx_blob);
178
173
  };
179
174
 
180
- // Disconnect client on demand or handle elsewhere?
181
- // For now, let's assume connection is managed outside or persists.
182
- // const disconnect = () => client.disconnect();
175
+ const disconnect = () => client.disconnect();
183
176
 
184
177
  return {
185
178
  // Signer related
@@ -194,6 +187,6 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
194
187
  broadcastTransaction,
195
188
  transfer,
196
189
  estimateTransactionFee,
197
- // disconnect, // Optional: expose disconnect
190
+ disconnect,
198
191
  };
199
192
  };
@@ -22,10 +22,79 @@ import {
22
22
  import { P } from "ts-pattern";
23
23
  import { match } from "ts-pattern";
24
24
  import type { SolanaCreateTransactionParams, SolanaProvider, SolanaTransferParams } from ".";
25
- import { getBalance } from "../utils";
26
25
 
27
26
  type SolanaSigner = SolanaProvider | Signer;
28
27
 
28
+ type TokenMetadata = {
29
+ name: string;
30
+ symbol: string;
31
+ decimals: number;
32
+ logoURI?: string;
33
+ tags?: string[];
34
+ daily_volume?: number;
35
+ };
36
+
37
+ async function fetchTokenMetaData(mintAddress: string): Promise<TokenMetadata | null> {
38
+ try {
39
+ const response = await fetch(`https://lite-api.jup.ag/tokens/v1/token/${mintAddress}`);
40
+ if (!response.ok) return null;
41
+ return await response.json();
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+
47
+ async function getSolanaBalance(address: string) {
48
+ const connection = await getConnection();
49
+ const { PublicKey } = await import("@solana/web3.js");
50
+ const { TOKEN_PROGRAM_ID } = await import("@solana/spl-token");
51
+ const publicKey = new PublicKey(address);
52
+
53
+ const balances: AssetValue[] = [];
54
+
55
+ // Get SOL balance
56
+ const solBalance = await connection.getBalance(publicKey);
57
+ if (solBalance > 0) {
58
+ balances.push(
59
+ AssetValue.from({
60
+ chain: Chain.Solana,
61
+ value: solBalance,
62
+ fromBaseDecimal: BaseDecimal[Chain.Solana],
63
+ }),
64
+ );
65
+ }
66
+
67
+ // Get token balances
68
+ const tokenAccounts = await connection.getParsedTokenAccountsByOwner(publicKey, {
69
+ programId: TOKEN_PROGRAM_ID,
70
+ });
71
+
72
+ for (const { account } of tokenAccounts.value) {
73
+ const tokenInfo = account.data.parsed.info;
74
+ const mintAddress = tokenInfo.mint;
75
+ const amount = tokenInfo.tokenAmount.amount;
76
+
77
+ if (Number(amount) === 0) continue;
78
+
79
+ // Fetch token metadata from Jupiter
80
+ const metadata = await fetchTokenMetaData(mintAddress);
81
+ const symbol = metadata?.symbol || "UNKNOWN";
82
+ const decimals = metadata?.decimals || tokenInfo.tokenAmount.decimals;
83
+
84
+ balances.push(
85
+ AssetValue.from({
86
+ chain: Chain.Solana,
87
+ symbol,
88
+ address: mintAddress,
89
+ value: amount,
90
+ fromBaseDecimal: decimals,
91
+ }),
92
+ );
93
+ }
94
+
95
+ return balances;
96
+ }
97
+
29
98
  export async function getSolanaAddressValidator() {
30
99
  const { PublicKey } = await import("@solana/web3.js");
31
100
 
@@ -68,7 +137,11 @@ export async function getSolanaToolbox(
68
137
  getPubkeyFromAddress,
69
138
  createTransaction: createTransaction(getConnection),
70
139
  createTransactionFromInstructions,
71
- getBalance: getBalance(Chain.Solana),
140
+ getBalance: (addressParam?: string) => {
141
+ const address = addressParam || getAddress();
142
+ if (!address) throw new SwapKitError("core_wallet_connection_not_found");
143
+ return getSolanaBalance(address);
144
+ },
72
145
  transfer: transfer(getConnection, signer),
73
146
  broadcastTransaction: broadcastTransaction(getConnection),
74
147
  getAddressValidator: getSolanaAddressValidator,