Navigating a multitude of dApps can be daunting for newcomers. The onboarding process is often riddled with complex concepts and steps, creating a barrier that hinders mass adoption.
One of these challenges is the concept of "gas"—the fee required to perform transactions on different chains.
To acquire native assets (like ETH, MATIC, etc.) to pay gas fees, you must create an account on an exchange, go through verification, purchase the assets, and then transfer them to your wallet. This process can be intimidating for new users. Even if you already hold ERC20 tokens in your wallet but no native assets, you can’t move or swap those ERC20 tokens because paying gas itself requires a native token. This creates a frustrating cycle.
Simplifying Transactions with Account Abstraction and Safe SDK
Safe tackles this issue with the Safe{Core} Account Abstraction SDK, which lets developers integrate account abstraction into their apps, making the UX smoother.
The Relay Kit, powered by Gelato Relay, enables users to cover gas fees with ERC-20 tokens or even execute gasless transactions.
Mint NFTs Without Paying Gas Using Gelato's Safe Relay Kit
Here’s how you can mint NFTs without gas using the Safe Relay Kit:
Example Contract: A simple ERC721 NFT minting contract with a `mintGelato` function:
pragma solidity ^0.8.14;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract GelatoNFT is ERC721, ERC721URIStorage {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
string public constant gelatoInitialURI = "https://...ipfs.nftstorage.link/";
constructor() ERC721("GelatoNFT", "GNFT") {}
function mintGelato(address to) public {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(to, newItemId);
_setTokenURI(newItemId, gelatoInitialURI);
}
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) {
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721URIStorage) returns (bool) {
return super.supportsInterface(interfaceId);
}
}
Step-by-Step Guide
Create a Safe: Go to Safe{Wallet} and create a 1/1 Safe.
Verify Your Contract: Paste your Safe address in a block explorer, verify it, and save the implementation ABI for Gelato.
Deposit Funds: Fund Gelato 1Balance with USDC (Polygon) or testnet tokens.
Create Relay App: In your Gelato Relay App, add your Safe address and enable `execTransaction` as gasless.
Setup Project:
mkdir gasless-nft-minting
cd gasless-nft-minting
yarn init -y
yarn add ethers @safe-global/relay-kit @safe-global/protocol-kit @safe-global/safe-core-sdk-types
Import Packages:
import { ethers } from 'ethers';
import { GelatoRelayPack } from '@safe-global/relay-kit';
import Safe, { EthersAdapter, getSafeContract } from '@safe-global/protocol-kit';
import { MetaTransactionData, MetaTransactionOptions, OperationType } from '@safe-global/safe-core-sdk-types';
Create Transaction Object:
const tx: MetaTransactionData = {
to: targetAddress,
data: nftContract.interface.encodeFunctionData("mintGelato", [
"0xYourWalletAddress",
]),
value: "0",
operation: OperationType.Call,
};
const options: MetaTransactionOptions = {
gasLimit,
isSponsored: true,
};
Initialize SDKs:
const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer });
const safeSDK = await Safe.create({ ethAdapter, safeAddress });
const relayKit = new GelatoRelayPack(GELATO_RELAY_API_KEY);
Encode Transaction:
const safeTransaction = await safeSDK.createTransaction({ safeTransactionData: tx });
const signedSafeTx = await safeSDK.signTransaction(safeTransaction);
const safeSingletonContract = await getSafeContract({
ethAdapter,
safeVersion: await safeSDK.getContractVersion(),
});
const encodedTx = safeSingletonContract.encode("execTransaction", [
signedSafeTx.data.to,
signedSafeTx.data.value,
signedSafeTx.data.data,
signedSafeTx.data.operation,
signedSafeTx.data.safeTxGas,
signedSafeTx.data.baseGas,
signedSafeTx.data.gasPrice,
signedSafeTx.data.gasToken,
signedSafeTx.data.refundReceiver,
signedSafeTx.encodedSignatures(),
]);
Send to Gelato Relay:
const relayTransaction = {
target: safeAddress,
encodedTransaction: encodedTx,
chainId,
options,
};
const response = await relayKit.relayTransaction(relayTransaction);
console.log(`Task ID: https://relay.gelato.digital/tasks/status/${response.taskId}`);
Conclusion
The Safe Account Abstraction SDK Relay Kit powered by Gelato Relay enables gasless NFT minting and seamless dApp interactions. By removing friction, it paves the way for broader blockchain adoption.
About Gelato Relay
Gelato abstracts blockchain complexities, delivering secure gasless transactions and smoother onboarding. Explore Gelato services: Web3 Functions, Automate, and the Account Abstraction SDK.
Join the community on Discord to connect with developers.