本文详尽介绍了Solana的数字资产标准(DAS)API,提供了关于如何简化NFT和代币检索的全方位指南。文章涵盖了资产类型、API方法及其用法示例,展示了一系列用例以帮助开发者高效使用该API。
15分钟阅读
2023年6月9日
由于引入了数字资产标准(DAS)API,在 Solana 上检索 NFT 和代币变得更加简化。DAS API 是 Solana 开发者工具包的最新补充,提供了一个统一的界面来检索 Solana 上的数字资产。开发者现在可以利用一个单一的 API 来获取他们应用程序所需的数据,而不必处理与不同资产类型交互的多个端点。
本互动指南将涵盖:
本指南将使你能够跟随每个用例,在结束时,你将能够熟练使用 DAS。
在 Solana 生态系统中,"资产" 可以是任何有价值的数字项目,比如存在于区块链上的代币或非同质化代币(NFT)。Solana 支持各种各样的这些资产。了解 DAS API 在交互这些资产时返回的数据类型至关重要。
让我们更详细地查看每种资产类型。
非同质化资产遵循标准 NFT 模型,存储在代币账户中的元数据。这些数据存储在程序派生地址(PDA)中,PDA 是由程序拥有而不是特定用户拥有的地址。它们在 Solana 区块链上具有元数据 PDA 和主版本 PDA。
同质化资产是具有有限元数据的 SPL 代币。它们可以代表像 USDC 或社区/项目代币这样的代币。如果在创建时其小数值大于 0,则一个代币将符合同质化标准。
同质化资产代表项目而不是单个单位。它们可以持有比标准同质化资产更多的元数据。如果在创建同质化标准项目时小数设置为 0,则会转变为同质化资产标准。
可编程非同质化资产镜像非同质化标准,但保持在一个冻结的代币账户中。这种状态防止用户在不与代币元数据程序交互的情况下销毁、锁定或转移可编程资产。该标准是对 Solana 上版税争论的回应。
DAS API 提供了多种方法,针对不同的用例,包括:
getAsset
: 通过 ID 检索资产。searchAssets
: 使用各种参数查找资产。getAssetProof
: 通过 ID 获取压缩资产的 merkle 证明。getAssetsByGroup
: 根据组键和值获取资产列表。getAssetsByOwner
: 检索特定地址拥有的资产列表。getAssetsByCreator
: 获取由特定地址创建的资产列表。getAssetsByAuthority
: 查找具有特定权限的资产列表。有关每种方法的详细信息,请参考我们的 文档。
getAsset
端点允许你通过 ID 检索特定资产。这个 ID 可以代表链上的代币地址或针对压缩资产的 merkle 树中的 ID。
欲了解更多信息,请参考 getAsset 文档 。
假设我们想获取 Rank 1 Claynosaurz 资产的元数据。在这种情况下,我们需要找到资产的 ID,设置我们的函数以向 DAS 发起调用,并安排我们的响应来解析我们需要的确切对象。
请在下面按照步骤操作:
代码
const url = `https://rpc.helius.xyz/?api-key=`;
const getAsset = async () => {
// 代码在这里
};
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("资产: ", 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("资产: ", result);
};
getAsset();
确保将 <api-key>
替换为你的实际 API 密钥。
在此代码中,我们定义了一个异步函数 getAsset
,它向 DAS API 发送一个 POST 请求。我们将资产的 ID 作为请求体的一部分传递。请求完成后,函数将响应解析为 JSON,并将资产数据打印到控制台。最后,我们调用 getAsset
函数以执行该过程。
getAssetProof
端点用于检索资产证明,这对于对压缩程序进行修改是必要的。这些修改包括转移、销毁、更新创造者、更新集合以及解压缩压缩资产等操作。
欲了解更多使用资产证明的修改详细信息,请参考 文档 。
要获取修改压缩资产所需的资产证明,请遵循以下步骤:
代码
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("资产: ", 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("资产证明: ", result);
const root = decode(proof.root);
console.log(root)
在这里,我们从资产证明中提取根,随后可以用它对压缩资产进行其他修改。
在终端运行 node getAssetProof.js
以获取你在此处设置的资产的返回值。
输出将包含资产证明信息:
代码
资产证明: {
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("资产证明: ", result);
const root = proof.root;
console.log(root)
};
getAssetProof();
确保将 <api-key>
替换为你的实际 API 密钥。
在此脚本中,我们定义了一个异步函数 getAssetProof
,它向 Helius API 发送了 POST 请求。我们在请求体中传递资产的 ID。请求完成后,该函数将响应解析为 JSON,并将资产证明及其根打印到控制台。最后,我们调用 getAssetProof
函数以执行该过程。
searchAssets
方法根据指定的搜索参数检索数字资产,提供了一种灵活的方法来获取数据。它允许用户自定义搜索,从而更详细地控制返回的资产。
详细参数可在 searchAssets 文档 中找到。
让我们通过一个示例,让我们想要从用户的钱包中显示属于 Drip Haus 集合的资产图像和名称,并且仅显示其中的压缩项。为了简化本教程,我们将以 JSON 文件形式发布这个示例钱包中每个 Drip 资产的名称和图像。
代码
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;
const searchAssets = async () => {
// 代码在这里
};
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: {
// 仅返回压缩项目。
compressed: true,
// 示例钱包
ownerAddress: "2k5AXX4guW9XwRQ1AKCpAuUqgWDpQpwFfpVFh3hnm2Ha",
// Drip Haus 集合 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) {
// 将资产添加到现有组
existingGroup.assets.push(asset);
} else {
// 为资产创建新组
const newGroup = {
id: asset.id,
assets: [asset],
};
// 将新组添加到分组结果中
groupedResults.push(newGroup);
}
}
5. 将搜索结果保存到名为 searchResults.json 的 JSON 文件中:
代码
const json = JSON.stringify(groupedResults, null, 2);
// 将 JSON 写入文件
fs.writeFileSync('searchResults.json', json);
console.log('结果已保存到 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: {
// 仅返回压缩项目。
compressed: true,
// 示例钱包
ownerAddress: "2k5AXX4guW9XwRQ1AKCpAuUqgWDpQpwFfpVFh3hnm2Ha",
// Drip Haus 集合 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,
};
// 查找资产的现有组,如果存在
const existingGroup = groupedResults.find(group => group.id === asset.id);
if (existingGroup) {
// 添加资产到现有组
existingGroup.assets.push(asset);
} else {
// 为资产创建新组
const newGroup = {
id: asset.id,
assets: [asset],
};
// 将新组加入分组结果
groupedResults.push(newGroup);
}
}
// 将分组结果转换为 JSON
const json = JSON.stringify(groupedResults, null, 2);
// 将 JSON 写入文件
fs.writeFileSync('searchResults.json', json);
console.log('结果已保存至 results.json');
};
searchAssets();
确保用你的实际 API 密钥替换 <api-key>
。
在这个脚本中,我们定义了一个异步函数 searchAssets
,该函数发送一个 POST 请求。它在请求体中使用了各种搜索参数,如压缩、所有者地址和集合 ID。一旦请求完成,函数将解析响应为 JSON 并提取相关资产信息(ID、名称、JSON URI)。它根据 ID 对这些资产进行分组,并将这个组织好的数据保存到文件名为 searchResults.json 的 JSON 文件中。最后,我们调用 searchAssets
函数来启动这个过程。
getAssetsByOwner
端点提供了特定地址拥有的数字资产列表。这是使用 Helius 获取特定数字资产所有权信息的最快方法。
要获取某个地址拥有的资产,请按照以下步骤操作:
代码
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;
const getAssetsByOwner = async () => {
// 代码放这里
};
getAssetsByOwner();
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: {
// 示例钱包
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)) {
// 添加资产到现有组
groupedResults[ownerAddress].assets.push(asset);
} else {
// 为所有者创建新组
groupedResults[ownerAddress] = {
assets: [asset],
};
}
}
代码
// 将分组结果转换为 JSON
const json = JSON.stringify(groupedResults, null, 2);
// 将 JSON 写入文件
fs.writeFileSync('results.json', json);
console.log('结果已保存至 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: {
// 示例钱包
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)) {
// 添加资产到现有组
groupedResults[ownerAddress].assets.push(asset);
} else {
// 为所有者创建新组
groupedResults[ownerAddress] = {
assets: [asset],
};
}
}
// 将分组结果转换为 JSON
const json = JSON.stringify(groupedResults, null, 2);
// 将 JSON 写入文件
fs.writeFileSync('results.json', json);
console.log('结果已保存至 results.json');
};
getAssetsByOwner();
确保用你的实际 API 密钥替换 <api-key>
。
在这个脚本中,我们定义了一个异步函数 getAssetsByOwner
,该函数向 Helius API 发送一个 POST 请求。我们将所有者的地址传递在请求体中。请求完成后,函数解析响应为 JSON 并将拥有指定地址的资产打印到控制台。最后,我们调用 getAssetsByOwner
函数以执行该过程。
getAssetsByGroup 端点用于检索与特定集合 ID 相关的数字资产。当你需要获取特定于集合的项目或希望将 token-gated dApp 与特定链上的集合关联时,此端点至关重要。
在这个场景中,我们将为 SMB 设置集合快照。解析响应以提取所有者的资产从所拥有的对象中非常重要,详细信息请参阅我们的 文档。目标是筛选出拥有多个 SMB 的所有者,并仅在我们的 JSON 中显示一次,有效地创建了一个“快照”。
代码
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');
const uniqueOwners = new Set();
const getAssetsByGroup = async () => {
// 代码放这里
};
getAssetsByGroup();
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();
// 将每个所有者添加到 Set 中,自动丢弃重复项
result.items.forEach(item => uniqueOwners.add(item.ownership.owner));
page
参数来设置分页。如果少于 1000,则将 hasMoreResults
设置为 false 以停止分页:代码
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}
代码
const uniqueOwnersArray = Array.from(uniqueOwners);
const root = {
count: uniqueOwners.size,
owners: uniqueOwnersArray
};
Set
转换为数组。设置根值以发布到 JSON,包括持有者的数量和每个唯一的所有者钱包:代码
fs.writeFile('./ownerResults.json', jsonResult, 'utf8', (err) => {
if (err) {
console.error("写入 JSON 文件时出错:", err);
} else {
console.log("JSON 文件保存成功。");
}
});
console.log("唯一所有者的总数量:", uniqueOwners.size);
};
然后可以运行命令 node getAssetsByGroup.js
以填充“ownerResults.json”文件。
你的结果将是一个持有快照的 JSON 等价物,包括唯一所有者的数量和所有唯一所有者的列表:
代码
{
"count": 2785,
"owners": [
"6VqzFgtrJb33nhvbug4KZoUx8p65dD2iT1QuAeAQgYiw",
"5Xeb43ASEa64b9i9owcLB4yrNbUw1oMiTpcWsAdXN8qG",
"Cb355XH2WGPeQUGTTXWiQZT4nhnyHCPkhScDezUGhXQF",
"Fuu7xpK3mWqpqPLTHaxF7pU2czkBESKyg3r2Lm2F3AWz",
"1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix",
"86tCSKzryE5KvbTmMXN9tkxyn8GNr4z54DnNqrcZwYuy",
"D2DYL5sdxBCpauvKs1oyQkkSm2B9rFzzGowMacv3Q58z",
// 更多结果 ...
]
}
代码
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();
// 将每个所有者添加到 Set 中,自动丢弃重复项
result.items.forEach(item => uniqueOwners.add(item.ownership.owner));
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}
// 将 Set 转换为 Array 以便转换为字符串
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("写入 JSON 文件时出错:", err);
} else {
console.log("JSON 文件保存成功。");
}
});
};
console.log("唯一所有者的总数量:", uniqueOwners.size);
getAssetsByGroup();
确保用你的实际 API 密钥替换 <api-key>
。
你现在已学习如何使用 getAssetsByGroup
端点检索与特定集合 ID 相关的数字资产。通过有效利用分页和 Set 数据结构以确保唯一所有者条目,你可以创建任何带有链上 ID 的集合的当前持有者快照。
getAssetsByCreator
端点用于根据特定公钥地址检索创建的资产。当你想查找与特定艺术家或 Solana 上项目相关的资产时,这个端点非常有用。
在这个示例中,我们将返回由 Zen0 创建的资产。我们可以使用创建者地址,并将 onlyVerified
参数设置为 true 以仅检索由经过验证的钱包创建的资产。我们将解析结果以显示每个资产的 ID 和其所有者。
fs
模块将结果发布到 JSON 文件:代码
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');
const getAssetsByCreator = async () => {
// 代码放这里
};
getAssetsByCreator();
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++;
}
}
代码
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)) {
// 将资产添加到现有组
groupedResults[ownershipId].assets.push(asset);
} else {
// 为所有权 ID 创建新组
groupedResults[ownershipId] = {
assets: [asset],
};
}
}
代码
// 创建新数组以保存所需属性
const modifiedResults = totalResults.map(item => ({
id: item.id,
owner: item.ownership.owner
}));
// 创建根对象以保存计数和结果
const root = {
count: modifiedResults.length,
results: modifiedResults
};
fs
模块将结果保存到名为 "creatorResults.json" 的文件:代码
// 将分组结果转换为 JSON
const json = JSON.stringify(groupedResults, null, 2);
// 将 JSON 写入文件
fs.writeFileSync('creatorResults.json', json);
console.log('结果已保存至 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"
},
...
}
}
'ownershipId' 代表 Solana 区块链上所有者的公钥地址,资产是与该地址关联的 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++;
}
}
// 创建一个对象来存储分组结果
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)) {
// 添加资产到现有组
groupedResults[ownershipId].assets.push(asset);
} else {
// 为所有权 ID 创建新组
groupedResults[ownershipId] = {
assets: [asset],
};
}
}
// 将分组结果转换为 JSON
const json = JSON.stringify(groupedResults, null, 2);
// 将 JSON 写入文件
fs.writeFileSync('creatorResults.json', json);
};
console.log('结果已保存到 results.json');\ };\ \ getAssetsByCreator();\
\
确保将 `<api-key>` 替换为你的实际 API 密钥。\
\
在这个例子中,我们向 DAS API 的 “getAssetsByCreator” 端点发起异步请求。然后,我们传入我们的创作者地址并表示他们是经过验证的创作者。最后,我们设置响应,以解析每个在创作者地址下的资产的所有者,并发布到外部 JSON 文件。\
\
总的来说,这是一个有价值的工具,适合任何对跟踪或分析资产在 Solana 区块链上移动感兴趣的人,尤其是那些与特定创作者或项目相关的资产。\
\
### [7\. 按权威获取资产](https://www.helius.dev/blog/all-you-need-to-know-about-solanas-new-das-api\#7-get-assets-by-authority)\
\
函数 `getAssetsByAuthority` 获取与特定更新权威相关的资产。更新权威是一个拥有修改集合权限的地址。当你需要在集合 ID 不存在的情况下获取一组资产时,此功能尤其有价值。此外,它还提供了从一个权威地址检索更多资产的优势,扩展到一个集合 ID 之外的范围。\
\
#### [示例](https://www.helius.dev/blog/all-you-need-to-know-about-solanas-new-das-api\#example)\
\
在以下示例中,我们将检索 Taiyo Robotics、Pilots 和 Infants 中的每个集合 NFT 及其各自的所有者。由于它们共享一个共同的更新权威,因此可以返回与该项目相关的所有结果。\
\
这是对 `getAssetsByGroup` 函数的升级,因为你可以将资产分组与设定的权威 `CDgbhX61QFADQAeeYKP5BQ7nnzDyMkkR3NEhYF2ETn1k` 相关联。\
\
1. 首先,在新创建的名为 "getAssetsByAuthority.js" 的文件中设置函数:\
\
代码\
\
```\
const url = `https://rpc.helius.xyz/?api-key=`;\
\
const getAssetsByAuthority = async () => {\
// 代码在这里\
};\
getAssetsByAuthority();\
```\
\
1. 配置获取请求并在请求体中整合必要的参数,例如 `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++;\
}\
}\
```\
\
1. 处理资产以获取所需的信息。在这里,我们旨在显示资产的 ID 和所有者。我们还将创建一个根对象,以包含资产的计数和处理过的资产数组:\
\
代码\
\
```\
// 创建新数组以保存所需属性\
const modifiedResults = totalResults.map(item => ({\
id: item.id,\
owner: item.ownership.owner\
}));\
// 创建根对象以保存计数和结果\
const root = {\
count: modifiedResults.length,\
results: modifiedResults\
};\
```\
\
1. 我们现在准备将返回的项目发布到名为 authorityResults.json 的 JSON 文件,并在处理完成后记录日志。\
\
代码\
\
```\
const jsonResult = JSON.stringify(root, null, 2);\
\
fs.writeFile('./authorityResults.json', jsonResult, 'utf8', (err) => {\
if (err) {\
console.error("写入 JSON 文件时出错:", err);\
} else {\
console.log("JSON 文件成功保存.");\
}\
});\
console.log("处理完成.");\
console.timeEnd("getAssetsByAuthority");\
```\
\
最后,执行命令 `node getAssetsByAuthority.js` 以运行脚本并用获取的结果填充 "authorityResults.json" 文件。\
\
#### [**结果**](https://www.helius.dev/blog/all-you-need-to-know-about-solanas-new-das-api\#result)\
\
`getAssetsByAuthority` 端点的输出包括资产的计数和一个对象数组,每个对象代表一个资产,包含其 ID 和所有者。下面是一个示例:\
\
代码\
\
```\
{\
"count": 37330,\
"results": [\
{\
"id": "HmwL6uy7gQcXv74Mi8xF5G9mymZNd9rnUCpUFwSx1DX1",\
"owner": "5gt59Q14FEhT8LuETjLyiNHRkqCQf5hQsPP58ucBy5oC"\
},\
{\
"id": "HmztH56n4GD3p3EdgMKdzj8x21LjFQk4Bcp2YAQD8Urx",\
"owner": "H3AkHZHfcqGCcJpBn3FJWe52LcLxFMJQoZvZ6XyApFWf"\
},\
{\
"id": "Hn1NZXCaAxcr1btsaDm3eZRtLNbamy9FyrcVGLbZ2k5w",\
"owner": "AEqhqiQZBBa3dPTY1GwGsZJJnf5vzRKJpdXv6xzakfx8"\
}, ...\
}\
```\
\
#### [完整代码](https://www.helius.dev/blog/all-you-need-to-know-about-solanas-new-das-api\#full-code)\
\
代码\
\
```\
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++;\
}\
}\
// 创建新数组以保存所需属性\
const modifiedResults = totalResults.map(item => ({\
id: item.id,\
owner: item.ownership.owner\
}));\
\
// 创建根对象以保存计数和结果\
const root = {\
count: modifiedResults.length,\
results: modifiedResults\
};\
\
// 以2个空格的缩进格式化为可读的 JSON 字符串\
const jsonResult = JSON.stringify(root, null, 2);\
\
fs.writeFile('./authorityResults.json', jsonResult, 'utf8', (err) => {\
if (err) {\
console.error("写入 JSON 文件时出错:", err);\
} else {\
console.log("JSON 文件成功保存.");\
}\
});\
console.log("处理完成.");\
console.timeEnd("getAssetsByAuthority");\
};\
getAssetsByAuthority()\
```\
\
确保将 `<api-key>` 替换为你的实际 API 密钥。\
\
在这个例子中,我们采用 "getAssetsByAuthority" 方法来返回与一个权威地址相关的所有资产,涵盖 3 个集合。我们只使用 `page` 和 `limit` 作为请求的附加参数。随后,我们解析结果以提取权威下的资产,并将它们存储在外部 JSON 文件中。\
\
## [结论](https://www.helius.dev/blog/all-you-need-to-know-about-solanas-new-das-api\#conclusion)\
\
你现在应该对如何使用数字资产标准 (DAS) API 以及每种方法的多个实际应用有了全面的理解。这标志着从之前需要多个端点来获取特定资产信息的做法重大转变。\
\
这些方法适用于压缩和常规资产,提供了一种统一的接口,以多种方式发起这些请求。\
\
如需更多信息,你始终可以参考我们的详细 [文档](https://docs.helius.dev/compression-and-das-api/digital-asset-standard-das-api) 关于数字资产标准 (DAS) API,并探索我们的 [开放 API 小部件](https://docs.helius.dev/compression-and-das-api/digital-asset-standard-das-api) ,详细分解请求和响应参数。\
\
我们始终欢迎你加入我们的 [**Discord**](https://discord.gg/VbxaGJwmEr) 社区。如有任何疑问,请随时与我联系!\
>- 原文链接: [helius.dev/blog/all-you-...](https://www.helius.dev/blog/all-you-need-to-know-about-solanas-new-das-api)
>- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!