Skip to content

Commit 462f0e8

Browse files
Add EIP-5792 support for wallet_sendCalls and wallet_getCallsStatus
1 parent 1586f15 commit 462f0e8

File tree

7 files changed

+191
-91
lines changed

7 files changed

+191
-91
lines changed

apps/wagmi-demo/src/App.tsx

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import type { ConnectionOptions } from "@thirdweb-dev/wagmi-adapter";
22
import { ConnectButton } from "thirdweb/react";
33
import {
44
useAccount,
5+
useCallsStatus,
56
useConnect,
67
useDisconnect,
8+
useSendCalls,
79
useSendTransaction,
810
} from "wagmi";
9-
import { chain, client } from "./wagmi.js";
11+
import { chain, client, thirdwebChainForWallet, wallet } from "./wagmi.js";
1012

1113
function App() {
1214
const account = useAccount();
@@ -20,6 +22,17 @@ function App() {
2022
error: sendTxError,
2123
data: sendTxData,
2224
} = useSendTransaction();
25+
const { sendCalls, data, isPending: isPendingSendCalls } = useSendCalls();
26+
const {
27+
data: callStatus,
28+
isLoading: isLoadingCallStatus,
29+
error: callStatusError,
30+
} = useCallsStatus({
31+
id: data?.id || "",
32+
query: {
33+
enabled: !!data?.id,
34+
},
35+
});
2336
return (
2437
<>
2538
<div>
@@ -44,6 +57,8 @@ function App() {
4457
<h2>Connect</h2>
4558
<ConnectButton
4659
client={client}
60+
chain={thirdwebChainForWallet}
61+
wallets={[wallet]}
4762
onConnect={(wallet) => {
4863
// auto connect to wagmi on tw connect
4964
const twConnector = connectors.find(
@@ -95,14 +110,40 @@ function App() {
95110
>
96111
Send Tx
97112
</button>
98-
<div>{isPending ? "Sending..." : ""}</div>
113+
<button
114+
onClick={() =>
115+
sendCalls({
116+
calls: [
117+
{
118+
to: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
119+
value: 0n,
120+
},
121+
],
122+
})
123+
}
124+
type="button"
125+
>
126+
Send Calls
127+
</button>
128+
<div>
129+
{isPending || isPendingSendCalls || isLoadingCallStatus
130+
? "Sending..."
131+
: ""}
132+
</div>
99133
<div>
100134
{isSuccess
101135
? `Success: ${sendTxData}`
102136
: isError
103137
? sendTxError?.message
104138
: ""}
105139
</div>
140+
<div>
141+
{callStatus
142+
? `Success: ${JSON.stringify(callStatus, null, 2)}`
143+
: callStatusError
144+
? callStatusError?.message
145+
: ""}
146+
</div>
106147
</div>
107148
)}
108149
</>

apps/wagmi-demo/src/wagmi.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { inAppWalletConnector } from "@thirdweb-dev/wagmi-adapter";
22
import { createThirdwebClient, defineChain as thirdwebChain } from "thirdweb";
3+
import { inAppWallet } from "thirdweb/wallets/in-app";
34
import { createConfig, http } from "wagmi";
45
import { baseSepolia } from "wagmi/chains";
56

@@ -15,6 +16,13 @@ export const client = createThirdwebClient({
1516
clientId,
1617
});
1718

19+
export const wallet = inAppWallet({
20+
executionMode: {
21+
mode: "EIP7702",
22+
sponsorGas: true,
23+
},
24+
});
25+
1826
export const chain = baseSepolia;
1927
export const thirdwebChainForWallet = thirdwebChain(baseSepolia.id);
2028

@@ -23,8 +31,8 @@ export const config = createConfig({
2331
connectors: [
2432
inAppWalletConnector({
2533
client,
26-
smartAccount: {
27-
chain: thirdwebChain(chain.id),
34+
executionMode: {
35+
mode: "EIP7702",
2836
sponsorGas: true,
2937
},
3038
}),

packages/thirdweb/src/adapters/eip1193/to-eip1193.ts

Lines changed: 123 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -64,100 +64,138 @@ export function toProvider(options: ToEip1193ProviderOptions): EIP1193Provider {
6464
// should invoke the return fn from subscribe instead
6565
},
6666
request: async (request) => {
67-
if (request.method === "eth_sendTransaction") {
68-
const account = wallet.getAccount();
69-
if (!account) {
70-
throw new Error("Account not connected");
67+
switch (request.method) {
68+
case "eth_sendTransaction": {
69+
const account = wallet.getAccount();
70+
if (!account) {
71+
throw new Error("Account not connected");
72+
}
73+
const result = await sendTransaction({
74+
account: account,
75+
transaction: prepareTransaction({
76+
...request.params[0],
77+
chain,
78+
client,
79+
}),
80+
});
81+
return result.transactionHash;
7182
}
72-
const result = await sendTransaction({
73-
account: account,
74-
transaction: prepareTransaction({
75-
...request.params[0],
76-
chain,
77-
client,
78-
}),
79-
});
80-
return result.transactionHash;
81-
}
82-
if (request.method === "eth_estimateGas") {
83-
const account = wallet.getAccount();
84-
if (!account) {
85-
throw new Error("Account not connected");
83+
case "eth_estimateGas": {
84+
const account = wallet.getAccount();
85+
if (!account) {
86+
throw new Error("Account not connected");
87+
}
88+
return estimateGas({
89+
account,
90+
transaction: prepareTransaction({
91+
...request.params[0],
92+
chain,
93+
client,
94+
}),
95+
});
8696
}
87-
return estimateGas({
88-
account,
89-
transaction: prepareTransaction({
90-
...request.params[0],
91-
chain,
92-
client,
93-
}),
94-
});
95-
}
96-
if (request.method === "personal_sign") {
97-
const account = wallet.getAccount();
98-
if (!account) {
99-
throw new Error("Account not connected");
97+
case "personal_sign": {
98+
const account = wallet.getAccount();
99+
if (!account) {
100+
throw new Error("Account not connected");
101+
}
102+
return account.signMessage({
103+
message: {
104+
raw: request.params[0],
105+
},
106+
});
100107
}
101-
return account.signMessage({
102-
message: {
103-
raw: request.params[0],
104-
},
105-
});
106-
}
107-
if (request.method === "eth_signTypedData_v4") {
108-
const account = wallet.getAccount();
109-
if (!account) {
110-
throw new Error("Account not connected");
108+
case "eth_signTypedData_v4": {
109+
const account = wallet.getAccount();
110+
if (!account) {
111+
throw new Error("Account not connected");
112+
}
113+
const data = JSON.parse(request.params[1]);
114+
return account.signTypedData(data);
111115
}
112-
const data = JSON.parse(request.params[1]);
113-
return account.signTypedData(data);
114-
}
115-
if (request.method === "eth_accounts") {
116-
const account = wallet.getAccount();
117-
if (!account) {
118-
return [];
116+
case "eth_accounts": {
117+
const account = wallet.getAccount();
118+
if (!account) {
119+
return [];
120+
}
121+
return [account.address];
119122
}
120-
return [account.address];
121-
}
122-
if (request.method === "eth_requestAccounts") {
123-
const connectedAccount = wallet.getAccount();
124-
if (connectedAccount) {
125-
return [connectedAccount.address];
123+
case "eth_requestAccounts": {
124+
const connectedAccount = wallet.getAccount();
125+
if (connectedAccount) {
126+
return [connectedAccount.address];
127+
}
128+
const account = connectOverride
129+
? await connectOverride(wallet)
130+
: await wallet
131+
.connect({
132+
client,
133+
})
134+
.catch((e) => {
135+
console.error("Error connecting wallet", e);
136+
return null;
137+
});
138+
if (!account) {
139+
throw new Error(
140+
"Unable to connect wallet - try passing a connectOverride function",
141+
);
142+
}
143+
return [account.address];
126144
}
127-
const account = connectOverride
128-
? await connectOverride(wallet)
129-
: await wallet
130-
.connect({
131-
client,
132-
})
133-
.catch((e) => {
134-
console.error("Error connecting wallet", e);
135-
return null;
136-
});
137-
if (!account) {
138-
throw new Error(
139-
"Unable to connect wallet - try passing a connectOverride function",
140-
);
145+
case "wallet_switchEthereumChain":
146+
case "wallet_addEthereumChain": {
147+
const data = request.params[0];
148+
const chainIdHex = data.chainId;
149+
if (!chainIdHex) {
150+
throw new Error("Chain ID is required");
151+
}
152+
// chainId is hex most likely, convert to number
153+
const chainId = isHex(chainIdHex)
154+
? hexToNumber(chainIdHex)
155+
: chainIdHex;
156+
const chain = getCachedChain(chainId);
157+
return wallet.switchChain(chain);
141158
}
142-
return [account.address];
143-
}
144-
if (
145-
request.method === "wallet_switchEthereumChain" ||
146-
request.method === "wallet_addEthereumChain"
147-
) {
148-
const data = request.params[0];
149-
const chainIdHex = data.chainId;
150-
if (!chainIdHex) {
151-
throw new Error("Chain ID is required");
159+
case "wallet_getCapabilities": {
160+
const account = wallet.getAccount();
161+
if (!account) {
162+
throw new Error("Account not connected");
163+
}
164+
if (!account.getCapabilities) {
165+
throw new Error("Wallet does not support EIP-5792");
166+
}
167+
return account.getCapabilities({ chainId: chain.id });
168+
}
169+
case "wallet_sendCalls": {
170+
const account = wallet.getAccount();
171+
if (!account) {
172+
throw new Error("Account not connected");
173+
}
174+
if (!account.sendCalls) {
175+
throw new Error("Wallet does not support EIP-5792");
176+
}
177+
return account.sendCalls({
178+
...request.params[0],
179+
chain: chain,
180+
});
181+
}
182+
case "wallet_getCallsStatus": {
183+
const account = wallet.getAccount();
184+
if (!account) {
185+
throw new Error("Account not connected");
186+
}
187+
if (!account.getCallsStatus) {
188+
throw new Error("Wallet does not support EIP-5792");
189+
}
190+
return account.getCallsStatus({
191+
id: request.params[0],
192+
chain: chain,
193+
client: client,
194+
});
152195
}
153-
// chainId is hex most likely, convert to number
154-
const chainId = isHex(chainIdHex)
155-
? hexToNumber(chainIdHex)
156-
: chainIdHex;
157-
const chain = getCachedChain(chainId);
158-
return wallet.switchChain(chain);
196+
default:
197+
return rpcClient(request);
159198
}
160-
return rpcClient(request);
161199
},
162200
};
163201
}

packages/thirdweb/src/wallets/in-app/core/eip5792/in-app-wallet-calls.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { eth_getTransactionReceipt } from "../../../../rpc/actions/eth_getTransa
44
import { getRpcClient } from "../../../../rpc/rpc.js";
55
import { sendAndConfirmTransaction } from "../../../../transaction/actions/send-and-confirm-transaction.js";
66
import { sendBatchTransaction } from "../../../../transaction/actions/send-batch-transaction.js";
7+
import type { SendTransactionOptions } from "../../../../transaction/actions/send-transaction.js";
78
import { LruMap } from "../../../../utils/caching/lru.js";
89
import type { Hex } from "../../../../utils/encoding/hex.js";
910
import { randomBytesHex } from "../../../../utils/random.js";
@@ -22,21 +23,29 @@ const bundlesToTransactions = new LruMap<Hex[]>(1000);
2223
export async function inAppWalletSendCalls(args: {
2324
account: Account;
2425
calls: PreparedSendCall[];
26+
chain: Chain;
2527
}): Promise<string> {
2628
const { account, calls } = args;
2729

30+
const transactions: SendTransactionOptions["transaction"][] = calls.map(
31+
(call) => ({
32+
...call,
33+
chain: args.chain,
34+
}),
35+
);
36+
2837
const hashes: Hex[] = [];
2938
const id = randomBytesHex(65);
3039
bundlesToTransactions.set(id, hashes);
3140
if (account.sendBatchTransaction) {
3241
const receipt = await sendBatchTransaction({
3342
account,
34-
transactions: calls,
43+
transactions,
3544
});
3645
hashes.push(receipt.transactionHash);
3746
bundlesToTransactions.set(id, hashes);
3847
} else {
39-
for (const tx of calls) {
48+
for (const tx of transactions) {
4049
const receipt = await sendAndConfirmTransaction({
4150
account,
4251
transaction: tx,

packages/thirdweb/src/wallets/in-app/core/eip7702/minimal-account.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ export const create7702MinimalAccount = (args: {
341341
const id = await inAppWalletSendCalls({
342342
account: minimalAccount,
343343
calls: options.calls,
344+
chain,
344345
});
345346
return { chain, client, id };
346347
},

packages/thirdweb/src/wallets/in-app/core/wallet/enclave-wallet.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ export class EnclaveWallet implements IWebWallet {
277277
const id = await inAppWalletSendCalls({
278278
account: account,
279279
calls: options.calls,
280+
chain,
280281
});
281282
return { chain, client, id };
282283
},

0 commit comments

Comments
 (0)