Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f3c55d7139 | ||
|
|
9545b43675 | ||
|
|
869bbcfa68 | ||
|
|
35c7d21e36 | ||
|
|
edf3aad8c4 | ||
|
|
ab4190e23a | ||
|
|
9086cdba20 | ||
|
|
0082e996ca | ||
|
|
28955e0ac5 | ||
|
|
05550d045f | ||
|
|
a0c45cb25d | ||
|
|
6fc4d838ff | ||
|
|
fe940b3c66 | ||
|
|
080d7f2122 | ||
|
|
ae75073a4a |
@@ -119,12 +119,17 @@ export function useCsvUpload<
|
||||
}
|
||||
Papa.parse(csv, {
|
||||
complete: (results) => {
|
||||
const data = props.csvParser(results.data as T[]);
|
||||
if (!data[0]?.address) {
|
||||
try {
|
||||
const data = props.csvParser(results.data as T[]);
|
||||
if (!data[0]?.address) {
|
||||
setNoCsv(true);
|
||||
return;
|
||||
}
|
||||
setRawData(data);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setNoCsv(true);
|
||||
return;
|
||||
}
|
||||
setRawData(data);
|
||||
},
|
||||
header: true,
|
||||
});
|
||||
|
||||
+21
-10
@@ -2,7 +2,7 @@
|
||||
|
||||
import { ExternalLinkIcon } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useState } from "react";
|
||||
import { Suspense, useState } from "react";
|
||||
import type { NFT, ThirdwebClient, ThirdwebContract } from "thirdweb";
|
||||
import { getNFT as getErc721NFT } from "thirdweb/extensions/erc721";
|
||||
import { getNFT as getErc1155NFT } from "thirdweb/extensions/erc1155";
|
||||
@@ -89,7 +89,7 @@ export const TokenIdPage: React.FC<TokenIdPageProps> = ({
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="flex h-[400px] items-center justify-center">
|
||||
<div className="flex h-[400px] items-center justify-center py-20">
|
||||
<Spinner className="size-10" />
|
||||
</div>
|
||||
);
|
||||
@@ -179,15 +179,26 @@ export const TokenIdPage: React.FC<TokenIdPageProps> = ({
|
||||
<NFTDetailsTab client={contract.client} nft={nft} />
|
||||
)}
|
||||
|
||||
{tabs.map((tb) => {
|
||||
return (
|
||||
tb.title === tab && (
|
||||
<div className="w-full" key={tb.title}>
|
||||
{tb.children}
|
||||
<Suspense
|
||||
fallback={
|
||||
<div className="h-full">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Spinner className="size-4" />
|
||||
<p className="text-sm text-muted-foreground"> Loading </p>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{tabs.map((tb) => {
|
||||
return (
|
||||
tb.title === tab && (
|
||||
<div className="w-full" key={tb.title}>
|
||||
{tb.children}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,6 +39,7 @@ export function TokensTable(props: {
|
||||
<TableHead>Price</TableHead>
|
||||
<TableHead>Market cap</TableHead>
|
||||
<TableHead>Volume (24h)</TableHead>
|
||||
<TableHead></TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -64,6 +65,9 @@ export function TokensTable(props: {
|
||||
<TableCell>
|
||||
<Skeleton className="ml-auto h-4 w-20" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Skeleton className="ml-auto h-4 w-20" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
: tokens.length > 0
|
||||
@@ -81,6 +85,7 @@ export function TokensTable(props: {
|
||||
<AvatarImage
|
||||
src={token.iconUri ?? undefined}
|
||||
alt={token.symbol}
|
||||
className="rounded-full"
|
||||
/>
|
||||
<AvatarFallback>
|
||||
{token.symbol?.slice(0, 2)?.toUpperCase()}
|
||||
@@ -90,20 +95,9 @@ export function TokensTable(props: {
|
||||
<span className="font-medium leading-none text-base">
|
||||
{token.symbol}
|
||||
</span>
|
||||
<Link
|
||||
href={
|
||||
token.address.toLowerCase() ===
|
||||
NATIVE_TOKEN_ADDRESS.toLowerCase()
|
||||
? `/${token.chainId}`
|
||||
: `/${token.chainId}/${token.address}`
|
||||
}
|
||||
prefetch={false}
|
||||
className="before:absolute before:inset-0"
|
||||
>
|
||||
<span className="text-sm text-muted-foreground leading-none">
|
||||
{token.name}
|
||||
</span>
|
||||
</Link>
|
||||
<span className="text-sm text-muted-foreground leading-none">
|
||||
{token.name}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</TableCell>
|
||||
@@ -120,6 +114,29 @@ export function TokensTable(props: {
|
||||
? formatUsdCompact(token.volume24hUsd)
|
||||
: "N/A"}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
asChild
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-2 rounded-full bg-card hover:border-foreground/50 text-muted-foreground hover:bg-inverted hover:text-inverted-foreground"
|
||||
>
|
||||
<Link
|
||||
aria-label={`Buy ${token.symbol}`}
|
||||
href={
|
||||
token.address.toLowerCase() ===
|
||||
NATIVE_TOKEN_ADDRESS.toLowerCase()
|
||||
? `/${token.chainId}`
|
||||
: `/${token.chainId}/${token.address}`
|
||||
}
|
||||
prefetch={false}
|
||||
className="before:absolute before:inset-0"
|
||||
>
|
||||
Buy
|
||||
<ArrowRightIcon className="size-3" />
|
||||
</Link>
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})
|
||||
|
||||
@@ -36,7 +36,7 @@ export default async function Page() {
|
||||
</h1>
|
||||
|
||||
<p className="text-muted-foreground">
|
||||
85+ chains, 3200+ tokens and 9+ million routes supported
|
||||
85+ chains, 4500+ tokens and 9+ million routes supported
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { TabButtons } from "@/components/ui/tabs";
|
||||
|
||||
type TabKey =
|
||||
| "ts"
|
||||
| "react"
|
||||
| "react-native"
|
||||
| "dotnet"
|
||||
| "unity"
|
||||
| "unreal"
|
||||
| "api"
|
||||
| "curl";
|
||||
|
||||
const tabNames: Record<TabKey, string> = {
|
||||
api: "API",
|
||||
ts: "TypeScript",
|
||||
react: "React",
|
||||
"react-native": "React Native",
|
||||
dotnet: ".NET",
|
||||
unity: "Unity",
|
||||
unreal: "Unreal Engine",
|
||||
curl: "cURL",
|
||||
};
|
||||
|
||||
export function IntegrateAPIKeyCodeTabs(props: {
|
||||
tabs: Record<TabKey, React.ReactNode>;
|
||||
}) {
|
||||
const [tab, setTab] = useState<TabKey>("api");
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TabButtons
|
||||
tabs={Object.entries(tabNames).map(([key, name]) => ({
|
||||
isActive: tab === key,
|
||||
name,
|
||||
onClick: () => setTab(key as TabKey),
|
||||
}))}
|
||||
/>
|
||||
<div className="h-2" />
|
||||
{props.tabs[tab]}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
+32
-214
@@ -1,15 +1,11 @@
|
||||
import {
|
||||
ArrowLeftRightIcon,
|
||||
ChevronRightIcon,
|
||||
CircleAlertIcon,
|
||||
ExternalLinkIcon,
|
||||
} from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import type { Project } from "@/api/project/projects";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { AlertDialogFooter } from "@/components/ui/alert-dialog";
|
||||
import { CodeServer } from "@/components/ui/code/code.server";
|
||||
import { UnderlineLink } from "@/components/ui/UnderlineLink";
|
||||
import { DotNetIcon } from "@/icons/brand-icons/DotNetIcon";
|
||||
import { GithubIcon } from "@/icons/brand-icons/GithubIcon";
|
||||
import { ReactIcon } from "@/icons/brand-icons/ReactIcon";
|
||||
@@ -25,10 +21,9 @@ import {
|
||||
getProjectWallet,
|
||||
type ProjectWalletSummary,
|
||||
} from "@/lib/server/project-wallet";
|
||||
import CreateServerWallet from "../../transactions/server-wallets/components/create-server-wallet.client";
|
||||
import { ClientIDSection } from "./ClientIDSection";
|
||||
import { IntegrateAPIKeyCodeTabs } from "./IntegrateAPIKeyCodeTabs";
|
||||
import { ProjectWalletControls } from "./ProjectWalletControls.client";
|
||||
import { ProjectWalletSetup } from "./ProjectWalletSetup.client";
|
||||
import { SecretKeySection } from "./SecretKeySection";
|
||||
|
||||
export async function ProjectFTUX(props: {
|
||||
@@ -47,10 +42,7 @@ export async function ProjectFTUX(props: {
|
||||
wallet={projectWallet}
|
||||
managementAccessToken={props.managementAccessToken}
|
||||
/>
|
||||
<IntegrateAPIKeySection
|
||||
project={props.project}
|
||||
teamSlug={props.teamSlug}
|
||||
/>
|
||||
<IntegrateAPIKeySection project={props.project} />
|
||||
<ProductsSection
|
||||
projectSlug={props.project.slug}
|
||||
teamSlug={props.teamSlug}
|
||||
@@ -84,8 +76,7 @@ export function ProjectWalletSection(props: {
|
||||
Project Wallet
|
||||
</p>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Default managed server wallet for this project. Use it for
|
||||
deployments, payments, and API integrations.
|
||||
Use it for deployments, payments, and API integrations.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,22 +99,11 @@ export function ProjectWalletSection(props: {
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<Alert variant="info">
|
||||
<CircleAlertIcon className="size-5" />
|
||||
<AlertTitle>No default project wallet set</AlertTitle>
|
||||
<AlertDescription>
|
||||
Set a default project wallet to use for dashboard and API
|
||||
integrations.
|
||||
</AlertDescription>
|
||||
<AlertDialogFooter className="flex justify-start sm:justify-start pt-4">
|
||||
<CreateServerWallet
|
||||
managementAccessToken={props.managementAccessToken}
|
||||
project={props.project}
|
||||
teamSlug={props.teamSlug}
|
||||
setAsProjectWallet={true}
|
||||
/>
|
||||
</AlertDialogFooter>
|
||||
</Alert>
|
||||
<ProjectWalletSetup
|
||||
managementAccessToken={props.managementAccessToken}
|
||||
project={props.project}
|
||||
teamSlug={props.teamSlug}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -133,13 +113,7 @@ export function ProjectWalletSection(props: {
|
||||
|
||||
// Integrate API key section ------------------------------------------------------------
|
||||
|
||||
function IntegrateAPIKeySection({
|
||||
project,
|
||||
teamSlug,
|
||||
}: {
|
||||
project: Project;
|
||||
teamSlug: string;
|
||||
}) {
|
||||
function IntegrateAPIKeySection({ project }: { project: Project }) {
|
||||
const secretKeyMasked = project.secretKeys[0]?.masked;
|
||||
const clientId = project.publishableKey;
|
||||
|
||||
@@ -161,194 +135,38 @@ function IntegrateAPIKeySection({
|
||||
</div>
|
||||
|
||||
<div className="h-5" />
|
||||
<IntegrationCodeExamples project={project} teamSlug={teamSlug} />
|
||||
<div className="flex flex-col gap-3">
|
||||
<p className="text-muted-foreground text-sm">
|
||||
Run this command in your terminal to send a test transaction using
|
||||
your Project Wallet.
|
||||
</p>
|
||||
<CodeServer
|
||||
className="bg-background"
|
||||
code={curlCodeExample(project)}
|
||||
lang="bash"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function IntegrationCodeExamples(props: {
|
||||
project: Project;
|
||||
teamSlug: string;
|
||||
}) {
|
||||
return (
|
||||
<IntegrateAPIKeyCodeTabs
|
||||
tabs={{
|
||||
dotnet: (
|
||||
<div className="flex flex-col gap-3">
|
||||
<CodeServer
|
||||
className="bg-background"
|
||||
code={dotNotCodeExample(props.project)}
|
||||
lang="csharp"
|
||||
/>
|
||||
<Alert className="bg-background" variant="info">
|
||||
<CircleAlertIcon className="size-5" />
|
||||
<AlertTitle>
|
||||
Configure your app's bundle ID in "Allowed Bundle IDs" in
|
||||
Project
|
||||
</AlertTitle>
|
||||
<AlertDescription className="leading-loose">
|
||||
Go to{" "}
|
||||
<UnderlineLink
|
||||
href={`/team/${props.teamSlug}/${props.project.slug}/settings`}
|
||||
target="_blank"
|
||||
>
|
||||
Project settings
|
||||
</UnderlineLink>{" "}
|
||||
and add your app's bundle ID to the "Allowed Bundle IDs" list.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
),
|
||||
react: (
|
||||
<CodeServer
|
||||
className="bg-background"
|
||||
code={reactCodeExample(props.project)}
|
||||
lang="ts"
|
||||
/>
|
||||
),
|
||||
"react-native": (
|
||||
<CodeServer
|
||||
className="bg-background"
|
||||
code={reactCodeExample(props.project)}
|
||||
lang="ts"
|
||||
/>
|
||||
),
|
||||
ts: (
|
||||
<CodeServer
|
||||
className="bg-background"
|
||||
code={typescriptCodeExample(props.project)}
|
||||
lang="ts"
|
||||
/>
|
||||
),
|
||||
unity: (
|
||||
<Alert className="bg-background" variant="info">
|
||||
<CircleAlertIcon className="size-5" />
|
||||
<AlertTitle>
|
||||
Configure Client ID in Thirdweb Manager prefab
|
||||
</AlertTitle>
|
||||
<AlertDescription className="leading-loose">
|
||||
Configure "Client ID" and "Bundle ID" in{" "}
|
||||
<UnderlineLink
|
||||
href="https://portal.thirdweb.com/unity/v5/thirdwebmanager"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Thirdweb Manager prefab
|
||||
</UnderlineLink>
|
||||
<span className="block text-sm">
|
||||
Make sure to configure your app's bundle ID in "Allowed Bundle
|
||||
IDs" in{" "}
|
||||
<UnderlineLink
|
||||
href={`/team/${props.teamSlug}/${props.project.slug}/settings`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Project settings
|
||||
</UnderlineLink>
|
||||
</span>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
),
|
||||
unreal: (
|
||||
<Alert className="bg-background" variant="info">
|
||||
<CircleAlertIcon className="size-5" />
|
||||
<AlertTitle>
|
||||
Configure Client ID in Thirdweb Unreal Plugin{" "}
|
||||
</AlertTitle>
|
||||
<AlertDescription className="leading-loose">
|
||||
Configure "Client ID" and "Bundle ID" in{" "}
|
||||
<UnderlineLink
|
||||
href="https://portal.thirdweb.com/unreal-engine/getting-started"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
thirdweb plugin settings
|
||||
</UnderlineLink>
|
||||
<span className="block text-sm">
|
||||
Make sure to configure your app's bundle ID in "Allowed Bundle
|
||||
IDs" in{" "}
|
||||
<UnderlineLink
|
||||
href={`/team/${props.teamSlug}/${props.project.slug}/settings`}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Project settings
|
||||
</UnderlineLink>
|
||||
</span>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
),
|
||||
api: (
|
||||
<CodeServer
|
||||
className="bg-background"
|
||||
code={apiCodeExample(props.project)}
|
||||
lang="javascript"
|
||||
/>
|
||||
),
|
||||
curl: (
|
||||
<CodeServer
|
||||
className="bg-background"
|
||||
code={curlCodeExample(props.project)}
|
||||
lang="bash"
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const typescriptCodeExample = (project: Project) => `\
|
||||
import { createThirdwebClient } from "thirdweb";
|
||||
|
||||
const client = createThirdwebClient({
|
||||
// use clientId for client side usage
|
||||
clientId: "${project.publishableKey}",
|
||||
// use secretKey for server side usage
|
||||
secretKey: "${project.secretKeys[0]?.masked}", // replace this with full secret key
|
||||
});`;
|
||||
|
||||
const reactCodeExample = (project: Project) => `\
|
||||
import { createThirdwebClient } from "thirdweb";
|
||||
|
||||
const client = createThirdwebClient({
|
||||
clientId: "${project.publishableKey}",
|
||||
});`;
|
||||
|
||||
const dotNotCodeExample = (project: Project) => `\
|
||||
using Thirdweb;
|
||||
|
||||
// For web applications
|
||||
var client = ThirdwebClient.Create(clientId: "${project.publishableKey}");
|
||||
|
||||
// For native applications - Replace "yourBundleId" with your app's bundle ID
|
||||
var client = ThirdwebClient.Create(clientId: "${project.publishableKey}", bundleId: "yourBundleId");
|
||||
|
||||
// For backend applications (Note: below shown secret key is not the full secret key)
|
||||
var client = ThirdwebClient.Create(secretKey: "${project.secretKeys[0]?.masked}");`;
|
||||
|
||||
const apiCodeExample = (project: Project): string => `\
|
||||
// Server-side only: replace with your full secret key. Never expose in browser code.
|
||||
fetch('https://api.thirdweb.com/v1/wallets/server', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-secret-key': '${project.secretKeys[0]?.masked ?? "<YOUR_SECRET_KEY>"}'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
identifier: 'treasury-wallet-123'
|
||||
})
|
||||
});`;
|
||||
|
||||
const curlCodeExample = (project: Project): string => `\
|
||||
// Server-side only: replace with your full secret key. Never expose in browser code.
|
||||
curl https://api.thirdweb.com/v1/wallets/server \\
|
||||
curl https://api.thirdweb.com/v1/transactions \\
|
||||
--request POST \\
|
||||
--header 'Content-Type: application/json' \\
|
||||
--header 'x-secret-key: ${project.secretKeys[0]?.masked ?? "<YOUR_SECRET_KEY>"}' \\
|
||||
--data '{
|
||||
"identifier": "treasury-wallet-123"
|
||||
}'`;
|
||||
"chainId": 421614,
|
||||
"transactions": [
|
||||
{
|
||||
"data": "0x",
|
||||
"to": "vitalik.eth",
|
||||
"value": "0"
|
||||
}
|
||||
]
|
||||
}'
|
||||
`;
|
||||
|
||||
// products section ------------------------------------------------------------
|
||||
|
||||
function ProductsSection(props: { teamSlug: string; projectSlug: string }) {
|
||||
|
||||
+66
-44
@@ -48,9 +48,14 @@ import {
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { Spinner } from "@/components/ui/Spinner";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
|
||||
import { useV5DashboardChain } from "@/hooks/chains/v5-adapter";
|
||||
import { useDashboardRouter } from "@/lib/DashboardRouter";
|
||||
@@ -163,7 +168,7 @@ export function ProjectWalletControls(props: ProjectWalletControlsProps) {
|
||||
},
|
||||
onSuccess: async (_, wallet) => {
|
||||
const descriptionLabel = wallet.label ?? wallet.address;
|
||||
toast.success("Default project wallet updated", {
|
||||
toast.success("Project wallet updated", {
|
||||
description: `Now pointing to ${descriptionLabel}`,
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
@@ -347,49 +352,66 @@ export function ProjectWalletControls(props: ProjectWalletControlsProps) {
|
||||
default.
|
||||
</p>
|
||||
) : (
|
||||
<RadioGroup
|
||||
className="space-y-3"
|
||||
onValueChange={(value) => setSelectedWalletId(value)}
|
||||
value={selectedWalletId}
|
||||
>
|
||||
{serverWallets.map((wallet) => {
|
||||
const isCurrent =
|
||||
wallet.address.toLowerCase() === currentWalletAddressLower;
|
||||
const isSelected = wallet.id === selectedWalletId;
|
||||
|
||||
return (
|
||||
<Label
|
||||
key={wallet.id}
|
||||
htmlFor={`project-wallet-${wallet.id}`}
|
||||
className={cn(
|
||||
"flex cursor-pointer items-center gap-3 rounded-lg border border-border bg-card px-4 py-3 transition",
|
||||
isSelected && "border-primary ring-2 ring-primary/20",
|
||||
)}
|
||||
>
|
||||
<RadioGroupItem
|
||||
id={`project-wallet-${wallet.id}`}
|
||||
value={wallet.id}
|
||||
className="mt-0.5"
|
||||
/>
|
||||
<div className="flex flex-1 flex-col overflow-hidden">
|
||||
<div className="flex flex-col gap-3">
|
||||
<Select
|
||||
onValueChange={(value) => setSelectedWalletId(value)}
|
||||
value={selectedWalletId ?? ""}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select server wallet">
|
||||
{selectedWallet ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
{wallet.label ?? "Unnamed server wallet"}
|
||||
</span>
|
||||
{isCurrent && (
|
||||
<Badge variant="success" className="text-xs">
|
||||
current
|
||||
</Badge>
|
||||
)}
|
||||
<WalletAddress
|
||||
address={selectedWallet.address}
|
||||
client={client}
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-foreground">
|
||||
{selectedWallet.label ?? "Unnamed server wallet"}
|
||||
</span>
|
||||
{selectedWallet.address.toLowerCase() ===
|
||||
currentWalletAddressLower && (
|
||||
<Badge variant="success" className="text-xs">
|
||||
current
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-xs text-muted-foreground break-all">
|
||||
{wallet.address}
|
||||
</span>
|
||||
</div>
|
||||
</Label>
|
||||
);
|
||||
})}
|
||||
</RadioGroup>
|
||||
) : (
|
||||
"Select server wallet"
|
||||
)}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{serverWallets.map((wallet) => {
|
||||
const isCurrent =
|
||||
wallet.address.toLowerCase() ===
|
||||
currentWalletAddressLower;
|
||||
|
||||
return (
|
||||
<SelectItem key={wallet.id} value={wallet.id}>
|
||||
<div className="flex items-center gap-2">
|
||||
<WalletAddress
|
||||
address={wallet.address}
|
||||
client={client}
|
||||
/>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-foreground">
|
||||
{wallet.label ?? "Unnamed server wallet"}
|
||||
</span>
|
||||
{isCurrent && (
|
||||
<Badge variant="success" className="text-xs">
|
||||
current
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
"use client";
|
||||
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { CircleAlertIcon } from "lucide-react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { listProjectServerWallets } from "@/actions/project-wallet/list-server-wallets";
|
||||
import type { Project } from "@/api/project/projects";
|
||||
import { WalletAddress } from "@/components/blocks/wallet-address";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Spinner } from "@/components/ui/Spinner";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
|
||||
import { useDashboardRouter } from "@/lib/DashboardRouter";
|
||||
import type { ProjectWalletSummary } from "@/lib/server/project-wallet";
|
||||
import { updateDefaultProjectWallet } from "../../transactions/lib/vault.client";
|
||||
import CreateServerWallet from "../../transactions/server-wallets/components/create-server-wallet.client";
|
||||
|
||||
export function ProjectWalletSetup(props: {
|
||||
project: Project;
|
||||
teamSlug: string;
|
||||
managementAccessToken: string | undefined;
|
||||
}) {
|
||||
const { project, teamSlug, managementAccessToken } = props;
|
||||
const router = useDashboardRouter();
|
||||
const queryClient = useQueryClient();
|
||||
const client = useMemo(() => getClientThirdwebClient(), []);
|
||||
const [selectedWalletId, setSelectedWalletId] = useState<string | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
const serverWalletsQuery = useQuery({
|
||||
enabled: Boolean(managementAccessToken),
|
||||
queryFn: async () => {
|
||||
if (!managementAccessToken) {
|
||||
return [] as ProjectWalletSummary[];
|
||||
}
|
||||
|
||||
return listProjectServerWallets({
|
||||
managementAccessToken,
|
||||
projectId: project.id,
|
||||
});
|
||||
},
|
||||
queryKey: ["project", project.id, "server-wallets", managementAccessToken],
|
||||
staleTime: 60_000,
|
||||
});
|
||||
|
||||
const serverWallets = serverWalletsQuery.data ?? [];
|
||||
|
||||
const effectiveSelectedWalletId = useMemo(() => {
|
||||
if (
|
||||
selectedWalletId &&
|
||||
serverWallets.some((wallet) => wallet.id === selectedWalletId)
|
||||
) {
|
||||
return selectedWalletId;
|
||||
}
|
||||
|
||||
return serverWallets[0]?.id;
|
||||
}, [selectedWalletId, serverWallets]);
|
||||
|
||||
const selectedWallet = useMemo(() => {
|
||||
if (!effectiveSelectedWalletId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return serverWallets.find(
|
||||
(wallet) => wallet.id === effectiveSelectedWalletId,
|
||||
);
|
||||
}, [effectiveSelectedWalletId, serverWallets]);
|
||||
|
||||
const setDefaultWalletMutation = useMutation({
|
||||
mutationFn: async (wallet: ProjectWalletSummary) => {
|
||||
await updateDefaultProjectWallet({
|
||||
project,
|
||||
projectWalletAddress: wallet.address,
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
const message =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Failed to update project wallet";
|
||||
toast.error(message);
|
||||
},
|
||||
onSuccess: async (_, wallet) => {
|
||||
const descriptionLabel = wallet.label ?? wallet.address;
|
||||
toast.success("Project wallet updated", {
|
||||
description: `Now pointing to ${descriptionLabel}`,
|
||||
});
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: [
|
||||
"project",
|
||||
project.id,
|
||||
"server-wallets",
|
||||
managementAccessToken,
|
||||
],
|
||||
});
|
||||
router.refresh();
|
||||
},
|
||||
});
|
||||
|
||||
const canSelectExisting =
|
||||
Boolean(managementAccessToken) && serverWallets.length > 0;
|
||||
|
||||
return (
|
||||
<Alert variant="info">
|
||||
<CircleAlertIcon className="size-5" />
|
||||
<AlertTitle>No project wallet set</AlertTitle>
|
||||
<AlertDescription>
|
||||
Set a project wallet to use for dashboard and API integrations.
|
||||
</AlertDescription>
|
||||
|
||||
<div className="mt-4 space-y-5">
|
||||
{serverWalletsQuery.isLoading ? (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<Spinner className="size-4" />
|
||||
<span>Loading existing server wallets…</span>
|
||||
</div>
|
||||
) : canSelectExisting ? (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-medium text-foreground">
|
||||
Choose an existing server wallet
|
||||
</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
These wallets were already created for this project. Pick one to
|
||||
set as the default.
|
||||
</p>
|
||||
<Select
|
||||
onValueChange={(value) => setSelectedWalletId(value)}
|
||||
value={effectiveSelectedWalletId ?? ""}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select server wallet">
|
||||
{selectedWallet ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<WalletAddress
|
||||
address={selectedWallet.address}
|
||||
client={client}
|
||||
/>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{selectedWallet.label ?? "Unnamed server wallet"}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
"Select server wallet"
|
||||
)}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{serverWallets.map((wallet) => (
|
||||
<SelectItem key={wallet.id} value={wallet.id}>
|
||||
<div className="flex items-center gap-2">
|
||||
<WalletAddress
|
||||
address={wallet.address}
|
||||
client={client}
|
||||
/>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
{wallet.label ?? "Unnamed server wallet"}
|
||||
</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<Button
|
||||
disabled={!selectedWallet || setDefaultWalletMutation.isPending}
|
||||
onClick={() => {
|
||||
if (selectedWallet) {
|
||||
setDefaultWalletMutation.mutate(selectedWallet);
|
||||
}
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{setDefaultWalletMutation.isPending && (
|
||||
<Spinner className="mr-2 size-4" />
|
||||
)}
|
||||
Set as project wallet
|
||||
</Button>
|
||||
<CreateServerWallet
|
||||
managementAccessToken={managementAccessToken}
|
||||
project={project}
|
||||
teamSlug={teamSlug}
|
||||
setAsProjectWallet
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3 text-sm text-muted-foreground">
|
||||
<p>
|
||||
Create a server wallet to start using transactions and other
|
||||
project features.
|
||||
</p>
|
||||
<CreateServerWallet
|
||||
managementAccessToken={managementAccessToken}
|
||||
project={project}
|
||||
teamSlug={teamSlug}
|
||||
setAsProjectWallet
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
+2
-2
@@ -292,7 +292,7 @@ function ServerWalletTableRow(props: {
|
||||
queryKey: ["smart-account-address", wallet.address, chainId],
|
||||
});
|
||||
|
||||
// Get the default project wallet address
|
||||
// Get the project wallet address
|
||||
const engineCloudService = project.services.find(
|
||||
(service) => service.name === "engineCloud",
|
||||
);
|
||||
@@ -422,7 +422,7 @@ function WalletActionsDropdown(props: {
|
||||
});
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success("Wallet set as default project wallet");
|
||||
toast.success("Wallet set as project wallet");
|
||||
router.refresh();
|
||||
},
|
||||
onError: (error) => {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { bridgeAppThirdwebClient } from "./constants";
|
||||
|
||||
const title = "thirdweb Bridge: Buy, Bridge & Swap Crypto on 85+ Chains";
|
||||
const description =
|
||||
"Bridge and swap 3,200+ tokens across 85+ chains (Ethereum, Base, Optimism, Arbitrum, BNB & more). Best-price routing with near-instant finality";
|
||||
"Bridge and swap 4500+ tokens across 85+ chains (Ethereum, Base, Optimism, Arbitrum, BNB & more). Best-price routing with near-instant finality";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
description,
|
||||
@@ -73,7 +73,7 @@ export default async function BridgePage({
|
||||
|
||||
<div className="flex-wrap flex gap-3 items-center justify-center">
|
||||
<DataPill>85+ Chains Supported</DataPill>
|
||||
<DataPill>3200+ Tokens Supported</DataPill>
|
||||
<DataPill>4500+ Tokens Supported</DataPill>
|
||||
<DataPill>9+ Million Routes Available</DataPill>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,24 +7,25 @@ import { token } from "../../payments/x402/components/constants";
|
||||
// Allow streaming responses up to 5 minutes
|
||||
export const maxDuration = 300;
|
||||
|
||||
const client = createThirdwebClient({
|
||||
secretKey: process.env.THIRDWEB_SECRET_KEY as string,
|
||||
});
|
||||
|
||||
const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string;
|
||||
// const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_SMART_WALLET as string;
|
||||
const ENGINE_VAULT_ACCESS_TOKEN = process.env
|
||||
.ENGINE_VAULT_ACCESS_TOKEN as string;
|
||||
// const API_URL = `https://${process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"}`;
|
||||
const API_URL = "http://localhost:3030";
|
||||
|
||||
const twFacilitator = facilitator({
|
||||
baseUrl: `${API_URL}/v1/payments/x402`,
|
||||
client,
|
||||
serverWalletAddress: BACKEND_WALLET_ADDRESS,
|
||||
vaultAccessToken: ENGINE_VAULT_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const client = createThirdwebClient({
|
||||
secretKey: process.env.THIRDWEB_SECRET_KEY as string,
|
||||
});
|
||||
|
||||
const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string;
|
||||
// const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_SMART_WALLET as string;
|
||||
const ENGINE_VAULT_ACCESS_TOKEN = process.env
|
||||
.ENGINE_VAULT_ACCESS_TOKEN as string;
|
||||
const API_URL = `https://${process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"}`;
|
||||
|
||||
const twFacilitator = facilitator({
|
||||
baseUrl: `${API_URL}/v1/payments/x402`,
|
||||
client,
|
||||
serverWalletAddress: BACKEND_WALLET_ADDRESS,
|
||||
vaultAccessToken: ENGINE_VAULT_ACCESS_TOKEN,
|
||||
});
|
||||
|
||||
const paymentData = request.headers.get("X-PAYMENT");
|
||||
const queryParams = request.nextUrl.searchParams;
|
||||
|
||||
@@ -38,6 +39,7 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
|
||||
const amount = queryParams.get("amount") || "0.01";
|
||||
const payTo = queryParams.get("payTo") ?? undefined;
|
||||
const tokenAddress = queryParams.get("tokenAddress") || token.address;
|
||||
const decimals = queryParams.get("decimals") || token.decimals.toString();
|
||||
const waitUntil =
|
||||
@@ -49,6 +51,7 @@ export async function GET(request: NextRequest) {
|
||||
method: "GET",
|
||||
paymentData,
|
||||
network: defineChain(Number(chainId)),
|
||||
payTo,
|
||||
price: {
|
||||
amount: toUnits(amount, parseInt(decimals)).toString(),
|
||||
asset: {
|
||||
|
||||
@@ -45,6 +45,7 @@ export function X402LeftSection(props: {
|
||||
const tokenId = useId();
|
||||
const amountId = useId();
|
||||
const waitUntilId = useId();
|
||||
const payToId = useId();
|
||||
|
||||
const handleChainChange = (chainId: number) => {
|
||||
setSelectedChain(chainId);
|
||||
@@ -81,6 +82,13 @@ export function X402LeftSection(props: {
|
||||
}));
|
||||
};
|
||||
|
||||
const handlePayToChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setOptions((v) => ({
|
||||
...v,
|
||||
payTo: e.target.value as `0x${string}`,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleWaitUntilChange = (
|
||||
value: "simulated" | "submitted" | "confirmed",
|
||||
) => {
|
||||
@@ -140,6 +148,22 @@ export function X402LeftSection(props: {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Pay To input */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor={payToId}>Pay To Address</Label>
|
||||
<Input
|
||||
id={payToId}
|
||||
type="text"
|
||||
placeholder="0x..."
|
||||
value={options.payTo}
|
||||
onChange={handlePayToChange}
|
||||
className="bg-card"
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
The wallet address that will receive the payment
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Wait Until selection */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<Label htmlFor={waitUntilId}>Wait Until</Label>
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# wagmi-inapp
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- thirdweb@5.108.13
|
||||
- @thirdweb-dev/wagmi-adapter@0.2.163
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0082e99`](https://github.com/thirdweb-dev/js/commit/0082e996cae47a326110e74457c72b3f3936743d), [`0082e99`](https://github.com/thirdweb-dev/js/commit/0082e996cae47a326110e74457c72b3f3936743d)]:
|
||||
- thirdweb@5.108.12
|
||||
- @thirdweb-dev/wagmi-adapter@0.2.162
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`05550d0`](https://github.com/thirdweb-dev/js/commit/05550d045f291b8e53afd0d7e73c438bee202fb7)]:
|
||||
- thirdweb@5.108.11
|
||||
- @thirdweb-dev/wagmi-adapter@0.2.161
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wagmi-inapp",
|
||||
"private": true,
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.8",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/engine
|
||||
|
||||
## 3.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#8238](https://github.com/thirdweb-dev/js/pull/8238) [`9545b43`](https://github.com/thirdweb-dev/js/commit/9545b4367598408dbb88c63d8a8fe21305f870b5) Thanks [@d4mr](https://github.com/d4mr)! - Add Solana endpoints
|
||||
|
||||
## 3.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/engine",
|
||||
"version": "3.2.2",
|
||||
"version": "3.3.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/thirdweb-dev/js.git#main"
|
||||
|
||||
@@ -11,11 +11,18 @@ import type {
|
||||
CancelTransactionResponses,
|
||||
CreateAccountData,
|
||||
CreateAccountResponses,
|
||||
CreateSolanaAccountData,
|
||||
CreateSolanaAccountResponses,
|
||||
EncodeContractData,
|
||||
EncodeContractResponses,
|
||||
GetActivityLogsData,
|
||||
GetActivityLogsErrors,
|
||||
GetActivityLogsResponses,
|
||||
GetSolanaActivityLogsData,
|
||||
GetSolanaActivityLogsErrors,
|
||||
GetSolanaActivityLogsResponses,
|
||||
GetSolanaTransactionsData,
|
||||
GetSolanaTransactionsResponses,
|
||||
GetTransactionAnalyticsData,
|
||||
GetTransactionAnalyticsResponses,
|
||||
GetTransactionAnalyticsSummaryData,
|
||||
@@ -25,17 +32,30 @@ import type {
|
||||
GetTransactionsResponses,
|
||||
ListAccountsData,
|
||||
ListAccountsResponses,
|
||||
ListSolanaAccountsData,
|
||||
ListSolanaAccountsResponses,
|
||||
ReadContractData,
|
||||
ReadContractResponses,
|
||||
SearchActivityLogsData,
|
||||
SearchActivityLogsErrors,
|
||||
SearchActivityLogsResponses,
|
||||
SearchSolanaActivityLogsData,
|
||||
SearchSolanaActivityLogsErrors,
|
||||
SearchSolanaActivityLogsResponses,
|
||||
SearchSolanaTransactionsData,
|
||||
SearchSolanaTransactionsResponses,
|
||||
SearchTransactionsData,
|
||||
SearchTransactionsResponses,
|
||||
SendSolanaTransactionData,
|
||||
SendSolanaTransactionResponses,
|
||||
SendTransactionData,
|
||||
SendTransactionResponses,
|
||||
SignMessageData,
|
||||
SignMessageResponses,
|
||||
SignSolanaMessageData,
|
||||
SignSolanaMessageResponses,
|
||||
SignSolanaTransactionData,
|
||||
SignSolanaTransactionResponses,
|
||||
SignTypedDataData,
|
||||
SignTypedDataResponses,
|
||||
WriteContractData,
|
||||
@@ -227,6 +247,33 @@ export const encodeContract = <ThrowOnError extends boolean = false>(
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Send Solana Transaction
|
||||
* Execute a Solana transaction with custom instructions
|
||||
*/
|
||||
export const sendSolanaTransaction = <ThrowOnError extends boolean = false>(
|
||||
options: Options<SendSolanaTransactionData, ThrowOnError>,
|
||||
) => {
|
||||
return (options.client ?? _heyApiClient).post<
|
||||
SendSolanaTransactionResponses,
|
||||
unknown,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-secret-key",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/transaction",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel Transaction
|
||||
* Attempt to cancel a queued transaction. Transactions that have been sent and are waiting for mine cannot be cancelled.
|
||||
@@ -300,6 +347,110 @@ export const createAccount = <ThrowOnError extends boolean = false>(
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* List Solana Accounts
|
||||
* List all Solana wallets provisioned for the project.
|
||||
*/
|
||||
export const listSolanaAccounts = <ThrowOnError extends boolean = false>(
|
||||
options?: Options<ListSolanaAccountsData, ThrowOnError>,
|
||||
) => {
|
||||
return (options?.client ?? _heyApiClient).get<
|
||||
ListSolanaAccountsResponses,
|
||||
unknown,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-secret-key",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/accounts",
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get or Create Solana Account
|
||||
* Create a new solana wallet in the vault or return the existing wallet for a given label.
|
||||
*/
|
||||
export const createSolanaAccount = <ThrowOnError extends boolean = false>(
|
||||
options?: Options<CreateSolanaAccountData, ThrowOnError>,
|
||||
) => {
|
||||
return (options?.client ?? _heyApiClient).post<
|
||||
CreateSolanaAccountResponses,
|
||||
unknown,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-secret-key",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/accounts",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sign Solana Message
|
||||
* Sign an arbitrary message with a Solana wallet.
|
||||
*/
|
||||
export const signSolanaMessage = <ThrowOnError extends boolean = false>(
|
||||
options?: Options<SignSolanaMessageData, ThrowOnError>,
|
||||
) => {
|
||||
return (options?.client ?? _heyApiClient).post<
|
||||
SignSolanaMessageResponses,
|
||||
unknown,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-secret-key",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/sign-message",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Sign Solana Transaction
|
||||
* Sign a serialized Solana transaction.
|
||||
*/
|
||||
export const signSolanaTransaction = <ThrowOnError extends boolean = false>(
|
||||
options?: Options<SignSolanaTransactionData, ThrowOnError>,
|
||||
) => {
|
||||
return (options?.client ?? _heyApiClient).post<
|
||||
SignSolanaTransactionResponses,
|
||||
unknown,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-secret-key",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/sign-transaction",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Transactions
|
||||
* Search transactions with various filters and pagination
|
||||
@@ -455,3 +606,103 @@ export const searchActivityLogs = <ThrowOnError extends boolean = false>(
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Solana Transactions
|
||||
* Search Solana transactions with various filters and pagination
|
||||
*/
|
||||
export const getSolanaTransactions = <ThrowOnError extends boolean = false>(
|
||||
options?: Options<GetSolanaTransactionsData, ThrowOnError>,
|
||||
) => {
|
||||
return (options?.client ?? _heyApiClient).get<
|
||||
GetSolanaTransactionsResponses,
|
||||
unknown,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-secret-key",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/transactions",
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Search Solana Transactions
|
||||
* Advanced search for Solana transactions with complex nested filters
|
||||
*/
|
||||
export const searchSolanaTransactions = <ThrowOnError extends boolean = false>(
|
||||
options?: Options<SearchSolanaTransactionsData, ThrowOnError>,
|
||||
) => {
|
||||
return (options?.client ?? _heyApiClient).post<
|
||||
SearchSolanaTransactionsResponses,
|
||||
unknown,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-secret-key",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/transactions/search",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Solana Activity Logs
|
||||
* Get paginated activity logs for a specific Solana transaction with tenancy enforcement
|
||||
*/
|
||||
export const getSolanaActivityLogs = <ThrowOnError extends boolean = false>(
|
||||
options: Options<GetSolanaActivityLogsData, ThrowOnError>,
|
||||
) => {
|
||||
return (options.client ?? _heyApiClient).get<
|
||||
GetSolanaActivityLogsResponses,
|
||||
GetSolanaActivityLogsErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-secret-key",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/transactions/activity-logs",
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Search Solana Activity Logs
|
||||
* Search Solana activity logs across transactions with advanced filtering and tenancy enforcement
|
||||
*/
|
||||
export const searchSolanaActivityLogs = <ThrowOnError extends boolean = false>(
|
||||
options?: Options<SearchSolanaActivityLogsData, ThrowOnError>,
|
||||
) => {
|
||||
return (options?.client ?? _heyApiClient).post<
|
||||
SearchSolanaActivityLogsResponses,
|
||||
SearchSolanaActivityLogsErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
security: [
|
||||
{
|
||||
name: "x-secret-key",
|
||||
type: "apiKey",
|
||||
},
|
||||
],
|
||||
url: "/v1/solana/transactions/activity-logs/search",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -17,6 +17,19 @@ export type TransactionsFilterNested = {
|
||||
filters: Array<TransactionsFilterValue | TransactionsFilterNested>;
|
||||
};
|
||||
|
||||
export type SolanaTransactionsFilterValue = {
|
||||
field: "id" | "chainId" | "signerAddress" | "signature";
|
||||
values: Array<string>;
|
||||
operation: "AND" | "OR";
|
||||
};
|
||||
|
||||
export type SolanaTransactionsFilterNested = {
|
||||
operation: "AND" | "OR";
|
||||
filters: Array<
|
||||
SolanaTransactionsFilterValue | SolanaTransactionsFilterNested
|
||||
>;
|
||||
};
|
||||
|
||||
/**
|
||||
* EVM Address
|
||||
* Used to represent an EVM address. This is a string of length 42 with a `0x` prefix. Non-checksummed addresses are also supported, but will be converted to checksummed.
|
||||
@@ -112,6 +125,21 @@ export type BatchResultItemEncodeResultSuccessItemEngineError =
|
||||
kind: RpcErrorKind;
|
||||
type: "BUNDLER_ERROR";
|
||||
}
|
||||
| {
|
||||
/**
|
||||
* Solana chain identifier
|
||||
*/
|
||||
chain_id: string;
|
||||
/**
|
||||
* Human-readable error message
|
||||
*/
|
||||
message: string;
|
||||
/**
|
||||
* Structured error kind
|
||||
*/
|
||||
kind: SolanaRpcErrorKind;
|
||||
type: "SOLANA_RPC_ERROR";
|
||||
}
|
||||
| {
|
||||
message: string;
|
||||
type: "VAULT_ERROR";
|
||||
@@ -202,6 +230,21 @@ export type BatchResultItemReadResultSuccessItemEngineError =
|
||||
kind: RpcErrorKind;
|
||||
type: "BUNDLER_ERROR";
|
||||
}
|
||||
| {
|
||||
/**
|
||||
* Solana chain identifier
|
||||
*/
|
||||
chain_id: string;
|
||||
/**
|
||||
* Human-readable error message
|
||||
*/
|
||||
message: string;
|
||||
/**
|
||||
* Structured error kind
|
||||
*/
|
||||
kind: SolanaRpcErrorKind;
|
||||
type: "SOLANA_RPC_ERROR";
|
||||
}
|
||||
| {
|
||||
message: string;
|
||||
type: "VAULT_ERROR";
|
||||
@@ -301,6 +344,21 @@ export type BatchResultItemSignResultDataEngineError =
|
||||
kind: RpcErrorKind;
|
||||
type: "BUNDLER_ERROR";
|
||||
}
|
||||
| {
|
||||
/**
|
||||
* Solana chain identifier
|
||||
*/
|
||||
chain_id: string;
|
||||
/**
|
||||
* Human-readable error message
|
||||
*/
|
||||
message: string;
|
||||
/**
|
||||
* Structured error kind
|
||||
*/
|
||||
kind: SolanaRpcErrorKind;
|
||||
type: "SOLANA_RPC_ERROR";
|
||||
}
|
||||
| {
|
||||
message: string;
|
||||
type: "VAULT_ERROR";
|
||||
@@ -392,6 +450,11 @@ export type CancelResult =
|
||||
}
|
||||
| "NOT_FOUND";
|
||||
|
||||
/**
|
||||
* Commitment Level
|
||||
*/
|
||||
export type CommitmentLevel = "confirmed" | "finalized";
|
||||
|
||||
/**
|
||||
* Represents a contract function call with parameters
|
||||
*
|
||||
@@ -765,6 +828,8 @@ export type InnerTransaction = (null | TransactionTypeData) & {
|
||||
gasLimit?: number | null;
|
||||
};
|
||||
|
||||
export type InstructionDataEncoding = "hex" | "base64";
|
||||
|
||||
export type MessageFormatDef = "text" | "hex";
|
||||
|
||||
/**
|
||||
@@ -783,6 +848,29 @@ export type MessageInput = {
|
||||
|
||||
export type MulticallDocType = boolean | AddressDef;
|
||||
|
||||
/**
|
||||
* Pubkey
|
||||
*/
|
||||
export type PubkeyDef = string;
|
||||
|
||||
/**
|
||||
* Response for a queued Solana transaction
|
||||
*/
|
||||
export type QueuedSolanaTransactionResponse = {
|
||||
/**
|
||||
* The idempotency key for this transaction
|
||||
*/
|
||||
transactionId: string;
|
||||
/**
|
||||
* The Solana chain
|
||||
*/
|
||||
chainId: SolanaChainId;
|
||||
/**
|
||||
* The signer address
|
||||
*/
|
||||
signerAddress: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* # QueuedTransaction
|
||||
* Response for any request that queues one or more transactions
|
||||
@@ -909,6 +997,28 @@ export type RpcErrorResponse = {
|
||||
data?: string | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request to send a Solana transaction
|
||||
*/
|
||||
export type SendSolanaTransactionRequest = {
|
||||
/**
|
||||
* Idempotency key for this transaction (defaults to random UUID)
|
||||
*/
|
||||
idempotencyKey?: string;
|
||||
/**
|
||||
* List of Solana instructions to execute
|
||||
*/
|
||||
instructions: Array<SolanaInstructionData>;
|
||||
/**
|
||||
* Solana execution options
|
||||
*/
|
||||
executionOptions: SolanaExecutionOptions;
|
||||
/**
|
||||
* Webhook options for transaction status notifications
|
||||
*/
|
||||
webhookOptions?: Array<WebhookOptions>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Incoming transaction request, parsed into InnerTransaction
|
||||
* Exposed API will have varying `params` but will all parse into InnerTransaction before execution
|
||||
@@ -975,6 +1085,9 @@ export type SerialisableAwsSignerError =
|
||||
| {
|
||||
message: string;
|
||||
type: "UNKNOWN";
|
||||
}
|
||||
| {
|
||||
type: "SIGNATURE_RECOVERY_FAILED";
|
||||
};
|
||||
|
||||
export type SerializableReqwestError =
|
||||
@@ -1149,6 +1262,196 @@ export type SigningOptions =
|
||||
chainId: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Account metadata for Solana instructions
|
||||
*/
|
||||
export type SolanaAccountMeta = {
|
||||
/**
|
||||
* Public key of the account
|
||||
*/
|
||||
pubkey: PubkeyDef;
|
||||
/**
|
||||
* Whether the account should sign the transaction
|
||||
*/
|
||||
isSigner: boolean;
|
||||
/**
|
||||
* Whether the account is writable
|
||||
*/
|
||||
isWritable: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Solana chain identifier
|
||||
*/
|
||||
export type SolanaChainId = "solana:mainnet" | "solana:devnet" | "solana:local";
|
||||
|
||||
/**
|
||||
* ### Solana Execution Options
|
||||
* This struct configures Solana transaction execution.
|
||||
*
|
||||
* Solana execution sends transactions directly to Solana RPC nodes with
|
||||
* support for priority fees, compute budgets, and commitment levels.
|
||||
*
|
||||
* ### Use Cases
|
||||
* - SOL transfers
|
||||
* - SPL token operations
|
||||
* - Program interactions (NFTs, DeFi, etc.)
|
||||
* - Arbitrary instruction composition
|
||||
*
|
||||
* ### Features
|
||||
* - Versioned transactions with address lookup tables
|
||||
* - Priority fee configuration for faster inclusion
|
||||
* - Compute budget optimization
|
||||
* - Configurable commitment levels
|
||||
* - Blockhash retry mechanism
|
||||
*/
|
||||
export type SolanaExecutionOptions = {
|
||||
/**
|
||||
* The Solana address (public key) to send transactions from
|
||||
* This account must have sufficient SOL to pay for transaction fees
|
||||
*/
|
||||
signerAddress: PubkeyDef;
|
||||
/**
|
||||
* Solana chain to use
|
||||
*/
|
||||
chainId: SolanaChainId;
|
||||
/**
|
||||
* Maximum number of times to retry fetching a new blockhash if transaction fails
|
||||
* Default: 0 (fail fast)
|
||||
* Max: 1000
|
||||
*/
|
||||
maxBlockhashRetries?: number;
|
||||
/**
|
||||
* Commitment level for transaction confirmation
|
||||
* Options: "processed", "confirmed", "finalized"
|
||||
* Default: "finalized"
|
||||
*/
|
||||
commitment?: CommitmentLevel;
|
||||
priorityFee?: null | SolanaPriorityFee;
|
||||
/**
|
||||
* Compute unit limit for the transaction. If omitted, the transaction will use the default compute unit limit. If provided, engine will add the compute budget instruction to the transaction.
|
||||
*/
|
||||
computeUnitLimit?: number | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Solana instruction data provided by the user
|
||||
* This is a simplified representation that will be converted to a proper Instruction
|
||||
*/
|
||||
export type SolanaInstructionData = {
|
||||
/**
|
||||
* Program ID to invoke
|
||||
*/
|
||||
programId: PubkeyDef;
|
||||
/**
|
||||
* Account keys that will be passed to the program
|
||||
*/
|
||||
accounts: Array<SolanaAccountMeta>;
|
||||
/**
|
||||
* Instruction data (hex-encoded or base64)
|
||||
*/
|
||||
data: string;
|
||||
encoding: InstructionDataEncoding;
|
||||
};
|
||||
|
||||
/**
|
||||
* Solana Priority Fee
|
||||
*/
|
||||
export type SolanaPriorityFee =
|
||||
| {
|
||||
type: "auto";
|
||||
}
|
||||
| {
|
||||
microLamportsPerUnit: number;
|
||||
type: "manual";
|
||||
}
|
||||
| {
|
||||
percentile: number;
|
||||
type: "percentile";
|
||||
};
|
||||
|
||||
/**
|
||||
* Solana-specific RPC error types
|
||||
*/
|
||||
export type SolanaRpcErrorKind =
|
||||
| {
|
||||
message: string;
|
||||
kind?: string | null;
|
||||
type: "IO";
|
||||
}
|
||||
| {
|
||||
message: string;
|
||||
status?: number | null;
|
||||
type: "REQWEST";
|
||||
}
|
||||
| {
|
||||
code: number;
|
||||
message: string;
|
||||
/**
|
||||
* Structured error data from Solana RPC
|
||||
*/
|
||||
data: SolanaRpcResponseErrorData;
|
||||
type: "RPC_ERROR";
|
||||
}
|
||||
| {
|
||||
message: string;
|
||||
line?: number | null;
|
||||
column?: number | null;
|
||||
type: "SERDE_JSON";
|
||||
}
|
||||
| {
|
||||
error_type: string;
|
||||
message: string;
|
||||
type: "TRANSACTION_ERROR";
|
||||
}
|
||||
| {
|
||||
message: string;
|
||||
type: "SIGNING_ERROR";
|
||||
}
|
||||
| {
|
||||
message: string;
|
||||
type: "CUSTOM";
|
||||
}
|
||||
| {
|
||||
message: string;
|
||||
type: "UNKNOWN";
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable version of Solana's RpcResponseErrorData
|
||||
*/
|
||||
export type SolanaRpcResponseErrorData =
|
||||
| {
|
||||
type: "EMPTY";
|
||||
}
|
||||
| {
|
||||
/**
|
||||
* Error message from simulation
|
||||
*/
|
||||
err?: string | null;
|
||||
/**
|
||||
* Logs from simulation
|
||||
*/
|
||||
logs?: Array<string> | null;
|
||||
/**
|
||||
* Accounts used in simulation
|
||||
*/
|
||||
accounts?: unknown;
|
||||
/**
|
||||
* Units consumed during simulation
|
||||
*/
|
||||
units_consumed?: number | null;
|
||||
/**
|
||||
* Return data from the transaction
|
||||
*/
|
||||
return_data?: unknown;
|
||||
type: "SEND_TRANSACTION_PREFLIGHT_FAILURE";
|
||||
}
|
||||
| {
|
||||
num_slots_behind?: number | null;
|
||||
type: "NODE_UNHEALTHY";
|
||||
};
|
||||
|
||||
/**
|
||||
* Execution Option Variants
|
||||
* All supported specific execution options are contained here
|
||||
@@ -1174,6 +1477,26 @@ export type SuccessResponseEmptyIdempotencySetResponse = {
|
||||
};
|
||||
};
|
||||
|
||||
export type SuccessResponseQueuedSolanaTransactionResponse = {
|
||||
/**
|
||||
* Response for a queued Solana transaction
|
||||
*/
|
||||
result: {
|
||||
/**
|
||||
* The idempotency key for this transaction
|
||||
*/
|
||||
transactionId: string;
|
||||
/**
|
||||
* The Solana chain
|
||||
*/
|
||||
chainId: SolanaChainId;
|
||||
/**
|
||||
* The signer address
|
||||
*/
|
||||
signerAddress: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type SuccessResponseQueuedTransactionsResponse = {
|
||||
result: {
|
||||
transactions: Array<QueuedTransaction>;
|
||||
@@ -1498,6 +1821,32 @@ export type EncodeContractResponses = {
|
||||
export type EncodeContractResponse =
|
||||
EncodeContractResponses[keyof EncodeContractResponses];
|
||||
|
||||
export type SendSolanaTransactionData = {
|
||||
/**
|
||||
* Solana transaction request
|
||||
*/
|
||||
body: SendSolanaTransactionRequest;
|
||||
headers?: {
|
||||
/**
|
||||
* Vault access token
|
||||
*/
|
||||
"x-vault-access-token"?: string | null;
|
||||
};
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: "/v1/solana/transaction";
|
||||
};
|
||||
|
||||
export type SendSolanaTransactionResponses = {
|
||||
/**
|
||||
* Solana transaction queued successfully
|
||||
*/
|
||||
202: SuccessResponseQueuedSolanaTransactionResponse;
|
||||
};
|
||||
|
||||
export type SendSolanaTransactionResponse =
|
||||
SendSolanaTransactionResponses[keyof SendSolanaTransactionResponses];
|
||||
|
||||
export type CancelTransactionData = {
|
||||
body?: never;
|
||||
path: {
|
||||
@@ -1598,6 +1947,178 @@ export type CreateAccountResponses = {
|
||||
export type CreateAccountResponse =
|
||||
CreateAccountResponses[keyof CreateAccountResponses];
|
||||
|
||||
export type ListSolanaAccountsData = {
|
||||
body?: never;
|
||||
headers?: {
|
||||
/**
|
||||
* Vault Access Token used to access your EOA
|
||||
*/
|
||||
"x-vault-access-token"?: string;
|
||||
};
|
||||
path?: never;
|
||||
query?: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
};
|
||||
url: "/v1/solana/accounts";
|
||||
};
|
||||
|
||||
export type ListSolanaAccountsResponses = {
|
||||
/**
|
||||
* Solana accounts retrieved
|
||||
*/
|
||||
200: {
|
||||
result: {
|
||||
accounts: Array<{
|
||||
/**
|
||||
* Base58 encoded Solana public key
|
||||
*/
|
||||
publicKey: string;
|
||||
label?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}>;
|
||||
pagination: {
|
||||
totalCount: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type ListSolanaAccountsResponse =
|
||||
ListSolanaAccountsResponses[keyof ListSolanaAccountsResponses];
|
||||
|
||||
export type CreateSolanaAccountData = {
|
||||
body?: {
|
||||
label: string;
|
||||
};
|
||||
headers?: {
|
||||
/**
|
||||
* Vault Access Token used to access your EOA
|
||||
*/
|
||||
"x-vault-access-token"?: string;
|
||||
};
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: "/v1/solana/accounts";
|
||||
};
|
||||
|
||||
export type CreateSolanaAccountResponses = {
|
||||
/**
|
||||
* Solana account retrieved
|
||||
*/
|
||||
200: {
|
||||
result: {
|
||||
/**
|
||||
* Base58 encoded Solana public key
|
||||
*/
|
||||
publicKey: string;
|
||||
label?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Solana account created
|
||||
*/
|
||||
201: {
|
||||
result: {
|
||||
/**
|
||||
* Base58 encoded Solana public key
|
||||
*/
|
||||
publicKey: string;
|
||||
label?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type CreateSolanaAccountResponse =
|
||||
CreateSolanaAccountResponses[keyof CreateSolanaAccountResponses];
|
||||
|
||||
export type SignSolanaMessageData = {
|
||||
body?: {
|
||||
/**
|
||||
* Base58 encoded Solana public key
|
||||
*/
|
||||
from: string;
|
||||
message: string;
|
||||
format?: "text" | "hex";
|
||||
};
|
||||
headers?: {
|
||||
/**
|
||||
* Vault Access Token used to access your EOA
|
||||
*/
|
||||
"x-vault-access-token"?: string;
|
||||
};
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: "/v1/solana/sign-message";
|
||||
};
|
||||
|
||||
export type SignSolanaMessageResponses = {
|
||||
/**
|
||||
* Message signed
|
||||
*/
|
||||
200: {
|
||||
result: {
|
||||
/**
|
||||
* Base58 encoded signature
|
||||
*/
|
||||
signature: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type SignSolanaMessageResponse =
|
||||
SignSolanaMessageResponses[keyof SignSolanaMessageResponses];
|
||||
|
||||
export type SignSolanaTransactionData = {
|
||||
body?: {
|
||||
/**
|
||||
* Base58 encoded Solana public key
|
||||
*/
|
||||
from: string;
|
||||
/**
|
||||
* Base64 encoded Solana transaction
|
||||
*/
|
||||
transaction: string;
|
||||
};
|
||||
headers?: {
|
||||
/**
|
||||
* Vault Access Token used to access your EOA
|
||||
*/
|
||||
"x-vault-access-token"?: string;
|
||||
};
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: "/v1/solana/sign-transaction";
|
||||
};
|
||||
|
||||
export type SignSolanaTransactionResponses = {
|
||||
/**
|
||||
* Transaction signed
|
||||
*/
|
||||
200: {
|
||||
result: {
|
||||
/**
|
||||
* Base58 encoded signature
|
||||
*/
|
||||
signature: string;
|
||||
/**
|
||||
* Base58 encoded Solana public key
|
||||
*/
|
||||
signerPublicKey: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type SignSolanaTransactionResponse =
|
||||
SignSolanaTransactionResponses[keyof SignSolanaTransactionResponses];
|
||||
|
||||
export type GetTransactionsData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
@@ -1967,6 +2488,277 @@ export type SearchActivityLogsResponses = {
|
||||
export type SearchActivityLogsResponse =
|
||||
SearchActivityLogsResponses[keyof SearchActivityLogsResponses];
|
||||
|
||||
export type GetSolanaTransactionsData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query?: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
id?: string;
|
||||
chainId?: string;
|
||||
signerAddress?: string;
|
||||
signature?: string;
|
||||
status?: "QUEUED" | "SUBMITTED" | "CONFIRMED" | "FAILED";
|
||||
sortBy?: "createdAt" | "confirmedAt";
|
||||
sortDirection?: "asc" | "desc";
|
||||
};
|
||||
url: "/v1/solana/transactions";
|
||||
};
|
||||
|
||||
export type GetSolanaTransactionsResponses = {
|
||||
/**
|
||||
* Solana Transactions
|
||||
*/
|
||||
200: {
|
||||
result: {
|
||||
transactions: Array<{
|
||||
id: string;
|
||||
clientId: string;
|
||||
chainId: string;
|
||||
signerAddress: string;
|
||||
transactionParams:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>;
|
||||
signature: string | null;
|
||||
status: string | null;
|
||||
confirmedAt: string | null;
|
||||
confirmedAtSlot: string | null;
|
||||
blockTime: number | null;
|
||||
enrichedData:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>;
|
||||
executionParams:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>;
|
||||
executionResult:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>
|
||||
| null;
|
||||
createdAt: string;
|
||||
errorMessage: string | null;
|
||||
cancelledAt: string | null;
|
||||
}>;
|
||||
pagination: {
|
||||
totalCount: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type GetSolanaTransactionsResponse =
|
||||
GetSolanaTransactionsResponses[keyof GetSolanaTransactionsResponses];
|
||||
|
||||
export type SearchSolanaTransactionsData = {
|
||||
body?: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
filters?: Array<
|
||||
SolanaTransactionsFilterValue | SolanaTransactionsFilterNested
|
||||
>;
|
||||
filtersOperation?: "AND" | "OR";
|
||||
sortBy?: "createdAt" | "confirmedAt";
|
||||
sortDirection?: "asc" | "desc";
|
||||
};
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: "/v1/solana/transactions/search";
|
||||
};
|
||||
|
||||
export type SearchSolanaTransactionsResponses = {
|
||||
/**
|
||||
* Solana Transactions
|
||||
*/
|
||||
200: {
|
||||
result: {
|
||||
transactions: Array<{
|
||||
id: string;
|
||||
clientId: string;
|
||||
chainId: string;
|
||||
signerAddress: string;
|
||||
transactionParams:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>;
|
||||
signature: string | null;
|
||||
status: string | null;
|
||||
confirmedAt: string | null;
|
||||
confirmedAtSlot: string | null;
|
||||
blockTime: number | null;
|
||||
enrichedData:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>;
|
||||
executionParams:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>;
|
||||
executionResult:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>
|
||||
| null;
|
||||
createdAt: string;
|
||||
errorMessage: string | null;
|
||||
cancelledAt: string | null;
|
||||
}>;
|
||||
pagination: {
|
||||
totalCount: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type SearchSolanaTransactionsResponse =
|
||||
SearchSolanaTransactionsResponses[keyof SearchSolanaTransactionsResponses];
|
||||
|
||||
export type GetSolanaActivityLogsData = {
|
||||
body?: never;
|
||||
path?: never;
|
||||
query: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
transactionId: string;
|
||||
eventType?: "SUCCESS" | "FAILURE" | "NACK";
|
||||
stageName?: string;
|
||||
executorName?: string;
|
||||
sortBy?: "timestamp" | "createdAt";
|
||||
sortDirection?: "asc" | "desc";
|
||||
};
|
||||
url: "/v1/solana/transactions/activity-logs";
|
||||
};
|
||||
|
||||
export type GetSolanaActivityLogsErrors = {
|
||||
/**
|
||||
* Invalid request parameters
|
||||
*/
|
||||
400: unknown;
|
||||
/**
|
||||
* Transaction not found or not accessible
|
||||
*/
|
||||
404: unknown;
|
||||
};
|
||||
|
||||
export type GetSolanaActivityLogsResponses = {
|
||||
/**
|
||||
* Solana Activity Logs
|
||||
*/
|
||||
200: {
|
||||
result: {
|
||||
activityLogs: Array<{
|
||||
id: string;
|
||||
transactionId: string;
|
||||
eventType: string;
|
||||
stageName: string;
|
||||
executorName: string;
|
||||
notificationId: string;
|
||||
payload:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>;
|
||||
timestamp: string;
|
||||
createdAt: string;
|
||||
}>;
|
||||
transaction: {
|
||||
id: string;
|
||||
clientId: string;
|
||||
};
|
||||
pagination: {
|
||||
totalCount: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type GetSolanaActivityLogsResponse =
|
||||
GetSolanaActivityLogsResponses[keyof GetSolanaActivityLogsResponses];
|
||||
|
||||
export type SearchSolanaActivityLogsData = {
|
||||
body?: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
transactionIds?: Array<string>;
|
||||
eventType?: "SUCCESS" | "FAILURE" | "NACK";
|
||||
stageName?: string;
|
||||
executorName?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
sortBy?: "timestamp" | "createdAt";
|
||||
sortDirection?: "asc" | "desc";
|
||||
};
|
||||
path?: never;
|
||||
query?: never;
|
||||
url: "/v1/solana/transactions/activity-logs/search";
|
||||
};
|
||||
|
||||
export type SearchSolanaActivityLogsErrors = {
|
||||
/**
|
||||
* Invalid request parameters
|
||||
*/
|
||||
400: unknown;
|
||||
};
|
||||
|
||||
export type SearchSolanaActivityLogsResponses = {
|
||||
/**
|
||||
* Solana Activity Logs Search Results
|
||||
*/
|
||||
200: {
|
||||
result: {
|
||||
activityLogs: Array<{
|
||||
id: string;
|
||||
transactionId: string;
|
||||
eventType: string;
|
||||
stageName: string;
|
||||
executorName: string;
|
||||
notificationId: string;
|
||||
payload:
|
||||
| (string | number | boolean | null)
|
||||
| {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
| Array<unknown>;
|
||||
timestamp: string;
|
||||
createdAt: string;
|
||||
}>;
|
||||
pagination: {
|
||||
totalCount: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type SearchSolanaActivityLogsResponse =
|
||||
SearchSolanaActivityLogsResponses[keyof SearchSolanaActivityLogsResponses];
|
||||
|
||||
export type ClientOptions = {
|
||||
baseUrl: "https://engine.thirdweb.com" | (string & {});
|
||||
};
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# @thirdweb-dev/nebula
|
||||
|
||||
## 0.2.66
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- thirdweb@5.108.13
|
||||
|
||||
## 0.2.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`0082e99`](https://github.com/thirdweb-dev/js/commit/0082e996cae47a326110e74457c72b3f3936743d), [`0082e99`](https://github.com/thirdweb-dev/js/commit/0082e996cae47a326110e74457c72b3f3936743d)]:
|
||||
- thirdweb@5.108.12
|
||||
|
||||
## 0.2.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`05550d0`](https://github.com/thirdweb-dev/js/commit/05550d045f291b8e53afd0d7e73c438bee202fb7)]:
|
||||
- thirdweb@5.108.11
|
||||
|
||||
## 0.2.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -57,5 +57,5 @@
|
||||
"type": "module",
|
||||
"types": "./dist/types/exports/thirdweb.d.ts",
|
||||
"typings": "./dist/types/exports/thirdweb.d.ts",
|
||||
"version": "0.2.63"
|
||||
"version": "0.2.66"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# thirdweb
|
||||
|
||||
## 5.108.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`9545b43`](https://github.com/thirdweb-dev/js/commit/9545b4367598408dbb88c63d8a8fe21305f870b5)]:
|
||||
- @thirdweb-dev/engine@3.3.0
|
||||
|
||||
## 5.108.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#8226](https://github.com/thirdweb-dev/js/pull/8226) [`0082e99`](https://github.com/thirdweb-dev/js/commit/0082e996cae47a326110e74457c72b3f3936743d) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add optional recipientAddress to x402 settlePayment
|
||||
|
||||
- [#8226](https://github.com/thirdweb-dev/js/pull/8226) [`0082e99`](https://github.com/thirdweb-dev/js/commit/0082e996cae47a326110e74457c72b3f3936743d) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose 7702 utility functions
|
||||
|
||||
## 5.108.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#8228](https://github.com/thirdweb-dev/js/pull/8228) [`05550d0`](https://github.com/thirdweb-dev/js/commit/05550d045f291b8e53afd0d7e73c438bee202fb7) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - Export ERC7702 MinimalAccount helpers and events
|
||||
|
||||
## 5.108.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -430,5 +430,5 @@
|
||||
}
|
||||
},
|
||||
"typings": "./dist/types/exports/thirdweb.d.ts",
|
||||
"version": "5.108.10"
|
||||
"version": "5.108.13"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
// --- KEEEP IN SYNC with exports/wallets/in-app.ts ---
|
||||
|
||||
export { executedEvent } from "../../extensions/erc7702/__generated__/MinimalAccount/events/Executed.js";
|
||||
export { sessionCreatedEvent } from "../../extensions/erc7702/__generated__/MinimalAccount/events/SessionCreated.js";
|
||||
export { valueReceivedEvent } from "../../extensions/erc7702/__generated__/MinimalAccount/events/ValueReceived.js";
|
||||
// ERC7702 generated helpers
|
||||
export {
|
||||
eip712Domain,
|
||||
isEip712DomainSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/eip712Domain.js";
|
||||
export {
|
||||
type GetCallPoliciesForSignerParams,
|
||||
getCallPoliciesForSigner,
|
||||
isGetCallPoliciesForSignerSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/getCallPoliciesForSigner.js";
|
||||
export {
|
||||
type GetSessionExpirationForSignerParams,
|
||||
getSessionExpirationForSigner,
|
||||
isGetSessionExpirationForSignerSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/getSessionExpirationForSigner.js";
|
||||
export {
|
||||
type GetSessionStateForSignerParams,
|
||||
getSessionStateForSigner,
|
||||
isGetSessionStateForSignerSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/getSessionStateForSigner.js";
|
||||
export {
|
||||
type GetTransferPoliciesForSignerParams,
|
||||
getTransferPoliciesForSigner,
|
||||
isGetTransferPoliciesForSignerSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/getTransferPoliciesForSigner.js";
|
||||
export {
|
||||
type IsWildcardSignerParams,
|
||||
isIsWildcardSignerSupported,
|
||||
isWildcardSigner,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/isWildcardSigner.js";
|
||||
export {
|
||||
type CreateSessionWithSigParams,
|
||||
createSessionWithSig,
|
||||
isCreateSessionWithSigSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/write/createSessionWithSig.js";
|
||||
export {
|
||||
type ExecuteParams,
|
||||
execute,
|
||||
isExecuteSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/write/execute.js";
|
||||
export {
|
||||
type ExecuteWithSigParams,
|
||||
executeWithSig,
|
||||
isExecuteWithSigSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/write/executeWithSig.js";
|
||||
//ACCOUNT
|
||||
export {
|
||||
type CreateSessionKeyOptions,
|
||||
|
||||
@@ -1,11 +1,60 @@
|
||||
// --- KEEEP IN SYNC with exports/wallets/in-app.native.ts ---
|
||||
|
||||
export { executedEvent } from "../../extensions/erc7702/__generated__/MinimalAccount/events/Executed.js";
|
||||
export { sessionCreatedEvent } from "../../extensions/erc7702/__generated__/MinimalAccount/events/SessionCreated.js";
|
||||
export { valueReceivedEvent } from "../../extensions/erc7702/__generated__/MinimalAccount/events/ValueReceived.js";
|
||||
// ERC7702 generated helpers
|
||||
export {
|
||||
eip712Domain,
|
||||
isEip712DomainSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/eip712Domain.js";
|
||||
export {
|
||||
type GetCallPoliciesForSignerParams,
|
||||
getCallPoliciesForSigner,
|
||||
isGetCallPoliciesForSignerSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/getCallPoliciesForSigner.js";
|
||||
export {
|
||||
type GetSessionExpirationForSignerParams,
|
||||
getSessionExpirationForSigner,
|
||||
isGetSessionExpirationForSignerSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/getSessionExpirationForSigner.js";
|
||||
export {
|
||||
type GetSessionStateForSignerParams,
|
||||
getSessionStateForSigner,
|
||||
isGetSessionStateForSignerSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/getSessionStateForSigner.js";
|
||||
export {
|
||||
type GetTransferPoliciesForSignerParams,
|
||||
getTransferPoliciesForSigner,
|
||||
isGetTransferPoliciesForSignerSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/getTransferPoliciesForSigner.js";
|
||||
export {
|
||||
type IsWildcardSignerParams,
|
||||
isIsWildcardSignerSupported,
|
||||
isWildcardSigner,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/read/isWildcardSigner.js";
|
||||
export {
|
||||
type CreateSessionWithSigParams,
|
||||
createSessionWithSig,
|
||||
isCreateSessionWithSigSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/write/createSessionWithSig.js";
|
||||
export {
|
||||
type ExecuteParams,
|
||||
execute,
|
||||
isExecuteSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/write/execute.js";
|
||||
export {
|
||||
type ExecuteWithSigParams,
|
||||
executeWithSig,
|
||||
isExecuteWithSigSupported,
|
||||
} from "../../extensions/erc7702/__generated__/MinimalAccount/write/executeWithSig.js";
|
||||
//ACCOUNT
|
||||
export {
|
||||
type CreateSessionKeyOptions,
|
||||
createSessionKey,
|
||||
isCreateSessionKeySupported,
|
||||
} from "../../extensions/erc7702/account/createSessionKey.js";
|
||||
|
||||
export type {
|
||||
Condition,
|
||||
LimitType,
|
||||
|
||||
@@ -44,6 +44,7 @@ export async function decodePaymentRequest(
|
||||
price,
|
||||
network,
|
||||
facilitator,
|
||||
payTo,
|
||||
resourceUrl,
|
||||
routeConfig = {},
|
||||
method,
|
||||
@@ -104,7 +105,7 @@ export async function decodePaymentRequest(
|
||||
resource: resourceUrl,
|
||||
description: description ?? "",
|
||||
mimeType: mimeType ?? "application/json",
|
||||
payTo: getAddress(facilitator.address),
|
||||
payTo: getAddress(facilitator.address), // always pay to the facilitator address first
|
||||
maxTimeoutSeconds: maxTimeoutSeconds ?? 300,
|
||||
asset: getAddress(asset.address),
|
||||
outputSchema: {
|
||||
@@ -117,6 +118,7 @@ export async function decodePaymentRequest(
|
||||
output: outputSchema,
|
||||
},
|
||||
extra: {
|
||||
recipientAddress: payTo, // input payTo is the final recipient address
|
||||
...((asset as ERC20TokenAmount["asset"]).eip712 ?? {}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ export type PaymentArgs = {
|
||||
facilitator: ThirdwebX402Facilitator;
|
||||
/** Optional configuration for the payment middleware route */
|
||||
routeConfig?: PaymentMiddlewareConfig;
|
||||
/** @deprecated Use facilitator.address instead */
|
||||
/** Optional recipient address to receive the payment if different from your facilitator address */
|
||||
payTo?: string;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/react-native-adapter
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#8168](https://github.com/thirdweb-dev/js/pull/8168) [`35c7d21`](https://github.com/thirdweb-dev/js/commit/35c7d21e368f9ea5636c8663ba31b7d473b5b343) Thanks [@d4mr](https://github.com/d4mr)! - Added Vault operations support for Solana.
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,16 +1,4 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
|
||||
"extends": "//",
|
||||
"overrides": [
|
||||
{
|
||||
"assist": {
|
||||
"actions": {
|
||||
"source": {
|
||||
"useSortedKeys": "off"
|
||||
}
|
||||
}
|
||||
},
|
||||
"includes": ["package.json"]
|
||||
}
|
||||
]
|
||||
"extends": "//"
|
||||
}
|
||||
|
||||
@@ -7,12 +7,20 @@
|
||||
"@noble/ciphers": "^1.2.1",
|
||||
"@noble/curves": "1.8.2",
|
||||
"@noble/hashes": "1.7.2",
|
||||
"@solana/addresses": "^3.0.0",
|
||||
"@solana/keys": "^3.0.0",
|
||||
"@solana/kit": "^4.0.0",
|
||||
"@solana/rpc": "^3.0.0",
|
||||
"@solana/transactions": "^3.0.0",
|
||||
"abitype": "1.0.8",
|
||||
"jose": "6.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.0.6",
|
||||
"rimraf": "6.0.1"
|
||||
"@solana-program/system": "^0.8.1",
|
||||
"bs58": "^6.0.0",
|
||||
"rimraf": "6.0.1",
|
||||
"vitest": "3.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -51,6 +59,7 @@
|
||||
"build:esm": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json",
|
||||
"build:types": "tsc --project ./tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
|
||||
"clean": "rimraf dist",
|
||||
"test:solana": "vitest ./tests/solana.test.ts",
|
||||
"dev": "tsc --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm --watch",
|
||||
"fix": "biome check ./src --fix",
|
||||
"format": "biome format ./src --write",
|
||||
@@ -59,5 +68,5 @@
|
||||
"type": "module",
|
||||
"types": "./dist/types/exports/thirdweb.d.ts",
|
||||
"typings": "./dist/types/exports/thirdweb.d.ts",
|
||||
"version": "0.0.3"
|
||||
"version": "0.1.0"
|
||||
}
|
||||
|
||||
@@ -3,15 +3,19 @@ export {
|
||||
createEoa,
|
||||
createServiceAccount,
|
||||
createSignedAccessToken,
|
||||
createSolanaAccount,
|
||||
createVaultClient,
|
||||
getServiceAccount,
|
||||
listAccessTokens,
|
||||
listEoas,
|
||||
listSolanaAccounts,
|
||||
ping,
|
||||
revokeAccessToken,
|
||||
rotateServiceAccount,
|
||||
signAuthorization,
|
||||
signMessage,
|
||||
signSolanaMessage,
|
||||
signSolanaTransaction,
|
||||
signStructuredMessage,
|
||||
signTransaction,
|
||||
signTypedData,
|
||||
@@ -31,6 +35,7 @@ export type {
|
||||
CreateAccessTokenPayload,
|
||||
CreateEoaPayload,
|
||||
CreateServiceAccountPayload,
|
||||
CreateSolanaAccountPayload,
|
||||
EncryptedPayload,
|
||||
GenericPayload,
|
||||
GetAccessTokensData,
|
||||
@@ -38,6 +43,7 @@ export type {
|
||||
GetServiceAccountPayload,
|
||||
ListAccessTokensPayload,
|
||||
ListEoaPayload,
|
||||
ListSolanaAccountsPayload,
|
||||
Payload,
|
||||
PingPayload,
|
||||
PolicyComponent,
|
||||
@@ -49,6 +55,8 @@ export type {
|
||||
SignAuthorizationRules,
|
||||
SignedAuthorization,
|
||||
SignMessagePayload,
|
||||
SignSolanaMessagePayload,
|
||||
SignSolanaTransactionPayload,
|
||||
SignStructuredMessageData,
|
||||
SignStructuredMessageOptions,
|
||||
SignStructuredMessagePayload,
|
||||
|
||||
@@ -3,18 +3,27 @@ import { x25519 } from "@noble/curves/ed25519";
|
||||
import { hkdf } from "@noble/hashes/hkdf";
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
import { bytesToHex, hexToBytes, randomBytes } from "@noble/hashes/utils";
|
||||
|
||||
import {
|
||||
address,
|
||||
getBase58Encoder,
|
||||
getTransactionDecoder,
|
||||
getTransactionEncoder,
|
||||
} from "@solana/kit";
|
||||
|
||||
import type { TypedData } from "abitype";
|
||||
import * as jose from "jose";
|
||||
|
||||
import type {
|
||||
CheckedSignTypedDataPayload,
|
||||
CreateAccessTokenPayload,
|
||||
CreateEoaPayload,
|
||||
CreateServiceAccountPayload,
|
||||
CreateSolanaAccountPayload,
|
||||
EncryptedPayload,
|
||||
GetServiceAccountPayload,
|
||||
ListAccessTokensPayload,
|
||||
ListEoaPayload,
|
||||
ListSolanaAccountsPayload,
|
||||
Payload,
|
||||
PingPayload,
|
||||
PolicyComponent,
|
||||
@@ -23,6 +32,8 @@ import type {
|
||||
RotateServiceAccountPayload,
|
||||
SignAuthorizationPayload,
|
||||
SignMessagePayload,
|
||||
SignSolanaMessagePayload,
|
||||
SignSolanaTransactionPayload,
|
||||
SignStructuredMessagePayload,
|
||||
SignTransactionPayload,
|
||||
UnencryptedErrorResponse,
|
||||
@@ -447,6 +458,96 @@ export function listAccessTokens({
|
||||
});
|
||||
}
|
||||
|
||||
// ========== Solana Functions ==========
|
||||
|
||||
export function createSolanaAccount({
|
||||
client,
|
||||
request: options,
|
||||
}: PayloadParams<CreateSolanaAccountPayload>) {
|
||||
return sendRequest<CreateSolanaAccountPayload>({
|
||||
client,
|
||||
request: {
|
||||
operation: "solana:create",
|
||||
...options,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function listSolanaAccounts({
|
||||
client,
|
||||
request: options,
|
||||
}: PayloadParams<ListSolanaAccountsPayload>) {
|
||||
return sendRequest<ListSolanaAccountsPayload>({
|
||||
client,
|
||||
request: {
|
||||
operation: "solana:list",
|
||||
...options,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function signSolanaTransaction({
|
||||
client,
|
||||
request: options,
|
||||
}: PayloadParams<SignSolanaTransactionPayload>) {
|
||||
return sendRequest<SignSolanaTransactionPayload>({
|
||||
client,
|
||||
request: {
|
||||
operation: "solana:signTransaction",
|
||||
...options,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstruct a signed solana transaction from the vault signature using @solana/kit
|
||||
*/
|
||||
export function reconstructSolanaSignedTransaction(
|
||||
base64Transaction: string,
|
||||
base58Signature: string,
|
||||
signerPubkey: string,
|
||||
): Uint8Array {
|
||||
// Decode the base64 transaction into bytes
|
||||
const base64TransactionBytes = new Uint8Array(
|
||||
Buffer.from(base64Transaction, "base64"),
|
||||
);
|
||||
// Decode the transaction to get its structure
|
||||
const transactionDecoder = getTransactionDecoder();
|
||||
const transaction = transactionDecoder.decode(base64TransactionBytes);
|
||||
|
||||
// Decode the base58 signature to bytes
|
||||
const base58Encoder = getBase58Encoder();
|
||||
const signatureBytes = base58Encoder.encode(base58Signature);
|
||||
|
||||
// Add the signature to the transaction
|
||||
const signedTransaction = {
|
||||
...transaction,
|
||||
signatures: {
|
||||
...transaction.signatures,
|
||||
[address(signerPubkey)]: signatureBytes,
|
||||
},
|
||||
};
|
||||
|
||||
// Re-encode the signed transaction
|
||||
const transactionEncoder = getTransactionEncoder();
|
||||
const signedTransactionBytes = transactionEncoder.encode(signedTransaction);
|
||||
|
||||
return new Uint8Array(signedTransactionBytes);
|
||||
}
|
||||
|
||||
export function signSolanaMessage({
|
||||
client,
|
||||
request: options,
|
||||
}: PayloadParams<SignSolanaMessagePayload>) {
|
||||
return sendRequest<SignSolanaMessagePayload>({
|
||||
client,
|
||||
request: {
|
||||
operation: "solana:signMessage",
|
||||
...options,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const SIGNED_TOKEN_PREFIX = "vt_sat_";
|
||||
const DEFAULT_SIGNING_CONTEXT = "encryption"; // Default context for HKDF
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ export type UnencryptedErrorResponse = {
|
||||
type EncryptedError = {
|
||||
code: string;
|
||||
message: string;
|
||||
details?: string;
|
||||
details?: string | { reason: string };
|
||||
};
|
||||
|
||||
type GenericSuccessResponse<Data> = {
|
||||
@@ -148,6 +148,50 @@ type SignMessageOptions = {
|
||||
format?: "text" | "hex";
|
||||
};
|
||||
|
||||
// ========== Solana Options Types ==========
|
||||
|
||||
// Solana message type that's compatible with both Kit and our Rust serialization
|
||||
export type SolanaVersionedMessage = {
|
||||
version: "legacy" | "v0";
|
||||
header: {
|
||||
numRequiredSignatures: number;
|
||||
numReadonlySignedAccounts: number;
|
||||
numReadonlyUnsignedAccounts: number;
|
||||
};
|
||||
staticAccountKeys: string[]; // Use string instead of SolanaAddress for simplicity
|
||||
recentBlockhash: string;
|
||||
instructions: Array<{
|
||||
programIdIndex: number;
|
||||
accountKeyIndexes: number[];
|
||||
data: Uint8Array;
|
||||
}>;
|
||||
addressTableLookups?: Array<{
|
||||
accountKey: string; // Use string instead of SolanaAddress
|
||||
writableIndexes: number[];
|
||||
readonlyIndexes: number[];
|
||||
}>;
|
||||
};
|
||||
|
||||
type CreateSolanaAccountOptions = {
|
||||
metadata: Record<string, MetadataValue>;
|
||||
};
|
||||
|
||||
type GetSolanaAccountsOptions = {
|
||||
page?: number;
|
||||
pageSize?: number;
|
||||
};
|
||||
|
||||
type SignSolanaTransactionOptions = {
|
||||
transaction: string; // Base64 encoded VersionedTransaction
|
||||
from: string; // Use string for Solana public key
|
||||
};
|
||||
|
||||
type SignSolanaMessageOptions = {
|
||||
message: string;
|
||||
from: string; // Use string for Solana public key
|
||||
format?: "text" | "hex";
|
||||
};
|
||||
|
||||
type CheckedSignTypedDataOptions<
|
||||
Types extends TypedData,
|
||||
PrimaryType extends keyof Types | "EIP712Domain" = keyof Types,
|
||||
@@ -315,12 +359,63 @@ export type PolicyComponent =
|
||||
useropV07?: UserOperationV07Rules;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: "solana:create";
|
||||
requiredMetadataPatterns?: MetadataRule[];
|
||||
allowedMetadataPatterns?: MetadataRule[];
|
||||
}
|
||||
| {
|
||||
type: "solana:read";
|
||||
metadataPatterns?: MetadataRule[];
|
||||
}
|
||||
| {
|
||||
type: "solana:signTransaction";
|
||||
allowlist?: string[]; // Use string for Solana addresses
|
||||
metadataPatterns?: MetadataRule[];
|
||||
payloadPatterns?: Record<string, Rule[]>;
|
||||
transactionPatterns?: SolanaTransactionPatterns;
|
||||
}
|
||||
| {
|
||||
type: "solana:signMessage";
|
||||
allowlist?: string[]; // Use string for Solana addresses
|
||||
metadataPatterns?: MetadataRule[];
|
||||
messagePattern?: string;
|
||||
}
|
||||
| {
|
||||
type: "accessToken:read";
|
||||
metadataPatterns?: MetadataRule[];
|
||||
revealSensitive: boolean;
|
||||
};
|
||||
|
||||
// Solana transaction patterns
|
||||
export type SolanaTransactionPatterns = {
|
||||
programs?: ProgramAccessControl;
|
||||
writableAccounts?: AccountAccessControl;
|
||||
requiredCosigners?: string[];
|
||||
maxInstructions?: number;
|
||||
canPayFees?: boolean;
|
||||
};
|
||||
|
||||
export type ProgramAccessControl =
|
||||
| {
|
||||
type: "allow";
|
||||
programs: string[];
|
||||
}
|
||||
| {
|
||||
type: "deny";
|
||||
programs: string[];
|
||||
};
|
||||
|
||||
export type AccountAccessControl =
|
||||
| {
|
||||
type: "allow";
|
||||
accounts: string[];
|
||||
}
|
||||
| {
|
||||
type: "deny";
|
||||
accounts: string[];
|
||||
};
|
||||
|
||||
type OwnerType = string; // Define based on your eoa models
|
||||
|
||||
type CreateAccessTokenOptions = {
|
||||
@@ -399,6 +494,30 @@ type SignMessageData = {
|
||||
signature: string;
|
||||
};
|
||||
|
||||
// ========== Solana Data Types ==========
|
||||
type CreateSolanaAccountData = {
|
||||
pubkey: string;
|
||||
metadata: Record<string, MetadataValue>;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
type GetSolanaAccountsData = {
|
||||
accounts: CreateSolanaAccountData[];
|
||||
totalCount: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
};
|
||||
|
||||
type SignSolanaTransactionData = {
|
||||
signature: string; // Base58 encoded signature
|
||||
signerPubkey: string; // Use string for Solana public key
|
||||
};
|
||||
|
||||
type SignSolanaMessageData = {
|
||||
signature: string; // Base58 encoded signature
|
||||
};
|
||||
|
||||
type SignTypedDataData = {
|
||||
signature: string;
|
||||
};
|
||||
@@ -553,6 +672,35 @@ export type RevokeAccessTokenPayload = GenericPayload<{
|
||||
data: AccessTokenData;
|
||||
}>;
|
||||
|
||||
// ========== Solana Payload Types ==========
|
||||
export type CreateSolanaAccountPayload = GenericPayload<{
|
||||
operation: "solana:create";
|
||||
auth: Auth;
|
||||
options: CreateSolanaAccountOptions;
|
||||
data: CreateSolanaAccountData;
|
||||
}>;
|
||||
|
||||
export type ListSolanaAccountsPayload = GenericPayload<{
|
||||
operation: "solana:list";
|
||||
auth: Auth;
|
||||
options: GetSolanaAccountsOptions;
|
||||
data: GetSolanaAccountsData;
|
||||
}>;
|
||||
|
||||
export type SignSolanaTransactionPayload = GenericPayload<{
|
||||
operation: "solana:signTransaction";
|
||||
auth: Auth;
|
||||
options: SignSolanaTransactionOptions;
|
||||
data: SignSolanaTransactionData;
|
||||
}>;
|
||||
|
||||
export type SignSolanaMessagePayload = GenericPayload<{
|
||||
operation: "solana:signMessage";
|
||||
auth: Auth;
|
||||
options: SignSolanaMessageOptions;
|
||||
data: SignSolanaMessageData;
|
||||
}>;
|
||||
|
||||
// ========== Union of all payloads ==========
|
||||
export type Payload =
|
||||
| PingPayload
|
||||
@@ -568,4 +716,8 @@ export type Payload =
|
||||
| RevokeAccessTokenPayload
|
||||
| SignAuthorizationPayload
|
||||
| SignStructuredMessagePayload
|
||||
| ListAccessTokensPayload;
|
||||
| ListAccessTokensPayload
|
||||
| CreateSolanaAccountPayload
|
||||
| ListSolanaAccountsPayload
|
||||
| SignSolanaTransactionPayload
|
||||
| SignSolanaMessagePayload;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# Solana RPC Configuration
|
||||
SOLANA_RPC_HTTP_URL=http://127.0.0.1:8899
|
||||
SOLANA_RPC_WS_URL=ws://127.0.0.1:8900
|
||||
|
||||
# Vault Configuration
|
||||
VAULT_URL=http://localhost:3000
|
||||
@@ -0,0 +1,11 @@
|
||||
import { dirname, join } from "node:path";
|
||||
import { loadEnvFile } from "node:process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
try {
|
||||
loadEnvFile(join(__dirname, ".env"));
|
||||
} catch (_error) {
|
||||
console.warn("No .env file found, using default values");
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
import { join } from "node:path";
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true,
|
||||
environment: "node",
|
||||
testTimeout: 60000, // 60 seconds default timeout
|
||||
hookTimeout: 60000, // 60 seconds for beforeAll/afterAll
|
||||
teardownTimeout: 10000,
|
||||
sequence: {
|
||||
shuffle: false, // Run tests in order
|
||||
},
|
||||
// load .env.test
|
||||
setupFiles: [join(__dirname, "./tests/env-setup.ts")],
|
||||
},
|
||||
});
|
||||
@@ -1,5 +1,11 @@
|
||||
# @thirdweb-dev/wagmi-adapter
|
||||
|
||||
## 0.2.163
|
||||
|
||||
## 0.2.162
|
||||
|
||||
## 0.2.161
|
||||
|
||||
## 0.2.160
|
||||
|
||||
## 0.2.159
|
||||
|
||||
@@ -56,5 +56,5 @@
|
||||
"type": "module",
|
||||
"types": "./dist/types/exports/thirdweb.d.ts",
|
||||
"typings": "./dist/types/exports/thirdweb.d.ts",
|
||||
"version": "0.2.160"
|
||||
"version": "0.2.163"
|
||||
}
|
||||
|
||||
Generated
+1076
-15
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user