@solana/connector 0.1.5 → 0.1.7
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 +110 -45
- package/dist/{chunk-VMSZJPR5.mjs → chunk-APQGEW7S.mjs} +82 -11
- package/dist/chunk-APQGEW7S.mjs.map +1 -0
- package/dist/{chunk-3STZXVXD.mjs → chunk-JK47EFJT.mjs} +940 -381
- package/dist/chunk-JK47EFJT.mjs.map +1 -0
- package/dist/{chunk-QKVL45F6.mjs → chunk-TQRJYZNK.mjs} +5 -3
- package/dist/chunk-TQRJYZNK.mjs.map +1 -0
- package/dist/{chunk-JUZVCBAI.js → chunk-VA6LKXCQ.js} +85 -10
- package/dist/chunk-VA6LKXCQ.js.map +1 -0
- package/dist/{chunk-NQXK7PGX.js → chunk-VZ5Y6DIM.js} +19 -17
- package/dist/chunk-VZ5Y6DIM.js.map +1 -0
- package/dist/{chunk-ULUYX23Q.js → chunk-Z22V3D4E.js} +949 -388
- package/dist/chunk-Z22V3D4E.js.map +1 -0
- package/dist/compat.d.mts +1 -1
- package/dist/compat.d.ts +1 -1
- package/dist/headless.d.mts +99 -7
- package/dist/headless.d.ts +99 -7
- package/dist/headless.js +128 -112
- package/dist/headless.mjs +2 -2
- package/dist/index.d.mts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +163 -139
- package/dist/index.mjs +3 -3
- package/dist/react.d.mts +179 -13
- package/dist/react.d.ts +179 -13
- package/dist/react.js +36 -28
- package/dist/react.mjs +2 -2
- package/dist/{transaction-signer-D9d8nxwb.d.mts → transaction-signer-CpGEvp7S.d.mts} +1 -1
- package/dist/{transaction-signer-D9d8nxwb.d.ts → transaction-signer-CpGEvp7S.d.ts} +1 -1
- package/dist/{wallet-standard-shim--YcrQNRt.d.ts → wallet-standard-shim-D4CYG5sU.d.mts} +35 -6
- package/dist/{wallet-standard-shim-Dx7H8Ctf.d.mts → wallet-standard-shim-DiMvGjOk.d.ts} +35 -6
- package/package.json +1 -1
- package/dist/chunk-3STZXVXD.mjs.map +0 -1
- package/dist/chunk-JUZVCBAI.js.map +0 -1
- package/dist/chunk-NQXK7PGX.js.map +0 -1
- package/dist/chunk-QKVL45F6.mjs.map +0 -1
- package/dist/chunk-ULUYX23Q.js.map +0 -1
- package/dist/chunk-VMSZJPR5.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: @solana/connector
|
|
2
|
+
title: '@solana/connector'
|
|
3
3
|
description: Production-ready wallet connector for Solana applications
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -30,7 +30,7 @@ npm install @solana/connector
|
|
|
30
30
|
pnpm add @solana/connector
|
|
31
31
|
# or
|
|
32
32
|
yarn add @solana/connector
|
|
33
|
-
# or
|
|
33
|
+
# or
|
|
34
34
|
bun add @solana/connector
|
|
35
35
|
```
|
|
36
36
|
|
|
@@ -610,6 +610,72 @@ const mobile = getDefaultMobileConfig({
|
|
|
610
610
|
|
|
611
611
|
## Security Considerations
|
|
612
612
|
|
|
613
|
+
### RPC API Key Protection
|
|
614
|
+
|
|
615
|
+
If you're using a paid RPC provider (Helius, QuickNode, etc.), avoid exposing your API key client-side. Anyone can grab it from the browser's network tab.
|
|
616
|
+
|
|
617
|
+
**Solution: RPC Proxy Route**
|
|
618
|
+
|
|
619
|
+
Create an API route that proxies RPC requests, keeping the API key server-side:
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
// app/api/rpc/route.ts
|
|
623
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
624
|
+
|
|
625
|
+
// Server-side only - not exposed to client
|
|
626
|
+
const RPC_URL = process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com';
|
|
627
|
+
|
|
628
|
+
export async function POST(request: NextRequest) {
|
|
629
|
+
try {
|
|
630
|
+
const body = await request.json();
|
|
631
|
+
|
|
632
|
+
const response = await fetch(RPC_URL, {
|
|
633
|
+
method: 'POST',
|
|
634
|
+
headers: { 'Content-Type': 'application/json' },
|
|
635
|
+
body: JSON.stringify(body),
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
const data = await response.json();
|
|
639
|
+
return NextResponse.json(data);
|
|
640
|
+
} catch (error) {
|
|
641
|
+
return NextResponse.json({ error: 'RPC request failed' }, { status: 500 });
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
Then configure the connector to use the proxy:
|
|
647
|
+
|
|
648
|
+
```typescript
|
|
649
|
+
'use client';
|
|
650
|
+
|
|
651
|
+
import { getDefaultConfig } from '@solana/connector/headless';
|
|
652
|
+
|
|
653
|
+
// Get origin for absolute URL (Kit requires full URLs)
|
|
654
|
+
const getOrigin = () => {
|
|
655
|
+
if (typeof window !== 'undefined') return window.location.origin;
|
|
656
|
+
return 'http://localhost:3000';
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
const config = getDefaultConfig({
|
|
660
|
+
appName: 'My App',
|
|
661
|
+
clusters: [
|
|
662
|
+
{
|
|
663
|
+
id: 'solana:mainnet' as const,
|
|
664
|
+
label: 'Mainnet',
|
|
665
|
+
name: 'mainnet-beta' as const,
|
|
666
|
+
url: `${getOrigin()}/api/rpc`, // Proxy URL
|
|
667
|
+
},
|
|
668
|
+
// ... other clusters
|
|
669
|
+
],
|
|
670
|
+
});
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
Your `.env` file (no `NEXT_PUBLIC_` prefix):
|
|
674
|
+
|
|
675
|
+
```
|
|
676
|
+
SOLANA_RPC_URL=https://mainnet.helius-rpc.com/?api-key=your-key
|
|
677
|
+
```
|
|
678
|
+
|
|
613
679
|
### Token Image Privacy
|
|
614
680
|
|
|
615
681
|
When using `useTokens()` or `useTransactions()`, token metadata (including logo URLs) is fetched from external APIs. By default, these image URLs are returned directly, which means when your users' browsers fetch these images, the image host can see:
|
|
@@ -643,12 +709,12 @@ https://raw.githubusercontent.com/.../token-logo.png
|
|
|
643
709
|
|
|
644
710
|
### Common Proxy Options
|
|
645
711
|
|
|
646
|
-
| Service
|
|
647
|
-
|
|
648
|
-
| **Next.js Image** | `imageProxy: '/_next/image?w=64&q=75&url='`
|
|
649
|
-
| **Cloudflare**
|
|
650
|
-
| **imgproxy**
|
|
651
|
-
| **Custom API**
|
|
712
|
+
| Service | Configuration |
|
|
713
|
+
| ----------------- | ----------------------------------------------------------------- |
|
|
714
|
+
| **Next.js Image** | `imageProxy: '/_next/image?w=64&q=75&url='` |
|
|
715
|
+
| **Cloudflare** | `imageProxy: '/cdn-cgi/image/width=64,quality=75/'` |
|
|
716
|
+
| **imgproxy** | `imageProxy: 'https://imgproxy.example.com/insecure/fill/64/64/'` |
|
|
717
|
+
| **Custom API** | `imageProxy: '/api/image-proxy?url='` |
|
|
652
718
|
|
|
653
719
|
### Custom Proxy API Route (Next.js Example)
|
|
654
720
|
|
|
@@ -725,14 +791,12 @@ function validateUrl(urlString: string): URL | null {
|
|
|
725
791
|
|
|
726
792
|
// Check if hostname is in the allowlist
|
|
727
793
|
function isAllowedDomain(hostname: string): boolean {
|
|
728
|
-
return ALLOWED_DOMAINS.some(
|
|
729
|
-
(domain) => hostname === domain || hostname.endsWith(`.${domain}`)
|
|
730
|
-
);
|
|
794
|
+
return ALLOWED_DOMAINS.some(domain => hostname === domain || hostname.endsWith(`.${domain}`));
|
|
731
795
|
}
|
|
732
796
|
|
|
733
797
|
export async function GET(request: NextRequest) {
|
|
734
798
|
const urlParam = request.nextUrl.searchParams.get('url');
|
|
735
|
-
|
|
799
|
+
|
|
736
800
|
// (1) Ensure URL exists and parses correctly with http/https
|
|
737
801
|
if (!urlParam) {
|
|
738
802
|
return new NextResponse('Missing URL parameter', { status: 400 });
|
|
@@ -764,7 +828,7 @@ export async function GET(request: NextRequest) {
|
|
|
764
828
|
try {
|
|
765
829
|
const response = await fetch(parsedUrl.toString());
|
|
766
830
|
const buffer = await response.arrayBuffer();
|
|
767
|
-
|
|
831
|
+
|
|
768
832
|
return new NextResponse(buffer, {
|
|
769
833
|
headers: {
|
|
770
834
|
'Content-Type': response.headers.get('Content-Type') || 'image/png',
|
|
@@ -785,16 +849,17 @@ The `useTokens()` hook fetches token prices from CoinGecko. CoinGecko has rate l
|
|
|
785
849
|
|
|
786
850
|
### Rate Limits (as of 2024)
|
|
787
851
|
|
|
788
|
-
| Tier
|
|
789
|
-
|
|
790
|
-
| **Free (Public)** | 10-30 requests/minute | No
|
|
791
|
-
| **Demo**
|
|
792
|
-
| **Analyst**
|
|
793
|
-
| **Pro**
|
|
852
|
+
| Tier | Rate Limit | API Key Required |
|
|
853
|
+
| ----------------- | --------------------- | ---------------- |
|
|
854
|
+
| **Free (Public)** | 10-30 requests/minute | No |
|
|
855
|
+
| **Demo** | 30 requests/minute | Yes (free) |
|
|
856
|
+
| **Analyst** | 500 requests/minute | Yes (paid) |
|
|
857
|
+
| **Pro** | 1000+ requests/minute | Yes (paid) |
|
|
794
858
|
|
|
795
859
|
### Handling Rate Limits
|
|
796
860
|
|
|
797
861
|
ConnectorKit automatically handles rate limits with:
|
|
862
|
+
|
|
798
863
|
- **Exponential backoff**: Retries with increasing delays
|
|
799
864
|
- **Jitter**: Random delay added to prevent thundering herd
|
|
800
865
|
- **Retry-After header**: Honors server-specified wait times
|
|
@@ -822,16 +887,16 @@ const config = getDefaultConfig({
|
|
|
822
887
|
coingecko: {
|
|
823
888
|
// API key for higher rate limits (optional)
|
|
824
889
|
apiKey: process.env.COINGECKO_API_KEY,
|
|
825
|
-
|
|
890
|
+
|
|
826
891
|
// Set to true if using a Pro API key (default: false for Demo keys)
|
|
827
892
|
isPro: false,
|
|
828
|
-
|
|
893
|
+
|
|
829
894
|
// Maximum retry attempts on 429 (default: 3)
|
|
830
895
|
maxRetries: 3,
|
|
831
|
-
|
|
896
|
+
|
|
832
897
|
// Base delay for exponential backoff in ms (default: 1000)
|
|
833
898
|
baseDelay: 1000,
|
|
834
|
-
|
|
899
|
+
|
|
835
900
|
// Maximum total timeout in ms (default: 30000)
|
|
836
901
|
maxTimeout: 30000,
|
|
837
902
|
},
|
|
@@ -942,35 +1007,35 @@ import { useConnector, useAccount } from '@solana/connector/react';
|
|
|
942
1007
|
|
|
943
1008
|
### Hooks
|
|
944
1009
|
|
|
945
|
-
| Hook
|
|
946
|
-
|
|
947
|
-
| `useConnector()`
|
|
948
|
-
| `useAccount()`
|
|
949
|
-
| `useCluster()`
|
|
950
|
-
| `useWalletInfo()`
|
|
951
|
-
| `useTransactionSigner()`
|
|
952
|
-
| `useKitTransactionSigner()` | Modern transaction signer (@solana/kit) | `{ signer, ready, address }`
|
|
953
|
-
| `useBalance()`
|
|
954
|
-
| `useTokens()`
|
|
955
|
-
| `useTransactions()`
|
|
1010
|
+
| Hook | Description | Returns |
|
|
1011
|
+
| --------------------------- | --------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
1012
|
+
| `useConnector()` | Main wallet connection hook | `{ wallets, selectedWallet, accounts, connected, connecting, select, disconnect }` |
|
|
1013
|
+
| `useAccount()` | Account management hook | `{ address, formatted, copy, copied, accounts, selectAccount }` |
|
|
1014
|
+
| `useCluster()` | Network/cluster management hook | `{ cluster, clusters, setCluster, isMainnet, isDevnet, rpcUrl }` |
|
|
1015
|
+
| `useWalletInfo()` | Wallet metadata hook | `{ name, icon, wallet, connecting }` |
|
|
1016
|
+
| `useTransactionSigner()` | Legacy transaction signer (web3.js) | `{ signer, ready, address, capabilities }` |
|
|
1017
|
+
| `useKitTransactionSigner()` | Modern transaction signer (@solana/kit) | `{ signer, ready, address }` |
|
|
1018
|
+
| `useBalance()` | SOL balance hook | `{ solBalance, isLoading, refetch }` |
|
|
1019
|
+
| `useTokens()` | SPL tokens hook | `{ tokens, isLoading, refetch }` |
|
|
1020
|
+
| `useTransactions()` | Transaction history hook | `{ transactions, isLoading, refetch }` |
|
|
956
1021
|
|
|
957
1022
|
### Configuration Functions
|
|
958
1023
|
|
|
959
|
-
| Function
|
|
960
|
-
|
|
961
|
-
| `getDefaultConfig(options)`
|
|
962
|
-
| `getDefaultMobileConfig(options)` | Create mobile wallet adapter configuration
|
|
963
|
-
| `createConfig(options)`
|
|
1024
|
+
| Function | Description |
|
|
1025
|
+
| --------------------------------- | ------------------------------------------------- |
|
|
1026
|
+
| `getDefaultConfig(options)` | Create default connector configuration |
|
|
1027
|
+
| `getDefaultMobileConfig(options)` | Create mobile wallet adapter configuration |
|
|
1028
|
+
| `createConfig(options)` | Create unified config for ConnectorKit + Armadura |
|
|
964
1029
|
|
|
965
1030
|
### Utility Functions
|
|
966
1031
|
|
|
967
|
-
| Function
|
|
968
|
-
|
|
969
|
-
| `formatAddress(address, options?)`
|
|
970
|
-
| `formatSOL(lamports, options?)`
|
|
971
|
-
| `copyAddressToClipboard(address)`
|
|
1032
|
+
| Function | Description |
|
|
1033
|
+
| --------------------------------------- | ----------------------------------- |
|
|
1034
|
+
| `formatAddress(address, options?)` | Format Solana address |
|
|
1035
|
+
| `formatSOL(lamports, options?)` | Format SOL amount |
|
|
1036
|
+
| `copyAddressToClipboard(address)` | Copy address to clipboard |
|
|
972
1037
|
| `getTransactionUrl(cluster, signature)` | Get Solana Explorer transaction URL |
|
|
973
|
-
| `getAddressUrl(cluster, address)`
|
|
1038
|
+
| `getAddressUrl(cluster, address)` | Get Solana Explorer address URL |
|
|
974
1039
|
|
|
975
1040
|
---
|
|
976
1041
|
|
|
@@ -228,6 +228,11 @@ function getNetworkDisplayName(network) {
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
// src/utils/cluster.ts
|
|
231
|
+
function getMaybeStringProp(value, prop) {
|
|
232
|
+
if (typeof value != "object" || value === null) return;
|
|
233
|
+
let v = value[prop];
|
|
234
|
+
return typeof v == "string" ? v : void 0;
|
|
235
|
+
}
|
|
231
236
|
function getClusterRpcUrl(cluster) {
|
|
232
237
|
if (typeof cluster == "string") {
|
|
233
238
|
let presets2 = {
|
|
@@ -238,7 +243,7 @@ function getClusterRpcUrl(cluster) {
|
|
|
238
243
|
return presets2[cluster];
|
|
239
244
|
throw new Error(`Unknown cluster: ${cluster}`);
|
|
240
245
|
}
|
|
241
|
-
let url = cluster.url
|
|
246
|
+
let url = cluster.url ?? getMaybeStringProp(cluster, "rpcUrl");
|
|
242
247
|
if (!url)
|
|
243
248
|
throw new Error("Cluster URL is required");
|
|
244
249
|
if (url.startsWith("http://") || url.startsWith("https://"))
|
|
@@ -283,16 +288,17 @@ function isTestnetCluster(cluster) {
|
|
|
283
288
|
return cluster.id === "solana:testnet";
|
|
284
289
|
}
|
|
285
290
|
function isLocalCluster(cluster) {
|
|
286
|
-
let url = cluster.url
|
|
291
|
+
let url = cluster.url ?? getMaybeStringProp(cluster, "rpcUrl");
|
|
287
292
|
return url ? cluster.id === "solana:localnet" || url.includes("localhost") || url.includes("127.0.0.1") : cluster.id === "solana:localnet";
|
|
288
293
|
}
|
|
289
294
|
function getClusterName(cluster) {
|
|
290
295
|
if (cluster.label) return cluster.label;
|
|
291
|
-
|
|
296
|
+
let name = getMaybeStringProp(cluster, "name");
|
|
297
|
+
if (name) return name;
|
|
292
298
|
let parts = cluster.id.split(":");
|
|
293
299
|
if (parts.length >= 2 && parts[1]) {
|
|
294
|
-
let
|
|
295
|
-
return
|
|
300
|
+
let name2 = parts.slice(1).join(":");
|
|
301
|
+
return name2.charAt(0).toUpperCase() + name2.slice(1).replace(/-/g, " ");
|
|
296
302
|
}
|
|
297
303
|
return "Unknown";
|
|
298
304
|
}
|
|
@@ -1284,7 +1290,7 @@ var TransactionTracker = class extends BaseCollaborator {
|
|
|
1284
1290
|
* Track a transaction for debugging and monitoring
|
|
1285
1291
|
*/
|
|
1286
1292
|
trackTransaction(activity) {
|
|
1287
|
-
let clusterId = this.getState().cluster?.id
|
|
1293
|
+
let clusterId = this.getState().cluster?.id ?? "solana:devnet", fullActivity = {
|
|
1288
1294
|
...activity,
|
|
1289
1295
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1290
1296
|
cluster: clusterId
|
|
@@ -1300,10 +1306,10 @@ var TransactionTracker = class extends BaseCollaborator {
|
|
|
1300
1306
|
* Update transaction status (e.g., from pending to confirmed/failed)
|
|
1301
1307
|
*/
|
|
1302
1308
|
updateStatus(signature, status, error) {
|
|
1303
|
-
let tx = this.transactions.find((t) => t.signature === signature);
|
|
1309
|
+
let tx = this.transactions.find((t) => String(t.signature) === signature);
|
|
1304
1310
|
tx && (tx.status = status, error && (tx.error = error), this.eventEmitter.emit({
|
|
1305
1311
|
type: "transaction:updated",
|
|
1306
|
-
signature,
|
|
1312
|
+
signature: tx.signature,
|
|
1307
1313
|
status,
|
|
1308
1314
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1309
1315
|
}), this.log("[Connector] Transaction updated:", { signature, status, error }));
|
|
@@ -1886,6 +1892,71 @@ function formatTokenAmount(amount, decimals, options = {}) {
|
|
|
1886
1892
|
maximumFractionDigits: maxDecimals
|
|
1887
1893
|
});
|
|
1888
1894
|
}
|
|
1895
|
+
var MAX_SAFE_INTEGER = BigInt(Number.MAX_SAFE_INTEGER);
|
|
1896
|
+
function isSafeInteger(value) {
|
|
1897
|
+
return value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
|
|
1898
|
+
}
|
|
1899
|
+
function splitBigIntDecimals(amount, decimals) {
|
|
1900
|
+
if (decimals <= 0)
|
|
1901
|
+
return { whole: amount.toString(), fraction: "" };
|
|
1902
|
+
let str = amount.toString(), isNegative = str.startsWith("-"), absStr = isNegative ? str.slice(1) : str;
|
|
1903
|
+
if (absStr.length <= decimals) {
|
|
1904
|
+
let padded = absStr.padStart(decimals, "0");
|
|
1905
|
+
return {
|
|
1906
|
+
whole: isNegative ? "-0" : "0",
|
|
1907
|
+
fraction: padded
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
let splitPoint = absStr.length - decimals;
|
|
1911
|
+
return {
|
|
1912
|
+
whole: (isNegative ? "-" : "") + absStr.slice(0, splitPoint),
|
|
1913
|
+
fraction: absStr.slice(splitPoint)
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
function formatBigIntBalance(amount, decimals, options = {}) {
|
|
1917
|
+
let { maxDecimals = Math.min(decimals, 6), minDecimals = 0, locale, useGrouping = true } = options;
|
|
1918
|
+
if (isSafeInteger(amount))
|
|
1919
|
+
return (Number(amount) / Math.pow(10, decimals)).toLocaleString(locale, {
|
|
1920
|
+
minimumFractionDigits: minDecimals,
|
|
1921
|
+
maximumFractionDigits: maxDecimals,
|
|
1922
|
+
useGrouping
|
|
1923
|
+
});
|
|
1924
|
+
let { whole, fraction } = splitBigIntDecimals(amount, decimals), truncatedFraction = fraction.slice(0, maxDecimals);
|
|
1925
|
+
for (; truncatedFraction.length > minDecimals && truncatedFraction.endsWith("0"); )
|
|
1926
|
+
truncatedFraction = truncatedFraction.slice(0, -1);
|
|
1927
|
+
truncatedFraction = truncatedFraction.padEnd(minDecimals, "0");
|
|
1928
|
+
let formattedWhole = whole;
|
|
1929
|
+
if (useGrouping) {
|
|
1930
|
+
let isNegative = whole.startsWith("-"), absWhole = isNegative ? whole.slice(1) : whole, parts = [];
|
|
1931
|
+
for (let i = absWhole.length; i > 0; i -= 3)
|
|
1932
|
+
parts.unshift(absWhole.slice(Math.max(0, i - 3), i));
|
|
1933
|
+
formattedWhole = (isNegative ? "-" : "") + parts.join(",");
|
|
1934
|
+
}
|
|
1935
|
+
return truncatedFraction.length === 0 ? formattedWhole : `${formattedWhole}.${truncatedFraction}`;
|
|
1936
|
+
}
|
|
1937
|
+
function formatLamportsToSolSafe(lamports, options = {}) {
|
|
1938
|
+
let { maxDecimals = 4, minDecimals = 0, suffix = false, locale } = options, formatted = formatBigIntBalance(lamports, 9, {
|
|
1939
|
+
maxDecimals,
|
|
1940
|
+
minDecimals,
|
|
1941
|
+
locale
|
|
1942
|
+
});
|
|
1943
|
+
return suffix ? `${formatted} SOL` : formatted;
|
|
1944
|
+
}
|
|
1945
|
+
function formatBigIntUsd(amount, decimals, usdPrice, options = {}) {
|
|
1946
|
+
let { locale, currency = "USD" } = options, { whole, fraction } = splitBigIntDecimals(amount, decimals), wholeNum = parseFloat(whole), fractionNum = fraction ? parseFloat("0." + fraction) : 0;
|
|
1947
|
+
return ((wholeNum + fractionNum) * usdPrice).toLocaleString(locale, {
|
|
1948
|
+
style: "currency",
|
|
1949
|
+
currency,
|
|
1950
|
+
minimumFractionDigits: 2,
|
|
1951
|
+
maximumFractionDigits: 2
|
|
1952
|
+
});
|
|
1953
|
+
}
|
|
1954
|
+
function formatTokenBalanceSafe(amount, decimals, options = {}) {
|
|
1955
|
+
return formatBigIntBalance(amount, decimals, {
|
|
1956
|
+
maxDecimals: options.maxDecimals ?? Math.min(decimals, 6),
|
|
1957
|
+
locale: options.locale
|
|
1958
|
+
});
|
|
1959
|
+
}
|
|
1889
1960
|
var ClipboardErrorType = /* @__PURE__ */ ((ClipboardErrorType2) => (ClipboardErrorType2.NOT_SUPPORTED = "not_supported", ClipboardErrorType2.PERMISSION_DENIED = "permission_denied", ClipboardErrorType2.SSR = "ssr", ClipboardErrorType2.EMPTY_VALUE = "empty_value", ClipboardErrorType2.INVALID_VALUE = "invalid_value", ClipboardErrorType2.UNKNOWN = "unknown", ClipboardErrorType2))(ClipboardErrorType || {});
|
|
1890
1961
|
function isClipboardAvailable() {
|
|
1891
1962
|
if (typeof window > "u" || typeof document > "u")
|
|
@@ -2447,6 +2518,6 @@ function createKitTransactionSigner(connectorSigner) {
|
|
|
2447
2518
|
}
|
|
2448
2519
|
var createGillTransactionSigner = createKitTransactionSigner;
|
|
2449
2520
|
|
|
2450
|
-
export { ClipboardErrorType, ConfigurationError, ConnectionError, ConnectorClient, ConnectorError, ConnectorErrorBoundary, DEFAULT_MAX_RETRIES, Errors, NetworkError, PUBLIC_RPC_ENDPOINTS, TransactionError, TransactionSignerError, ValidationError, WalletErrorType, copyAddressToClipboard, copySignatureToClipboard, copyToClipboard, createGillTransactionSigner, createKitTransactionSigner, createTransactionSigner, formatAddress, formatNumber, formatSOL, formatTokenAmount, getAddressUrl, getBlockUrl, getChainIdForWalletStandard, getClusterChainId, getClusterExplorerUrl, getClusterName, getClusterRpcUrl, getClusterType, getDefaultRpcUrl, getNetworkDisplayName, getPolyfillStatus, getTokenUrl, getTransactionUrl, getUserFriendlyMessage, getWalletsRegistry, installPolyfills, isClipboardAvailable, isConfigurationError, isConnectionError, isConnectorError, isCryptoAvailable, isDevnet, isDevnetCluster, isLocalCluster, isLocalnet, isMainnet, isMainnetCluster, isNetworkError, isPolyfillInstalled, isTestnet, isTestnetCluster, isTransactionError, isTransactionSignerError, isValidationError, normalizeNetwork, toClusterId, toConnectorError, truncate, withErrorBoundary };
|
|
2451
|
-
//# sourceMappingURL=chunk-
|
|
2452
|
-
//# sourceMappingURL=chunk-
|
|
2521
|
+
export { ClipboardErrorType, ConfigurationError, ConnectionError, ConnectorClient, ConnectorError, ConnectorErrorBoundary, DEFAULT_MAX_RETRIES, Errors, NetworkError, PUBLIC_RPC_ENDPOINTS, TransactionError, TransactionSignerError, ValidationError, WalletErrorType, copyAddressToClipboard, copySignatureToClipboard, copyToClipboard, createGillTransactionSigner, createKitTransactionSigner, createTransactionSigner, formatAddress, formatBigIntBalance, formatBigIntUsd, formatLamportsToSolSafe, formatNumber, formatSOL, formatTokenAmount, formatTokenBalanceSafe, getAddressUrl, getBlockUrl, getChainIdForWalletStandard, getClusterChainId, getClusterExplorerUrl, getClusterName, getClusterRpcUrl, getClusterType, getDefaultRpcUrl, getNetworkDisplayName, getPolyfillStatus, getTokenUrl, getTransactionUrl, getUserFriendlyMessage, getWalletsRegistry, installPolyfills, isClipboardAvailable, isConfigurationError, isConnectionError, isConnectorError, isCryptoAvailable, isDevnet, isDevnetCluster, isLocalCluster, isLocalnet, isMainnet, isMainnetCluster, isNetworkError, isPolyfillInstalled, isTestnet, isTestnetCluster, isTransactionError, isTransactionSignerError, isValidationError, normalizeNetwork, toClusterId, toConnectorError, truncate, withErrorBoundary };
|
|
2522
|
+
//# sourceMappingURL=chunk-APQGEW7S.mjs.map
|
|
2523
|
+
//# sourceMappingURL=chunk-APQGEW7S.mjs.map
|