feat(playground): zksync in playground + gasPerPubData increase (#4291)

This commit is contained in:
Joaquim Verges
2024-08-28 00:51:05 +12:00
committed by GitHub
parent 98493314fb
commit f346bb8fca
13 changed files with 402 additions and 85 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"thirdweb": patch
---
ZkSync gasPubPerData increase for faster inclusion
+5
View File
@@ -56,6 +56,11 @@ const nextConfig = {
destination: "/connect/sign-in/button",
permanent: false,
},
{
source: "/connect/account-abstraction",
destination: "/connect/account-abstraction/connect",
permanent: false,
},
];
},
};
@@ -3,10 +3,9 @@ import type { Metadata } from "next";
import {
ConnectSmartAccountCustomPreview,
ConnectSmartAccountPreview,
} from "../../../components/account-abstraction/connect-smart-account";
import { SponsoredTxPreview } from "../../../components/account-abstraction/sponsored-tx";
import { APIHeader } from "../../../components/blocks/APIHeader";
import { CodeExample } from "../../../components/code/code-example";
} from "../../../../components/account-abstraction/connect-smart-account";
import { APIHeader } from "../../../../components/blocks/APIHeader";
import { CodeExample } from "../../../../components/code/code-example";
export const metadata: Metadata = {
metadataBase,
@@ -34,12 +33,6 @@ export default function Page() {
<section className="space-y-8">
<ConnectSmartAccount />
</section>
<div className="h-14" />
<section className="space-y-8">
<SponsoredTx />
</section>
</main>
);
}
@@ -84,40 +77,10 @@ accountAbstraction={{ chain, sponsorGas: true }} />
<button onClick={() => connect(async () => {
// any wallet connected here will be
// converted to a smart account
const adminWallet = createWallet("io.metamask");
await adminWallet.connect({ client });
const adminWallet = inAppWallet();
await adminWallet.connect({ client, strategy: "google" });
return adminWallet;
})}>Connect (metamask)</button>
</>);
};`}
lang="tsx"
/>
</>
);
}
function SponsoredTx() {
return (
<>
<div className="space-y-2">
<h2 className="text-2xl sm:text-3xl font-semibold tracking-tight">
Sponsored transactions
</h2>
<p className="max-w-[600px]">
Set `sponsorGas: true` to enable gas-free transactions for your users.
<br />
Free on testnets, billed at the end of the month on mainnets.
</p>
</div>
<CodeExample
preview={<SponsoredTxPreview />}
code={`import { claimTo } from "thirdweb/extensions/erc1155";
import { TransactionButton } from "thirdweb/react";
function App(){
return (<>
{/* transactions will be sponsored */}
<TransactionButton transaction={() => claimTo({ contract, to: "0x123...", tokenId: 0n, quantity: 1n })}>Mint</TransactionButton>
})}>Connect with Google</button>
</>);
};`}
lang="tsx"
@@ -0,0 +1,74 @@
import { metadataBase } from "@/lib/constants";
import type { Metadata } from "next";
import { SponsoredTxZksyncPreview } from "../../../../components/account-abstraction/sponsored-tx-zksync";
import { APIHeader } from "../../../../components/blocks/APIHeader";
import { CodeExample } from "../../../../components/code/code-example";
export const metadata: Metadata = {
metadataBase,
title: "Sign In, Account Abstraction and SIWE Auth | thirdweb Connect",
description:
"Let users sign up with their email, phone number, social media accounts or directly with a wallet. Seamlessly integrate account abstraction and SIWE auth.",
};
export default function Page() {
return (
<main className="pb-20 container px-0">
<APIHeader
title="Account Abstraction"
description={
<>
Let users connect to their smart accounts with any wallet and unlock
gas sponsorship, batched transactions, session keys and full wallet
programmability.
</>
}
docsLink="https://portal.thirdweb.com/connect/account-abstraction/overview"
heroLink="/account-abstraction.png"
/>
<section className="space-y-8">
<SponsoredZksyncTx />
</section>
</main>
);
}
function SponsoredZksyncTx() {
return (
<>
<div className="space-y-2">
<h2 className="text-2xl sm:text-3xl font-semibold tracking-tight">
Native Account Abstraction
</h2>
<p className="max-w-[600px]">
On zkSync chains, you can take advantage of native account abstraction
no code changes. The `sponsorGas` option also works out of the box.
</p>
</div>
<CodeExample
preview={<SponsoredTxZksyncPreview />}
code={`import { claimTo } from "thirdweb/extensions/erc1155";
import { TransactionButton } from "thirdweb/react";
function App(){
return (<>
<ConnectButton
client={client}
accountAbstraction={{
chain: zkSyncSepolia, // zkSync chain with native AA
sponsorGas: true, // sponsor gas for all transactions
}}
connectButton={{
label: "Login to mint this Kitten!",
}}
/>
{/* since sponsorGas is true, transactions will be sponsored */}
<TransactionButton transaction={() => claimTo({ contract, to: "0x123...", tokenId: 0n, quantity: 1n })}>Mint</TransactionButton>
</>);
};`}
lang="tsx"
/>
</>
);
}
@@ -0,0 +1,75 @@
import { metadataBase } from "@/lib/constants";
import type { Metadata } from "next";
import { SponsoredTxPreview } from "../../../../components/account-abstraction/sponsored-tx";
import { APIHeader } from "../../../../components/blocks/APIHeader";
import { CodeExample } from "../../../../components/code/code-example";
export const metadata: Metadata = {
metadataBase,
title: "Sign In, Account Abstraction and SIWE Auth | thirdweb Connect",
description:
"Let users sign up with their email, phone number, social media accounts or directly with a wallet. Seamlessly integrate account abstraction and SIWE auth.",
};
export default function Page() {
return (
<main className="pb-20 container px-0">
<APIHeader
title="Account Abstraction"
description={
<>
Let users connect to their smart accounts with any wallet and unlock
gas sponsorship, batched transactions, session keys and full wallet
programmability.
</>
}
docsLink="https://portal.thirdweb.com/connect/account-abstraction/overview"
heroLink="/account-abstraction.png"
/>
<section className="space-y-8">
<SponsoredTx />
</section>
</main>
);
}
function SponsoredTx() {
return (
<>
<div className="space-y-2">
<h2 className="text-2xl sm:text-3xl font-semibold tracking-tight">
Sponsored transactions
</h2>
<p className="max-w-[600px]">
Set `sponsorGas: true` to enable gas-free transactions for your users.
<br />
Free on testnets, billed at the end of the month on mainnets.
</p>
</div>
<CodeExample
preview={<SponsoredTxPreview />}
code={`import { claimTo } from "thirdweb/extensions/erc1155";
import { TransactionButton } from "thirdweb/react";
function App(){
return (<>
<ConnectButton
client={client}
accountAbstraction={{
chain,
sponsorGas: true, // sponsor gas for all transactions
}}
connectButton={{
label: "Login to mint this Kitten!",
}}
/>
{/* since sponsorGas is true, transactions will be sponsored */}
<TransactionButton transaction={() => claimTo({ contract, to: "0x123...", tokenId: 0n, quantity: 1n })}>Mint</TransactionButton>
</>);
};`}
lang="tsx"
/>
</>
);
}
+15 -1
View File
@@ -21,7 +21,21 @@ export const navLinks: SidebarLink[] = [
},
{
name: "Account Abstraction",
href: "/connect/account-abstraction",
expanded: true,
links: [
{
name: "Connect",
href: "/connect/account-abstraction/connect",
},
{
name: "Sponsor Gas",
href: "/connect/account-abstraction/sponsor",
},
{
name: "Native AA (zkSync)",
href: "/connect/account-abstraction/native-aa",
},
],
},
{
name: "in-App wallet",
@@ -1,18 +1,19 @@
"use client";
import { useEffect } from "react";
import { baseSepolia } from "thirdweb/chains";
import {
useActiveAccount,
useActiveWallet,
useConnect,
useDisconnect,
useWalletBalance,
} from "thirdweb/react";
import { shortenAddress } from "thirdweb/utils";
import { createWallet } from "thirdweb/wallets";
import { inAppWallet, socialIcons } from "thirdweb/wallets/in-app";
import { THIRDWEB_CLIENT } from "../../lib/client";
import { StyledConnectButton } from "../styled-connect-button";
import { Button } from "../ui/button";
import { chain } from "./constants";
export function ConnectSmartAccountPreview() {
// force disconnect if not smart wallet already
@@ -27,7 +28,7 @@ export function ConnectSmartAccountPreview() {
<div className="flex flex-col">
<StyledConnectButton
accountAbstraction={{
chain,
chain: baseSepolia,
sponsorGas: true,
}}
/>
@@ -40,15 +41,22 @@ export function ConnectSmartAccountCustomPreview() {
const wallet = useActiveWallet();
const connectMutation = useConnect({
client: THIRDWEB_CLIENT,
accountAbstraction: { chain, sponsorGas: true },
accountAbstraction: { chain: baseSepolia, sponsorGas: true },
});
const { disconnect } = useDisconnect();
const balanceQuery = useWalletBalance({
client: THIRDWEB_CLIENT,
address: account?.address,
chain: baseSepolia,
});
const connect = async () => {
const wallet = await connectMutation.connect(async () => {
const adminWallet = createWallet("io.metamask");
const adminWallet = inAppWallet();
await adminWallet.connect({
client: THIRDWEB_CLIENT,
strategy: "google",
chain: baseSepolia,
});
return adminWallet;
});
@@ -59,14 +67,25 @@ export function ConnectSmartAccountCustomPreview() {
<div className="flex flex-col">
{account && wallet ? (
<>
<p className="py-4">Connected as {shortenAddress(account.address)}</p>
<div className="py-4">
<p>Smart Account: {shortenAddress(account.address)}</p>
<p>
Balance: {balanceQuery.data?.displayValue}{" "}
{balanceQuery.data?.symbol}
</p>
</div>
<Button variant={"outline"} onClick={() => disconnect(wallet)}>
Disconnect
</Button>
</>
) : (
<Button variant={"default"} onClick={connect}>
Connect (metamask)
<Button
variant={"default"}
onClick={connect}
className="p-6 rounded-full"
>
<img src={socialIcons.google} alt="Google" className="w-4 h-4 mr-2" />{" "}
Connect with Google
</Button>
)}
</div>
@@ -1,13 +0,0 @@
import { getContract } from "thirdweb";
import { baseSepolia } from "thirdweb/chains";
import { THIRDWEB_CLIENT } from "../../lib/client";
export const chain = baseSepolia;
export const editionDropAddress = "0x638263e3eAa3917a53630e61B1fBa685308024fa";
export const editionDropTokenId = 1n;
export const editionDropContract = getContract({
address: editionDropAddress,
chain,
client: THIRDWEB_CLIENT,
});
@@ -0,0 +1,133 @@
"use client";
import { useEffect, useState } from "react";
import { getContract } from "thirdweb";
import { zkSyncSepolia } from "thirdweb/chains";
import { claimTo, getNFT, getOwnedNFTs } from "thirdweb/extensions/erc1155";
import {
ConnectButton,
MediaRenderer,
TransactionButton,
useActiveAccount,
useActiveWallet,
useActiveWalletChain,
useDisconnect,
useReadContract,
} from "thirdweb/react";
import { shortenHex } from "thirdweb/utils";
import { THIRDWEB_CLIENT } from "../../lib/client";
import { WALLETS } from "../../lib/constants";
const chain = zkSyncSepolia;
const editionDropContract = getContract({
client: THIRDWEB_CLIENT,
address: "0xd563ACBeD80e63B257B2524562BdD7Ec666eEE77",
chain,
});
const editionDropTokenId = 0n;
export function SponsoredTxZksyncPreview() {
const [txHash, setTxHash] = useState<string | null>(null);
const wallet = useActiveWallet();
const { disconnect } = useDisconnect();
const activeChain = useActiveWalletChain();
useEffect(() => {
if (
wallet &&
(wallet.id !== "smart" ||
(activeChain && activeChain?.id !== zkSyncSepolia.id))
) {
disconnect(wallet);
}
}, [wallet, disconnect, activeChain]);
const smartAccount = useActiveAccount();
const { data: nft, isLoading: isNftLoading } = useReadContract(getNFT, {
contract: editionDropContract,
tokenId: editionDropTokenId,
});
const { data: ownedNfts } = useReadContract(getOwnedNFTs, {
contract: editionDropContract,
// biome-ignore lint/style/noNonNullAssertion: handled by queryOptions
address: smartAccount?.address!,
queryOptions: { enabled: !!smartAccount },
});
return (
<div className="flex flex-col justify-center items-center">
{isNftLoading ? (
<div className="w-full mt-24">Loading...</div>
) : (
<>
<div className="flex flex-col justify-center p-2 gap-2">
<ConnectButton
client={THIRDWEB_CLIENT}
chain={chain}
wallets={WALLETS}
accountAbstraction={{
chain,
sponsorGas: true,
}}
connectButton={{
label: "Login to mint this Kitten!",
}}
/>
</div>
{nft ? (
<MediaRenderer
client={THIRDWEB_CLIENT}
src={nft.metadata.image}
style={{ width: "400px", marginTop: "10px" }}
/>
) : null}
{smartAccount ? (
<div className="flex flex-col justify-center p-2">
<p className="font-semibold text-center mb-2">
You own {ownedNfts?.[0]?.quantityOwned.toString() || "0"}{" "}
Kittens
</p>
<TransactionButton
transaction={() =>
claimTo({
contract: editionDropContract,
tokenId: editionDropTokenId,
to: smartAccount.address,
quantity: 1n,
})
}
payModal={{
metadata: nft?.metadata,
}}
onError={(error) => {
alert(`Error: ${error.message}`);
}}
onClick={() => {
setTxHash(null);
}}
onTransactionConfirmed={async (receipt) => {
setTxHash(receipt.transactionHash);
}}
>
Mint
</TransactionButton>
</div>
) : null}
{txHash ? (
<div className="flex flex-col justify-center p-2">
<p className="text-green-500 text-center mb-2">
Minted! Tx Hash:{" "}
<a
href={`${chain.blockExplorers?.[0]?.url}/tx/${txHash}`}
target="_blank"
rel="noopener noreferrer"
className="underline"
>
{shortenHex(txHash)}
</a>
</p>
</div>
) : null}
</>
)}
</div>
);
}
@@ -1,8 +1,11 @@
"use client";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { getContract } from "thirdweb";
import { baseSepolia } from "thirdweb/chains";
import { claimTo, getNFT, getOwnedNFTs } from "thirdweb/extensions/erc1155";
import {
ConnectButton,
MediaRenderer,
TransactionButton,
useActiveAccount,
@@ -10,10 +13,22 @@ import {
useDisconnect,
useReadContract,
} from "thirdweb/react";
import { shortenHex } from "thirdweb/utils";
import { THIRDWEB_CLIENT } from "../../lib/client";
import { editionDropContract, editionDropTokenId } from "./constants";
import { WALLETS } from "../../lib/constants";
export const chain = baseSepolia;
export const editionDropAddress = "0x638263e3eAa3917a53630e61B1fBa685308024fa";
export const editionDropTokenId = 1n;
export const editionDropContract = getContract({
address: editionDropAddress,
chain,
client: THIRDWEB_CLIENT,
});
export function SponsoredTxPreview() {
const [txHash, setTxHash] = useState<string | null>(null);
const wallet = useActiveWallet();
const { disconnect } = useDisconnect();
useEffect(() => {
@@ -34,11 +49,25 @@ export function SponsoredTxPreview() {
});
return (
<div className="flex flex-col">
<div className="flex flex-col justify-center items-center">
{isNftLoading ? (
<div className="w-full mt-24">Loading...</div>
) : (
<>
<div className="flex flex-col justify-center p-2 gap-2">
<ConnectButton
client={THIRDWEB_CLIENT}
chain={chain}
wallets={WALLETS}
accountAbstraction={{
chain,
sponsorGas: true,
}}
connectButton={{
label: "Login to mint this Kitten!",
}}
/>
</div>
{nft ? (
<MediaRenderer
client={THIRDWEB_CLIENT}
@@ -47,7 +76,7 @@ export function SponsoredTxPreview() {
/>
) : null}
{smartAccount ? (
<div className="flex flex-col justify-center p-8">
<div className="flex flex-col justify-center p-2">
<p className="font-semibold text-center mb-2">
You own {ownedNfts?.[0]?.quantityOwned.toString() || "0"}{" "}
Kittens
@@ -67,24 +96,32 @@ export function SponsoredTxPreview() {
onError={(error) => {
alert(`Error: ${error.message}`);
}}
onTransactionConfirmed={async () => {
alert("Minted successful!");
onClick={() => {
setTxHash(null);
}}
onTransactionConfirmed={async (receipt) => {
setTxHash(receipt.transactionHash);
}}
>
Mint
</TransactionButton>
</div>
) : (
<p
style={{
textAlign: "center",
width: "400px",
marginTop: "10px",
}}
>
Login to mint this Kitten!
</p>
)}
) : null}
{txHash ? (
<div className="flex flex-col justify-center p-2">
<p className="text-green-500 text-center mb-2">
Minted! Tx Hash:{" "}
<a
href={`${chain.blockExplorers?.[0]?.url}/tx/${txHash}`}
target="_blank"
rel="noopener noreferrer"
className="underline"
>
{shortenHex(txHash)}
</a>
</p>
</div>
) : null}
</>
)}
</div>
@@ -131,7 +131,7 @@ export async function populateEip712Transaction(
const baseFee = toBigInt(result.max_fee_per_gas);
maxFeePerGas = baseFee * 2n; // bumping the base fee per gas to ensure fast inclusion
maxPriorityFeePerGas = toBigInt(result.max_priority_fee_per_gas) || 1n;
gasPerPubdata = toBigInt(result.gas_per_pubdata_limit);
gasPerPubdata = toBigInt(result.gas_per_pubdata_limit) * 2n; // doubling for fast inclusion;
}
// serialize the transaction (with fees, gas, nonce)
@@ -304,6 +304,7 @@ export class IFrameWallet {
return signedMessage as Hex;
},
async signTypedData(_typedData) {
console.log("signTypedData", _typedData);
const parsedTypedData = parseTypedData(_typedData);
// deleting EIP712 Domain as it results in ambiguous primary type on some cases
// this happens when going from viem to ethers via the iframe
@@ -312,8 +313,11 @@ export class IFrameWallet {
}
const domain = parsedTypedData.domain as TypedDataDefinition["domain"];
const chainId = domain?.chainId;
const verifyingContract = domain?.verifyingContract
? { verifyingContract: domain?.verifyingContract }
: {};
const domainData = {
verifyingContract: domain?.verifyingContract,
...verifyingContract,
name: domain?.name,
version: domain?.version,
};
@@ -6,6 +6,7 @@ import { zkSyncSepolia } from "../../chains/chain-definitions/zksync-sepolia.js"
import { defineChain } from "../../chains/utils.js";
import { getContract } from "../../contract/contract.js";
import { claimTo } from "../../extensions/erc1155/drops/write/claimTo.js";
import { sendAndConfirmTransaction } from "../../transaction/actions/send-and-confirm-transaction.js";
import { sendTransaction } from "../../transaction/actions/send-transaction.js";
import { prepareTransaction } from "../../transaction/prepare-transaction.js";
import type { Account, Wallet } from "../interfaces/wallet.js";
@@ -50,7 +51,7 @@ describe.runIf(process.env.TW_SECRET_KEY).skip(
});
it("should send a transactions", async () => {
const tx = await sendTransaction({
const tx = await sendAndConfirmTransaction({
transaction: claimTo({
contract,
quantity: 1n,