Guía Rápida del SDK
Configuración Inicial
A continuación verás la inicialización de algunas variables que se usarán a lo largo de diferentes ejemplos.
Inicialización del SDK
Crea una nueva instancia del SDK:
import { LedgerSdk } from '@minka/ledger-sdk';
const sdk = new LedgerSdk({
// Identificador del ledger a utilizar
ledger: 'kamin-stg',
// Servidor al cual conectarse, sin la barra al final
server: 'https://ldg-stg.one/v2',
// Opcional, tiempo de espera en milisegundos. Por defecto es 15000
timeout: 15000,
// Opcional, verificar automáticamente las respuestas del servidor. Esto significa que
// el SDK realizará validaciones de todas las pruebas en los registros usando la clave pública del Ledger
verifyResponseProofs: true,
// Opcional, clave pública utilizada para verificar las respuestas del servidor
signer: {
format: 'ed25519-raw', // Único formato soportado por ahora
public: '<clave pública del ledger>',
},
// Opcional, valores por defecto para la autenticación con JWT
secure: {
iss: '<emisor del jwt>', // identificador del firmante o clave pública
sub: '<sujeto del jwt>', // signer:<handle>, bridge:<handle>, ...
aud: '<audiencia objetivo del jwt>', // identificador del ledger o clave pública
exp: 60, // Tiempo de expiración del token, en segundos
keyPair: {
format: 'ed25519-raw',
public: '<clave pública>',
secret: '<clave secreta>',
},
},
});Onboarding
Sigamos el proceso para tener todo listo antes de enviar nuestros primeros intents.
Obtener una billetera y su saldo
Después de crear nuestra billetera o cualquier registro, podemos usar el método read para obtenerlo.
Para billeteras, también tenemos el método balances para consultar los saldos de una billetera específica.
const { wallet } = await sdk.wallet.read('kamin.one');
// Salida: Datos de la billetera `kamin.one`
const { balances } = await sdk.wallet.getBalances('kamin.one');
// Salida: Arreglo vacío, sin saldos por ahoraEnviar intents
Ahora estamos listos para enviar intents entre nuestras billeteras en el sistema.
Crear un intent
Primero, creemos un intent de transferencia desde nuestra billetera kamin.one, para que tenga algún saldo.
const claim = {
action: 'transfer',
source: 'kamin.one',
target: 'rail',
symbol: 'cop',
amount: 1000000, // Equivale a 100000.00$, porque cop tiene un factor de 100
};
await sdk.intent
.init()
.data({
handle: sdk.handle.unique(), // devuelve un identificador único aleatorio
claims: [claim],
access: getOwnerAccessRules(keyPair.public),
})
.hash()
.sign([{ keyPair }])
.send();
const { balances } = await sdk.wallet.getBalances('kamin.one');
// Salida: [ { wallet: 'kamin.one', symbol: 'cop', amount: 10000 } ]Firmar un intent existente
En algunos casos, queremos agregar firmas a intents que ya existen, por ejemplo, al validarlos desde bridges.
Es similar a una actualización, pero agregando firmas en lugar de cambiar los datos.
const { response } = await sdk.intent.read('<intent-handle>');
await sdk.intent
.from(response.data)
.hash()
.sign([
{
keyPair,
custom: {
// Datos personalizados opcionales para la firma
status: 'prepared',
},
},
])
.send();Verificar pruebas de un registro
Usando la propiedad .proofs de nuestra instancia del SDK, podemos obtener un cliente verificador de pruebas que nos permite verificar las pruebas de un registro.
const { response } = await sdk.intent.read('<intent-handle>');
const record = response.data;
const verifier = sdk.proofs;
// Se puede agregar aserciones al cliente de verifiación
verifier
.length(1) // Al menos 1 prueba presente, es el valor por defecto
.length(2, 3) // Al menos 2 pruebas, pero menos de 3
// Al menos una prueba realizada con el firmante configurado en el SDK
.ledger()
// Al menos una prueba que coincida parcialmente con el objeto
.expect({ custom: { status: 'prepared' } });
// El método de verificación revia todas las aserciones del registro.
// También verifica que todas las proofs sean validas.
await verifier.verify(record);
await verifier.verify(record); // Las aserciones se pueden reutilizar con otros registros
// Obtener un nuevo verificador limpio con solo la aserción `length(1)`
const otherVerifier = sdk.proofs;
await otherVerifier.verify(record);Obtener errores desde las pruebas (si existen)
Si nuestro intent falla por alguna razón, se agregará una firma en sus pruebas que contiene el motivo del error.
Podemos extraer ese error usando el método error del verificador de pruebas.
const {
response: { data: record },
} = await sdk.intent.read('<intent-handle>');
const error = sdk.proofs.error(record);
// Salida: LedgerSdkError encontrado en la última prueba, si existe.Conceptos Generales
Crear registros
Las reglas para crear diferentes tipos de registros pueden variar ligeramente, pero como verás, siguen el mismo patrón: enviar un registro firmado al servidor.
// Obtener el cliente
const client = sdk.wallet; // Puede ser wallet, effect, intent...
// Inicializar el registro
const record = client.init();
// Establecer los datos
record.data({
handle: 'my-wallet',
});
// Crear el hash de la data
record.hash();
// Firmar el regustro usando el arreglo de paráetros proporcionaos
record.sign([
{ keyPair },
{
/**
* Se pueden asignar datos personalizados a las firmas.
* Estos se incluirán en el cálculo del resultado
* para esta firma específica y deben usarse en el
* futuro para validarla.
*/
keyPair,
custom: {
identifier: 123456,
},
},
]);
// Enviar el registro al backend
await record.send();
/**
* También se pueden agregar todos los datos del registro directamente en el método `.init`.
* Esto significa se puede pasar el hash y las pruebas manualmente en lugar de usar
* los métodos `hash` y `sign` respectivamente, o simplemente pasar los datos en lugar de usar el método `.data`.
*/
await client
.init({
data: {
handle: 'my-wallet',
},
hash: '<valid-hash>',
meta: {
proofs: [
{},
// Más proofs
],
},
})
.send();Leer registros
Al leer un registro con el método read, el valor devuelto tendrá una propiedad cuyo nombre coincide con el tipo de registro (wallet, intent, etc.)
que contiene los datos del registro. También recibiremos hash y meta.
// Obtener el cliente
const client = sdk.wallet;
// Obtener la data de la billetera con el handle `my-wallet`
const walletResponse = await client.read('my-wallet');
const record = {
hash: walletResponse.hash, // Has del registro
meta: walletResponse.meta, // Metadata del registro, incluyendo las proof
data: walletResponse.wallet, // Data del registro
};
/**
* Al actualizar, leer o crear registros usando el SDK, el valor devuelto
* incluirá la propiedad `response`, que es una instancia de la respuesta de axios.
* Esto significa que también se puede obtener el registro completo desde el cuerpo de esa respuesta.
*/
const record = walletResponse.response.data;Actualizar registros
Similar al uso de init para inicializar un registro completo, podemos usar from con todos los datos del registro (incluyendo meta y hash) para actualizarlo.
Ten en cuenta que el identificador debe existir y el hash será validado.
const client = sdk.wallet;
const record = (await client.read('my-wallet')).response.data;
await client
.from(record)
.data({
handle: 'my-wallet',
})
.hash() // El hash del registre cambiara con nueva data
.sign([{ keyPair }]) // El nuevo hash tiene que ser firmado
.send();
// Actualizar el regustro completo
await client
.from(record)
.data(
{
...record.data, // Expandir todos los datos del registro anterior
factor: 10,
},
true // Pasar true (reemplazar) como segundo argumento
)
.hash()
.sign([{ keyPair }])
.send();Listas y paginación
Al leer registros usando el método list, el valor devuelto tendrá una propiedad cuyo nombre
coincidirá con el nombre del tipo de registro en plural (wallets e intents, por ejemplo), que contendrá una lista con los datos de los registros.
// Obtener el cliente
const client = sdk.wallet;
// Obtener las primeras 20 billeteras (Default)
const { wallets } = await client.list();
// Obtener las primeras 10 billeteras
const { wallets: firstTen } = await client.list({
page: {
index: 0,
limit: 10,
},
});
// Obtener las siguientes 10 billeteras
const { wallets: nextTen } = await client.list({
page: {
index: 1,
limit: 10,
},
});
/**
* Tener en cuenta que el resultado de `wallets` contendrá solo los datos del registro.
* Si se desea obtener el registro completo (incluyendo las propiedades `hash` y `meta`),
* puede que se necesite obtener la lista directamente desde la propiedad `response`.
*/
const listResponse = await client.list();
const walletRecords = listResponse.response.data;Como se describe en Sobre las Consultas, también puedes aplicar filtros al listar registros.
Por ejemplo, para obtener solo las billeteras cuyo esquema es topup, usarías:
// Obtener los primero 10 topup intents
const { intents } = await client.list({
page: {
index: 0,
limit: 10,
},
'data.schema.$eq': 'topup',
});Wallet
// Crear una billetera
await sdk.wallet
.init()
.data(...)
.hash()
.sign(...)
.send();
// Actualizar una billetera
await sdk.wallet
.from(...)
.data(...)
.hash()
.sign(...)
.send();
// Obtener los datos de una billetera específica
await sdk.wallet.read('<handle>')
// Obtener los saldos de una billetera específica
await sdk.wallet.getBalances('<handle>')
// Obtener los anclajes de una billetera específica
await sdk.wallet.getAnchors('<handle>')
// Obtener los anchors de una billetera específica mediante lookup. Permite pasar
// argumentos adicionales
await sdk
.wallet
.with('<handle>')
.anchor.lookup()
.data(...)
.hash()
.sign(...)
.send();Consulta Sobre los Anchors y Sobre las Billeteras para mas detalles.
Intent
// Crear un intent
await sdk.intent
.init()
.data(...)
.hash()
.sign(...)
.send()
// Firmar un intent
await sdk.intent
.from(...)
.hash()
.sign(...)
.send()
// Obtener datos de un intent específico
await sdk.intent.read('<handle>')
// Obtener lista de intents
await sdk.intent.list(...)Effect
// Crear un effect
await sdk.effect
.init()
.data(...)
.hash()
.sign(...)
.send()
// Actualizar un effect
await sdk.effect
.from(...)
.data(...)
.hash()
.sign(...)
.send()
// Obtener datos de un effect específico
await sdk.effect.read('<handle>')
// Obtener lista de effects
await sdk.effect.list(...)Historial de cambios
- Agregado• Versión inicial