Skip to content

Commit 44986f3

Browse files
Add EIP-5792 wallet capabilities support
1 parent e739de1 commit 44986f3

File tree

15 files changed

+547
-66
lines changed

15 files changed

+547
-66
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import ThirdwebProvider from "@/components/thirdweb-provider";
2+
import { metadataBase } from "@/lib/constants";
3+
import type { Metadata } from "next";
4+
import { Eip5792GetCapabilitiesPreview } from "../../../../components/account-abstraction/5792-get-capabilities";
5+
import { Eip5792SendCallsPreview } from "../../../../components/account-abstraction/5792-send-calls";
6+
import { PageLayout } from "../../../../components/blocks/APIHeader";
7+
import { CodeExample } from "../../../../components/code/code-example";
8+
9+
export const metadata: Metadata = {
10+
metadataBase,
11+
title: "EIP-5792 Wallet Capabilities | thirdweb Connect",
12+
description:
13+
"EIP-5792 capabilities allow you to view the capabilities of the connected wallet",
14+
};
15+
16+
export default function Page() {
17+
return (
18+
<ThirdwebProvider>
19+
<PageLayout
20+
title="EIP-5792 Wallet Capabilities"
21+
description={
22+
<>
23+
EIP-5792 capabilities allow you to view the capabilities of the
24+
connected wallet.
25+
</>
26+
}
27+
docsLink="https://portal.thirdweb.com/connect/account-abstraction/overview?utm_source=playground"
28+
>
29+
<div className="flex flex-col gap-14">
30+
<Eip5792GetCapabilities />
31+
<Eip5792SendCalls />
32+
</div>
33+
</PageLayout>
34+
</ThirdwebProvider>
35+
);
36+
}
37+
38+
function Eip5792GetCapabilities() {
39+
return (
40+
<>
41+
<CodeExample
42+
header={{
43+
title: "Getting the wallet capabilities",
44+
description:
45+
"Get the capabilities of the connected wallet using the useCapabilities hook",
46+
}}
47+
preview={<Eip5792GetCapabilitiesPreview />}
48+
code={`\
49+
import { useCapabilities } from "thirdweb/react";
50+
51+
function App() {
52+
// requires a connected wallet
53+
// try metamask or coinbase wallet to view their capabilities
54+
// works with in-app wallets too!
55+
const capabilities = useCapabilities();
56+
console.log(capabilities);
57+
58+
return <div>Capabilities: {JSON.stringify(capabilities)}</div>;
59+
}
60+
`}
61+
lang="tsx"
62+
/>
63+
</>
64+
);
65+
}
66+
67+
function Eip5792SendCalls() {
68+
return (
69+
<>
70+
<CodeExample
71+
header={{
72+
title: "Sending calls to the wallet",
73+
description:
74+
"Send batched calls to the connected wallet using the useSendCalls hook",
75+
}}
76+
preview={<Eip5792SendCallsPreview />}
77+
lang="tsx"
78+
code={`\
79+
import { useSendCalls } from "thirdweb/react";
80+
81+
function App() {
82+
const sendCalls = useSendCalls({
83+
client,
84+
waitForResult: true,
85+
});
86+
87+
const handleClick = async () => {
88+
const result = await sendCalls.mutateAsync({
89+
calls: [firstTransaction, secondTransaction],
90+
});
91+
// result can be a either the transaction id
92+
// or the full transaction receipt if waitForResult is true
93+
if (typeof result === "string") {
94+
console.log("Transaction id", result);
95+
} else {
96+
console.log("Transaction hash", result.receipts?.[0]?.transactionHash);
97+
}
98+
};
99+
100+
return <button onClick={handleClick}>Send calls</button>;
101+
}
102+
`}
103+
/>
104+
</>
105+
);
106+
}

apps/playground-web/src/app/connect/account-abstraction/7702/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ function Eip7702SmartAccount() {
3535
return (
3636
<>
3737
<CodeExample
38+
header={{
39+
title: "Turning in-app wallets into EIP-7702 smart accounts",
40+
description:
41+
"In-app wallets can be turned into EIP-7702 smart accounts by changing the execution mode",
42+
}}
3843
preview={<Eip7702SmartAccountPreview />}
3944
code={`\
4045
import { claimTo } from "thirdweb/extensions/erc1155";

apps/playground-web/src/app/navLinks.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ const staticSidebarLinks: SidebarLink[] = [
5858
name: "EIP-7702",
5959
href: "/connect/account-abstraction/7702",
6060
},
61+
{
62+
name: "EIP-5792",
63+
href: "/connect/account-abstraction/5792",
64+
},
6165
{
6266
name: "Native (zkSync)",
6367
href: "/connect/account-abstraction/native-aa",
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"use client";
2+
import { sepolia } from "thirdweb/chains";
3+
import {} from "thirdweb/extensions/erc1155";
4+
import {
5+
ConnectButton,
6+
useActiveWallet,
7+
useCapabilities,
8+
useWalletInfo,
9+
} from "thirdweb/react";
10+
import { createWallet } from "thirdweb/wallets";
11+
import { THIRDWEB_CLIENT } from "../../lib/client";
12+
import CodeClient from "../code/code.client";
13+
14+
export function Eip5792GetCapabilitiesPreview() {
15+
const capabilities = useCapabilities();
16+
const activeWallet = useActiveWallet();
17+
const walletInfo = useWalletInfo(activeWallet?.id);
18+
19+
return (
20+
<div className="flex flex-col items-center justify-center gap-4">
21+
{capabilities.isLoading ? (
22+
<div className="mt-24 w-full">Loading...</div>
23+
) : (
24+
<>
25+
<div className="flex flex-col justify-center gap-2 p-2">
26+
<ConnectButton
27+
client={THIRDWEB_CLIENT}
28+
chain={sepolia}
29+
wallets={[
30+
createWallet("io.metamask"),
31+
createWallet("com.coinbase.wallet"),
32+
]}
33+
connectButton={{
34+
label: "Login to view wallet capabilities",
35+
}}
36+
/>
37+
</div>
38+
<p className="text-lg">
39+
{walletInfo.data?.name || "Wallet"} Capabilities
40+
</p>
41+
{capabilities.data ? (
42+
<CodeClient
43+
code={JSON.stringify(capabilities.data, null, 2)}
44+
lang="json"
45+
loader={<div className="mt-24 w-full">Loading...</div>}
46+
className="max-h-[500px] w-[400px] overflow-y-auto"
47+
scrollableContainerClassName="h-full"
48+
scrollableClassName="h-full"
49+
/>
50+
) : null}
51+
</>
52+
)}
53+
</div>
54+
);
55+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
import { getContract } from "thirdweb";
5+
import { sepolia } from "thirdweb/chains";
6+
import { claimTo } from "thirdweb/extensions/erc1155";
7+
import { getNFT, getOwnedNFTs } from "thirdweb/extensions/erc1155";
8+
import {
9+
ConnectButton,
10+
MediaRenderer,
11+
useActiveAccount,
12+
useReadContract,
13+
useSendCalls,
14+
} from "thirdweb/react";
15+
import { shortenHex } from "thirdweb/utils";
16+
import { createWallet } from "thirdweb/wallets";
17+
import { THIRDWEB_CLIENT } from "../../lib/client";
18+
import { Button } from "../ui/button";
19+
20+
const chain = sepolia;
21+
22+
const editionDropContract = getContract({
23+
address: "0x7B3e0B8353Ad5cD6C60355B50550F63335752f9F",
24+
chain,
25+
client: THIRDWEB_CLIENT,
26+
});
27+
28+
const editionDropContract2 = getContract({
29+
address: "0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
30+
chain,
31+
client: THIRDWEB_CLIENT,
32+
});
33+
34+
export function Eip5792SendCallsPreview() {
35+
const [txHash, setTxHash] = useState<string | null>(null);
36+
const activeEOA = useActiveAccount();
37+
const { data: nft, isLoading: isNftLoading } = useReadContract(getNFT, {
38+
contract: editionDropContract2,
39+
tokenId: 0n,
40+
});
41+
const { data: nft2, isLoading: isNft2Loading } = useReadContract(getNFT, {
42+
contract: editionDropContract,
43+
tokenId: 1n,
44+
});
45+
const { data: ownedNfts } = useReadContract(getOwnedNFTs, {
46+
contract: editionDropContract,
47+
useIndexer: false,
48+
// biome-ignore lint/style/noNonNullAssertion: handled by queryOptions
49+
address: activeEOA?.address!,
50+
queryOptions: { enabled: !!activeEOA },
51+
});
52+
const { data: ownedNfts2 } = useReadContract(getOwnedNFTs, {
53+
contract: editionDropContract2,
54+
useIndexer: false,
55+
// biome-ignore lint/style/noNonNullAssertion: handled by queryOptions
56+
address: activeEOA?.address!,
57+
queryOptions: { enabled: !!activeEOA },
58+
});
59+
60+
const sendCalls = useSendCalls({
61+
client: THIRDWEB_CLIENT,
62+
waitForResult: true,
63+
});
64+
65+
return (
66+
<div className="flex flex-col items-center justify-center gap-4">
67+
{isNftLoading || isNft2Loading ? (
68+
<div className="mt-24 w-full">Loading...</div>
69+
) : (
70+
<>
71+
<div className="flex flex-col justify-center gap-2 p-2">
72+
<ConnectButton
73+
client={THIRDWEB_CLIENT}
74+
chain={sepolia}
75+
wallets={[
76+
createWallet("io.metamask"),
77+
createWallet("com.coinbase.wallet"),
78+
]}
79+
connectButton={{
80+
label: "Login to mint!",
81+
}}
82+
/>
83+
</div>
84+
<p className="font-semibold text-lg">Send batched transactions</p>
85+
<div className="flex flex-row items-center gap-2 p-2">
86+
{nft ? (
87+
<MediaRenderer
88+
client={THIRDWEB_CLIENT}
89+
src={nft.metadata.image}
90+
style={{ width: "100px", marginTop: "10px" }}
91+
/>
92+
) : null}
93+
<p className="text-2xl">+</p>
94+
{nft2 ? (
95+
<MediaRenderer
96+
client={THIRDWEB_CLIENT}
97+
src={nft2.metadata.image}
98+
style={{ width: "100px", marginTop: "10px" }}
99+
/>
100+
) : null}
101+
</div>
102+
{activeEOA ? (
103+
<div className="flex flex-col justify-center gap-4 p-2">
104+
<p className="mb-2 text-center font-semibold">
105+
You own {ownedNfts?.[0]?.quantityOwned.toString() || "0"}{" "}
106+
{nft?.metadata?.name} and{" "}
107+
{ownedNfts2?.[0]?.quantityOwned.toString() || "0"}{" "}
108+
{nft2?.metadata?.name}
109+
</p>
110+
<Button
111+
onClick={async () => {
112+
const result = await sendCalls.mutateAsync({
113+
calls: [
114+
claimTo({
115+
contract: editionDropContract2,
116+
tokenId: 0n,
117+
to: activeEOA.address,
118+
quantity: 1n,
119+
}),
120+
claimTo({
121+
contract: editionDropContract,
122+
tokenId: 1n,
123+
to: activeEOA.address,
124+
quantity: 1n,
125+
}),
126+
],
127+
});
128+
if (typeof result === "string") {
129+
setTxHash(result);
130+
} else {
131+
setTxHash(result?.receipts?.[0]?.transactionHash);
132+
}
133+
}}
134+
>
135+
{sendCalls.isPending
136+
? "Minting..."
137+
: "Batch Mint with EIP-5792"}
138+
</Button>
139+
</div>
140+
) : null}
141+
{txHash ? (
142+
<div className="flex flex-col justify-center p-2">
143+
<p className="mb-2 text-center text-green-500">
144+
Minted! Tx Hash:{" "}
145+
<a
146+
href={`${chain.blockExplorers?.[0]?.url}/tx/${txHash}`}
147+
target="_blank"
148+
rel="noopener noreferrer"
149+
className="underline"
150+
>
151+
{shortenHex(txHash)}
152+
</a>
153+
</p>
154+
</div>
155+
) : null}
156+
</>
157+
)}
158+
</div>
159+
);
160+
}

0 commit comments

Comments
 (0)