本文介绍了如何使用 Gelato Relay 和 USDC 实现 gasless NFT minting。通过结合 Gelato Relay 和 USDC,用户无需原生 gas 代币即可在任何网络上无缝交易,从而简化了流程,改善了用户体验。
非同质化代币 (NFT) 已经吸引了全世界,并重塑了我们感知和交易数字资产的方式。然而,一个长期存在的准入障碍阻碍了大规模采用 —— 需要一种原生代币来促成在适当网络上的交易。
通过将 Gelato Relay 与 USDC 结合,这个过程得到了简化,同时保持了最小信任。在这篇文章中,我们将探讨将无 Gas 铸造集成到你的下一个 NFT 项目中的简单过程。
用户将签署一个链下 permit signature,允许 NFT 合约花费指定数量的 USDC。
函数参数以及签名,将使用 Gelato Relay SDK 提交给 Gelato,并由 relayer 在链上执行。
铸造函数使用提供的签名来允许自己花费 USDC;一个 USDC 将用于支付 NFT 本身,一部分用于补偿 relayer。允许的金额包括用于考虑 Gas 价格波动情况的开销 —— 很少会花费全部金额。
仅有两个要求来支持无 Gas 铸造,我们必须:
通过利用 USDC 的链下 permit 签名,我们可以使用 Gelato Relay 启用真正的无 Gas 体验。由于交易是由 relayer 代表我们执行的,因此消息发送者是 relayer 而不是签名者,这施加了一些限制。
尽管被授权促成交互,智能合约不能随意代表我们花费代币。因此,我们必须首先批准目标合约的花费。签署链下 permit 签名证明了我们允许合约花费一定数量代币的意图。另一种方法是“批准”合约花费代币,但这需要在链上进行交易,从而适得其反。
relayer 代表我们在链上进行交易,因此会产生需要补偿的 Gas 成本。这可以通过两种方式实现;使用 1Balance 赞助交易,或在交易内同步支付 relay 费用。后者非常适合我们的项目,因为我们可以在同一交易中使用 USDC 支付 NFT 和 relay 费用。
在开始之前,请确保已完成以下操作:
完整的源代码以及如何自行部署合约和前端的说明,可在此处 GitHub 上找到。
NFT 合约代表一个典型的 ERC271 实现。部署者在构造函数中指定支付代币 (USDC) 和金额,用户调用 "mint" 函数以 铸造新的 NFT。这从指定地址转移支付代币,然后在递增供应量之前 铸造 NFT(铸造期间的供应量决定了代币 ID)。该合约跟踪 铸造的代币及其所有权。
以下是一个 ERC721 NFT 智能合约的最小实现,需要一个 ERC20 代币来支付 NFT,以及一个原生 Gas 代币来在网络上进行交易。
contract NFT is ERC721 {
uint256 public price;
uint256 public supply;
ERC20 public token;
constructor(ERC20 _token, uint256 _price)
ERC721("NFT", "NFT")
{
price = _price;
token = _token;
}
function mint(address to) external {
token.transferFrom(to, address(this), price);
_mint(to, supply++);
}
}
为了支持无 Gas 铸造,我们必须满足概述的要求。我们必须修改 "mint" 函数以接受额外的参数,这些参数会被转发到 ERC20Permit 代币的 "permit" 函数。
这允许我们花费用户指定数量的代币。在批准花费后,我们将适当的 relay 费用转移到费用收款人。由于我们转移到费用收款人,我们必须限制 铸造函数,以防止恶意行为者冒充 relayer 并通过报价高昂的 relay 费用来耗尽合约。
为了实现这一点,我们只需在函数定义中包含 "onlyGelatoRelay" 修饰符,该修饰符通过从 "GelatoRelayContext" 继承来提供。 注意:除了 "onlyGelatoRelay" 修饰符和 "transferRelayFee" 方法之外,从 "GelatoRelayContext" 继承还可以访问 relay 费用信息(例如,费用代币、费用金额、费用收款人)。
修改后的,现在是无 Gas 的 NFT 合约可以在下面找到。
contract GaslessNFT is ERC721, GelatoRelayContext {
uint256 public price;
uint256 public supply;
ERC20Permit public token;
constructor(ERC20Permit _token, uint256 _price)
ERC721("Gasless NFT", "GNFT")
{
price = _price;
token = _token;
}
function mint(address to, uint256 amount, uint256 deadline, uint8 v,
bytes32 r, bytes32 s) external onlyGelatoRelay
{
require(address(token) == _getFeeToken(),
"GaslessNFT.mint: incorrect fee token");
token.permit(to, address(this), amount, deadline, v, r, s);
token.transferFrom(to, address(this), price);
uint256 fee = _getFee();
uint256 maxFee = amount - price;
require(fee <= maxFee,
"GaslessNFT.mint: insufficient fee");
token.transferFrom(to, _getFeeCollector(), fee);
_mint(to, supply++);
}
}
注意: 一般建议使用 ERC-2771,但在这种情况下,USDC 为我们处理身份验证,它是 ERC-2612 permit 扩展的实现。
前端负责估算 relay 费用并签署 permit 消息,允许 NFT 合约花费一定数量的 USDC(NFT 价格 + relay 费用)。
签名完成后,它将构造请求并使用 "callWithSyncFee" 将其提交给 Gelato。估算 relay 费用和提交请求都由 Gelato Relay SDK 处理。
const purchase = async () => {
const wallet = new ethers.BrowserProvider(window.ethereum);
const signer = await wallet.getSigner();
const amount = price + fee;
const deadline = ethers.MaxUint256;
const { chainId } = await provider.getNetwork();
const sig = await sign(signer, token, amount, nft, deadline, chainId);
const { v, r, s } = sig;
const { data } = await nft.mint.populateTransaction(
signer.address, amount, deadline, v, r, s);
const request: CallWithSyncFeeRequest = {
chainId: chainId.toString(),
target: nft.target.toString(),
feeToken: token.target.toString(),
isRelayContext: true,
data: data
};
const { taskId } = await relay.callWithSyncFee(request);
};
注意: 为了更清晰,某些检查已被省略。完整的源代码可在 此 存储库中找到。
无 Gas NFT 铸造为更广泛的 web3 采用铺平了道路。通过利用链下 permit 签名和 Gelato Relay,用户可以在任何网络上无缝交易,而无需原生 Gas 代币。这种简化的流程增强了用户体验,同时保持了最小信任 —— 真正是两全其美!
Gelato 为你处理区块链的复杂性,从而实现安全、无 Gas 的交易,以实现无缝的用户体验和引导。
查看 Relay 以及其他 Gelato 服务,如 Web3 Functions、Automate 和 Account Abstraction SDK。
与此同时,加入我们的社区和我们在 Discord 上的开发者讨论!
- 原文链接: gelato.cloud/blog/gasles...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!