本文介绍了Nifty OSS在Solana上创建和管理数字资产的最新开源协议,强调了其高效轻量和低成本的特点。通过详细的步骤,读者创建了一个数字资产示例,并体验了铸造、转移和管理权限等功能。重要的是,文章为开发者提供了实际的代码示例和项目结构,适合有Solana和TypeScript基础的开发者使用。
随着对数字资产和去中心化金融(DeFi)的兴奋不断增加,区块链上数字资产的使用案例也在不断增长。无论是对现实世界资产(RWAs)进行代币化、铸造数字艺术、销售游戏内资产、管理俱乐部会员资格,还是其他数字商品/服务,你都需要一些工具来高效且经济地创建、管理和与区块链上的数字资产进行交互。
Nifty OSS 是一组新的开源协议,基于 Solana 提供轻量级工具和高效标准,用于管理数字资产。与 Metaplex Core 类似,Nifty Asset 是一种单账户数字资产标准,显著降低了在 Solana 上创建和管理数字资产的存储成本、计算要求和账户要求。
在本指南中,我们将使用 Nifty JavaScript 客户端创建并实验一个数字资产。
在深入之前,请确保你已安装以下内容:
依赖项 | 版本 |
---|---|
@metaplex-foundation/umi | ^0.9.1 |
@metaplex-foundation/umi-bundle-defaults | ^0.9.1 |
@nifty-oss/asset | ^0.5.0 |
solana cli | 1.18.8 |
本指南将指导你设置本地开发环境以使用 Nifty Asset。我们将创建一个示例应用程序来演示它的功能。具体来说,我们将涵盖以下功能:
让我们开始吧!
大多数传统 NFT 标准在 Solana 上是建立在 SPL Token 程序之上的,该程序最初是为了可替代代币设计的。这种方法要求 NFT 遵守可替代代币的数据要求,如拥有代币供应量和小数,这导致开发和存储上的低效。
Nifty Asset 采用了一种新的方法来表示 Solana 上的非同质化代币。它不使用多个账户,而是将 NFT 视为由一个地址及关联持有者唯一标识的字节块。这种方法最小化了账户使用,只需要一个账户来表示一个资产。通过优化计算单位的消耗,并使用零拷贝(bytemuck)技术以避免序列化开销,Nifty Asset 提供了一种轻量、高效和灵活的解决方案,用于在 Solana 区块链上管理 NFT。这个新标准提高了性能和可组合性,使创建和与数字资产进行交互变得更加简单。Nifty 宣传的特点包括:
它通过扩展启用了以下链上功能:
每个资产包含:
168
字节的基本元数据。16
字节。基本元数据包括以下字段:
字段 | 描述 |
---|---|
Discriminator | 表示账户类型。目前:Unitialized 或 Asset |
State | 资产的状态:Locked 或 Unlocked |
Standard | Nifty Asset 的类型 - 当前选项:NonFungible 、Subscription 和 Soulbound |
Mutable | 资产是否可以被修改 |
Owner | 资产的所有者。所有者可以批准委托、转移和销毁资产。 |
Group | 资产所属的组(如有)。 |
Authority | 资产的权限。权限可以更新资产并验证其为组的成员。 |
Delegate | 资产的委托。根据分配给他们的角色,委托可以销毁、锁定或转移资产。 |
Name | 资产的名称,最长 35 个字符。 |
来源: Nifty OSS 文档
请注意,owner
被定义在资产账户中,而不是一个单独的链接账户(如 SPL 代币账户)。这允许更高效的资产存储和管理。
未经审核的程序
Nifty Asset 标准仍在开发中,尚未经过审核。在部署到主网时请谨慎,并确保你在 devnet 或 testnet 上彻底测试了你的应用程序,然后再部署到主网。请查看他们的 GitHub 获取最新更新和文档。
我们今天将在本地验证器上运行我们的测试。由于资产程序不包含在你的本地验证器中,因此我们需要从网络下载它,以便在启动本地验证器时对其进行初始化。
solana program dump -um AssetGtQBTSgm5s91d1RAQod5JmaZiJDxqsgtqrZud73 nifty_asset.so
该命令会将程序可执行数据写入你的项目目录中的 nifty_asset.so
。我们将在准备好运行脚本时使用它。
首先,为你的项目创建一个新目录并初始化 Node.js 项目。
mkdir nifty-asset-project
cd nifty-asset-project
npm init -y
接下来,安装必要的依赖项:
npm install @metaplex-foundation/umi @metaplex-foundation/umi-bundle-defaults @nifty-oss/asset
在你的项目目录中创建一个名为 index.ts
的新文件。
echo > index.ts
首先,导入所需的模块,设置 UMI 实例和签名者。在 index.ts
文件中添加以下代码:
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
import {
TransactionBuilderSendAndConfirmOptions,
generateSigner,
keypairIdentity,
sol
} from '@metaplex-foundation/umi';
import {
DelegateRole,
approve,
attributes,
creators,
delegateInput,
grouping,
lock,
mint,
niftyAsset,
revoke,
royalties,
transfer,
unlock,
verify
} from '@nifty-oss/asset';
createUmi
函数使用默认选项初始化 Umi 客户端。Umi 是一个 Solana 客户端库,提供与 Solana 区块链交互的高级 API。Nifty Asset 库包括用于铸造、转移和管理数字资产的函数——我们稍后将详细讨论这些函数。
接下来,初始化 Umi 客户端,创建 creator
、owner
、asset
、groupAsset
(即集合)和 delegate
账户的签名者。我们还将设置发送和确认交易的默认选项(在本地测试时可以使用 processed
)。
在 index.ts
文件中添加以下代码:
const umi = createUmi('http://127.0.0.1:8899', { commitment: 'processed' }).use(niftyAsset());
const creator = generateSigner(umi);
const owner = generateSigner(umi);
const asset = generateSigner(umi);
const groupAsset = generateSigner(umi);
const delegate = generateSigner(umi);
umi.use(keypairIdentity(creator));
const options: TransactionBuilderSendAndConfirmOptions = {
confirm: { commitment: 'processed' }
};
让我们将代码分解成几个部分,以便解释每个功能,然后通过一个 main()
函数将所有内容连接在一起。
首先,我们需要确保我们的 creator
、owner
和 delegate
钱包中有 SOL 用于支付交易费用和租金。在 index.ts
文件中添加以下函数以向这些账户空投 SOL:
async function airdropFunds() {
try {
await umi.rpc.airdrop(creator.publicKey, sol(100), options.confirm);
await umi.rpc.airdrop(owner.publicKey, sol(100), options.confirm);
await umi.rpc.airdrop(delegate.publicKey, sol(100), options.confirm);
console.log(`1. ✅ - 向 ${creator.publicKey.toString()} 空投了 100 SOL`);
} catch (error) {
console.error('1. ❌ - 向钱包空投 SOL 时出错。', error);
}
}
请注意,我们将函数放置在一个 try-catch
块中,以处理空投过程中可能出现的任何错误。当我们的预期结果发生时,我们记录 ✅
,如果没有发生则记录 ❌
-我们将在整个代码中使用这种模式来跟踪应用程序的进展。
让我们开始创建 groupAsset
,它将是一个管理资产组关联的资产。在 index.ts
文件中添加以下函数以铸造一个新的组资产:
async function mintGroupAsset() {
try {
await mint(umi, {
asset: groupAsset,
payer: umi.identity,
name: 'Group',
extensions: [\
grouping(10),\
creators([{ address: creator.publicKey, share: 100 }]),\
royalties(5)\
],
}).sendAndConfirm(umi, options);
await verify(umi, {
asset: groupAsset.publicKey,
creator,
}).sendAndConfirm(umi);
console.log(`2. ✅ - 铸造了一个新的组资产: ${groupAsset.publicKey.toString()}`);
} catch (error) {
console.error('2. ❌ - 铸造新的组资产时出错。', error);
}
}
让我们稍微分解一下,因为我们在这里做了几件事:
首先,我们使用 mint
函数创建一个新资产。我们传入 groupAsset
签名者来定义资产账户地址。我们为资产应用三个扩展:
grouping(10)
:设置最大组大小。creators([{ address: creator.publicKey, share: 100 }])
:定义资产的创作者及其份额(总和必须为 100%)。royalties(5)
:设置版税百分比(在这种情况下为 5%)。创作者份额和版税字段将用于将版税分配给该组中任何资产的创作者(这意味着我们不需要在各个资产中使用账户空间来存储此信息)。
verify
函数验证资产的 creator
。这防止了某人铸造资产并声称自己是创作者的情况。验证创作者后,账户中的布尔值被设置为 true,其他程序可以检查以验证资产的创作者。现在我们已经创建了一个组,让我们铸造一个新的数字资产并将其添加到组中。在 index.ts
文件中添加以下函数以铸造新的数字资产:
async function mintAsset() {
try {
await mint(umi, {
asset,
owner: owner.publicKey,
authority: creator.publicKey,
payer: umi.identity,
group: groupAsset.publicKey,
name: 'Digital Asset1',
extensions: [\
attributes([{ name: 'head', value: 'hat' }]),\
]
}).sendAndConfirm(umi, options);
console.log(`3. ✅ - 铸造了一个新的资产: ${asset.publicKey.toString()}`);
} catch (error) {
console.error('3. ❌ - 铸造新的 NFT 时出错。', error);
}
}
由于我们使用同一个签名者/权限来创建资产,因此我们可以通过传递 group
参数将资产添加到组中。如果我们使用的是不同的签名者/权限,我们需要使用 nifty-asset
库中的 group
函数来将资产添加到组中。
我们还为资产添加了一个 attributes
扩展,这将允许我们为其添加元数据。在这种情况下,我们添加了一个名为 head
、值为 hat
的特征,作为示例。注意,在这种情况下,我们希望我们的 extensions
是资产独有的——我们不需要添加 creators
或 royalties
扩展,因为它们已经在组资产中定义。
现在,让我们尝试 Nifty Asset 标准的一些本机功能。我们将为资产分配一个委托,并给予他们锁定和解锁资产的权限。在 index.ts
文件中添加以下函数以批准一个委托:
async function approveDelegate() {
try {
await approve(umi, {
asset: asset.publicKey,
owner,
delegate: delegate.publicKey,
delegateInput: delegateInput('Some', {
roles: [DelegateRole.Lock],
}),
}).sendAndConfirm(umi, options);
console.log(`4. ✅ - 为资产分配了委托锁定权限`);
} catch (error) {
console.error('4. ❌ - 为资产分配委托锁定权限时出错。', error);
}
}
我们使用 approve
函数并传入一个 delegateInput
对象来定义委托的角色。在这种情况下,我们将 Lock
角色分配给委托,允许他们锁定和解锁资产(其他选项包括 Transfer
、Burn
和 None
)。我们还传递了 owner
签名者来批准该委托。
现在,让我们创建一个函数来使用委托锁定资产。这将防止资产被转移。在 index.ts
文件中添加以下函数以锁定资产:
async function lockAsset() {
try {
await lock(umi, {
asset: asset.publicKey,
signer: delegate,
}).sendAndConfirm(umi, options);
console.log(`5. ✅ - 锁定资产: ${asset.publicKey.toString()}`);
} catch (error) {
console.error('5. ❌ - 锁定资产时出错。', error);
}
}
nifty/asset
库提供了一个 lock
函数来锁定资产。我们传递 delegate
签名者来锁定资产。这将防止资产被转移,直到它被解锁。让我们看看当我们尝试转移锁定资产时会发生什么。
让我们添加一个 transfer
函数,它将尝试将 asset
发送给新的接收者。由于资产被锁定,转移应该会失败。在 index.ts
文件中添加以下函数以尝试转移锁定资产:
async function tryTransferLockedAsset() {
try {
await transfer(umi, {
asset: asset.publicKey,
signer: owner,
recipient: generateSigner(umi).publicKey,
group: groupAsset.publicKey
}).sendAndConfirm(umi, options);
console.log(`6. ❌ - 资产不应该被转移,因为它被锁定。`);
} catch (error) {
console.log('6. ✅ - 资产不能被转移,因为它被锁定。');
}
}
让我们创建一个函数,使用 unlock
函数来解锁资产。在 index.ts
文件中添加以下函数以解锁资产:
async function unlockAsset() {
try {
await unlock(umi, {
asset: asset.publicKey,
signer: delegate,
}).sendAndConfirm(umi, options);
console.log(`7. ✅ - 解锁资产: ${asset.publicKey.toString()}`);
} catch (error) {
console.error('7. ❌ - 解锁资产时出错。', error);
}
}
请注意,我们必须使用与锁定资产相同的 delegate
签名者来解锁资产。
现在,资产应该已经解锁。在我们尝试转移它之前,让我们撤销委托的锁定权限,以防止对资产的任何意外限制。在 index.ts
文件中添加以下函数以撤销委托:
async function revokeDelegate() {
try {
await revoke(umi, {
asset: asset.publicKey,
signer: owner,
delegateInput: delegateInput('Some', {
roles: [DelegateRole.Lock],
}),
}).sendAndConfirm(umi, options);
console.log(`8. ✅ - 撤销了资产的委托锁定权限`);
} catch (error) {
console.error('8. ❌ - 撤销资产的委托锁定权限时出错。', error);
}
}
revoke
函数的功能与 approve
函数相反。我们传递 owner
签名者以撤销委托的锁定权限。
最后,既然委托已经被移除,让我们尝试将资产转移到新的接收者。在 index.ts
文件中添加以下函数以转移资产:
async function transferAsset() {
try {
await transfer(umi, {
asset: asset.publicKey,
signer: owner,
recipient: generateSigner(umi).publicKey,
group: groupAsset.publicKey
}).sendAndConfirm(umi, options);
console.log(`9. ✅ - 转移资产: ${asset.publicKey.toString()}`);
} catch (error) {
console.error('9. ❌ - 转移资产时出错。', error);
}
}
我们使用 transfer
函数将资产转移到新的接收者。我们传递 owner
签名者将资产转移到一个新生成的账户。请注意,我们还必须传递 group
参数,以确保如果适用则执行版税执行。
创建一个 main()
函数,将所有单独的函数结合在一起,按顺序执行整个过程。在 index.ts
文件的末尾添加以下内容:
async function main() {
await airdropFunds();
await mintGroupAsset();
await mintAsset();
await approveDelegate();
await lockAsset();
await tryTransferLockedAsset();
await unlockAsset();
await revokeDelegate();
await transferAsset();
}
main();
要运行你的脚本,请启动你的本地验证器,并将我们之前下载的 Nifty Asset 程序加载到其中。确保从包含文件的相同目录中运行此操作(或提供文件的完整路径):
solana-test-validator -r --bpf-program AssetGtQBTSgm5s91d1RAQod5JmaZiJDxqsgtqrZud73 nifty_asset.so
你的验证器应该启动并加载程序。如果遇到任何问题,请查看我们的 Solana 验证器设置指南 以获取更多信息,或者,如果你愿意,可以使用来自 QuickNode.com 的免费 Solana Devnet 端点。
要运行代码,请在终端中执行以下命令:
ts-node index.ts
如果一切设置正确,你应该会看到控制台日志,指示每个步骤的成功执行,或者如果出现问题,则显示详细的错误消息。
ts-node index.ts
1. ✅ - 向 3qmxo6SBygjbwj4mZZ5ivw7XEniXXSt6m6MGqVWacCvt 空投了 100 SOL
2. ✅ - 铸造了一个新的组资产: Auma2yBkHa59SKeWT9ru31KGYc8TrC8V8xwMW7pmTNgj
3. ✅ - 铸造了一个新的资产: FKGAfNdmGEPfqb2j7HiDmTfMurVPmWY8uoP2v2viyB1
4. ✅ - 为资产分配了委托锁定权限
5. ✅ - 锁定资产: FKGAfNdmGEPfqb2j7HiDmTfMurVPmWY8uoP2v2viyB1
6. ✅ - 资产不能被转移,因为它被锁定。
7. ✅ - 解锁资产: FKGAfNdmGEPfqb2j7HiDmTfMurVPmWY8uoP2v2viyB1
8. ✅ - 撤销了资产的委托锁定权限
9. ✅ - 转移资产: FKGAfNdmGEPfqb2j7HiDmTfMurVPmWY8uoP2v2viyB1
让我们开始吧!!!真是不错的东西,是吧?
在本指南中,我们涵盖了 Nifty OSS 新数字资产标准的基本功能。你现在拥有用于构建客户端应用程序的工具,该应用程序可以在 Solana 上对数字资产执行各种操作。那么,你还在等什么?让我们开始构建吧!如果你准备将项目带到主网,可以免费获取 Solana 主网端点,访问 QuickNode.com。
如果你有问题或想分享的想法,请在 Discord 或 Twitter 上告诉我们!
让我们知道 如果你有任何反馈或新主题请求。我们期待听到你的来信。
- 原文链接: quicknode.com/guides/sol...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!