简介

常见问题

什么是Bubblegum V2?

Bubblegum V2是Bubblegum程序的新迭代,引入了多项改进和新功能。 它是已知Bubblegum程序的一部分,但指令和数据结构有所不同。 在Bubblegum V2中,cNFT使用MPL-Core集合而不是Metaplex Token Metadata集合进行分组。它还引入了冻结、解冻和灵魂绑定NFT等新功能,以及其他功能,如:

  • 冻结和解冻功能:项目创建者现在可以冻结和解冻cNFT,为各种用例提供对资产的更大控制,例如在特定事件期间阻止转账或实现锁定机制。
  • MPL-Core集合集成:Bubblegum V2 NFT现在可以添加到MPL-Core集合,而不仅限于代币元数据集合,允许更大的灵活性和与更广泛的Metaplex生态系统的集成。
  • 版税强制执行:由于Bubblegum V2使用MPL-Core集合,可以使用ProgramDenyList等方式对cNFT强制执行版税。
  • 灵魂绑定NFT:cNFT现在可以设为灵魂绑定(不可转让),将其永久绑定到所有者的钱包。这非常适合凭证、出席证明、身份验证等。它需要在集合上启用PermanentFreezeDelegate插件。
  • 允许永久转账:如果在集合上启用了PermanentTransferDelegate插件,永久转账委托人现在可以在没有叶子所有者交互的情况下将cNFT转移给新所有者。

如何找到转移、委托、销毁等操作所需的参数?

每当我们使用最终替换Bubblegum树中叶子的指令时——例如转移、委托、销毁等——程序需要一系列参数来确保当前叶子有效并可以更新。这是因为压缩NFT的数据在链上账户中不可用,因此需要额外的参数,如证明叶子索引Nonce等,以便程序填充这些内容。

所有这些信息都可以使用getAssetgetAssetProof RPC方法从Metaplex DAS API检索。然而,这些方法的RPC响应与指令期望的参数并不完全相同,从一个解析到另一个并不简单。

幸运的是,我们的SDK提供了一个辅助方法,可以为我们完成所有繁重的工作,如下面的代码示例所示。它接受压缩NFT的资产ID并返回一系列参数,可以直接注入到替换叶子的指令中——例如销毁、转移、更新等。

也就是说,如果您需要自己进行解析,以下是指令期望的参数及其如何从Metaplex DAS API检索的快速分解。这里我们假设getAssetgetAssetProof RPC方法的结果分别可通过rpcAssetrpcAssetProof变量访问。

  • 叶子所有者:可通过rpcAsset.ownership.owner访问。
  • 叶子委托人:可通过rpcAsset.ownership.delegate访问,当为null时应默认为rpcAsset.ownership.owner
  • 默克尔树:可通过rpcAsset.compression.treerpcAssetProof.tree_id访问。
  • :可通过rpcAssetProof.root访问。
  • 数据哈希:可通过rpcAsset.compression.data_hash访问。
  • 创作者哈希:可通过rpcAsset.compression.creator_hash访问。
  • Nonce:可通过rpcAsset.compression.leaf_id访问。
  • 索引:可通过rpcAssetProof.node_index - 2^max_depth访问,其中max_depth是树的最大深度,可从rpcAssetProof.proof数组的长度推断。
  • 证明:可通过rpcAssetProof.proof访问。
  • 元数据:目前需要从rpcAsset响应中的各个字段重建。

获取替换叶子指令的参数

Bubblegum Umi库提供了符合上述描述的getAssetWithProof辅助方法。以下是如何使用transfer指令的示例。请注意,在这种情况下,我们覆盖了leafOwner参数,因为它需要是签名者,而assetWithProof给我们的是公钥形式的所有者。

根据树冠大小,使用getAssetWithProof辅助函数的truncateCanopy: true参数可能是有意义的。它获取树配置并截断不需要的证明。这将有助于解决交易大小过大的问题。

import { getAssetWithProof, transfer } from '@metaplex-foundation/mpl-bubblegum'
const assetWithProof = await getAssetWithProof(umi, assetId,
// { truncateCanopy: true } // 可选,用于修剪证明
);
await transferV2(umi, {
...assetWithProof,
leafOwner: leafOwnerA, // 作为签名者。
newLeafOwner: leafOwnerB.publicKey,
}).sendAndConfirm(umi);
await transferV2(umi, {
...assetWithProof,
leafOwner: leafOwnerA, // 作为签名者。
newLeafOwner: leafOwnerB.publicKey,
}).sendAndConfirm(umi)

如何解决"交易过大"错误

在执行转移或销毁等叶子替换操作时,您可能会遇到"交易过大"错误。要解决此问题,请考虑以下解决方案:

  1. 使用truncateCanopy选项: getAssetWithProof函数中传递{ truncateCanopy: true }

    const assetWithProof = await getAssetWithProof(umi, assetId,
    { truncateCanopy: true }
    );

    此选项检索默克尔树配置并根据树冠删除不必要的证明来优化assetWithProof。虽然它增加了额外的RPC调用,但显著减少了交易大小。

  2. 使用版本化交易和地址查找表: 另一种方法是实现版本化交易和地址查找表。此方法可以帮助更有效地管理交易大小。

通过应用这些技术,您可以克服交易大小限制并成功执行您的操作。