Skip to content

Commit 58e343c

Browse files
[SDK] Improve EIP-5792 wallet capabilities support (#7003)
1 parent bad9db9 commit 58e343c

35 files changed

+1287
-462
lines changed

.changeset/forty-seals-raise.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
"thirdweb": minor
3+
---
4+
5+
Breaking change: EIP-5792 support
6+
7+
We've significantly improved our EIP-5792 apis, which come with some breaking changes:
8+
9+
### New Functions Added
10+
11+
1. **`useSendAndConfirmCalls`**
12+
13+
- Description: Hook to send and wait for confirmation of EIP-5792 calls
14+
- Returns: React Query mutation object with transaction receipts
15+
- Example:
16+
17+
```tsx
18+
const { mutate: sendAndConfirmCalls, data: result } =
19+
useSendAndConfirmCalls();
20+
await sendAndConfirmCalls({
21+
client,
22+
calls: [tx1, tx2],
23+
});
24+
console.log("Transaction hash:", result.receipts?.[0]?.transactionHash);
25+
```
26+
27+
2. **`useWaitForCallsReceipt`**
28+
- Description: Hook to wait for the receipt of EIP-5792 calls, perfect for splitting submitting the call and waiting for receipt
29+
- Returns: React Query object with call receipts
30+
- Example:
31+
```tsx
32+
const { mutate: sendCalls, data: result } = useSendCalls();
33+
const { data: receipt, isLoading } = useWaitForCallsReceipt(result);
34+
```
35+
36+
### Breaking Changes
37+
38+
#### `useSendCalls` Changes
39+
40+
**Before**
41+
42+
```tsx
43+
// mutation returns id a string
44+
const sendCalls = useSendCalls({ client });
45+
```
46+
47+
**After**
48+
49+
```tsx
50+
// no longer needs client
51+
// mutation returns an object with id
52+
const sendCalls = useSendCalls();
53+
```
54+
55+
Waiting for call receipts is now done separately, via the `useWaitForCallsReceipt`.
56+
57+
**Before**
58+
59+
```tsx
60+
const { mutate: sendCalls, data: receipt } = useSendCalls({
61+
client,
62+
waitForBundle: true,
63+
});
64+
```
65+
66+
**After**
67+
68+
```tsx
69+
const { mutate: sendCalls, data: result } = useSendCalls();
70+
const { data: receipt, isLoading } = useWaitForCallsReceipt(result);
71+
```
72+
73+
You can also use the helper `useSendAndConfirmCalls` to combine both submitting and waiting for confirmation.
74+
75+
```tsx
76+
const { mutate: sendAndConfirmCalls, data: receipt } = useSendAndConfirmCalls();
77+
```
78+
79+
#### `sendCalls` Changes
80+
81+
**Before**:
82+
83+
```tsx
84+
// Old output type
85+
type SendCallsResult = string;
86+
```
87+
88+
**After**:
89+
90+
```tsx
91+
// New output type
92+
type SendCallsResult = {
93+
id: string;
94+
client: ThirdwebClient;
95+
chain: Chain;
96+
wallet: Wallet;
97+
};
98+
```

apps/playground-web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "0.1.1",
44
"private": true,
55
"scripts": {
6-
"dev": "next dev --turbopack",
6+
"dev": "rm -rf .next && next dev --turbopack",
77
"build": "next build",
88
"start": "next start",
99
"format": "biome format ./src --write",
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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, useWaitForCallsReceipt } from "thirdweb/react";
80+
81+
function App() {
82+
const { mutate: sendCalls, isPending, data } = useSendCalls();
83+
const { data: receipt, isLoading: isConfirming } = useWaitForCallsReceipt(data);
84+
85+
const handleClick = async () => {
86+
sendCalls({
87+
calls: [firstTransaction, secondTransaction],
88+
});
89+
};
90+
91+
return (
92+
<>
93+
<button onClick={handleClick}>Send calls</button>
94+
{isPending && <p>Sending...</p>}
95+
{isConfirming && <p>Confirming...</p>}
96+
{receipt && <p>Confirmed! {receipt?.receipts?.[0]?.transactionHash}</p>}
97+
</>
98+
);
99+
}
100+
`}
101+
/>
102+
</>
103+
);
104+
}

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/connect/account-abstraction/sponsor/page.tsx

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import ThirdwebProvider from "@/components/thirdweb-provider";
22
import { metadataBase } from "@/lib/constants";
33
import type { Metadata } from "next";
4+
import { ConnectSmartAccountCustomPreview } from "../../../../components/account-abstraction/connect-smart-account";
45
import { SponsoredTxPreview } from "../../../../components/account-abstraction/sponsored-tx";
56
import { PageLayout } from "../../../../components/blocks/APIHeader";
67
import { CodeExample } from "../../../../components/code/code-example";
8+
import { SponsoredInAppTxPreview } from "../../../../components/in-app-wallet/sponsored-tx";
79

810
export const metadata: Metadata = {
911
metadataBase,
@@ -21,7 +23,11 @@ export default function Page() {
2123
}
2224
docsLink="https://portal.thirdweb.com/connect/account-abstraction/overview?utm_source=playground"
2325
>
24-
<SponsoredTx />
26+
<div className="flex flex-col gap-14">
27+
<SponsoredTx />
28+
<SponsoredInAppTx />
29+
<ConnectSmartAccount />
30+
</div>
2531
</PageLayout>
2632
</ThirdwebProvider>
2733
);
@@ -30,9 +36,15 @@ export default function Page() {
3036
function SponsoredTx() {
3137
return (
3238
<CodeExample
39+
header={{
40+
title: "Usage with any external wallet",
41+
description:
42+
"Use the accountAbstraction flag on the ConnectButton or useConnect hook to automatically convert any external wallet to a EIP-4337 smart contract wallet.",
43+
}}
3344
preview={<SponsoredTxPreview />}
34-
code={`import { claimTo } from "thirdweb/extensions/erc1155";
35-
import { TransactionButton } from "thirdweb/react";
45+
code={`\
46+
import { useConnect } from "thirdweb/react";
47+
import { inAppWallet } from "thirdweb/wallets";
3648
3749
function App(){
3850
return (<>
@@ -54,3 +66,93 @@ function SponsoredTx() {
5466
/>
5567
);
5668
}
69+
70+
function SponsoredInAppTx() {
71+
return (
72+
<CodeExample
73+
header={{
74+
title: "Usage with in-app wallets",
75+
description:
76+
"Set the executionMode when creating your in-app wallet to turn it into a EIP-4337 smart contract wallet. Note that when set, the returned address will be the smart contract wallet address.",
77+
}}
78+
preview={<SponsoredInAppTxPreview />}
79+
code={`
80+
import { inAppWallet } from "thirdweb/wallets";
81+
import { claimTo } from "thirdweb/extensions/erc1155";
82+
import {
83+
ConnectButton,
84+
TransactionButton,
85+
} from "thirdweb/react";
86+
import { baseSepolia } from "thirdweb/chains";
87+
88+
const wallets = [
89+
inAppWallet(
90+
{
91+
// turn on gas sponsorship for in-app wallets
92+
// Can use EIP4337 or EIP7702 on supported chains
93+
executionMode: {
94+
mode: "EIP4337",
95+
smartAccount: { chain: baseSepolia, sponsorGas: true },
96+
},
97+
}),
98+
];
99+
100+
function App() {
101+
return (
102+
<>
103+
<ConnectButton client={client} wallets={wallets} />
104+
105+
{/* signless, sponsored transactions */}
106+
<TransactionButton
107+
transaction={() =>
108+
claimTo({
109+
contract,
110+
to: "0x123...",
111+
tokenId: 0n,
112+
quantity: 1n,
113+
})
114+
}
115+
>
116+
Mint
117+
</TransactionButton>
118+
</>
119+
);
120+
}`}
121+
lang="tsx"
122+
/>
123+
);
124+
}
125+
126+
function ConnectSmartAccount() {
127+
return (
128+
<CodeExample
129+
header={{
130+
title: "Build custom UI",
131+
description: "Build your own UI to connect to 4337 smart accounts",
132+
}}
133+
preview={<ConnectSmartAccountCustomPreview />}
134+
code={`\
135+
import { useConnect } from "thirdweb/react";
136+
import { inAppWallet } from "thirdweb/wallets";
137+
138+
const wallet = inAppWallet({
139+
executionMode: {
140+
mode: "EIP4337",
141+
smartAccount: { chain: baseSepolia, sponsorGas: true },
142+
},
143+
});
144+
145+
function App(){
146+
const { connect } = useConnect();
147+
148+
return (<>
149+
<button onClick={() => connect(async () => {
150+
await wallet.connect({ client, strategy: "google" });
151+
return adminWallet;
152+
})}>Connect with Google</button>
153+
</>);
154+
};`}
155+
lang="tsx"
156+
/>
157+
);
158+
}

apps/playground-web/src/app/connect/in-app-wallet/page.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ function UIIntegration() {
5353
const wallets = [
5454
inAppWallet(
5555
// built-in auth methods
56+
// or bring your own auth endpoint
5657
{ auth: {
5758
options: [
5859
"google",
@@ -70,8 +71,12 @@ function UIIntegration() {
7071
"guest",
7172
]
7273
}
74+
},
75+
// optional execution mode, defaults to "EOA"
76+
executionMode: {
77+
mode: "EIP7702", // or "EIP4337" or "EOA"
78+
sponsorGas: true, // sponsor gas for all transactions
7379
}
74-
// or bring your own auth endpoint
7580
)
7681
];
7782

0 commit comments

Comments
 (0)