- The user knows the fee amount when signing, and is allowing the paymaster only that
- Any gas that isn’t spent is refunded to the user in the fee token itself
- The smart contracts are audited, immutable and verified
Project prerequisites
To follow along with this guide, you’ll need three things:- A Magic Publishable API Key
- A web client
- zkSync Sepolia tokens
make-scoped-magic-app
CLI tool to bootstrap a Next.js app with Magic authentication already baked into the client. You’re welcome to use your own client, but this tutorial and its accompanying code snippets assume the output of the make-scoped-magic-app
CLI as the starting point.
The make-scoped-magic-app
CLI tool is an easy way to bootstrap new projects with Magic. To get started, simply run the command below in the shell of your choice. Be sure to replace <YOUR_PUBLISHABLE_API_KEY>
with the Publishable API Key from your Magic Dashboard.
.env
as NEXT_PUBLIC_MAGIC_API_KEY
if you didn’t add it to the CLI command above
Install additional project dependencies
In addition to the packages included in the scaffold produced by themake-scoped-magic-app
CLI, you’ll also need to install viem
for EVM-related types and transaction convenience methods.
Run the following command to install the required dependencies:
Initialize wallet client
The code snippets provided below outline the process of initializing thewalletClient
within the application. This client serves as an interface for the application to interact with the zkSync network, minimizing the complexities of direct communication and transaction handling.
Inside of src/components/magic/MagicProvider.tsx
, import the following from Viem:
TypeScript
TypeScript
createWalletClient
. This function returns an object that acts as an interface for interacting with Ethereum wallets. It takes in the following arguments:
chain
: The network that the wallet client is connecting to. In this casezkSyncSepoliaTestnet
.account
: Ethereum address of the connected user. In this case it is the Magic user that has logged in using Email OTP.transport
: Acts as the intermediary layer tasked with handling outbound requests, such as RPC requests
eip712WalletActions
. This is a suite of Wallet Actions for developing with zkSync chains.
Inside the useEffect underneath the magic
variable declaration, add the following function and invocation:
TypeScript
useMemo
hook and add walletClient
:
TypeScript
Mint testnet tokens
In this guide, we’re utilizing a testnet token calledERC20Mock
to cover gas fees. This requires minting tokens to the wallet associated with the Magic user currently logged in, ensuring sufficient funds are available for gas expenses.
Here’s a step-by-step guide:
- Start Your Development Server: Begin by launching your development server.
- Login via Email OTP: Proceed through the Email OTP login flow to authenticate.
- Copy Your Wallet Address: Once logged in, locate the wallet component on your dashboard. Copy the address displayed there.
- Access the ERC20Mock Contract: Visit the ERC20Mock contract page on the Sepolia Explorer.
- Navigate to the “Write” tab.
- Minting Tokens: Scroll to the “mint” function. Here, paste the wallet address you copied earlier into the designated field. We’ll be minting an equivalent of 0.1 ETH worth of tokens. In the amount input, enter
100000000000000000
(representing 0.1 ETH in wei, the smallest unit of ether). Click on the “Write” button and follow the on-screen prompts to complete the process.
Call to Zyfi paymaster API
Zyfi has created a straightforward API modeled after the standard transaction format. First send the transaction object to their provided paymaster endpoint. Their server will generate and return the required payload to submit to the network. See the steps below on how to use Zyfi:- The frontend calls the paymaster API, which then processes transaction details and incorporates paymaster-specific information, such as the fee charged in ERC-20 tokens to cover gas expenses
- The user starts a transaction, choosing a paymaster for gas fees and granting it an ERC-20 token allowance. The bootloader checks with the paymaster on-chain, which confirms the user’s intent and collects the token. Once validated, the paymaster covers the transaction’s costs, executed by the bootloader. Unused gas gets refunded to the paymaster, who then returns it to the user in the ERC-20 token, making the process efficient and free of direct gas charges for the user.
- Following this, the Zyfi paymaster collects the ERC-20 token fee, which enables it to validate and carry out the transaction on behalf of the user, covering the necessary ETH gas costs
- The transaction is then verified and submitted to the network
walletClient
that is vital for processing transactions. Before this client handles the transaction data, it needs to incorporate the paymaster details, including the fee charged in ERC-20 tokens.
Go to src/components/magic/cards/SendTransactionCard.tsx
and take a look at the sendTransaction
function. This is where we will simulate a transaction for transferring testnet ETH to another wallet.
Inside this function is where the POST request is sent to Zyfi with the required payload which includes the following:
feeTokenAddress
: The ERC-20 token address used to pay for gasisTestnet
: Boolean indicating if the transaction is executed on the zkSync Sepolia chaintxData
: Transaction data. In this case it is the sender, transfer recipient, and transfer amount.
TypeScript
customData
attribute. It includes the paymaster address and paymasterInput
, which includes the following values:
0x949431dc
: Specifies that this is an approval flow, where the user pays with a given tokenfd1fbff2e1baa053c927dc513579a8b2727233d8
: Fee token address, which in this case is the ERC20Mock token1d54c9cb44
: Fee token amount that the user allows to the paymaster for payment. This is calculated off-chain and enables gas savings since the gas used for modifying the allowance storage slot is entirely reimbursed at the transaction’s conclusion, due to the slot’s value changing from zero to a specific value and back to zero.18e2f1dcacf
: block.timestamp at which the transaction expires41fffe1f0df68221efb3c42f18bcbd7762e22a7d1e2a86441e0eb74515bc6eedb677756f3656b03d39ea1490d29940e083c5224af228983678009b07e215f9707e1c
: Message signed by Zyfi API
Sending the transaction
Once you receive the response, you can use destructuring assignment to extract thetxData
property from the JSON response. Next, format the transaction data necessary for submission, including key details like the account address, recipient, value, chain specifications, gas limits, and paymaster information. This structured data is tailored specifically for the transaction and ensures that all necessary parameters are correctly set for processing the transaction properly.
TypeScript
try/catch
for sending the transaction beneath the rest of the code:
TypeScript
Next Steps
You now know how to integrate Zyfi with Magic and include the following features:- Simple authentication with Email OTP
- Transfer funds using Zyfi paymaster to pay for gas using any ERC-20 token