Skip to content

Commit 7237de9

Browse files
[SDK] Add enclave wallet message signing and minimal account implementation
1 parent 4e6daac commit 7237de9

File tree

333 files changed

+3063
-76
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

333 files changed

+3063
-76
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import ThirdwebProvider from "@/components/thirdweb-provider";
2+
import { metadataBase } from "@/lib/constants";
3+
import type { Metadata } from "next";
4+
import { Eip7702SmartAccountPreview } from "../../../../components/account-abstraction/7702-smart-account";
5+
import { PageLayout } from "../../../../components/blocks/APIHeader";
6+
import { CodeExample } from "../../../../components/code/code-example";
7+
8+
export const metadata: Metadata = {
9+
metadataBase,
10+
title: "EIP-7702 Smart Accounts | thirdweb Connect",
11+
description:
12+
"EIP-7702 smart accounts allow you to turn your EOA into a smart account with no code changes",
13+
};
14+
15+
export default function Page() {
16+
return (
17+
<ThirdwebProvider>
18+
<PageLayout
19+
title="EIP-7702 Smart Accounts"
20+
description={
21+
<>
22+
EIP-7702 smart accounts allow you to turn your EOA into a smart
23+
account with no code changes.
24+
</>
25+
}
26+
docsLink="https://portal.thirdweb.com/connect/account-abstraction/overview?utm_source=playground"
27+
>
28+
<Eip7702SmartAccount />
29+
</PageLayout>
30+
</ThirdwebProvider>
31+
);
32+
}
33+
34+
function Eip7702SmartAccount() {
35+
return (
36+
<>
37+
<CodeExample
38+
preview={<Eip7702SmartAccountPreview />}
39+
code={`\
40+
import { claimTo } from "thirdweb/extensions/erc1155";
41+
import { TransactionButton } from "thirdweb/react";
42+
43+
const wallet = inAppWallet({
44+
executionMode: {
45+
mode: "EIP7702",
46+
sponsorGas: true,
47+
},
48+
});
49+
50+
function App() {
51+
return (
52+
<>
53+
<ConnectButton
54+
client={client}
55+
wallet={[wallet]}
56+
connectButton={{
57+
label: "Login to mint!",
58+
}}
59+
/>
60+
{/* since sponsorGas is true, transactions will be sponsored */}
61+
<TransactionButton
62+
transaction={() =>
63+
claimTo({
64+
contract,
65+
to: "0x123...",
66+
tokenId: 0n,
67+
quantity: 1n,
68+
})
69+
}
70+
>
71+
Mint
72+
</TransactionButton>
73+
</>
74+
);
75+
}`}
76+
lang="tsx"
77+
/>
78+
</>
79+
);
80+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { CodeExample } from "../../../../components/code/code-example";
1010

1111
export const metadata: Metadata = {
1212
metadataBase,
13-
title: "Sign In, Account Abstraction and SIWE Auth | thirdweb Connect",
13+
title: "Account Abstraction | thirdweb Connect",
1414
description:
1515
"Let users sign up with their email, phone number, social media accounts or directly with a wallet. Seamlessly integrate account abstraction and SIWE auth.",
1616
};

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,17 @@ import { CodeExample } from "../../../../components/code/code-example";
77

88
export const metadata: Metadata = {
99
metadataBase,
10-
title: "Sponsored transactions | thirdweb Connect",
11-
description:
12-
"Easily enable gas-free transactions for your users, Free on testnets, billed at the end of the month on mainnets.",
10+
title: "EIP-4337 Smart Contract Wallets | thirdweb Connect",
11+
description: "Turn any EOA into a smart contract wallet with EIP-4337.",
1312
};
1413

1514
export default function Page() {
1615
return (
1716
<ThirdwebProvider>
1817
<PageLayout
19-
title="Sponsored transactions"
18+
title="EIP-4337 Smart Contract Wallets"
2019
description={
21-
<>
22-
Easily enable gas-free transactions for your users, Free on
23-
testnets, billed at the end of the month on mainnets.
24-
</>
20+
<>Turn any EOA into a smart contract wallet with EIP-4337.</>
2521
}
2622
docsLink="https://portal.thirdweb.com/connect/account-abstraction/overview?utm_source=playground"
2723
>

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,19 @@ import {
4545
ConnectButton,
4646
TransactionButton,
4747
} from "thirdweb/react";
48+
import { baseSepolia } from "thirdweb/chains";
4849
4950
const wallets = [
5051
inAppWallet(
51-
// turn on gas sponsorship for in-app wallets
52-
{ smartAccount: { chain, sponsorGas: true } },
53-
),
54-
];
52+
{
53+
// turn on gas sponsorship for in-app wallets
54+
// Can use EIP4337 or EIP7702 on supported chains
55+
executionMode: {
56+
mode: "EIP4337",
57+
smartAccount: { chain: baseSepolia, sponsorGas: true },
58+
},
59+
}),
60+
];
5561
5662
function App() {
5763
return (

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,15 @@ const staticSidebarLinks: SidebarLink[] = [
5151
href: "/connect/account-abstraction/connect",
5252
},
5353
{
54-
name: "Sponsor Gas",
54+
name: "EIP-4337",
5555
href: "/connect/account-abstraction/sponsor",
5656
},
5757
{
58-
name: "Native AA (zkSync)",
58+
name: "EIP-7702",
59+
href: "/connect/account-abstraction/7702",
60+
},
61+
{
62+
name: "Native (zkSync)",
5963
href: "/connect/account-abstraction/native-aa",
6064
},
6165
],
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
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+
TransactionButton,
12+
useActiveAccount,
13+
useReadContract,
14+
} from "thirdweb/react";
15+
import { shortenHex } from "thirdweb/utils";
16+
import { inAppWallet } from "thirdweb/wallets/in-app";
17+
import { THIRDWEB_CLIENT } from "../../lib/client";
18+
19+
const chain = sepolia;
20+
const editionDropAddress = "0x7B3e0B8353Ad5cD6C60355B50550F63335752f9F";
21+
const editionDropTokenId = 1n;
22+
23+
const editionDropContract = getContract({
24+
address: editionDropAddress,
25+
chain,
26+
client: THIRDWEB_CLIENT,
27+
});
28+
29+
const iaw = inAppWallet({
30+
executionMode: {
31+
mode: "EIP7702",
32+
sponsorGas: true,
33+
},
34+
});
35+
36+
export function Eip7702SmartAccountPreview() {
37+
const [txHash, setTxHash] = useState<string | null>(null);
38+
const activeEOA = useActiveAccount();
39+
const { data: nft, isLoading: isNftLoading } = useReadContract(getNFT, {
40+
contract: editionDropContract,
41+
tokenId: editionDropTokenId,
42+
});
43+
const { data: ownedNfts } = useReadContract(getOwnedNFTs, {
44+
contract: editionDropContract,
45+
// biome-ignore lint/style/noNonNullAssertion: handled by queryOptions
46+
address: activeEOA?.address!,
47+
queryOptions: { enabled: !!activeEOA },
48+
});
49+
50+
return (
51+
<div className="flex flex-col items-center justify-center gap-4">
52+
{isNftLoading ? (
53+
<div className="mt-24 w-full">Loading...</div>
54+
) : (
55+
<>
56+
<div className="flex flex-col justify-center gap-2 p-2">
57+
<ConnectButton
58+
client={THIRDWEB_CLIENT}
59+
chain={sepolia}
60+
wallets={[iaw]}
61+
connectButton={{
62+
label: "Login to mint!",
63+
}}
64+
/>
65+
</div>
66+
{nft ? (
67+
<MediaRenderer
68+
client={THIRDWEB_CLIENT}
69+
src={nft.metadata.image}
70+
style={{ width: "300px", marginTop: "10px" }}
71+
/>
72+
) : null}
73+
{activeEOA ? (
74+
<div className="flex flex-col justify-center gap-4 p-2">
75+
{/* <p className="mb-2 text-center font-semibold">
76+
You own {ownedNfts?.[0]?.quantityOwned.toString() || "0"}{" "}
77+
{nft?.metadata?.name}
78+
</p> */}
79+
<TransactionButton
80+
transaction={() =>
81+
claimTo({
82+
contract: editionDropContract,
83+
tokenId: editionDropTokenId,
84+
to: activeEOA.address,
85+
quantity: 1n,
86+
})
87+
}
88+
payModal={{
89+
metadata: nft?.metadata,
90+
}}
91+
onError={(error) => {
92+
alert(`Error: ${error.message}`);
93+
}}
94+
onClick={() => {
95+
setTxHash(null);
96+
}}
97+
onTransactionSent={async (tx) => {
98+
setTxHash(tx.transactionHash);
99+
}}
100+
>
101+
Mint with EIP-7702
102+
</TransactionButton>
103+
</div>
104+
) : null}
105+
{txHash ? (
106+
<div className="flex flex-col justify-center p-2">
107+
<p className="mb-2 text-center text-green-500">
108+
Minted! Tx Hash:{" "}
109+
<a
110+
href={`${chain.blockExplorers?.[0]?.url}/tx/${txHash}`}
111+
target="_blank"
112+
rel="noopener noreferrer"
113+
className="underline"
114+
>
115+
{shortenHex(txHash)}
116+
</a>
117+
</p>
118+
</div>
119+
) : null}
120+
</>
121+
)}
122+
</div>
123+
);
124+
}

apps/playground-web/src/components/account-abstraction/sponsored-tx.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function SponsoredTxPreview() {
4040
});
4141

4242
return (
43-
<div className="flex flex-col items-center justify-center">
43+
<div className="flex flex-col items-center justify-center gap-4">
4444
{isNftLoading ? (
4545
<div className="mt-24 w-full">Loading...</div>
4646
) : (
@@ -63,15 +63,15 @@ export function SponsoredTxPreview() {
6363
<MediaRenderer
6464
client={THIRDWEB_CLIENT}
6565
src={nft.metadata.image}
66-
style={{ width: "400px", marginTop: "10px" }}
66+
style={{ width: "300px", marginTop: "10px" }}
6767
/>
6868
) : null}
6969
{smartAccount ? (
7070
<div className="flex flex-col justify-center p-2">
71-
<p className="mb-2 text-center font-semibold">
71+
{/* <p className="mb-2 text-center font-semibold">
7272
You own {ownedNfts?.[0]?.quantityOwned.toString() || "0"}{" "}
7373
Kittens
74-
</p>
74+
</p> */}
7575
<TransactionButton
7676
transaction={() =>
7777
claimTo({
@@ -94,7 +94,7 @@ export function SponsoredTxPreview() {
9494
setTxHash(receipt.transactionHash);
9595
}}
9696
>
97-
Mint
97+
Mint with EIP-4337
9898
</TransactionButton>
9999
</div>
100100
) : null}

apps/playground-web/src/components/in-app-wallet/sponsored-tx.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ export function SponsoredInAppTxPreview() {
4444
"guest",
4545
],
4646
},
47-
smartAccount: {
48-
chain: baseSepolia,
49-
sponsorGas: true,
47+
// TODO (7702): update to 7702 once pectra is out
48+
executionMode: {
49+
mode: "EIP4337",
50+
smartAccount: {
51+
chain: baseSepolia,
52+
sponsorGas: true,
53+
},
5054
},
5155
}),
5256
]}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[
2+
"error AllowanceExceeded(uint256 allowanceUsage, uint256 limit, uint64 period)",
3+
"error CallPolicyViolated(address target, bytes4 selector)",
4+
"error CallReverted()",
5+
"error ConditionFailed(bytes32 param, bytes32 refValue, uint8 condition)",
6+
"error InvalidDataLength(uint256 actualLength, uint256 expectedLength)",
7+
"error InvalidSignature(address msgSender, address thisAddress)",
8+
"error LifetimeUsageExceeded(uint256 lifetimeUsage, uint256 limit)",
9+
"error MaxValueExceeded(uint256 value, uint256 maxValuePerUse)",
10+
"error NoCallsToExecute()",
11+
"error SessionExpired()",
12+
"error SessionExpiresTooSoon()",
13+
"error SessionZeroSigner()",
14+
"error TransferPolicyViolated(address target)",
15+
"error UIDAlreadyProcessed()",
16+
"event Executed(address indexed to, uint256 value, bytes data)",
17+
"event SessionCreated(address indexed signer, (address signer, bool isWildcard, uint256 expiresAt, (address target, bytes4 selector, uint256 maxValuePerUse, (uint8 limitType, uint256 limit, uint256 period) valueLimit, (uint8 condition, uint64 index, bytes32 refValue, (uint8 limitType, uint256 limit, uint256 period) limit)[] constraints)[] callPolicies, (address target, uint256 maxValuePerUse, (uint8 limitType, uint256 limit, uint256 period) valueLimit)[] transferPolicies, bytes32 uid) sessionSpec)",
18+
"function createSessionWithSig((address signer, bool isWildcard, uint256 expiresAt, (address target, bytes4 selector, uint256 maxValuePerUse, (uint8 limitType, uint256 limit, uint256 period) valueLimit, (uint8 condition, uint64 index, bytes32 refValue, (uint8 limitType, uint256 limit, uint256 period) limit)[] constraints)[] callPolicies, (address target, uint256 maxValuePerUse, (uint8 limitType, uint256 limit, uint256 period) valueLimit)[] transferPolicies, bytes32 uid) sessionSpec, bytes signature)",
19+
"function eip712Domain() view returns (bytes1 fields, string name, string version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] extensions)",
20+
"function execute((address target, uint256 value, bytes data)[] calls) payable",
21+
"function executeWithSig(((address target, uint256 value, bytes data)[] calls, bytes32 uid) wrappedCalls, bytes signature) payable",
22+
"function getCallPoliciesForSigner(address signer) view returns ((address target, bytes4 selector, uint256 maxValuePerUse, (uint8 limitType, uint256 limit, uint256 period) valueLimit, (uint8 condition, uint64 index, bytes32 refValue, (uint8 limitType, uint256 limit, uint256 period) limit)[] constraints)[])",
23+
"function getSessionExpirationForSigner(address signer) view returns (uint256)",
24+
"function getSessionStateForSigner(address signer) view returns (((uint256 remaining, address target, bytes4 selector, uint256 index)[] transferValue, (uint256 remaining, address target, bytes4 selector, uint256 index)[] callValue, (uint256 remaining, address target, bytes4 selector, uint256 index)[] callParams))",
25+
"function getTransferPoliciesForSigner(address signer) view returns ((address target, uint256 maxValuePerUse, (uint8 limitType, uint256 limit, uint256 period) valueLimit)[])",
26+
"function isWildcardSigner(address signer) view returns (bool)"
27+
]

packages/thirdweb/scripts/generate/generate.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ export function ${f.name}(
336336
nonce: async () => (await asyncOptions()).overrides?.nonce,
337337
extraGas: async () => (await asyncOptions()).overrides?.extraGas,
338338
erc20Value: async () => (await asyncOptions()).overrides?.erc20Value,
339+
authorizationList: async () => (await asyncOptions()).overrides?.authorizationList,
339340
`
340341
: ""
341342
}
@@ -885,7 +886,7 @@ async function main() {
885886
for (const folder of folders) {
886887
const OUT_PATH = join(EXTENSIONS_FOLDER, folder, "__generated__");
887888
// delete the "__generated__" folder inside the extension folder
888-
await rmdir(OUT_PATH, { recursive: true });
889+
await rmdir(OUT_PATH, { recursive: true }).catch(() => {});
889890

890891
// create the "__generated__" folder inside the extension folder
891892
await mkdir(OUT_PATH, { recursive: true });

packages/thirdweb/src/contract/actions/get-bytecode.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export function getBytecode(contract: ThirdwebContract): Promise<Hex> {
2727
address: contract.address,
2828
blockTag: "latest",
2929
});
30+
console.log("getBytecode", result);
3031
if (result === "0x") {
3132
BYTECODE_CACHE.delete(contract);
3233
}

0 commit comments

Comments
 (0)