可用守卫

Allow List 守卫

概述

Allow List 守卫根据预定义的钱包列表验证铸造钱包。如果铸造钱包不在此列表中,铸造将失败。

在此守卫的设置中提供大量钱包列表将需要在区块链上大量存储,并且可能需要多个交易才能将它们全部插入。因此,Allow List 守卫使用 Merkle 树来验证铸造钱包是否属于预配置的钱包列表。

这通过创建一个哈希二叉树来工作,其中所有叶子两两散列,直到我们到达称为 Merkle 根的最终哈希。这意味着如果任何叶子发生变化,最终的 Merkle 根将被破坏。

要验证一个叶子是否是树的一部分,我们只需要一个所有中间哈希的列表,这些哈希允许我们向上遍历树并重新计算 Merkle 根。我们称这个中间哈希列表为 Merkle 证明。如果计算的 Merkle 根与存储的 Merkle 根匹配,我们可以确定该叶子是树的一部分,因此是原始列表的一部分。

因此,Allow List 守卫的设置需要一个 Merkle 根,它充当预配置的允许钱包列表的事实来源。为了让钱包证明它在允许列表中,它必须提供有效的 Merkle 证明,使程序能够重新计算 Merkle 根并确保它与守卫的设置匹配。

请注意,我们的 SDK 提供了辅助函数,可以轻松为给定的钱包列表创建 Merkle 根和 Merkle 证明。

守卫设置

Allow List 守卫包含以下设置:

  • Merkle Root(Merkle 根):代表允许列表的 Merkle 树的根。

使用 Allowlist 守卫设置 Candy Machine

为了帮助我们管理 Merkle 树,Umi 库提供了两个名为 getMerkleRootgetMerkleProof 的辅助方法,您可以这样使用。

import {
getMerkleProof,
getMerkleRoot,
} from "@metaplex-foundation/mpl-candy-machine";
const allowList = [
"Ur1CbWSGsXCdedknRbJsEk7urwAvu1uddmQv51nAnXB",
"GjwcWFQYzemBtpUoN5fMAP2FZviTtMRWCmrppGuTthJS",
"AT8nPwujHAD14cLojTcB1qdBzA1VXnT6LVGuUd6Y73Cy",
];
const merkleRoot = getMerkleRoot(allowList);
const validMerkleProof = getMerkleProof(
allowList,
"Ur1CbWSGsXCdedknRbJsEk7urwAvu1uddmQv51nAnXB"
);
const invalidMerkleProof = getMerkleProof(allowList, "invalid-address");

一旦我们计算出允许列表的 Merkle 根,我们就可以使用它在 Candy Machine 上设置 Allow List 守卫。

import { getMerkleRoot } from "@metaplex-foundation/mpl-candy-machine";
const allowList = [
"Ur1CbWSGsXCdedknRbJsEk7urwAvu1uddmQv51nAnXB",
"GjwcWFQYzemBtpUoN5fMAP2FZviTtMRWCmrppGuTthJS",
"AT8nPwujHAD14cLojTcB1qdBzA1VXnT6LVGuUd6Y73Cy",
];
create(umi, {
// ...
guards: {
allowList: some({ merkleRoot: getMerkleRoot(allowList) }),
},
});

API 参考:createAllowList

铸造设置

Allow List 守卫包含以下铸造设置:

  • Merkle Root(Merkle 根):代表允许列表的 Merkle 树的根。

请注意,在能够铸造之前,我们必须通过提供 Merkle 证明来验证铸造钱包。有关更多详细信息,请参阅下面的验证 Merkle 证明

另请注意,如果您计划在没有我们 SDK 帮助的情况下构建指令,您需要将 Allow List Proof PDA 添加到铸造指令的剩余账户中。有关更多详细信息,请参阅 Candy Guard 程序文档

使用 Allow List 守卫铸造

您可以使用 mintArgs 参数传递 Allow List 守卫的铸造设置,如下所示。

import { getMerkleRoot } from "@metaplex-foundation/mpl-candy-machine";
const allowList = [
"Ur1CbWSGsXCdedknRbJsEk7urwAvu1uddmQv51nAnXB",
"GjwcWFQYzemBtpUoN5fMAP2FZviTtMRWCmrppGuTthJS",
"AT8nPwujHAD14cLojTcB1qdBzA1VXnT6LVGuUd6Y73Cy",
];
mintV2(umi, {
// ...
mintArgs: {
allowList: some({ merkleRoot: getMerkleRoot(allowList) }),
},
});

API 参考:mintV2AllowListMintArgs

Route 指令

Allow List route 指令支持以下功能。

验证 Merkle 证明

路径:proof

铸造钱包必须通过使用 Allow List 守卫的 route 指令执行预验证,而不是直接将 Merkle 证明传递给铸造指令。

此 route 指令将从提供的 Merkle 证明计算 Merkle 根,如果有效,将创建一个新的 PDA 账户作为铸造钱包属于允许列表的证明。因此,在铸造时,Allow List 守卫只需要检查此 PDA 账户的存在即可授权或拒绝钱包铸造。

那么为什么我们不能直接在铸造指令中验证 Merkle 证明呢?这只是因为,对于大型允许列表,Merkle 证明可能会变得相当长。超过一定大小后,就无法将其包含在已经包含相当数量指令的铸造交易中。通过将验证过程与铸造过程分开,我们使允许列表可以根据需要变得无限大。

此 route 指令路径接受以下参数:

  • Path = proof:选择在 route 指令中执行的路径。
  • Merkle Root(Merkle 根):代表允许列表的 Merkle 树的根。
  • Merkle Proof(Merkle 证明):应用于计算 Merkle 根并验证其与守卫设置中存储的 Merkle 根匹配的中间哈希列表。
  • Minter(铸造者)(可选):如果与付款人不同,则作为签名者的铸造者账户。提供时,此账户必须是允许列表的一部分,证明才能有效。

预验证钱包

您可以使用 routeArgs 参数传递 Allow List 守卫的"Proof"Route 设置,如下所示。

import {
getMerkleProof,
getMerkleRoot,
} from "@metaplex-foundation/mpl-candy-machine";
import { publicKey } from "@metaplex-foundation/umi";
const allowList = [
"Ur1CbWSGsXCdedknRbJsEk7urwAvu1uddmQv51nAnXB",
"GjwcWFQYzemBtpUoN5fMAP2FZviTtMRWCmrppGuTthJS",
"AT8nPwujHAD14cLojTcB1qdBzA1VXnT6LVGuUd6Y73Cy",
];
await route(umi, {
// ...
guard: "allowList",
routeArgs: {
path: "proof",
merkleRoot: getMerkleRoot(allowList),
merkleProof: getMerkleProof(allowList, publicKey(umi.identity)),
},
}).sendAndConfirm(umi);

umi.identity 钱包现在被允许从 Candy Machine 铸造。

API 参考:routeAllowListRouteArgs