
全面了解 Solana 全新 DAS API
概述
随着数字资产标准(DAS)API 的推出,在 Solana 上检索 NFT 和代币变得更加简单。DAS API 是 Solana 开发者工具包中的新成员,提供了统一接口来检索 Solana 上的数字资产。开发者不再需要通过多个端点与不同类型的资产交互,只需使用一个 API,即可获取应用所需的数据。
本交互式指南将介绍:
- 了解 Solana 上可用的资产类型。
- 全面解析 DAS API 提供的方法。
- 演示每个端点的实际用例,并且都可轻松自定义。
你可以跟随本指南完成每个用例。学完后,你将能够熟练使用 DAS。
前提条件
- 已安装 Node.js(使用内置 fetch 需要 v18.0)
- Helius RPC
- 具备 JavaScript 基础知识
环境设置
- 创建名为 functions 的项目文件夹。
- 针对每个示例,在此文件夹中创建一个新文件。
资产类型
在 Solana 生态系统中,“资产”可以是区块链上任何有价值的数字项目,例如代币或非同质化代币(NFT)。Solana 支持多种此类资产。与这些资产交互时,了解 DAS API 返回的数据类型至关重要。
下面详细了解每种资产类型。
非同质化资产
非同质化资产遵循标准 NFT 模型,将元数据存储在代币账户中。这些数据位于程序派生地址(PDA),即由程序而非特定用户拥有的地址。它们在 Solana 区块链上拥有元数据 PDA 和主版本 PDA。
同质化资产
同质化资产是元数据有限的 SPL 代币。它们可以表示 USDC 等代币,也可以表示社区或项目代币。如果代币创建时的小数位数大于 0,则符合 Fungible 标准。
同质化资产项目
Fungible Asset 表示项目,而不是单个单位。与标准 Fungible 资产相比,它可以包含更多元数据。如果创建 Fungible 标准项目时将小数位数设为 0,它就会转换为 Fungible Asset 标准。
可编程非同质化资产
可编程非同质化资产与 Non-Fungible 标准类似,但始终保存在冻结的代币账户中。此状态可防止用户在不与 Token Metadata 程序交互的情况下销毁、锁定或转移可编程资产。该标准是为回应 Solana 上的版税争议而制定的。
可用方法
DAS API 提供了适用于不同用例的多种方法,包括:
getAsset:按 ID 检索资产。searchAssets:使用各种参数查找资产。getAssetProof:按 ID 获取压缩资产的 Merkle 证明。getAssetsByGroup:按分组键和值获取资产列表。getAssetsByOwner:检索某个地址拥有的资产列表。getAssetsByCreator:获取某个地址创建的资产列表。getAssetsByAuthority:查找具有特定权限的资产列表。
有关每种方法的详细信息,请参阅我们的文档。
1. 获取资产
通过 getAsset 端点,你可以按 ID 检索特定资产。此 ID 可以是链上代币地址,也可以是压缩资产在 Merkle 树上的 ID。
有关更多信息,请参阅 getAsset 文档。
示例
假设我们要获取排名第一的 Claynosaurz 资产的元数据。此时,我们需要找到资产 ID,设置函数以调用 DAS,并整理响应,从结果中解析出所需的具体对象。
请按照以下步骤操作:
- 首先,在名为“getAsset.js”的新文件中设置函数:
const url = `https://rpc.helius.xyz/?api-key=`;
const getAsset = async () => {
// Code goes here
};
getAsset();2. 接下来,设置 fetch 和 await 操作。在请求正文中包含必需的 ID 参数:
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAsset',
params: {
// Rank 1 Claynosaurz #7392
id: 'B1rzqj4cEM6pWsrm3rLPCu8QwcXMn6H6bd7xAnk941dU',
},
}),
});在此步骤中,我们向 DAS API 发送 POST 请求,并在请求正文中包含资产的唯一 ID。
3. 解析结果并显示元数据信息:
const { result } = await response.json();
console.log("asset: ", result);此代码片段将 API 响应解析为 JSON 格式,并将结果记录到控制台。
然后,你可以使用命令 node getAsset.js 运行脚本。
此方法用于检索单个资产的数据。如果需要搜索一组资产,DAS API 还提供了其他方法,我们将在后文介绍。
结果
执行此脚本将显示指定资产的元数据:
asset: {
interface: 'Custom',
id: 'B1rzqj4cEM6pWsrm3rLPCu8QwcXMn6H6bd7xAnk941dU',
content: {
'$schema': 'https://schema.metaplex.com/nft1.0.json',
json_uri: 'https://nftstorage.link/ipfs/bafybeig2dp7oyauxdkhwduh274ekbl3cixyvbnky444qfewz3vfcauos6m/7391.json',
files: [],
metadata: { name: 'Claynosaurz #7392', symbol: 'DINO' }
},
authorities: [
{
address: 'B7B2g3WbdZMDV3YcDGRGhEt5KyWqDJZFwRR8zpWVEkUF',
scopes: [Array]
}
],
compression: {
eligible: false,
compressed: false,
data_hash: '',
creator_hash: '',
asset_hash: '',
tree: '',
seq: 0,
leaf_id: 0
},
grouping: [
{
group_key: 'collection',
group_value: '6mszaj17KSfVqADrQj3o4W3zoLMTykgmV37W4QadCczK'
}
],
royalty: {
royalty_model: 'creators',
target: null,
percent: 0.05,
basis_points: 500,
primary_sale_happened: true,
locked: false
},
creators: [
{
address: 'AoebZtN5iKpVyUBc82aouWhugVknLzjUmEEUezxviYNo',
share: 0,
verified: true
},
{
address: '36tfiBtaDGjAMKd6smPacHQhe4MXycLL6f9ww9CD1naT',
share: 100,
verified: false
}
],
ownership: {
frozen: false,
delegated: false,
delegate: null,
ownership_model: 'single',
owner: '4zdNGgAtFsW1cQgHqkiWyRsxaAgxrSRRynnuunxzjxue'
},
supply: null,
mutable: true
}此输出提供资产的详细信息,包括接口类型、ID、元数据、创建者、权限和所有权。
完整代码
以下是使用资产 ID 获取资产的完整代码:
const url = `https://rpc.helius.xyz/?api-key=`;
const getAsset = async () => {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAsset',
params: {
id: 'B1rzqj4cEM6pWsrm3rLPCu8QwcXMn6H6bd7xAnk941dU',
},
}),
});
const { result } = await response.json();
console.log("asset: ", result);
};
getAsset();请务必将 <api-key> 替换为你的实际 API 密钥。
在此代码中,我们定义了异步函数 getAsset,用于向 DAS API 发送 POST 请求。我们在请求正文中传入资产 ID。请求完成后,该函数会将响应解析为 JSON,并把资产数据输出到控制台。最后,我们调用 getAsset 函数来执行此流程。
2. 获取资产证明
getAssetProof 端点用于检索修改压缩程序所需的资产证明。这类修改包括转移、销毁、更新创建者、更新集合以及解压缩压缩资产等操作。
有关使用资产证明进行修改的详细列表,请参阅文档。
示例
要获取修改压缩资产所需的资产证明,请按照以下步骤操作:
- 首先,在名为“getAssetProof.js”的新文件中设置函数:
const url = `https://rpc.helius.xyz/?api-key=`;
const getAsset = async () => {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAsset',
params: {
id: 'B1rzqj4cEM6pWsrm3rLPCu8QwcXMn6H6bd7xAnk941dU',
},
}),
});
const { result } = await response.json();
console.log("asset: ", result);
};
getAsset();2. 接着设置 fetch 和 await。在请求正文中包含必需的 ID 参数:
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAssetProof',
params: {
id: 'JDuAmJjiiNKCfK9SyW1aQCNvhL7krhVWZbeijVupAz4i'
},
}),
});3. 解析结果并提取根:
const { proof } = await response.json();
console.log("Asset Proof: ", result);
const root = decode(proof.root);
console.log(root)这里,我们从资产证明中提取根,之后可用它进一步修改压缩资产。
在终端中运行 node getAssetProof.js,即可获取此处所设资产的返回结果。
结果
输出将包含资产证明信息:
Assets Proof: {
root: 'FCdCNPGauQp1NqZbs1f4DDAWawHLbBqfD9LYjMy1fqH4',
proof: [
'EmJXiXEAhEN3FfNQtBa5hwR8LC5kHvdLsaGCoERosZjK',
'7NEfhcNPAwbw3L87fjsPqTz2fQdd1CjoLE138SD58FDQ',
'6dM3VyeQoYkRFZ74G53EwvUPbQC6LsMZge6c7S1Ds4ks',
'34dQBtcjnCUoPVzZEmVPAMH7b3b8aD6GUB9aYS11AaWJ',
'2VG5cKeBZdqozwhHGGzs13b9tzy9TXt9kPfN8MzSJ1Sm',
'r1o8vR5KFHJeER7A1K7kBCjceDHnUbSwiFEqqmeAQSd',
'88sRtuz1QHWhYEKtx1VamwwrmtDkb8vyDyUuqWCJrxoa',
'9Y8Xa2qwARx7Mg6deJwP37UEX9BA2tM75N4f6vaGyBDU',
'CKWwHXAcqoTptkjZkuKqhQ9iuajC8dK6f8eGpknesqWS',
'4n9Z4eSKNZa1a4oA3sbFGowA7go9BV9WopLpA4KqnYdD',
'6MJKrpnK1GbYsnEzwMRWStNGkTjAZF23NhzTQSQVXsD3',
'HjnrJn5vBUUzpCxzjjM9ZnCPuXei2cXKJjX468B9yWD7',
'4YCF1CSyTXm1Yi9W9JeYevawupkomdgy2dLxEBHL9euq',
'E3oMtCuPEauftdZLX8EZ8YX7BbFzpBCVRYEiLxwPJLY2'
],
node_index: 16384,
leaf: '6YdZXw49M97mfFTwgQb6kxM2c6eqZkHSaW9XhhoZXtzv',
tree_id: '2kuTFCcjbV22wvUmtmgsFR7cas7eZUzAu96jzJUvUcb7'
}完整代码
以下是使用资产 ID 获取资产证明的完整代码:
const url = `https://rpc.helius.xyz/?api-key=`;
const getAssetProof = async () => {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAssetProof',
params: {
id: 'JDuAmJjiiNKCfK9SyW1aQCNvhL7krhVWZbeijVupAz4i'
},
}),
});
const { result } = await response.json();
console.log("Asset Proof: ", result);
const root = proof.root;
console.log(root)
};
getAssetProof();请务必将 <api-key> 替换为你的实际 API 密钥。
在此脚本中,我们定义了异步函数 getAssetProof,用于向 Helius API 发送 POST 请求。我们在请求正文中传入资产 ID。请求完成后,该函数会将响应解析为 JSON,并把资产证明及其根输出到控制台。最后,我们调用 getAssetProof 函数来执行此流程。
3. 搜索资产
searchAssets 方法根据指定的搜索参数检索数字资产,提供灵活的数据获取方式。用户可以自定义搜索,从而更精细地控制返回的资产。
有关详细参数,请参阅 searchAssets 文档。
示例
下面来看一个示例:我们希望显示用户钱包中属于 Drip Haus 集合的资产图片和名称,并且仅显示其中的压缩项目。为使本教程简洁明了,我们会将示例钱包中每个 Drip 资产的名称和图片写入一个 JSON 文件。
- 首先,创建名为 searchAssets.js 的新文件,并添加以下异步函数:
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;
const searchAssets = async () => {
// Code goes here
};
searchAssets();2. 实现该函数,使用指定的搜索参数发送 POST 请求。这里我们使用压缩状态、所有者地址和集合分组参数来获得所需结果:
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "my-id",
method: "searchAssets",
params: {
// Returning only compressed items.
compressed: true,
// Example wallet
ownerAddress: "2k5AXX4guW9XwRQ1AKCpAuUqgWDpQpwFfpVFh3hnm2Ha",
// Drip Haus collection ID.
grouping: [
"collection",
"DRiP2Pn2K6fuMLKQmt5rZWyHiUZ6WK3GChEySUpHSS4x"
],
page: 1,
},
}),
});3. 解析响应,按 ID 对资产分组,并通过明确指定每项响应中所需的具体内容来处理潜在的重复项:
const { result } = await response.json();
const groupedResults = [];
for (let i = 0; i < result.items.length; i++) {
const asset = {
id: result.items[i].id,
name: result.items[i].content.metadata.name,
json_uri: result.items[i].content.json_uri,
};4. 下一个函数会查找重复项并将其从列表中移除。如果要显示重复资产,可以不使用此函数。当确定资产并非重复项时,该函数还会将其添加到新的资产组中:
const existingGroup = groupedResults.find(group => group.id === asset.id);
if (existingGroup) {
// Add the asset to the existing group
existingGroup.assets.push(asset);
} else {
// Create a new group for the asset
const newGroup = {
id: asset.id,
assets: [asset],
};
// Add the new group to the grouped results
groupedResults.push(newGroup);
}
}5. 将搜索结果保存到名为 searchResults.json 的 JSON 文件中:
const json = JSON.stringify(groupedResults, null, 2);
// Write the JSON to a file
fs.writeFileSync('searchResults.json', json);
console.log('Results saved to results.json');要执行脚本,请运行 node searchAssets.js。搜索结果将写入 searchResults.json 文件。
结果
[
{
"id": "4XSuZ2JaCPYA76EomCd1mZCtrjkx4F4sdcepBgBF2LKE",
"assets": [
{
"id": "4XSuZ2JaCPYA76EomCd1mZCtrjkx4F4sdcepBgBF2LKE",
"name": "MOMENT",
"json_uri": "https://arweave.net/3DniodKpcCTio-GlyB4GMjdA4c5epHzYQecdLZctt5s"
}
]
},
{
"id": "AJw2QNwWMLWTuUTiUWYpEyGjUQSPB5rYEcbn5uiBjQ2g",
"assets": [
{
"id": "AJw2QNwWMLWTuUTiUWYpEyGjUQSPB5rYEcbn5uiBjQ2g",
"name": "\"Kokoro\" (心)",
"json_uri": "https://arweave.net/PyPo4Zr4iWH2iRROBDtZTFZv3qWw1dVcrYPq4A_6ttM"
}
]
}, ...
}完整代码
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');
const searchAssets = async () => {
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: "my-id",
method: "searchAssets",
params: {
// Returning only compressed items.
compressed: true,
// Example wallet
ownerAddress: "2k5AXX4guW9XwRQ1AKCpAuUqgWDpQpwFfpVFh3hnm2Ha",
// Drip Haus collection ID.
grouping: [
"collection",
"DRiP2Pn2K6fuMLKQmt5rZWyHiUZ6WK3GChEySUpHSS4x"
],
page: 1,
},
}),
});
const { result } = await response.json();
const groupedResults = [];
for (let i = 0; i < result.items.length; i++) {
const asset = {
id: result.items[i].id,
name: result.items[i].content.metadata.name,
json_uri: result.items[i].content.json_uri,
};
// Find an existing group for the asset if it exists
const existingGroup = groupedResults.find(group => group.id === asset.id);
if (existingGroup) {
// Add the asset to the existing group
existingGroup.assets.push(asset);
} else {
// Create a new group for the asset
const newGroup = {
id: asset.id,
assets: [asset],
};
// Add the new group to the grouped results
groupedResults.push(newGroup);
}
}
// Convert the grouped results to JSON
const json = JSON.stringify(groupedResults, null, 2);
// Write the JSON to a file
fs.writeFileSync('searchResults.json', json);
console.log('Results saved to results.json');
};
searchAssets();请务必将 <api-key> 替换为你的实际 API 密钥。
在此脚本中,我们定义了异步函数 searchAssets,用于发送 POST 请求。它在请求正文中使用多种搜索参数,例如压缩状态、所有者地址和集合 ID。请求完成后,该函数会将响应解析为 JSON,并提取相关资产信息(ID、名称、JSON URI)。它按 ID 对这些资产分组,并将整理后的数据保存到名为 searchResults.json 的 JSON 文件中。最后,我们调用 searchAssets 函数来启动此流程。
4. 按所有者获取资产
getAssetsByOwner 端点提供特定地址拥有的数字资产列表。目前,这是使用 Helius 检索数字资产特定所有权信息的最快方式。
示例
要获取某个地址拥有的资产,请按照以下步骤操作:
- 首先,在名为“getAssetsByOwner.js”的新文件中设置函数:
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;
const getAssetsByOwner = async () => {
// Code goes here
};
getAssetsByOwner();- 设置 fetch 和 await,并在请求正文中包含参数。对于此端点,我们使用
ownerAddress:
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'hunter-test',
method: 'getAssetsByOwner',
params: {
// Example wallet
ownerAddress: '2k5AXX4guW9XwRQ1AKCpAuUqgWDpQpwFfpVFh3hnm2Ha',
page: 1
},
}),
});- 然后解析响应并提取必要的资产信息,以便写入 JSON。我们将使用资产 ID、名称和 JSON URI,按正在搜索的钱包进行分组:
const { result } = await response.json();
const groupedResults = {};
for (let i = 0; i < result.items.length; i++) {
const ownerAddress = result.items[i].owner.address;
const asset = {
id: result.items[i].id,
name: result.items[i].content.metadata.name,
json_uri: result.items[i].content.json_uri,
};
if (groupedResults.hasOwnProperty(ownerAddress)) {
// Add the asset to the existing group
groupedResults[ownerAddress].assets.push(asset);
} else {
// Create a new group for the owner
groupedResults[ownerAddress] = {
assets: [asset],
};
}
}- 现在可以设置函数,将结果写入 JSON:
// Convert the grouped results to JSON
const json = JSON.stringify(groupedResults, null, 2);
// Write the JSON to a file
fs.writeFileSync('results.json', json);
console.log('Results saved to results.json');结果
输出将包含指定地址拥有的数字资产:
{
"2k5AXX4guW9XwRQ1AKCpAuUqgWDpQpwFfpVFh3hnm2Ha": {
"assets": [
{
"id": "7Qj3QGCqRChr3uBR4R756usz2eoPSisoWcPfeozY7Bo",
"name": "",
"json_uri": "https://nftstorage.link/ipfs/bafybeiewlaxjeredwgsboqqha2ww25g46dgrqs6lwn5cooq3evsvye33iy/3071.json"
},
{
"id": "8W1Dx9vhyQ8fNyi6oVu2EFbZHo2kKpcRxMVbQ3em3ne",
"name": "Compass Rose #2745",
"json_uri": "https://shdw-drive.genesysgo.net/HqhFDmVhqqN23g4soMd8UzrfLEXT8GsjWtWaqxfm9A2x/2745.json"
},
{
"id": "Ba5qsjq5LryLPZ1e6AVqwPzB5LBBBzGWvvRQww4KCiG",
"name": "Foxy Pixel Demon #423",
"json_uri": "https://cdn.secretsphinx.io/ml/1c22a51697c644a8e45f603ed884ade7.json"
},
{
"id": "Hmid2Dhi3zLV7AxCAibQ8n4nviWdPv2ZvUeZq4N33oe",
"name": "",
"json_uri": "https://nftstorage.link/ipfs/bafybeiewlaxjeredwgsboqqha2ww25g46dgrqs6lwn5cooq3evsvye33iy/140.json"
}, ...
}完整代码
以下是获取特定地址所拥有资产的完整代码:
const url = `https://rpc.helius.xyz/?api-key=`;
const getAssetsByOwner = async () => {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'hunter-test',
method: 'getAssetsByOwner',
params: {
// Example wallet
ownerAddress: '2k5AXX4guW9XwRQ1AKCpAuUqgWDpQpwFfpVFh3hnm2Ha',
page: 1,
},
}),
});
const { result } = await response.json();
const groupedResults = {};
for (let i = 0; i < result.items.length; i++) {
const ownerAddress = result.items[i].owner.address;
const asset = {
id: result.items[i].id,
name: result.items[i].content.metadata.name,
json_uri: result.items[i].content.json_uri,
};
if (groupedResults.hasOwnProperty(ownerAddress)) {
// Add the asset to the existing group
groupedResults[ownerAddress].assets.push(asset);
} else {
// Create a new group for the owner
groupedResults[ownerAddress] = {
assets: [asset],
};
}
}
// Convert the grouped results to JSON
const json = JSON.stringify(groupedResults, null, 2);
// Write the JSON to a file
fs.writeFileSync('results.json', json);
console.log('Results saved to results.json');
};
getAssetsByOwner();请务必将 <api-key> 替换为你的实际 API 密钥。
在此脚本中,我们定义了异步函数 getAssetsByOwner,用于向 Helius API 发送 POST 请求。我们在请求正文中传入所有者地址。请求完成后,该函数会将响应解析为 JSON,并把指定地址拥有的资产输出到控制台。最后,我们调用 getAssetsByOwner 函数来执行此流程。
5. 按分组获取资产
getAssetsByGroup 端点用于检索与特定集合 ID 关联的数字资产。当你需要获取某个集合中的特定项目,或需要让代币门控 dApp 与某个链上集合关联时,此端点至关重要。
示例
在此场景中,我们将为 SMB 创建集合快照。请务必解析响应,从 ownership 对象中提取资产所有者,具体方法请参阅我们的文档。目标是筛选拥有多个 SMB 的所有者,并且在 JSON 中只显示一次,从而有效创建一个“快照”。
- 首先,在名为“getAssetsByGroup.js”的新文件中设置函数。使用 Set,确保只存储唯一所有者:
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');
const uniqueOwners = new Set();
const getAssetsByGroup = async () => {
// Code goes here
};
getAssetsByGroup();- 接着设置 fetch 和 await。在请求正文中设置上述参数。设置请求的 groupKey 和 groupValue。将
page初始化为 1,将hasMoreResults初始化为 true,为分页做好准备。之后将设置分页函数:如果某一页的结果少于 1000 条(每次请求的最大限制),则返回 false:
let page = 1;
let hasMoreResults = true;
while (hasMoreResults) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAssetsByGroup',
params: {
groupKey: 'collection',
groupValue: 'SMBtHCCC6RYRutFEPb4gZqeBLUZbMNhRKaMKZZLHi7W',
page,
limit: 1000,
},
}),
});- 解析结果,提取创建当前所有者快照所需的所有者字符串:
const { result } = await response.json();
// Add each owner to the Set, automatically discarding duplicates
result.items.forEach(item => uniqueOwners.add(item.ownership.owner));- 设置分页:如果有 1000 条结果,则增加
page参数。如果少于 1000 条,则将hasMoreResults设为 false 以停止分页:
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}- 现在,我们可以将所有者设为数组,并设置根值,将持有者数量和每个唯一所有者钱包写入 JSON:
const uniqueOwnersArray = Array.from(uniqueOwners);
const root = {
count: uniqueOwners.size,
owners: uniqueOwnersArray
};- 将唯一所有者的
Set转换为数组。设置root值,将持有者数量和每个唯一所有者钱包写入 JSON:
fs.writeFile('./ownerResults.json', jsonResult, 'utf8', (err) => {
if (err) {
console.error("Error writing JSON file:", err);
} else {
console.log("JSON file saved successfully.");
}
});
console.log("Total number of unique owners:", uniqueOwners.size);
};然后,你可以运行命令 node getAssetsByGroup.js,将结果写入“ownerResults.json”文件。
结果
结果将是与持有者快照等效的 JSON,其中包含唯一所有者的数量及所有唯一所有者的列表:
{
"count": 2785,
"owners": [
"6VqzFgtrJb33nhvbug4KZoUx8p65dD2iT1QuAeAQgYiw",
"5Xeb43ASEa64b9i9owcLB4yrNbUw1oMiTpcWsAdXN8qG",
"Cb355XH2WGPeQUGTTXWiQZT4nhnyHCPkhScDezUGhXQF",
"Fuu7xpK3mWqpqPLTHaxF7pU2czkBESKyg3r2Lm2F3AWz",
"1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix",
"86tCSKzryE5KvbTmMXN9tkxyn8GNr4z54DnNqrcZwYuy",
"D2DYL5sdxBCpauvKs1oyQkkSm2B9rFzzGowMacv3Q58z",
// Additional results ...
]
}完整代码
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');
const uniqueOwners = new Set();
const getAssetsByGroup = async () => {
let page = 1;
let hasMoreResults = true;
while (hasMoreResults) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAssetsByGroup',
params: {
groupKey: 'collection',
groupValue: 'SMBtHCCC6RYRutFEPb4gZqeBLUZbMNhRKaMKZZLHi7W',
page,
limit: 1000,
},
}),
});
const { result } = await response.json();
// Add each owner to the Set, automatically discarding duplicates
result.items.forEach(item => uniqueOwners.add(item.ownership.owner));
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}
// Convert Set to Array for stringification
const uniqueOwnersArray = Array.from(uniqueOwners);
const root = {
count: uniqueOwners.size,
owners: uniqueOwnersArray
};
const jsonResult = JSON.stringify(root, null, 2);
fs.writeFile('./ownerResults.json', jsonResult, 'utf8', (err) => {
if (err) {
console.error("Error writing JSON file:", err);
} else {
console.log("JSON file saved successfully.");
}
});
};
console.log("Total number of unique owners:", uniqueOwners.size);
getAssetsByGroup();请务必将 <api-key> 替换为你的实际 API 密钥。
现在,你已经学会如何使用 getAssetsByGroup 端点检索与特定集合 ID 关联的数字资产。通过有效使用分页和 Set 数据结构来确保所有者条目唯一,你可以为任何具有链上 ID 的集合创建当前持有者快照。
6. 按创建者获取资产
getAssetsByCreator 端点用于检索由特定公钥地址创建的资产。当你想查找 Solana 上与特定艺术家或项目相关的资产时,此端点非常有用。
示例
在此示例中,我们将返回 Zen0 创建的资产。我们可以使用创建者地址,并将 onlyVerified 参数设为 true,从而仅检索由已验证钱包创建的资产。我们将解析结果,显示每项资产的 ID 及其所有者。
- 首先,在名为“getAssetsByCreator.js”的新文件中设置函数。我们将使用
fs模块,把结果写入 JSON 文件:
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');
const getAssetsByCreator = async () => {
// Code goes here
};
getAssetsByCreator();- 现在可以设置 fetch 请求,并对响应执行
await。在请求正文中设置必要参数,包括creatorAddress和onlyVerified:
let page = 1;
let allResults = [];
let hasMoreResults = true;
while (hasMoreResults) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAssetsByCreator',
params: {
creatorAddress: 'zvrsoq2LbNxekPqLK1v8DsLgeC4LHxMQL52beX8Ktn8',
onlyVerified: true,
page,
limit: 1000,
},
}),
});不要忘记将 <creator-address> 替换为你要检索其资产的创建者实际地址。
- 解析响应以提取结果,并将其存储在数组中:
const { result } = await response.json();
allResults = allResults.concat(result.items);
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}- 根据所有权 ID 对资产分组(因为一个人可以拥有多项资产),并显示每个 ID 拥有的资产。如果检测到新所有者,则会在 JSON 文件中创建一个新分组:
const groupedResults = {};
for (let i = 0; i < allResults.length; i++) {
const ownershipId = allResults[i].ownership.owner;
const asset = {
id: allResults[i].id,
ownershipId: ownershipId,
};
if (groupedResults.hasOwnProperty(ownershipId)) {
// Add the asset to the existing group
groupedResults[ownershipId].assets.push(asset);
} else {
// Create a new group for the ownership ID
groupedResults[ownershipId] = {
assets: [asset],
};
}
}- 下一步是构建结果结构。这里我们关注 NFT 的地址以及每项返回资产的所有者。我们使用 root 指定返回结果的长度,并存储修改后的结果以供输出:
// Create new array to hold the desired properties
const modifiedResults = totalResults.map(item => ({
id: item.id,
owner: item.ownership.owner
}));
// Create a root object to hold the count and the results
const root = {
count: modifiedResults.length,
results: modifiedResults
};- 最后,我们使用
fs模块将结果保存到名为“creatorResults.json”的文件中:
// Convert the grouped results to JSON
const json = JSON.stringify(groupedResults, null, 2);
// Write the JSON to a file
fs.writeFileSync('creatorResults.json', json);
console.log('Results saved to results.json');最后,运行命令 node getAssetsByCreator.js 执行脚本,并将检索结果写入“creatorResults.json”文件。
结果
生成的 JSON 文件包含每位所有者的公钥地址及其各自拥有的资产。每项资产均由其 ID 表示,从而清晰呈现特定创建者所创建资产的所有权状态快照。
{
"ZVcBfkk3Be8QMn4rmQL2VtP2WJQp9wpU8udFwrTGA22": {
"assets": [
{
"id": "KvbtDebCi6BGSFuafJWZpwV5mt1XYng13Pt2vh4G2Qa",
"ownershipId": "ZVcBfkk3Be8QMn4rmQL2VtP2WJQp9wpU8udFwrTGA22"
},
{
"id": "28bXCZaETv6ihBGbtavDkedzRcWZPbmDG5VYXxSdmZBc",
"ownershipId": "ZVcBfkk3Be8QMn4rmQL2VtP2WJQp9wpU8udFwrTGA22"
},
{
"id": "2H4txSfZwV3nX4fJ1D8dPNHiafn247iQ8vtq3y3UYdpe",
"ownershipId": "ZVcBfkk3Be8QMn4rmQL2VtP2WJQp9wpU8udFwrTGA22"
},
{
"id": "5oauJRPWbboJVUBms2mqBF2wMQGMSCFScgX18SawyKV3",
"ownershipId": "ZVcBfkk3Be8QMn4rmQL2VtP2WJQp9wpU8udFwrTGA22"
},
"Fb7pzfL6SLDNi79WSWkZm6zKA94LYNsYKDJC7GNvkZaC": {
"assets": [
{
"id": "2jLjf8Vmbisu5eac1NgSiDcqkcJfR8R9LSGjD6SExC99",
"ownershipId": "Fb7pzfL6SLDNi79WSWkZm6zKA94LYNsYKDJC7GNvkZaC"
},
{
"id": "2rVtLCHWp1hpUc7YVoAkFrSL3iwGQDcCzAvboCvrq5kT",
"ownershipId": "Fb7pzfL6SLDNi79WSWkZm6zKA94LYNsYKDJC7GNvkZaC"
},
{
"id": "6QXfTMwuaKTMZyFYoUwNWpaT692Z9Zqg94WE9MTi4J2p",
"ownershipId": "Fb7pzfL6SLDNi79WSWkZm6zKA94LYNsYKDJC7GNvkZaC"
}
]
}, ...
}'ownershipId' 表示所有者在 Solana 区块链上的公钥地址,而 assets 则是与该地址关联的 NFT。
完整代码
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;
const getAssetsByCreator = async () => {
let page = 1;
let allResults = [];
let hasMoreResults = true;
while (hasMoreResults) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAssetsByCreator',
params: {
creatorAddress: 'zvrsoq2LbNxekPqLK1v8DsLgeC4LHxMQL52beX8Ktn8',
onlyVerified: true,
page,
limit: 1000,
},
}),
});
const { result } = await response.json();
allResults = allResults.concat(result.items);
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}
// Create an object to store the grouped results
const groupedResults = {};
for (let i = 0; i < allResults.length; i++) {
const ownershipId = allResults[i].ownership.owner;
const asset = {
id: allResults[i].id,
ownershipId: ownershipId,
};
if (groupedResults.hasOwnProperty(ownershipId)) {
// Add the asset to the existing group
groupedResults[ownershipId].assets.push(asset);
} else {
// Create a new group for the ownership ID
groupedResults[ownershipId] = {
assets: [asset],
};
}
}
// Convert the grouped results to JSON
const json = JSON.stringify(groupedResults, null, 2);
// Write the JSON to a file
fs.writeFileSync('creatorResults.json', json);
console.log('Results saved to results.json');
};
getAssetsByCreator();请务必将 <api-key> 替换为你的实际 API 密钥。
在此示例中,我们向 DAS API 的“getAssetsByCreator”端点发出异步请求。然后传入创建者地址,并指明该创建者已经验证。最后,我们设置响应解析逻辑,提取该创建者地址下每项资产的所有者,并将结果写入外部 JSON 文件。
总而言之,对于任何有兴趣追踪或分析 Solana 区块链上资产流动的人来说,这都是一项实用工具,尤其适用于与特定创建者或项目关联的资产。
7. 按权限获取资产
函数 getAssetsByAuthority 用于获取与特定更新权限关联的资产。更新权限是拥有修改集合权利的地址。当集合 ID 不存在,而你需要获取一组资产时,此功能尤其有用。此外,它还可以检索与某个权限地址关联的更大范围资产,不受单个集合 ID 的限制。
示例
在以下示例中,我们将检索 Taiyo Robotics、Pilots 和 Infants 各集合中的 NFT 及其相应所有者。由于它们共享同一个更新权限,因此可以返回与该项目相关的全部结果。
这是对 getAssetsByGroup 函数的升级,因为你可以按指定权限 CDgbhX61QFADQAeeYKP5BQ7nnzDyMkkR3NEhYF2ETn1k 对关联资产进行分组。
- 首先,在新建的“getAssetsByAuthority.js”文件中设置函数:
const url = `https://rpc.helius.xyz/?api-key=`;
const getAssetsByAuthority = async () => {
// Code goes here
};
getAssetsByAuthority();- 配置 fetch 请求,并在正文中加入必要参数,例如
authorityAddress、page和limit:
let page = 1;
let hasMoreResults = true;
while (hasMoreResults) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAssetsByAuthority',
params: {
authorityAddress: 'CDgbhX61QFADQAeeYKP5BQ7nnzDyMkkR3NEhYF2ETn1k',
page,
limit: 1000,
},
}),
});请务必将 <authority-address> 替换为你要提取其资产的实际权限地址。
3. 现在可以安排返回逻辑,在结果达到 1000 条时继续循环获取。
如果结果数量较少,该标志将设为 false 并终止分页,此时 hasMoreResults 将返回 false。
const { result } = await response.json();
totalResults.push(...result.items);
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}- 处理资产以提取所需信息。这里我们要显示资产 ID 及其所有者。我们还会创建一个根对象,其中包含资产数量和处理后的资产数组:
// Create new array to hold the desired properties
const modifiedResults = totalResults.map(item => ({
id: item.id,
owner: item.ownership.owner
}));
// Create a root object to hold the count and the results
const root = {
count: modifiedResults.length,
results: modifiedResults
};- 现在,我们可以将返回项写入名为 authorityResults.json 的 JSON 文件,并在流程结束后记录日志。
const jsonResult = JSON.stringify(root, null, 2);
fs.writeFile('./authorityResults.json', jsonResult, 'utf8', (err) => {
if (err) {
console.error("Error writing JSON file:", err);
} else {
console.log("JSON file saved successfully.");
}
});
console.log("Process completed.");
console.timeEnd("getAssetsByAuthority");最后,执行命令 node getAssetsByAuthority.js 运行脚本,并将获取的结果写入“authorityResults.json”文件。
结果
getAssetsByAuthority 端点的输出包含资产数量和一个对象数组。每个对象代表一项资产,并包含其 ID 和所有者。以下是一个示例:
{
"count": 37330,
"results": [
{
"id": "HmwL6uy7gQcXv74Mi8xF5G9mymZNd9rnUCpUFwSx1DX1",
"owner": "5gt59Q14FEhT8LuETjLyiNHRkqCQf5hQsPP58ucBy5oC"
},
{
"id": "HmztH56n4GD3p3EdgMKdzj8x21LjFQk4Bcp2YAQD8Urx",
"owner": "H3AkHZHfcqGCcJpBn3FJWe52LcLxFMJQoZvZ6XyApFWf"
},
{
"id": "Hn1NZXCaAxcr1btsaDm3eZRtLNbamy9FyrcVGLbZ2k5w",
"owner": "AEqhqiQZBBa3dPTY1GwGsZJJnf5vzRKJpdXv6xzakfx8"
}, ...
}完整代码
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;
const totalResults = [];
const getAssetsByAuthority = async () => {
let page = 1;
let hasMoreResults = true;
while (hasMoreResults) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 'my-id',
method: 'getAssetsByAuthority',
params: {
authorityAddress: 'CDgbhX61QFADQAeeYKP5BQ7nnzDyMkkR3NEhYF2ETn1k',
page,
limit: 1000,
},
}),
});
const { result } = await response.json();
totalResults.push(...result.items);
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}
// Create new array to hold the desired properties
const modifiedResults = totalResults.map(item => ({
id: item.id,
owner: item.ownership.owner
}));
// Create a root object to hold the count and the results
const root = {
count: modifiedResults.length,
results: modifiedResults
};
// Stringify with 2 spaces indentation for readability
const jsonResult = JSON.stringify(root, null, 2);
fs.writeFile('./authorityResults.json', jsonResult, 'utf8', (err) => {
if (err) {
console.error("Error writing JSON file:", err);
} else {
console.log("JSON file saved successfully.");
}
});
console.log("Process completed.");
console.timeEnd("getAssetsByAuthority");
};
getAssetsByAuthority()请务必将 <api-key> 替换为你的实际 API 密钥。
在此示例中,我们使用“getAssetsByAuthority”方法返回 3 个集合中与某个权限地址关联的所有资产。请求仅使用 page 和 limit 作为附加参数。随后,我们解析结果以提取该权限下的资产,并将其存储到外部 JSON 文件中。
总结
现在,你应该已经全面了解如何使用数字资产标准(DAS)API,以及每种方法的多个实际应用。这与过去必须使用多个端点才能获取特定资产信息的做法相比,是一次重大转变。
这些方法同时支持压缩资产和普通资产,并提供统一接口,让你能以多种方式发出这些请求。
如需了解更多信息,你可以随时查阅我们有关数字资产标准(DAS)API 的详尽文档,并探索 Open API 小组件,其中详细说明了请求和响应参数。
一如既往,我们邀请你加入我们的 Discord 社区。如果有任何问题,欢迎在那里联系我!
相关文章
订阅 Helius
及时了解 Solana 开发的最新动态,并在我们发布新内容时收到更新


