Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc0295487b | ||
|
|
90b779107d |
+70
-13
@@ -40,6 +40,13 @@ import {
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
} from "@/components/ui/pagination";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import {
|
||||
@@ -57,6 +64,7 @@ import { useV5DashboardChain } from "@/hooks/chains/v5-adapter";
|
||||
import { WalletProductIcon } from "@/icons/WalletProductIcon";
|
||||
import { useDashboardRouter } from "@/lib/DashboardRouter";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { fetchSolanaBalance } from "../lib/getSolanaBalance";
|
||||
import { updateDefaultProjectWallet } from "../lib/vault.client";
|
||||
import { CreateServerWallet } from "../server-wallets/components/create-server-wallet.client";
|
||||
import type { Wallet as EVMWallet } from "../server-wallets/wallet-table/types";
|
||||
@@ -79,6 +87,7 @@ interface ServerWalletsTableProps {
|
||||
teamSlug: string;
|
||||
client: ThirdwebClient;
|
||||
solanaPermissionError?: boolean;
|
||||
authToken: string;
|
||||
}
|
||||
|
||||
export function ServerWalletsTable(props: ServerWalletsTableProps) {
|
||||
@@ -95,10 +104,14 @@ export function ServerWalletsTable(props: ServerWalletsTableProps) {
|
||||
solanaTotalPages,
|
||||
client,
|
||||
solanaPermissionError,
|
||||
authToken,
|
||||
} = props;
|
||||
|
||||
const [activeChain, setActiveChain] = useState<WalletChain>("evm");
|
||||
const [selectedChainId, setSelectedChainId] = useState<number>(1);
|
||||
const [selectedSolanaChain, setSelectedSolanaChain] = useState<
|
||||
"solana:mainnet" | "solana:devnet"
|
||||
>("solana:mainnet");
|
||||
const [showSmartAccount, setShowSmartAccount] = useState(false);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
@@ -145,11 +158,33 @@ export function ServerWalletsTable(props: ServerWalletsTableProps) {
|
||||
</>
|
||||
)}
|
||||
{activeChain === "solana" && (
|
||||
<CreateSolanaWallet
|
||||
project={project}
|
||||
teamSlug={teamSlug}
|
||||
disabled={solanaPermissionError}
|
||||
/>
|
||||
<>
|
||||
<CreateSolanaWallet
|
||||
project={project}
|
||||
teamSlug={teamSlug}
|
||||
disabled={solanaPermissionError}
|
||||
/>
|
||||
<Select
|
||||
value={selectedSolanaChain}
|
||||
onValueChange={(value) =>
|
||||
setSelectedSolanaChain(
|
||||
value as "solana:mainnet" | "solana:devnet",
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-fit min-w-[180px] rounded-full bg-background hover:bg-accent/50">
|
||||
<SelectValue placeholder="Select network" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="rounded-xl">
|
||||
<SelectItem value="solana:mainnet" className="rounded-lg">
|
||||
Solana Mainnet
|
||||
</SelectItem>
|
||||
<SelectItem value="solana:devnet" className="rounded-lg">
|
||||
Solana Devnet
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -278,6 +313,8 @@ export function ServerWalletsTable(props: ServerWalletsTableProps) {
|
||||
project={project}
|
||||
teamSlug={teamSlug}
|
||||
client={client}
|
||||
authToken={authToken}
|
||||
chainId={selectedSolanaChain}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
@@ -507,11 +544,15 @@ function SolanaWalletRow({
|
||||
project,
|
||||
teamSlug,
|
||||
client,
|
||||
authToken,
|
||||
chainId,
|
||||
}: {
|
||||
wallet: SolanaWallet;
|
||||
project: Project;
|
||||
teamSlug: string;
|
||||
client: ThirdwebClient;
|
||||
authToken: string;
|
||||
chainId: "solana:mainnet" | "solana:devnet";
|
||||
}) {
|
||||
const engineService = project.services.find(
|
||||
(s) => s.name === "engineCloud",
|
||||
@@ -547,7 +588,12 @@ function SolanaWalletRow({
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<SolanaWalletBalance publicKey={wallet.publicKey} />
|
||||
<SolanaWalletBalance
|
||||
publicKey={wallet.publicKey}
|
||||
authToken={authToken}
|
||||
clientId={project.publishableKey}
|
||||
chainId={chainId}
|
||||
/>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
@@ -739,16 +785,27 @@ function WalletBalance({
|
||||
);
|
||||
}
|
||||
|
||||
function SolanaWalletBalance({ publicKey }: { publicKey: string }) {
|
||||
function SolanaWalletBalance({
|
||||
publicKey,
|
||||
authToken,
|
||||
clientId,
|
||||
chainId,
|
||||
}: {
|
||||
publicKey: string;
|
||||
authToken: string;
|
||||
clientId: string;
|
||||
chainId: "solana:mainnet" | "solana:devnet";
|
||||
}) {
|
||||
const balance = useQuery({
|
||||
queryFn: async () => {
|
||||
// TODO: Implement actual Solana balance fetching
|
||||
return {
|
||||
displayValue: "0",
|
||||
symbol: "SOL",
|
||||
};
|
||||
return await fetchSolanaBalance({
|
||||
publicKey,
|
||||
authToken,
|
||||
clientId,
|
||||
chainId,
|
||||
});
|
||||
},
|
||||
queryKey: ["solanaWalletBalance", publicKey],
|
||||
queryKey: ["solanaWalletBalance", publicKey, chainId],
|
||||
});
|
||||
|
||||
if (balance.isFetching) {
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
import { configure, getSolanaWalletBalance } from "@thirdweb-dev/api";
|
||||
import { THIRDWEB_API_HOST } from "@/constants/urls";
|
||||
|
||||
// Configure the API client to use the correct base URL
|
||||
configure({
|
||||
override: {
|
||||
baseUrl: THIRDWEB_API_HOST,
|
||||
},
|
||||
});
|
||||
|
||||
export async function fetchSolanaBalance({
|
||||
publicKey,
|
||||
authToken,
|
||||
clientId,
|
||||
chainId = "solana:mainnet",
|
||||
}: {
|
||||
publicKey: string;
|
||||
authToken: string;
|
||||
clientId: string;
|
||||
chainId?: "solana:mainnet" | "solana:devnet";
|
||||
}): Promise<{
|
||||
displayValue: string;
|
||||
symbol: string;
|
||||
value: string;
|
||||
decimals: number;
|
||||
} | null> {
|
||||
try {
|
||||
const response = await getSolanaWalletBalance({
|
||||
path: {
|
||||
address: publicKey,
|
||||
},
|
||||
query: {
|
||||
chainId,
|
||||
},
|
||||
headers: {
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
"Content-Type": "application/json",
|
||||
"x-client-id": clientId,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.error || !response.data) {
|
||||
console.error(
|
||||
"Error fetching Solana balance:",
|
||||
response.error || "No data returned",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
displayValue: response.data.result.displayValue,
|
||||
symbol: "SOL",
|
||||
value: response.data.result.value,
|
||||
decimals: response.data.result.decimals,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error fetching Solana balance:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+1
@@ -215,6 +215,7 @@ export default async function TransactionsAnalyticsPage(props: {
|
||||
solanaWallets={solanaAccounts.data.items}
|
||||
teamSlug={params.team_slug}
|
||||
solanaPermissionError={isSolanaPermissionError}
|
||||
authToken={authToken}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -70,8 +70,8 @@ export function CreateSolanaWallet(props: {
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
variant="default"
|
||||
className="gap-2 rounded-full bg-foreground hover:bg-foreground/90"
|
||||
variant="outline"
|
||||
className="gap-1.5 rounded-full bg-background text-foreground"
|
||||
disabled={props.disabled}
|
||||
>
|
||||
<PlusIcon className="size-4" />
|
||||
|
||||
+1
@@ -202,6 +202,7 @@ export default async function Page(props: {
|
||||
solanaWallets={solanaAccounts.data.items}
|
||||
teamSlug={params.team_slug}
|
||||
solanaPermissionError={isSolanaPermissionError || false}
|
||||
authToken={authToken}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/api
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#8338](https://github.com/thirdweb-dev/js/pull/8338) [`90b7791`](https://github.com/thirdweb-dev/js/commit/90b779107d3cb726adeca6a3f885129c12599c6a) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - added solana token balances endpoint
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/api",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/thirdweb-dev/js.git#main"
|
||||
|
||||
@@ -66,6 +66,9 @@ import type {
|
||||
GetSolanaTransactionData,
|
||||
GetSolanaTransactionErrors,
|
||||
GetSolanaTransactionResponses,
|
||||
GetSolanaWalletBalanceData,
|
||||
GetSolanaWalletBalanceErrors,
|
||||
GetSolanaWalletBalanceResponses,
|
||||
GetTokenOwnersData,
|
||||
GetTokenOwnersErrors,
|
||||
GetTokenOwnersResponses,
|
||||
@@ -1590,6 +1593,31 @@ export const createSolanaWallet = <ThrowOnError extends boolean = false>(
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Solana Wallet Balance
|
||||
* Get the SOL or SPL token balance for a Solana wallet on a specific Solana network.
|
||||
*
|
||||
* **Authentication**: Pass `x-client-id` for frontend usage from allowlisted origins or `x-secret-key` for backend usage.
|
||||
*/
|
||||
export const getSolanaWalletBalance = <ThrowOnError extends boolean = false>(
|
||||
options: Options<GetSolanaWalletBalanceData, ThrowOnError>,
|
||||
) => {
|
||||
return (options.client ?? _heyApiClient).get<
|
||||
GetSolanaWalletBalanceResponses,
|
||||
GetSolanaWalletBalanceErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-client-id",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/wallets/{address}/balance",
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sign Solana Message
|
||||
* Sign an arbitrary message with a Solana wallet. Supports both text and hexadecimal message formats with automatic format detection.
|
||||
|
||||
@@ -2135,6 +2135,10 @@ export type GetWalletTransactionsData = {
|
||||
address: string;
|
||||
};
|
||||
query: {
|
||||
/**
|
||||
* Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137
|
||||
*/
|
||||
chainId: Array<number>;
|
||||
/**
|
||||
* Filter by block timestamp (Unix timestamp) greater than or equal to this value
|
||||
*/
|
||||
@@ -2171,10 +2175,6 @@ export type GetWalletTransactionsData = {
|
||||
* Sort order: 'asc' for ascending, 'desc' for descending
|
||||
*/
|
||||
sortOrder?: "asc" | "desc";
|
||||
/**
|
||||
* Chain ID(s) to request transaction data for. You can specify multiple chain IDs by repeating the parameter, up to a maximum of 50. Example: ?chainId=1&chainId=137
|
||||
*/
|
||||
chainId: Array<number>;
|
||||
};
|
||||
url: "/v1/wallets/{address}/transactions";
|
||||
};
|
||||
@@ -3234,11 +3234,11 @@ export type WriteContractErrors = {
|
||||
/**
|
||||
* Payment ID
|
||||
*/
|
||||
id: string;
|
||||
id?: string;
|
||||
/**
|
||||
* Bridge quote for completing the payment
|
||||
*/
|
||||
quote: {
|
||||
quote?: {
|
||||
/**
|
||||
* Block number when quote was generated
|
||||
*/
|
||||
@@ -4314,11 +4314,11 @@ export type SendTransactionsErrors = {
|
||||
/**
|
||||
* Payment ID
|
||||
*/
|
||||
id: string;
|
||||
id?: string;
|
||||
/**
|
||||
* Bridge quote for completing the payment
|
||||
*/
|
||||
quote: {
|
||||
quote?: {
|
||||
/**
|
||||
* Block number when quote was generated
|
||||
*/
|
||||
@@ -4725,11 +4725,11 @@ export type PaymentsPurchaseErrors = {
|
||||
/**
|
||||
* Payment ID
|
||||
*/
|
||||
id: string;
|
||||
id?: string;
|
||||
/**
|
||||
* Bridge quote for completing the payment
|
||||
*/
|
||||
quote: {
|
||||
quote?: {
|
||||
/**
|
||||
* Block number when quote was generated
|
||||
*/
|
||||
@@ -4914,17 +4914,7 @@ export type VerifyX402PaymentData = {
|
||||
paymentPayload: {
|
||||
x402Version: number;
|
||||
scheme: "exact";
|
||||
network:
|
||||
| "base-sepolia"
|
||||
| "base"
|
||||
| "avalanche-fuji"
|
||||
| "avalanche"
|
||||
| "iotex"
|
||||
| "solana-devnet"
|
||||
| "solana"
|
||||
| "sei"
|
||||
| "sei-testnet"
|
||||
| string;
|
||||
network: string;
|
||||
payload:
|
||||
| {
|
||||
signature: string;
|
||||
@@ -4943,17 +4933,7 @@ export type VerifyX402PaymentData = {
|
||||
};
|
||||
paymentRequirements: {
|
||||
scheme: "exact";
|
||||
network:
|
||||
| "base-sepolia"
|
||||
| "base"
|
||||
| "avalanche-fuji"
|
||||
| "avalanche"
|
||||
| "iotex"
|
||||
| "solana-devnet"
|
||||
| "solana"
|
||||
| "sei"
|
||||
| "sei-testnet"
|
||||
| string;
|
||||
network: string;
|
||||
maxAmountRequired: string;
|
||||
resource: string;
|
||||
description: string;
|
||||
@@ -5015,7 +4995,6 @@ export type VerifyX402PaymentResponses = {
|
||||
| "invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked"
|
||||
| "invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked"
|
||||
| "invalid_exact_svm_payload_transaction_not_a_transfer_instruction"
|
||||
| "invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata"
|
||||
| "invalid_exact_svm_payload_transaction_receiver_ata_not_found"
|
||||
| "invalid_exact_svm_payload_transaction_sender_ata_not_found"
|
||||
| "invalid_exact_svm_payload_transaction_simulation_failed"
|
||||
@@ -5049,17 +5028,7 @@ export type SettleX402PaymentData = {
|
||||
paymentPayload: {
|
||||
x402Version: number;
|
||||
scheme: "exact";
|
||||
network:
|
||||
| "base-sepolia"
|
||||
| "base"
|
||||
| "avalanche-fuji"
|
||||
| "avalanche"
|
||||
| "iotex"
|
||||
| "solana-devnet"
|
||||
| "solana"
|
||||
| "sei"
|
||||
| "sei-testnet"
|
||||
| string;
|
||||
network: string;
|
||||
payload:
|
||||
| {
|
||||
signature: string;
|
||||
@@ -5078,17 +5047,7 @@ export type SettleX402PaymentData = {
|
||||
};
|
||||
paymentRequirements: {
|
||||
scheme: "exact";
|
||||
network:
|
||||
| "base-sepolia"
|
||||
| "base"
|
||||
| "avalanche-fuji"
|
||||
| "avalanche"
|
||||
| "iotex"
|
||||
| "solana-devnet"
|
||||
| "solana"
|
||||
| "sei"
|
||||
| "sei-testnet"
|
||||
| string;
|
||||
network: string;
|
||||
maxAmountRequired: string;
|
||||
resource: string;
|
||||
description: string;
|
||||
@@ -5154,7 +5113,6 @@ export type SettleX402PaymentResponses = {
|
||||
| "invalid_exact_svm_payload_transaction_instruction_not_spl_token_transfer_checked"
|
||||
| "invalid_exact_svm_payload_transaction_instruction_not_token_2022_transfer_checked"
|
||||
| "invalid_exact_svm_payload_transaction_not_a_transfer_instruction"
|
||||
| "invalid_exact_svm_payload_transaction_cannot_derive_receiver_ata"
|
||||
| "invalid_exact_svm_payload_transaction_receiver_ata_not_found"
|
||||
| "invalid_exact_svm_payload_transaction_sender_ata_not_found"
|
||||
| "invalid_exact_svm_payload_transaction_simulation_failed"
|
||||
@@ -5183,7 +5141,10 @@ export type SettleX402PaymentResponses = {
|
||||
| "solana-devnet"
|
||||
| "solana"
|
||||
| "sei"
|
||||
| "sei-testnet";
|
||||
| "sei-testnet"
|
||||
| "polygon"
|
||||
| "polygon-amoy"
|
||||
| "peaq";
|
||||
errorMessage?: string;
|
||||
};
|
||||
};
|
||||
@@ -5226,17 +5187,7 @@ export type SupportedX402PaymentsResponses = {
|
||||
kinds: Array<{
|
||||
x402Version: 1;
|
||||
scheme: "exact";
|
||||
network:
|
||||
| "base-sepolia"
|
||||
| "base"
|
||||
| "avalanche-fuji"
|
||||
| "avalanche"
|
||||
| "iotex"
|
||||
| "solana-devnet"
|
||||
| "solana"
|
||||
| "sei"
|
||||
| "sei-testnet"
|
||||
| string;
|
||||
network: string;
|
||||
extra?: {
|
||||
defaultAsset?: {
|
||||
/**
|
||||
@@ -5340,11 +5291,11 @@ export type FetchWithPaymentErrors = {
|
||||
/**
|
||||
* Payment ID
|
||||
*/
|
||||
id: string;
|
||||
id?: string;
|
||||
/**
|
||||
* Bridge quote for completing the payment
|
||||
*/
|
||||
quote: {
|
||||
quote?: {
|
||||
/**
|
||||
* Block number when quote was generated
|
||||
*/
|
||||
@@ -5552,17 +5503,7 @@ export type ListPayableServicesResponses = {
|
||||
x402Version: number;
|
||||
accepts: Array<{
|
||||
scheme: "exact";
|
||||
network:
|
||||
| "base-sepolia"
|
||||
| "base"
|
||||
| "avalanche-fuji"
|
||||
| "avalanche"
|
||||
| "iotex"
|
||||
| "solana-devnet"
|
||||
| "solana"
|
||||
| "sei"
|
||||
| "sei-testnet"
|
||||
| string;
|
||||
network: string;
|
||||
maxAmountRequired: string;
|
||||
resource: string;
|
||||
description: string;
|
||||
@@ -6298,11 +6239,11 @@ export type BridgeSwapErrors = {
|
||||
/**
|
||||
* Payment ID
|
||||
*/
|
||||
id: string;
|
||||
id?: string;
|
||||
/**
|
||||
* Bridge quote for completing the payment
|
||||
*/
|
||||
quote: {
|
||||
quote?: {
|
||||
/**
|
||||
* Block number when quote was generated
|
||||
*/
|
||||
@@ -6640,6 +6581,74 @@ export type CreateSolanaWalletResponses = {
|
||||
export type CreateSolanaWalletResponse =
|
||||
CreateSolanaWalletResponses[keyof CreateSolanaWalletResponses];
|
||||
|
||||
export type GetSolanaWalletBalanceData = {
|
||||
body?: never;
|
||||
path: {
|
||||
/**
|
||||
* Public key of the Solana wallet.
|
||||
*/
|
||||
address: string;
|
||||
};
|
||||
query: {
|
||||
/**
|
||||
* Solana network to query. Choose either solana:mainnet or solana:devnet.
|
||||
*/
|
||||
chainId: "solana:mainnet" | "solana:devnet";
|
||||
/**
|
||||
* SPL token mint address. Omit to retrieve native SOL balance.
|
||||
*/
|
||||
tokenAddress?: string;
|
||||
};
|
||||
url: "/v1/solana/wallets/{address}/balance";
|
||||
};
|
||||
|
||||
export type GetSolanaWalletBalanceErrors = {
|
||||
/**
|
||||
* Invalid request parameters. This occurs when the wallet address or token mint is invalid, or the request mixes a token mint with multiple networks.
|
||||
*/
|
||||
400: unknown;
|
||||
/**
|
||||
* Authentication required. Include `x-client-id` or `x-secret-key` headers.
|
||||
*/
|
||||
401: unknown;
|
||||
/**
|
||||
* Internal server error. This may occur due to RPC connectivity issues or unexpected failures.
|
||||
*/
|
||||
500: unknown;
|
||||
};
|
||||
|
||||
export type GetSolanaWalletBalanceResponses = {
|
||||
/**
|
||||
* Wallet balance retrieved successfully for the requested Solana network.
|
||||
*/
|
||||
200: {
|
||||
/**
|
||||
* Balance data for the requested Solana network.
|
||||
*/
|
||||
result: {
|
||||
/**
|
||||
* Requested Solana network.
|
||||
*/
|
||||
chainId: "solana:mainnet" | "solana:devnet";
|
||||
/**
|
||||
* Number of decimals used by the token.
|
||||
*/
|
||||
decimals: number;
|
||||
/**
|
||||
* Human-readable balance formatted using token decimals.
|
||||
*/
|
||||
displayValue: string;
|
||||
/**
|
||||
* Raw balance value expressed in base units (lamports).
|
||||
*/
|
||||
value: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type GetSolanaWalletBalanceResponse =
|
||||
GetSolanaWalletBalanceResponses[keyof GetSolanaWalletBalanceResponses];
|
||||
|
||||
export type SignSolanaMessageData = {
|
||||
/**
|
||||
* Request payload for signing an arbitrary Solana message.
|
||||
|
||||
Reference in New Issue
Block a user