
Alles, was du über Solanas neue DAS API wissen musst
Überblick
Dank der Digital Asset Standard (DAS) API lassen sich NFTs und Token auf Solana jetzt einfacher abrufen. Die DAS API ist eine neue Ergänzung des Toolkits für Solana-Entwickler und bietet eine einheitliche Schnittstelle zum Abrufen digitaler Assets auf Solana. Statt für verschiedene Asset-Typen mehrere Endpunkte zu verwenden, können Entwickler jetzt über eine einzige API die benötigten Daten für ihre Anwendungen abrufen.
Dieser interaktive Leitfaden behandelt:
- Die verfügbaren Asset-Typen auf Solana.
- Einen umfassenden Überblick über die Methoden der DAS API.
- Einfach anpassbare Beispiele für reale Anwendungsfälle jedes Endpunkts.
In diesem Leitfaden kannst du jeden Anwendungsfall nachvollziehen. Am Ende kannst du DAS souverän einsetzen.
Voraussetzungen
- Node.js installiert (v18.0 ist für die integrierte Fetch-Funktion erforderlich)
- Helius RPC
- Grundkenntnisse in JavaScript
Umgebung einrichten
- Erstelle einen Projektordner namens functions.
- Erstelle für jedes Beispiel eine neue Datei in diesem Ordner.
Asset-Typen
Im Solana-Ökosystem kann ein „Asset“ jedes digitale Wertobjekt sein, das auf der Blockchain existiert, etwa ein Token oder Non-Fungible Token (NFT). Solana unterstützt eine große Bandbreite dieser Assets. Deshalb ist es wichtig zu verstehen, welche Daten die DAS API bei der Interaktion mit ihnen zurückgibt.
Sehen wir uns die einzelnen Asset-Typen genauer an.
Non-Fungible
Non-Fungible Assets folgen dem NFT-Standardmodell und speichern Metadaten in einem Token-Account. Diese Daten befinden sich in einer Program Derived Address (PDA), also einer Adresse, die einem Programm und nicht einem bestimmten Benutzer gehört. Auf der Solana-Blockchain besitzen sie eine Metadata PDA und eine Master Edition PDA.
Fungible
Fungible Assets sind SPL-Token mit begrenzten Metadaten. Sie können Token wie USDC oder Community-/Projekt-Token darstellen. Ein Token entspricht dem Fungible-Standard, wenn sein Dezimalwert bei der Erstellung größer als 0 ist.
Fungible Asset
Fungible Assets stellen Objekte statt einzelner Einheiten dar. Sie können mehr Metadaten als ein standardmäßiges Fungible Asset enthalten. Wird der Dezimalwert bei der Erstellung eines Elements nach dem Fungible-Standard auf 0 gesetzt, wird es in den Standard Fungible Asset umgewandelt.
Programmable Non-Fungible
Programmable Non-Fungible Assets entsprechen dem Non-Fungible-Standard, verbleiben jedoch in einem eingefrorenen Token-Account. Dadurch können Benutzer programmierbare Assets nicht burnen, sperren oder übertragen, ohne mit dem Token-Metadata-Programm zu interagieren. Dieser Standard entstand als Reaktion auf die Debatte über Lizenzgebühren auf Solana.
Verfügbare Methoden
Die DAS API bietet verschiedene Methoden für unterschiedliche Anwendungsfälle, darunter:
getAsset: Ruft ein Asset anhand seiner ID ab.searchAssets: Findet Assets anhand verschiedener Parameter.getAssetProof: Ruft anhand der ID einen Merkle-Proof für ein komprimiertes Asset ab.getAssetsByGroup: Ruft eine Liste von Assets anhand eines Gruppenschlüssels und -werts ab.getAssetsByOwner: Ruft eine Liste der Assets ab, die einer Adresse gehören.getAssetsByCreator: Ruft eine Liste der Assets ab, die von einer Adresse erstellt wurden.getAssetsByAuthority: Findet eine Liste von Assets mit einer bestimmten Authority.
Ausführliche Informationen zu den einzelnen Methoden findest du in unserer Dokumentation.
1. Asset abrufen
Mit dem Endpunkt getAsset kannst du ein bestimmtes Asset anhand seiner ID abrufen. Diese ID kann eine On-Chain-Token-Adresse oder bei komprimierten Assets die ID im Merkle-Baum darstellen.
Weitere Informationen findest du in der getAsset-Dokumentation.
Beispiel
Angenommen, wir möchten die Metadaten des Claynosaurz-Assets auf Rang 1 abrufen. Dazu müssen wir die ID des Assets ermitteln, unsere Funktion für den Aufruf von DAS einrichten und die Antwort so verarbeiten, dass wir aus den Ergebnissen genau das benötigte Objekt erhalten.
Führe die folgenden Schritte aus:
- Richte zunächst die Funktion in einer neuen Datei namens „getAsset.js“ ein:
const url = `https://rpc.helius.xyz/?api-key=`;
const getAsset = async () => {
// Code goes here
};
getAsset();2. Richte als Nächstes die Fetch- und Await-Operationen ein. Füge den erforderlichen ID-Parameter in den Body deiner Anfrage ein:
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',
},
}),
});In diesem Schritt senden wir eine POST-Anfrage an die DAS API. Der Request-Body enthält die eindeutige ID des Assets.
3. Parse die Ergebnisse und zeige die Metadaten an:
const { result } = await response.json();
console.log("asset: ", result);Dieses Code-Snippet parst die API-Antwort in das JSON-Format und gibt das Ergebnis in der Konsole aus.
Anschließend kannst du das Skript mit dem Befehl node getAsset.js ausführen.
Diese Methode ruft Daten für ein einzelnes Asset ab. Wenn du nach einer Gruppe von Assets suchen möchtest, bietet die DAS API weitere Methoden, die wir später erläutern.
Ergebnis
Beim Ausführen dieses Skripts werden die Metadaten des angegebenen Assets angezeigt:
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
}Diese Ausgabe enthält detaillierte Informationen zum Asset, darunter Schnittstellentyp, ID, Metadaten, Ersteller, Authorities und Eigentumsverhältnisse.
Vollständiger Code
Hier ist der vollständige Code, um ein Asset anhand seiner ID abzurufen:
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();Ersetze <api-key> durch deinen tatsächlichen API-Schlüssel.
In diesem Code definieren wir die asynchrone Funktion getAsset, die eine POST-Anfrage an die DAS API sendet. Wir übergeben die ID des Assets im Request-Body. Sobald die Anfrage abgeschlossen ist, parst die Funktion die Antwort als JSON und gibt die Asset-Daten in der Konsole aus. Abschließend rufen wir die Funktion getAsset auf, um diesen Prozess auszuführen.
2. Asset-Proof abrufen
Der Endpunkt getAssetProof ruft einen Asset-Proof ab, der für Änderungen am Komprimierungsprogramm erforderlich ist. Dazu gehören Aktionen wie das Übertragen, Burnen, Aktualisieren des Erstellers, Aktualisieren der Collection und Dekomprimieren komprimierter Assets.
Eine ausführliche Liste der Änderungen, für die der Asset-Proof verwendet wird, findest du in der Dokumentation.
Beispiel
Führe die folgenden Schritte aus, um den Asset-Proof abzurufen, der zum Ändern eines komprimierten Assets erforderlich ist:
- Richte zunächst die Funktion in einer neuen Datei namens „getAssetProof.js“ ein:
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. Richte anschließend Fetch und Await ein. Füge den erforderlichen ID-Parameter in den Body deiner Anfrage ein:
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. Parse das Ergebnis und extrahiere die Root:
const { proof } = await response.json();
console.log("Asset Proof: ", result);
const root = decode(proof.root);
console.log(root)Hier extrahieren wir die Root aus dem Asset-Proof. Anschließend kannst du sie für weitere Änderungen am komprimierten Asset verwenden.
Führe node getAssetProof.js in deinem Terminal aus, um eine Antwort für das hier angegebene Asset zu erhalten.
Ergebnis
Die Ausgabe enthält die Informationen zum Asset-Proof:
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'
}Vollständiger Code
Hier ist der vollständige Code, um einen Asset-Proof anhand seiner ID abzurufen:
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();Ersetze <api-key> durch deinen tatsächlichen API-Schlüssel.
In diesem Skript definieren wir die asynchrone Funktion getAssetProof, die eine POST-Anfrage an die Helius API sendet. Wir übergeben die ID des Assets im Request-Body. Sobald die Anfrage abgeschlossen ist, parst die Funktion die Antwort als JSON und gibt den Asset-Proof sowie dessen Root in der Konsole aus. Abschließend rufen wir die Funktion getAssetProof auf, um diesen Prozess auszuführen.
3. Assets suchen
Die Methode searchAssets ruft digitale Assets anhand bestimmter Suchparameter ab und ermöglicht so eine flexible Datenabfrage. Benutzer können die Suche anpassen und dadurch genauer steuern, welche Assets zurückgegeben werden.
Ausführliche Informationen zu den Parametern findest du in der searchAssets-Dokumentation.
Beispiel
Sehen wir uns ein Beispiel an: Wir möchten Bild und Namen der Assets aus einer Benutzer-Wallet anzeigen, die zur Drip-Haus-Collection gehören. Dabei sollen nur die enthaltenen komprimierten Elemente erscheinen. Um dieses Tutorial kurz zu halten, schreiben wir die Namen und Bilder der einzelnen Drip-Assets in der Beispiel-Wallet in eine JSON-Datei.
- Erstelle zunächst eine neue Datei namens searchAssets.js mit der folgenden asynchronen Funktion:
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;
const searchAssets = async () => {
// Code goes here
};
searchAssets();2. Implementiere die Funktion so, dass sie eine POST-Anfrage mit den angegebenen Suchparametern sendet. In diesem Fall verwenden wir die Parameter für Komprimierung, Eigentümeradresse und Collection-Gruppierung, um das gewünschte Ergebnis zu erhalten:
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. Parse die Antwort, gruppiere Assets anhand ihrer ID und behandle mögliche Duplikate, indem du genau die benötigten Daten aus der Antwort für jedes Element auswählst:
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. Die nächste Funktion sucht nach Duplikaten und entfernt sie aus unserer Liste. Wenn du wiederholte Assets anzeigen möchtest, kannst du auf diese Funktion verzichten. Ist ein Asset kein Duplikat, fügt die Funktion außerdem eine neue Asset-Gruppe hinzu:
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. Speichere die Suchergebnisse in einer JSON-Datei namens searchResults.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');Führe node searchAssets.js aus, um das Skript zu starten. Dadurch wird die Datei searchResults.json mit den Suchergebnissen gefüllt.
Ergebnis
[
{
"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"
}
]
}, ...
}Vollständiger Code
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();Ersetze <api-key> durch deinen tatsächlichen API-Schlüssel.
In diesem Skript definieren wir die asynchrone Funktion searchAssets, die eine POST-Anfrage sendet. Im Request-Body verwendet sie verschiedene Suchparameter, etwa Komprimierung, Eigentümeradresse und Collection-ID. Sobald die Anfrage abgeschlossen ist, parst die Funktion die Antwort als JSON und extrahiert die relevanten Asset-Informationen (ID, Name, JSON-URI). Sie gruppiert diese Assets nach ID und speichert die strukturierten Daten in einer JSON-Datei namens searchResults.json. Abschließend rufen wir die Funktion searchAssets auf, um den Prozess zu starten.
4. Assets nach Eigentümer abrufen
Der Endpunkt getAssetsByOwner stellt eine Liste der digitalen Assets bereit, die einer bestimmten Adresse gehören. Derzeit ist dies der schnellste Weg, mit Helius spezifische Eigentumsinformationen für digitale Assets abzurufen.
Beispiel
Führe die folgenden Schritte aus, um die Assets abzurufen, die einer bestimmten Adresse gehören:
- Richte zunächst die Funktion in einer neuen Datei namens „getAssetsByOwner.js“ ein:
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;
const getAssetsByOwner = async () => {
// Code goes here
};
getAssetsByOwner();- Richte Fetch und Await ein und füge deine Parameter in den Body der Anfrage ein. Für diesen Endpunkt verwenden wir
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
},
}),
});- Parse anschließend die Antwort und extrahiere die erforderlichen Asset-Informationen für die JSON-Ausgabe. Wir gruppieren Asset-ID, Name und JSON-URI unter der Wallet, nach der wir suchen:
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],
};
}
}- Jetzt können wir unsere Funktion für die Ausgabe in eine JSON-Datei einrichten:
// 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');Ergebnis
Die Ausgabe enthält die digitalen Assets, die der angegebenen Adresse gehören:
{
"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"
}, ...
}Vollständiger Code
Hier ist der vollständige Code, um die Assets abzurufen, die einer bestimmten Adresse gehören:
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();Ersetze <api-key> durch deinen tatsächlichen API-Schlüssel.
In diesem Skript definieren wir die asynchrone Funktion getAssetsByOwner, die eine POST-Anfrage an die Helius API sendet. Wir übergeben die Adresse des Eigentümers im Request-Body. Sobald die Anfrage abgeschlossen ist, parst die Funktion die Antwort als JSON und gibt die Assets, die der angegebenen Adresse gehören, in der Konsole aus. Abschließend rufen wir die Funktion getAssetsByOwner auf, um diesen Prozess auszuführen.
5. Assets nach Gruppe abrufen
Der Endpunkt getAssetsByGroup ruft digitale Assets ab, die einer bestimmten Collection-ID zugeordnet sind. Dieser Endpunkt ist wichtig, wenn du Elemente aus einer bestimmten Collection abrufen musst oder eine Token-gated dApp mit einer bestimmten On-Chain-Collection verknüpfen möchtest.
Beispiel
In diesem Szenario erstellen wir einen Collection-Snapshot für SMBs. Wie in unserer Dokumentation beschrieben, muss die Antwort geparst werden, um den Asset-Eigentümer aus dem Ownership-Objekt zu extrahieren. Wir möchten Eigentümer mehrerer SMBs filtern und jeden nur einmal in unserem JSON anzeigen. So erstellen wir effektiv einen „Snapshot“.
- Richte zunächst die Funktion in einer neuen Datei namens „getAssetsByGroup.js“ ein. Verwende ein Set, damit wir nur eindeutige Eigentümer speichern:
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');
const uniqueOwners = new Set();
const getAssetsByGroup = async () => {
// Code goes here
};
getAssetsByGroup();- Richte anschließend Fetch und Await ein. Füge die oben aufgeführten Parameter in den Body deiner Anfrage ein. Lege groupKey und groupValue in der Anfrage fest. Initialisiere
pagemit 1 undhasMoreResultsmit true, um die Paginierung vorzubereiten. Später sorgt eine Paginierungsfunktion dafür, dass false zurückgegeben wird, wenn die Ergebnisse einer Seite weniger als 1000 Elemente enthalten (das maximale Limit pro Anfrage):
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,
},
}),
});- Parse die Ergebnisse, um den Eigentümer-String zu extrahieren, der für den Snapshot der aktuellen Eigentümer erforderlich ist:
const { result } = await response.json();
// Add each owner to the Set, automatically discarding duplicates
result.items.forEach(item => uniqueOwners.add(item.ownership.owner));- Richte die Paginierung ein, indem du den Parameter
pageerhöhst, wenn 1000 Ergebnisse vorliegen. Sind es weniger, setzehasMoreResultsauf false, um die Paginierung zu beenden:
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}- Jetzt können wir unsere Eigentümer als Array festlegen und den Root-Wert für die Ausgabe in eine JSON-Datei einrichten. Diese enthält die Anzahl der Holder und jede eindeutige Eigentümer-Wallet:
const uniqueOwnersArray = Array.from(uniqueOwners);
const root = {
count: uniqueOwners.size,
owners: uniqueOwnersArray
};- Wandle das
Setmit eindeutigen Eigentümern in ein Array um. Richte den Wertrootfür die Ausgabe in eine JSON-Datei ein, die die Anzahl der Holder und jede eindeutige Eigentümer-Wallet enthält:
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);
};Anschließend kannst du den Befehl node getAssetsByGroup.js ausführen, um die Datei "ownerResults.json" mit deinen Ergebnissen zu füllen.
Ergebnis
Das Ergebnis entspricht einem Holder-Snapshot im JSON-Format. Es enthält die Anzahl der eindeutigen Eigentümer und eine Liste aller eindeutigen Eigentümer:
{
"count": 2785,
"owners": [
"6VqzFgtrJb33nhvbug4KZoUx8p65dD2iT1QuAeAQgYiw",
"5Xeb43ASEa64b9i9owcLB4yrNbUw1oMiTpcWsAdXN8qG",
"Cb355XH2WGPeQUGTTXWiQZT4nhnyHCPkhScDezUGhXQF",
"Fuu7xpK3mWqpqPLTHaxF7pU2czkBESKyg3r2Lm2F3AWz",
"1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix",
"86tCSKzryE5KvbTmMXN9tkxyn8GNr4z54DnNqrcZwYuy",
"D2DYL5sdxBCpauvKs1oyQkkSm2B9rFzzGowMacv3Q58z",
// Additional results ...
]
}Vollständiger Code
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();Ersetze <api-key> durch deinen tatsächlichen API-Schlüssel.
Du weißt jetzt, wie du mit dem Endpunkt getAssetsByGroup digitale Assets abrufst, die einer bestimmten Collection-ID zugeordnet sind. Mit Paginierung und der Datenstruktur Set stellst du eindeutige Eigentümereinträge sicher und kannst einen Snapshot der aktuellen Holder jeder Collection mit einer On-Chain-ID erstellen.
6. Assets nach Ersteller abrufen
Der Endpunkt getAssetsByCreator ruft Assets ab, die von einer bestimmten Public-Key-Adresse erstellt wurden. Dieser Endpunkt ist nützlich, wenn du Assets finden möchtest, die mit einem bestimmten Künstler oder Projekt auf Solana verknüpft sind.
Beispiel
In diesem Beispiel geben wir Assets zurück, die von Zen0 erstellt wurden. Wir können die Erstelleradresse verwenden und den Parameter onlyVerified auf true setzen, um nur Assets abzurufen, die von einer verifizierten Wallet erstellt wurden. Wir parsen die Ergebnisse, um die ID und den Eigentümer jedes Assets anzuzeigen.
- Richte zunächst die Funktion in einer neuen Datei namens "getAssetsByCreator.js" ein. Wir verwenden das Modul
fs, um unsere Ergebnisse in eine JSON-Datei zu schreiben:
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');
const getAssetsByCreator = async () => {
// Code goes here
};
getAssetsByCreator();- Jetzt können wir die Fetch-Anfrage einrichten und mit
awaitauf die Antwort warten. Lege die erforderlichen Parameter im Request-Body fest, daruntercreatorAddressundonlyVerified:
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,
},
}),
});Vergiss nicht, <creator-address> durch die tatsächliche Adresse des Erstellers zu ersetzen, dessen Assets du abrufen möchtest.
- Parse die Antwort, um das Ergebnis zu extrahieren und in einem Array zu speichern:
const { result } = await response.json();
allResults = allResults.concat(result.items);
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}- Gruppiere die Assets anhand der Ownership-ID, da eine Person mehrere Assets besitzen kann, und zeige die Assets an, die zu jeder ID gehören. Wird ein neuer Eigentümer erkannt, wird in der JSON-Datei eine neue Gruppe erstellt:
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],
};
}
}- Im nächsten Schritt strukturieren wir die Ergebnisse. In diesem Fall interessieren uns die Adresse des NFTs und der Eigentümer jedes zurückgegebenen Assets. Mit root geben wir die Länge der Rückgabe an und speichern unsere bearbeiteten Ergebnisse für die Ausgabe:
// 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
};- Abschließend speichern wir die Ergebnisse mithilfe des Moduls
fsin einer Datei namens "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');Führe abschließend den Befehl node getAssetsByCreator.js aus, um das Skript zu starten und die Datei "creatorResults.json" mit den abgerufenen Ergebnissen zu füllen.
Ergebnis
Die resultierende JSON-Datei enthält die Public-Key-Adresse jedes Eigentümers und die zugehörigen Assets. Jedes Asset wird durch seine ID dargestellt. So entsteht ein klarer Snapshot der Eigentumsverhältnisse für die Assets dieses Erstellers.
{
"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' steht für die Public-Key-Adresse des Eigentümers auf der Solana-Blockchain. Die Assets sind die mit dieser Adresse verknüpften NFTs.
Vollständiger Code
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();Ersetze <api-key> durch deinen tatsächlichen API-Schlüssel.
In diesem Beispiel senden wir eine asynchrone Anfrage an den Endpunkt „getAssetsByCreator“ der DAS API. Dann übergeben wir unsere Erstelleradresse und geben an, dass es sich um einen verifizierten Ersteller handelt. Abschließend richten wir unsere Antwort so ein, dass sie den Eigentümer jedes Assets unter dieser Erstelleradresse parst, und schreiben das Ergebnis in eine externe JSON-Datei.
Insgesamt ist dies ein wertvolles Tool für alle, die die Bewegung von Assets auf der Solana-Blockchain verfolgen oder analysieren möchten. Das gilt besonders für Assets, die mit einem bestimmten Ersteller oder Projekt verknüpft sind.
7. Assets nach Authority abrufen
Die Funktion getAssetsByAuthority ruft Assets ab, die einer bestimmten Update Authority zugeordnet sind. Eine Update Authority ist eine Adresse mit den Rechten, eine Collection zu ändern. Diese Funktion ist besonders nützlich, wenn du mehrere Assets abrufen musst, aber keine Collection-ID vorhanden ist. Außerdem kannst du damit eine größere Gruppe von Assets abrufen, die einer Authority-Adresse zugeordnet sind und über die Grenzen einer einzelnen Collection-ID hinausgehen.
Beispiel
Im folgenden Beispiel rufen wir jedes Collection-NFT und den jeweiligen Eigentümer aus Taiyo Robotics, Pilots und Infants ab. Da alle dieselbe Update Authority haben, können wir sämtliche für das Projekt relevanten Ergebnisse zurückgeben.
Dies ist eine Erweiterung gegenüber der Funktion getAssetsByGroup, da du Assets anhand einer festgelegten Authority CDgbhX61QFADQAeeYKP5BQ7nnzDyMkkR3NEhYF2ETn1k gruppieren kannst.
- Richte zunächst die Funktion in einer neu erstellten Datei namens "getAssetsByAuthority.js" ein:
const url = `https://rpc.helius.xyz/?api-key=`;
const getAssetsByAuthority = async () => {
// Code goes here
};
getAssetsByAuthority();- Konfiguriere die Fetch-Anfrage und füge dem Body die erforderlichen Parameter hinzu, etwa
authorityAddress,pageundlimit:
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,
},
}),
});Ersetze <authority-address> durch die tatsächliche Authority-Adresse, deren Assets du extrahieren möchtest.
3. Jetzt können wir unsere Rückgabe so einrichten, dass bei 1000 Ergebnissen weitere Ergebnisse durchlaufen werden.
Sind es weniger Ergebnisse, wird das Flag auf false gesetzt und die Paginierung beendet. hasMoreResults gibt dann false zurück.
const { result } = await response.json();
totalResults.push(...result.items);
if (result.items.length < 1000) {
hasMoreResults = false;
} else {
page++;
}
}- Verarbeite die Assets, um die benötigten Informationen zu ermitteln. Hier möchten wir die ID des Assets und seinen Eigentümer anzeigen. Außerdem erstellen wir ein Root-Objekt, das die Anzahl der Assets und das Array der verarbeiteten Assets enthält:
// 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
};- Jetzt können wir die zurückgegebenen Elemente in eine JSON-Datei namens authorityResults.json schreiben. Nach Abschluss des Prozesses geben wir eine Meldung aus.
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");Führe abschließend den Befehl node getAssetsByAuthority.js aus, um das Skript zu starten und die Datei "authorityResults.json" mit den abgerufenen Ergebnissen zu füllen.
Ergebnis
Die Ausgabe des Endpunkts getAssetsByAuthority enthält die Anzahl der Assets und ein Array von Objekten. Jedes Objekt stellt ein Asset dar und enthält dessen ID und Eigentümer. Hier ist ein Beispiel:
{
"count": 37330,
"results": [
{
"id": "HmwL6uy7gQcXv74Mi8xF5G9mymZNd9rnUCpUFwSx1DX1",
"owner": "5gt59Q14FEhT8LuETjLyiNHRkqCQf5hQsPP58ucBy5oC"
},
{
"id": "HmztH56n4GD3p3EdgMKdzj8x21LjFQk4Bcp2YAQD8Urx",
"owner": "H3AkHZHfcqGCcJpBn3FJWe52LcLxFMJQoZvZ6XyApFWf"
},
{
"id": "Hn1NZXCaAxcr1btsaDm3eZRtLNbamy9FyrcVGLbZ2k5w",
"owner": "AEqhqiQZBBa3dPTY1GwGsZJJnf5vzRKJpdXv6xzakfx8"
}, ...
}Vollständiger 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++;
}
}
// 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()Ersetze <api-key> durch deinen tatsächlichen API-Schlüssel.
In diesem Beispiel verwenden wir die Methode "getAssetsByAuthority", um alle Assets zurückzugeben, die über drei Collections hinweg mit einer Authority-Adresse verknüpft sind. Als zusätzliche Parameter für die Anfrage verwenden wir nur page und limit. Anschließend parsen wir die Ergebnisse, extrahieren die Assets unter dieser Authority und speichern sie in einer externen JSON-Datei.
Fazit
Du solltest jetzt genau verstehen, wie du die Digital Asset Standard (DAS) API verwendest, und mehrere praktische Anwendungen für jede Methode kennen. Dies ist eine deutliche Abkehr von früheren Ansätzen, bei denen mehrere Endpunkte zum Abrufen bestimmter Asset-Informationen erforderlich waren.
Diese Methoden unterstützen sowohl komprimierte als auch reguläre Assets und bieten eine einheitliche Schnittstelle, über die du diese Anfragen auf unterschiedliche Weise stellen kannst.
Weitere Informationen findest du jederzeit in unserer ausführlichen Dokumentation zur Digital Asset Standard (DAS) API. Du kannst auch unser Open-API-Widget erkunden, das die Anfrage- und Antwortparameter detailliert aufschlüsselt.
Wie immer laden wir dich ein, unserer Discord-Community beizutreten. Wenn du Fragen hast, kannst du mich dort jederzeit anpingen!
Ähnliche Artikel
Helius abonnieren
Bleib bei der Solana-Entwicklung auf dem Laufenden und erhalte Updates, wenn wir neue Beiträge veröffentlichen


