NUEVO: Helius adquiere Light Protocol
API de NFT DAS de Solana
Blog/Actualizaciones

Todo lo que necesitas saber sobre la nueva DAS API de Solana

Líder de relaciones con desarrolladoresHunter Davis en LinkedIn
15 min de lectura

Descripción general

Recuperar NFT y tokens en Solana ahora es más sencillo gracias a la introducción de la API del estándar de activos digitales (DAS). La DAS API, una incorporación reciente al conjunto de herramientas para desarrolladores de Solana, ofrece una interfaz unificada para recuperar activos digitales en Solana. En lugar de usar varios endpoints para interactuar con distintos tipos de activos, los desarrolladores ahora pueden aprovechar una sola API para obtener los datos que necesitan sus aplicaciones.

Esta guía interactiva abordará:

  1. Los tipos de activos disponibles en Solana.
  2. Un análisis completo de los métodos que ofrece la DAS API.
  3. Demostraciones de casos de uso reales para cada endpoint que puedes personalizar fácilmente.

Esta guía te permitirá seguir cada caso de uso y, al finalizar, podrás utilizar DAS con soltura.

Requisitos previos

  • Node.js instalado (se requiere v18.0 para usar fetch integrado)
  • Helius RPC
  • Conocimientos básicos de JavaScript

Configuración del entorno

  1. Crea una carpeta de proyecto llamada functions.
  2. Para cada ejemplo, crea un archivo nuevo dentro de esta carpeta.

Tipos de activos

En el ecosistema de Solana, un "activo" puede ser cualquier elemento digital de valor, como tokens o tokens no fungibles (NFT), que exista en la blockchain. Solana admite una amplia variedad de estos activos. Es fundamental comprender el tipo de datos que devuelve la DAS API al interactuar con ellos.

Veamos cada tipo de activo con más detalle.

No fungible

Los activos no fungibles siguen el modelo estándar de NFT y almacenan metadatos en una cuenta de token. Estos datos residen en una dirección derivada de programa (PDA), una dirección que pertenece a un programa y no a un usuario específico. Incluyen una PDA de metadatos y una PDA de edición maestra en la blockchain de Solana.

Fungible

Los activos fungibles son tokens SPL con metadatos limitados. Pueden representar tokens como USDC o tokens de una comunidad o proyecto. Un token cumplirá con el estándar Fungible si su valor decimal es mayor que 0 al crearlo.

Activo fungible

Los activos fungibles representan elementos en lugar de unidades individuales. Pueden contener más metadatos que un activo Fungible estándar. Si el valor decimal se establece en 0 al crear un elemento del estándar Fungible, este se transforma al estándar Fungible Asset.

No fungible programable

Los activos no fungibles programables siguen el estándar Non-Fungible, pero permanecen en una cuenta de token congelada. Este estado impide que los usuarios quemen, bloqueen o transfieran activos programables sin interactuar con el programa Token Metadata. Este estándar surgió como respuesta al debate sobre las regalías en Solana.

Métodos disponibles

La DAS API ofrece varios métodos adaptados a distintos casos de uso, entre ellos:

  1. getAsset: Recupera un activo por su ID.
  2. searchAssets: Localiza activos mediante distintos parámetros.
  3. getAssetProof: Obtén una prueba de Merkle para un activo comprimido mediante su ID.
  4. getAssetsByGroup: Obtén una lista de activos mediante una clave y un valor de grupo.
  5. getAssetsByOwner: Recupera una lista de activos que pertenecen a una dirección.
  6. getAssetsByCreator: Obtén una lista de activos creados por una dirección.
  7. getAssetsByAuthority: Encuentra una lista de activos con una autoridad específica.

Para obtener información detallada sobre cada método, consulta nuestra documentación.

1. Obtener un activo

El endpoint getAsset te permite recuperar un activo específico mediante su ID. Este ID puede representar la dirección de un token onchain o el ID en el árbol de Merkle para activos comprimidos.

Para obtener más información, consulta la documentación de getAsset.

Ejemplo

Supongamos que queremos obtener los metadatos del activo Rank 1 Claynosaurz. En este caso, debemos localizar el ID del activo, configurar nuestra función para llamar a DAS y organizar la respuesta para analizar el objeto exacto que necesitamos de los resultados.

Sigue estos pasos:

  1. Primero, configura la función en un archivo nuevo llamado “getAsset.js”:
Código
const url = `https://rpc.helius.xyz/?api-key=`;

const getAsset = async () => {
// Code goes here
};
getAsset();

     2. Después, configura las operaciones fetch y await. Incluye el parámetro ID requerido en el cuerpo de la solicitud:

Código
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',
      },
    }),
  });

En este paso, enviamos una solicitud POST a la DAS API con el ID único del activo en el cuerpo de la solicitud.

    3. Analiza los resultados y muestra la información de los metadatos:

Código
const { result } = await response.json();
console.log("asset: ", result);

Este fragmento de código analiza la respuesta de la API en formato JSON y registra el resultado en la consola.

Luego puedes ejecutar el script con el comando node getAsset.js.

Resultado

Al ejecutar este script, se mostrarán los metadatos del activo especificado:

Código
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
}

Esta salida proporciona información detallada sobre el activo, como el tipo de interfaz, el ID, los metadatos, los creadores, las autoridades y la propiedad.

Código completo

A continuación se muestra el código completo para obtener un activo mediante su ID:

Código
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();

Asegúrate de reemplazar <api-key> por tu clave de API real.

En este código, definimos una función asíncrona, getAsset, que envía una solicitud POST a la DAS API. Pasamos el ID del activo en el cuerpo de la solicitud. Cuando finaliza la solicitud, la función analiza la respuesta como JSON e imprime los datos del activo en la consola. Por último, invocamos la función getAsset para ejecutar este proceso.

2. Obtener una prueba de activo

El endpoint getAssetProof se usa para recuperar una prueba de activo necesaria para modificar el programa de compresión. Estas modificaciones incluyen acciones como transferir, quemar, actualizar al creador, actualizar la colección y descomprimir activos comprimidos.

Para consultar una lista detallada de las modificaciones que usan la prueba de activo, revisa la documentación.

Ejemplo

Para obtener la prueba de activo necesaria para modificar un activo comprimido, sigue estos pasos:

  1. Primero, configura la función en un archivo nuevo llamado “getAssetProof.js”:
Código
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. Continúa configurando fetch y await. Incluye el parámetro ID requerido en el cuerpo de la solicitud:

Código
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. Analiza el resultado y extrae la raíz:

Código
const { proof } = await response.json();
console.log("Asset Proof: ", result);
const root = decode(proof.root);
console.log(root)

‍Aquí extraemos la raíz de la prueba de activo, que después puede usarse para hacer otras modificaciones en el activo comprimido.

Ejecuta node getAssetProof.js en tu terminal para obtener una respuesta sobre el activo que configuraste aquí.

Resultado

La salida incluirá la información de la prueba de activo:

Código
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'
}

Código completo

Este es el código completo para obtener una prueba de activo mediante su ID:

Código
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();

Asegúrate de reemplazar <api-key> por tu clave de API real.

En este script, definimos una función asíncrona, getAssetProof, que envía una solicitud POST a la API de Helius. Pasamos el ID del activo en el cuerpo de la solicitud. Cuando finaliza la solicitud, la función analiza la respuesta como JSON e imprime la prueba del activo y su raíz en la consola. Por último, llamamos a la función getAssetProof para ejecutar este proceso.

3. Buscar activos

El método searchAssets recupera activos digitales según los parámetros de búsqueda especificados, lo que ofrece una forma flexible de obtener datos. Permite personalizar la búsqueda y tener un control más detallado sobre los activos devueltos.

Los parámetros detallados están disponibles en la documentación de searchAssets.

Ejemplo

Veamos un ejemplo en el que queremos mostrar la imagen y el nombre de los activos de la billetera de un usuario que pertenecen a la colección Drip Haus, y mostrar solo los elementos comprimidos. Para mantener breve este tutorial, guardaremos los datos en un archivo JSON con el nombre y la imagen de cada activo de Drip incluido en la billetera de ejemplo.

  1. Primero, crea un archivo nuevo llamado searchAssets.js con la siguiente función asíncrona:
Código
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;

const searchAssets = async () => {
	// Code goes here
};
searchAssets();

     2. Implementa la función para enviar una solicitud POST con los parámetros de búsqueda especificados. En este caso, usamos los parámetros de compresión, dirección del propietario y agrupación por colección para obtener el resultado deseado:

Código
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. Analiza la respuesta, agrupa los activos por ID y gestiona los posibles duplicados. Para ello, especifica los elementos exactos que necesitamos de la respuesta de cada elemento:

Código
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. La siguiente función busca elementos repetidos y los elimina de nuestra lista. Puedes omitirla si quieres mostrar activos repetidos. También agregará un nuevo grupo de activos cuando determine que un elemento no está repetido:

Código
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. Guarda los resultados de la búsqueda en un archivo JSON llamado searchResults.json:

Código
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');

Para ejecutar el script, usa node searchAssets.js. Esto llenará el archivo searchResults.json con los resultados de la búsqueda.

Resultado

Código
[
  {
    "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"
      }
    ]
  }, ...
}

Código completo

Código
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();

Asegúrate de reemplazar <api-key> por tu clave de API real.

En este script, definimos una función asíncrona, searchAssets, que envía una solicitud POST. Usa varios parámetros de búsqueda en el cuerpo de la solicitud, como la compresión, la dirección del propietario y el ID de la colección. Cuando finaliza la solicitud, la función analiza la respuesta como JSON y extrae la información relevante de los activos (ID, nombre y URI del JSON). Agrupa estos activos por ID y guarda los datos organizados en un archivo JSON llamado searchResults.json. Por último, llamamos a la función searchAssets para iniciar este proceso.

4. Obtener activos por propietario

El endpoint getAssetsByOwner proporciona una lista de los activos digitales que pertenecen a una dirección específica. Actualmente, esta es la forma más rápida de recuperar información específica sobre la propiedad de activos digitales con Helius.

Ejemplo

Para obtener los activos que pertenecen a una dirección determinada, sigue estos pasos:

  1. Primero, configura la función en un archivo nuevo llamado “getAssetsByOwner.js”:
Código
const fs = require('fs');
const url = `https://rpc.helius.xyz/?api-key=`;

const getAssetsByOwner = async () => {
  // Code goes here
};
getAssetsByOwner();
  1. Configura fetch y await e incluye los parámetros en el cuerpo de la solicitud. Para este endpoint, usamos ownerAddress:
Código
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
      },
    }),
  });
  1. Después, analiza la respuesta y extrae la información necesaria de los activos para publicarla en el JSON. Usaremos el ID, el nombre y la URI del JSON del activo para agruparlos en la billetera que estamos buscando:
Código
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],
      };
    }
  }
  1. Ahora podemos configurar nuestra función para publicar los datos en un JSON:
Código
// 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');

Resultado

La salida incluirá los activos digitales que pertenecen a la dirección especificada:

Código
{
  "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"
      }, ...
}

Código completo

Este es el código completo para obtener los activos que pertenecen a una dirección específica:

Código
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();

Asegúrate de reemplazar <api-key> por tu clave de API real.

En este script, definimos una función asíncrona, getAssetsByOwner, que envía una solicitud POST a la API de Helius. Pasamos la dirección del propietario en el cuerpo de la solicitud. Cuando finaliza la solicitud, la función analiza la respuesta como JSON e imprime en la consola los activos que pertenecen a la dirección especificada. Por último, llamamos a la función getAssetsByOwner para ejecutar este proceso.

5. Obtener activos por grupo

El endpoint getAssetsByGroup se usa para recuperar activos digitales asociados con el ID de una colección específica. Este endpoint es fundamental cuando necesitas obtener elementos específicos de una colección o asociar una dApp con acceso restringido por token a una colección onchain determinada.

Ejemplo

En este escenario, configuraremos una instantánea de la colección de SMB. Es importante analizar la respuesta para extraer al propietario del activo desde el objeto de propiedad, como se explica en nuestra documentación. El objetivo es filtrar a los propietarios de varios SMB y mostrarlos solo una vez en nuestro JSON para crear una “instantánea”.

  1. Primero, configura la función en un archivo nuevo llamado “getAssetsByGroup.js”. Usa un Set para asegurarte de almacenar solo propietarios únicos:
Código
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');
const uniqueOwners = new Set();

const getAssetsByGroup = async () => {
		 // Code goes here
};
getAssetsByGroup();
  1. Continúa configurando fetch y await. Define los parámetros indicados anteriormente en el cuerpo de la solicitud. Establece groupKey y groupValue en la solicitud. Inicializa page en 1 e hasMoreResults en true para preparar la paginación. Después, esto configurará una función de paginación que devolverá false si los resultados de la página son menos de 1000 (el límite máximo por solicitud):
Código
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,
        },
      }),
    });
  1. Analiza los resultados para extraer la cadena del propietario necesaria para crear la instantánea de los propietarios actuales:
Código
const { result } = await response.json();
// Add each owner to the Set, automatically discarding duplicates
result.items.forEach(item => uniqueOwners.add(item.ownership.owner));
  1. Configura la paginación aumentando el parámetro page si hay 1000 resultados. Si hay menos, establece hasMoreResults en false para detener la paginación:
Código
if (result.items.length < 1000) {
      hasMoreResults = false;
    } else {
      page++;
    }
  }
  1. Ahora podemos convertir nuestros propietarios en un array y configurar el valor raíz para publicar en un JSON el número de titulares y cada billetera de propietario única:
Código
const uniqueOwnersArray = Array.from(uniqueOwners);
  
  const root = {
    count: uniqueOwners.size,
    owners: uniqueOwnersArray
  };
  1. Convierte el Set de propietarios únicos en un array. Configura el valor root para publicar en un JSON el número de titulares y cada billetera de propietario única:
Código
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);
};

Después puedes ejecutar el comando node getAssetsByGroup.js para llenar el archivo "ownerResults.json" con tus resultados.

Resultado

El resultado será un JSON equivalente a una instantánea de titulares, con la cantidad de propietarios únicos y una lista de todos ellos:

Código
{
  "count": 2785,
  "owners": [
    "6VqzFgtrJb33nhvbug4KZoUx8p65dD2iT1QuAeAQgYiw",
    "5Xeb43ASEa64b9i9owcLB4yrNbUw1oMiTpcWsAdXN8qG",
    "Cb355XH2WGPeQUGTTXWiQZT4nhnyHCPkhScDezUGhXQF",
    "Fuu7xpK3mWqpqPLTHaxF7pU2czkBESKyg3r2Lm2F3AWz",
    "1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix",
    "86tCSKzryE5KvbTmMXN9tkxyn8GNr4z54DnNqrcZwYuy",
    "D2DYL5sdxBCpauvKs1oyQkkSm2B9rFzzGowMacv3Q58z",
		// Additional results ...
]
}

Código completo

Código
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();

Asegúrate de reemplazar <api-key> por tu clave de API real.

Ahora sabes cómo recuperar activos digitales asociados con el ID de una colección específica mediante el endpoint getAssetsByGroup. Al usar correctamente la paginación y la estructura de datos Set para garantizar que cada propietario aparezca una sola vez, puedes crear una instantánea de los titulares actuales de cualquier colección con un ID onchain.

6. Obtener activos por creador

El endpoint getAssetsByCreator se usa para recuperar activos creados por una dirección de clave pública específica. Este endpoint es útil cuando quieres encontrar activos relacionados con un artista o proyecto específico en Solana.

Ejemplo

En este ejemplo, devolveremos los activos creados por Zen0. Podemos usar la dirección del creador y establecer el parámetro onlyVerified en true para recuperar únicamente activos creados por una billetera verificada. Analizaremos los resultados para mostrar el ID de cada activo y su propietario.

  1. Primero, configura la función en un archivo nuevo llamado "getAssetsByCreator.js". Usaremos el módulo fs para publicar nuestros resultados en un archivo JSON:
Código
const url = `https://rpc.helius.xyz/?api-key=`;
const fs = require('fs');

const getAssetsByCreator = async () => {
  // Code goes here
};
getAssetsByCreator();
  1. Ahora podemos configurar la solicitud fetch y usar await con la respuesta. Define los parámetros necesarios en el cuerpo de la solicitud, incluidos creatorAddress e onlyVerified:
Código
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,
        },
      }),
    });

No olvides reemplazar <creator-address> por la dirección real del creador cuyos activos quieres recuperar.

  1. Analiza la respuesta para extraer el resultado y guardarlo en un array:
Código
const { result } = await response.json();
allResults = allResults.concat(result.items);

if (result.items.length < 1000) {
      hasMoreResults = false;
    } else {
      page++;
    }
  }
  1. Agrupa los activos según el ID de propiedad, ya que una misma persona puede tener varios activos, y muestra los activos que pertenecen a cada ID. Si se detecta un nuevo propietario, se creará un grupo nuevo en el archivo JSON:
Código
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],
      };
    }
  }
  1. El siguiente paso es estructurar los resultados. En este caso, nos interesan la dirección del NFT y el propietario de cada activo devuelto. Usamos root para especificar la longitud de la respuesta y almacenar nuestros resultados modificados para la salida:
Código
// 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
  };
  1. Por último, guardamos los resultados en un archivo llamado "creatorResults.json" mediante el módulo fs:
Código
// 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');

Por último, ejecuta el comando node getAssetsByCreator.js para ejecutar el script y llenar el archivo "creatorResults.json" con los resultados recuperados.

Resultado

El archivo JSON resultante contiene la dirección de clave pública de cada propietario y los activos que le pertenecen. Cada activo se representa mediante su ID, lo que proporciona una instantánea clara del estado de propiedad de los activos creados por el creador específico.

Código
{
  "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' representa la dirección de clave pública del propietario en la blockchain de Solana, y los activos son los NFT vinculados a la dirección.

Código completo

Código
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();

Asegúrate de reemplazar <api-key> por tu clave de API real.

En este ejemplo, hacemos una solicitud asíncrona a la DAS API para el endpoint “getAssetsByCreator”. Después, pasamos la dirección de nuestro creador e indicamos que se trata de un creador verificado. Por último, configuramos la respuesta para analizar al propietario de cada activo asociado con la dirección del creador y publicamos los datos en un archivo JSON externo.

En general, esta es una herramienta valiosa para cualquiera que quiera seguir o analizar el movimiento de activos en la blockchain de Solana, en especial los vinculados a un creador o proyecto específico.

7. Obtener activos por autoridad

La función getAssetsByAuthority obtiene los activos asociados con una autoridad de actualización específica. Una autoridad de actualización es una dirección que posee los derechos para modificar una colección. Esta función es muy útil cuando necesitas obtener un conjunto de activos y no existe un ID de colección. Además, permite recuperar un conjunto más amplio de activos asociados con una dirección de autoridad, más allá de los límites de un solo ID de colección.

Ejemplo

En el siguiente ejemplo, recuperaremos cada NFT de las colecciones Taiyo Robotics, Pilots e Infants, junto con su propietario. Como todas comparten una autoridad de actualización, es posible devolver todos los resultados pertinentes para el proyecto.

Esto mejora la función getAssetsByGroup, ya que puedes agrupar activos vinculados a una autoridad definida mediante CDgbhX61QFADQAeeYKP5BQ7nnzDyMkkR3NEhYF2ETn1k.

  1. Primero, configura la función en un archivo nuevo llamado "getAssetsByAuthority.js":
Código
const url = `https://rpc.helius.xyz/?api-key=`;

const getAssetsByAuthority = async () => {
  // Code goes here
};
getAssetsByAuthority();
  1. Configura la solicitud fetch e incorpora los parámetros necesarios en el cuerpo, como authorityAddress, page e limit:
Código
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,
        },
      }),
    });

Asegúrate de sustituir <authority-address> por la dirección real de la autoridad cuyos activos quieres extraer.

     3. Ahora podemos organizar la respuesta para recorrer los resultados cuando haya 1000.

     Si hay menos resultados, la marca se establecerá en false y finalizará la paginación, por lo que hasMoreResults devolverá false.

Código
const { result } = await response.json();
    totalResults.push(...result.items);

    if (result.items.length < 1000) {
      hasMoreResults = false;
    } else {
      page++;
    }
  }
  1. Procesa los activos para obtener la información necesaria. Aquí queremos mostrar el ID del activo y su propietario. También crearemos un objeto raíz que contenga la cantidad de activos y el array de activos procesados:
Código
// 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
  };
  1. Ahora podemos publicar los elementos devueltos en un JSON llamado authorityResults.json y registrar un mensaje cuando finalice el proceso.
Código
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");

Por último, ejecuta el comando node getAssetsByAuthority.js para ejecutar el script y llenar el archivo "authorityResults.json" con los resultados obtenidos.

Resultado

La salida del endpoint getAssetsByAuthority incluye una cantidad de activos y un array de objetos. Cada objeto representa un activo y contiene su ID y propietario. Este es un ejemplo:

Código
{
  "count": 37330,
  "results": [
    {
      "id": "HmwL6uy7gQcXv74Mi8xF5G9mymZNd9rnUCpUFwSx1DX1",
      "owner": "5gt59Q14FEhT8LuETjLyiNHRkqCQf5hQsPP58ucBy5oC"
    },
    {
      "id": "HmztH56n4GD3p3EdgMKdzj8x21LjFQk4Bcp2YAQD8Urx",
      "owner": "H3AkHZHfcqGCcJpBn3FJWe52LcLxFMJQoZvZ6XyApFWf"
    },
    {
      "id": "Hn1NZXCaAxcr1btsaDm3eZRtLNbamy9FyrcVGLbZ2k5w",
      "owner": "AEqhqiQZBBa3dPTY1GwGsZJJnf5vzRKJpdXv6xzakfx8"
    }, ...
}

Código completo

Código
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()

Asegúrate de sustituir <api-key> por tu clave de API real.

En este ejemplo, usamos el método "getAssetsByAuthority" para devolver todos los activos vinculados a una dirección de autoridad en tres colecciones. Solo usamos page e limit como parámetros adicionales de la solicitud. Después, analizamos los resultados para extraer los activos bajo esa autoridad y los guardamos en un archivo JSON externo.

Conclusión

Ahora deberías comprender por completo cómo usar la API del estándar de activos digitales (DAS), además de varias aplicaciones prácticas de cada método. Esto supone un cambio importante respecto a las prácticas anteriores, que requerían varios endpoints para obtener información específica sobre los activos.

Estos métodos funcionan tanto con activos comprimidos como normales y ofrecen una interfaz unificada para hacer estas solicitudes de distintas maneras.

Para obtener más información, siempre puedes consultar nuestra amplia documentación sobre la API del estándar de activos digitales (DAS) y explorar nuestro widget de Open API, que ofrece un desglose detallado de los parámetros de solicitud y respuesta.

Como siempre, te invitamos a unirte a nuestra comunidad de Discord. ¡No dudes en mencionarme allí si tienes alguna pregunta!

‍

Suscríbete a Helius

Mantente al día con las novedades del desarrollo en Solana y recibe actualizaciones cuando publiquemos