如何用 OpenZeppelin Contracts Base64 将链上 JSON 元数据编码为 NFT 的 Data URI?

如何用 OpenZeppelin Contracts Base64 将链上 JSON 元数据编码为 NFT 的 Data URI? 如何用 OpenZeppelin Contracts Base64 将链上 JSON 元数据编码为 NFT 的 Data URI【免费下载链接】openzeppelin-contractsOpenZeppelin Contracts is a library for secure smart contract development.项目地址: https://gitcode.com/GitHub_Trending/op/openzeppelin-contracts用 ERC-721 时tokenURI通常返回一个指向链下 JSON 文件的 URL。OpenZeppelin 官方 ERC-721 指南指出了这种做法的隐患元数据不在链上“a game developer could change the underlying metadata”游戏开发者可以随时改动底层元数据。如果希望把所有信息放进链上指南给出的方案是让tokenURI返回一个 Base64 编码的 Data URI同时明确提醒这种全链上元数据的方式 “will be rather costly”成本相当高。这篇文章的目标就是完成这一改造使用 OpenZeppelin Contracts 的Base64库把 JSON 元数据编码后拼进data:application/json;base64,...形式的 Data URI并给出基于仓库自带测试的验证方式。适用前提OpenZeppelin Contracts v5contracts/utils/Base64.sol 文件头标注 last updated v5.6.0。Solidity 版本Base64.sol要求pragma solidity ^0.8.20官方示例合约 Base64NFT.sol 使用pragma solidity ^0.8.24因为它同时继承了ERC721你的项目编译器版本需与之一致。Base64是一个libraryencode与decode都是internal pure函数只能在你的合约内部调用没有对外暴露的外部接口。场景来自 docs/modules/ROOT/pages/utilities.adoc 的 Base64 章节该库用于把bytes转成 Base64string文档明确说它适合构建 URL-safe 的tokenURI同时适用于 ERC-721 的tokenURI和 ERC-1155 的uri。将 JSON 元数据编码为 Data URI官方文档给出的示例合约Base64NFT完整实现如下contracts/mocks/docs/utilities/Base64NFT.sol文档中// ...处省略了你自己的铸造mint逻辑需要自行补齐// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import {ERC721} from ../../../token/ERC721/ERC721.sol; import {Strings} from ../../../utils/Strings.sol; import {Base64} from ../../../utils/Base64.sol; contract Base64NFT is ERC721 { using Strings for uint256; constructor() ERC721(Base64NFT, MTK) {} // ... function tokenURI(uint256 tokenId) public pure override returns (string memory) { // Equivalent to: // { // name: Base64NFT #1, // // Replace with extra ERC-721 Metadata properties // } // prettier-ignore string memory dataURI string.concat({\name\: \Base64NFT #, tokenId.toString(), \}); return string.concat(data:application/json;base64,, Base64.encode(bytes(dataURI))); } }tokenURI里发生了三件事按顺序理解即可拼 JSON。using Strings for uint256让你可以调用tokenId.toString()用string.concat把 tokenId 拼进 JSON 模板得到{name: Base64NFT #1}这样的元数据字符串。注释里 “Replace with extra ERC-721 Metadata properties” 表示你可以继续追加image、description等 ERC-721 元数据字段。Base64 编码。Base64.encode(bytes(dataURI))把 JSON 的bytes转成带填充的标准 Base64 字符串RFC 4648。加 Data URI 前缀。string.concat(data:application/json;base64,, ...)把 MIME 前缀拼在编码结果前面最终返回值形如data:application/json;base64,eyJ...整个 URI 不再依赖任何链下服务。同一个库还有两个可选函数按需使用Base64.encodeURL(bytes memory data)使用 Base64Url 字母表且按 RFC 4648 规范不加填充适合需要 URL-safe 输出的场合。Base64.decode(string memory data)把 Base64 字符串还原为bytes同时支持带填充和不带填充的输入、两种字母表遇到非法字符会以InvalidBase64Char(bytes1)回滚并携带该非法字符。这个函数正好可以用于下一步的验证。验证结果运行仓库自带的 Base64 测试仓库自带两套针对Base64库的测试可以直接运行来确认库行为。测试在本地临时链上执行不涉及真实交易也不修改仓库文件。Hardhat主路径仓库 package.json 中test脚本即运行hardhat testnpx hardhat test test/utils/Base64.test.jsFoundry可选仓库根目录含 foundry.toml 与lib/forge-stdnpx forge test --match-path test/utils/Base64.t.sol测试文件 test/utils/Base64.test.js 中列出了一组期望值以下是测试文件中的示例结果不是必须复现的固定基准输入encode期望输出testdGVzdAtest1dGVzdDEtest12dGVzdDEy空bytes空字符串test/utils/Base64.t.sol 则用 Foundry 断言Base64.encode与vm.toBase64一致并断言Base64.decode(Base64.encode(input))能还原输入。验证自己的 tokenURI上面验证的是库本身要确认自己合约的tokenURI输出正确可以在测试里用库自带的encode在本地独立构造一份期望值做对比。以下片段是示例写法仅使用了仓库已有的 API1是示例 tokenId换成你要验证的值// 示例在测试合约中验证 Base64NFT 的 tokenURI Base64NFT base64nft new Base64NFT(); string memory expected string.concat( data:application/json;base64,, Base64.encode({name: Base64NFT #1}) ); assertEq(base64nft.tokenURI(1), expected);assertEq来自 forge-stdTest基类若你用 Hardhat 测试则用 chai 的expect(...).to.equal(...)代替即可。两条路径都能通过说明链上tokenURI返回的就是可直接被钱包/市场解析的 Data URI。限制与注意Gas 成本官方 ERC-721 指南明确说明把全部元数据放链上 “rather costly”。Data URI 的长度取决于 JSON 大小tokenURI每次调用都会重新编码长元数据会显著推高调用成本。函数可见性encode/encodeURL/decode均为internal无法在链下或外部合约中直接调用Base64.encode必须像上面那样写进自己的合约。仓库测试里用ethers.deployContract($Base64)部署库的包装合约见 test/utils/Base64.test.js只是为了测试内部函数这是测试侧的手段。decode 的失败行为输入含非法字符测试覆盖了*、{、三种情况时decode会 revert 并抛出InvalidBase64Char携带该字符。encode 与 encodeURL 不要混用两者字母表和填充规则不同//对比-/_后者无填充但decode对两种输出都能解码。ERC-1155同样适用——把Base64.encode的结果拼进uri(uint256)的返回值即可文档在 utilities 页面同时列出了两个代币标准的入口。相关文档docs/modules/ROOT/pages/utilities.adocBase64 章节Data URI 用途与示例的出处。docs/modules/ROOT/pages/erc721.adoctokenURI元数据结构、链下 URL 的问题与链上 Base64 方案的 TIP。contracts/utils/Base64.sol库的完整实现与函数注释。contracts/mocks/docs/utilities/Base64NFT.sol可直接参考的tokenURI示例合约。【免费下载链接】openzeppelin-contractsOpenZeppelin Contracts is a library for secure smart contract development.项目地址: https://gitcode.com/GitHub_Trending/op/openzeppelin-contracts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考