使用 USDC 实现 Gasless NFT Minting:由 Gelato Relay 提供支持

  • gelato
  • 发布于 2023-06-21 16:39
  • 阅读 35

本文介绍了如何使用 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 铸造,我们必须:

  1. 使用链下签名允许 USDC 的花费
  2. 通过支付费用来补偿 relayer

通过利用 USDC 的链下 permit 签名,我们可以使用 Gelato Relay 启用真正的无 Gas 体验。由于交易是由 relayer 代表我们执行的,因此消息发送者是 relayer 而不是签名者,这施加了一些限制。

尽管被授权促成交互,智能合约不能随意代表我们花费代币。因此,我们必须首先批准目标合约的花费。签署链下 permit 签名证明了我们允许合约花费一定数量代币的意图。另一种方法是“批准”合约花费代币,但这需要在链上进行交易,从而适得其反。

relayer 代表我们在链上进行交易,因此会产生需要补偿的 Gas 成本。这可以通过两种方式实现;使用 1Balance 赞助交易,或在交易内同步支付 relay 费用。后者非常适合我们的项目,因为我们可以在同一交易中使用 USDC 支付 NFT 和 relay 费用。

前提条件

在开始之前,请确保已完成以下操作:

  • 安装 Node.js、NPM 和 Git
  • 在你的浏览器中设置一个 web3 钱包,例如 MetaMask
  • RPC 提供商

你的开发环境

完整的源代码以及如何自行部署合约和前端的说明,可在此处 GitHub 上找到。

代码解释

NFT 合约代表一个典型的 ERC271 实现。部署者在构造函数中指定支付代币 (USDC) 和金额,用户调用 "mint" 函数以 铸造新的 NFT。这从指定地址转移支付代币,然后在递增供应量之前 铸造 NFT(铸造期间的供应量决定了代币 ID)。该合约跟踪 铸造的代币及其所有权。

传统的 NFT 合约

以下是一个 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 NFT 合约

为了支持无 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 Relay

Gelato 为你处理区块链的复杂性,从而实现安全、无 Gas 的交易,以实现无缝的用户体验和引导。

查看 Relay 以及其他 Gelato 服务,如 Web3 FunctionsAutomateAccount Abstraction SDK

与此同时,加入我们的社区和我们在 Discord 上的开发者讨论!

  • 原文链接: gelato.cloud/blog/gasles...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
gelato
gelato
The Web3 Developer Cloud. Launch your own chain via our #1 Rollup-As-A-Service platform.