Transaction Lifecycle
This guide will help you manage the lifecycle of Lens transactions.
Tiered Transaction Model
The Lens API’s approach to write operations prioritizes user convenience through a tiered transaction model. This model spans from signless transactions to options requiring user signatures and gas fees, offering the best possible experience based on the individual user's circumstances.
There are two classes of operations in this model:
Delegable Operations: These operations can be signed by an Account Manager if the user chooses.
Restricted Operations: These operations require the user's signature due to their nature.
Server Fundable Operations: These operations could be funded by the server if the user is eligible. This is used to facilitate management operations such as creating new Apps, creating Custom Graphs, etc.
The Lens API adapts its operation results based on user eligibility, ensuring users can proceed with the best available options, from the smoothest experience to necessary fallbacks.
Delegable Operations
The tiered transaction model for Delegable Operations is as follows:
Description: Automatically signed and sent by the Lens API, with gas fees sponsored.
Requirements: Available when the user enabled the signless experience, the user is eligible for sponsorship, and the operation is deemed secure for signless execution.
Description: Requires the user to sign and send a gasless transaction request, powered by ZKsync EIP-712.
Requirements: Available if the user is eligible for sponsorship but lacks signless support.
Description: Requires user signature and gas payment, following a standard EIP-1559 transaction request.
Requirements: Used when neither signless nor sponsored transactions are available.
Restricted Operations
The tiered transaction model for Restricted Operations is as follows:
Description: Requires the user to sign and send a gasless transaction request, powered by ZKsync EIP-712.
Requirements: Available when the user is eligible for sponsorship.
Description: Requires user signature and gas payment, following a standard EIP-1559 transaction request.
Requirements: Used when the user is not eligible for sponsorship.
Server Fundable Operations
The tiered transaction model for Server Fundable Operations is as follows:
Description: Automatically signed and sent by the Lens API, with gas fees sponsored.
Requirements: Available when the user is eligible for sponsorship and the operation is deemed secure for signless execution.
Description: Requires user signature and gas payment, following a standard EIP-1559 transaction request.
Requirements: Used when the server deems the user as not eligible for sponsorship.
Operation Results
- GraphQL
- React
- TypeScript
With Operation representing the operation of interest, the <Operation>Result is a union type with the possible outcomes depending on the class of operation:
OperationResponse being is a placeholder for operation-specific responses like PostResponse, FollowResponse, etc.)
Where:
OperationResponse: Indicates that the transaction was successfully sent and returns the transaction hash for further monitoring.
SponsoredTransactionRequest: Requests the user to sign and send the transaction, with gas fees covered.
SelfFundedTransactionRequest: Requests the user to sign and send the transaction, with the user covering gas fees.
TransactionWillFail: This is an omnipresent entry that, if present, indicates that the transaction will fail for a specific reason.
Transaction Requests
Both SponsoredTransactionRequest and SelfFundedTransactionRequest types include the the typed transaction envelope informations of the transaction request.
For sponsored transactions, this is the typed transaction envelope of a ZKsync EIP-712 transaction request.
Decoding and Sending Transactions
To decode the encoded response, you can use the zksync-ethers package, which allows parsing it into a TransactionLike object for sending via the user's wallet:
zksync-ethers
import { types } from "zksync-ethers";
if ( result.__typename === "SponsoredTransactionRequest" || result.__typename === "SelfFundedTransactionRequest") { const tx: types.TransactionLike = types.Transaction.from(result.encoded);
await wallet.sendTransaction(tx);}
Using the Raw Values
If you prefer using a different library, you can use the raw values to create the appropriate transaction request. Below is an example using the viem library:
viem
import type { WalletClient } from 'viem';import { sendEip712Transaction, sendTransaction } from 'viem/zksync';
const walletClient: WalletClient = ...;
if (operationResult.__typename === 'SponsoredTransactionRequest') { await sendEip712Transaction(walletClient, { account: transaction.raw.from, chain: transaction.raw.chainId, data: transaction.raw.data, gas: BigInt(transaction.raw.gasLimit), gasPrice: BigInt(transaction.raw.gasPrice), nonce: transaction.raw.nonce, paymaster: transaction.raw.customData.paymasterParams?.paymaster, paymasterInput: transaction.raw.customData.paymasterParams?.paymasterInput, to: transaction.raw.to, value: BigInt(transaction.raw.value), });}
if (operationResult.__typename === 'SelfFundedTransactionRequest') { await sendTransaction(walletClient, { account: transaction.raw.from, chain: transaction.raw.chainId, data: transaction.raw.data, gas: BigInt(transaction.raw.gasLimit), maxFeePerGas: BigInt(transaction.raw.maxFeePerGas), maxPriorityFeePerGas: BigInt(transaction.raw.maxPriorityFeePerGas), nonce: transaction.raw.nonce, to: transaction.raw.to, type: 'eip1559', value: BigInt(transaction.raw.value), });}
As you may have noticed, Viem offers first-class support for ZKsync chains. Your experience may vary depending on the library you choose.
Transaction Monitoring
At this point, whether you received an Operation Response or you sent a Transaction Request via the user's wallet (SponsoredTransactionRequest or SelfFundedTransactionRequest), you should have a transaction hash.
- GraphQL
- React
- TypeScript
You can poll the transactionStatus query with the transaction hash to monitor the transaction's lifecycle.
It's recommended to poll this query no more frequently than once per second.
where:
NotIndexedYetStatus: The transaction has not been indexed yet. This could be due to delays in broadcasting to all nodes, not being mined, or events not being picked up by the Lens Indexer.
PendingTransactionStatus: The transaction is being processed by the Lens Indexer. This status can take longer for transactions involving metadata URIs, which need to be fetched and parsed.
FinishedTransactionStatus: The transaction has been successfully mined and indexed. You can go ahead with the desired user experience.
FailedTransactionStatus: The transaction has failed, with the response providing a reason for the failure.