Los tokens no fungibles (NFT) se están convirtiendo en una locura en estos días, ya que brindan el beneficio de la autoridad, la autenticidad de la emisión y el ciclo de vida de un activo digital. La emisión de éstos sobre Algorand proporcionan mayor velocidad, bajo costo y fácil trazabilidad para las partes involucradas con el mismo.
Solución
Les traemos a Channel Manager, como un medio para emitir y digitalizar NFT, brindar una solución de custodia al mapear a cada usuario a un número de teléfono móvil, realizar transacciones comerciales como Comprar, Vender, Revender y Enviar. Para la solución de custodia, utilizamos Hashicorp Vault, que brinda administración de secretos en Amazon Web Service.
La funcionalidad del administrador de canales se puede descentralizar creando un protocolo de gobernanza y dando control a múltiples autoridades según el caso de uso. En este ejemplo, hemos creado un administrador de canales para el sistema de emisión de boletos, donde múltiples mercados pueden conectarse al administrador de canales, digitalizarlos como una NFT y permitir el comercio utilizando estos tickets digitales en la parte superior de la cadena de bloques de Algorand.
Por ejemplo, si un organizador de eventos desea albergar el concierto de Katy Perry en Reino Unido y quiere vender las entradas en múltiples mercados como Ticketmaster, Eventbrite (entre otras plataformas locales) ¿Cómo haría?
El organizador de eventos puede conectarse al administrador de canales y emitir los boletos como NFT y el mercado puede hacer uso del mismo para realizar transacciones comerciales según las condiciones establecidas por el organizador. De esta forma, se puede incorporar interoperabilidad y transparencia al sistema. La reventa o el envío de tickets puede ser posible con el bajo costo y la escalabilidad de Algorand, resolviendo el problema de la promoción y la autenticidad de los boletos.
Blockchain puede tener inmensas ventajas para los consumidores, sin embargo, la facilidad de uso es la cuestión clave. En éste mapeo se almacena en la bóveda de Hashicorp, aprovechando la seguridad de un módulo de seguridad basado en software. Channel Manager tiene la capacidad de proporcionar diferentes mercados con la facilidad de mapear la dirección de Algorand de su usuario con un número de móvil comprensible para humanos, y transferir a sus usuarios a blockchain con facilidad.
func saveAddress(ctx context.Context, v vault.Vault, algo algorand.Algo,
addressPath string) error {
a, err := algo.GenerateAccount()
if err != nil {
return fmt.Errorf("saveAddress: error generating address:
%w", err)
}
path := fmt.Sprintf("%s/%s", v.UserPath, addressPath)
data := map[string]interface{}{
constants.AccountAddress: a.AccountAddress,
constants.PrivateKey: a.PrivateKey,
constants.SecurityPassphrase: a.SecurityPassphrase,
}
_, err = v.Logical().Write(path, data)
if err != nil {
return fmt.Errorf("saveAddress: unable to write to vault:
%w", err)
}
err = algo.Send(ctx, a, 5)
if err != nil {
return fmt.Errorf("saveAddress: error sending algos
to: %+v: err: %w", a, err)
}
return nil
}
func (u *User) userAddress(addressPath string) (*algorand.Account,
bool, error) {
path := fmt.Sprintf("%s/%s", u.Vault.UserPath, addressPath)
secret, err := u.Vault.Logical().Read(path)
if err != nil {
return nil, false, fmt.Errorf("userAddress: could not
get account of user: %d", addressPath)
}
accountAddress, accountAddressOK := secret.Data[constants.AccountAddress]
if !accountAddressOK {
return nil, false, fmt.Errorf("userAddress: account address not found")
}
privateKey, privateKeyOK := secret.Data[constants.PrivateKey]
if !privateKeyOK {
return nil, false, fmt.Errorf("userAddress: private key not found")
}
securityPassphrase, securityPassphraseOK :=
secret.Data[constants.SecurityPassphrase]
if !securityPassphraseOK {
return nil, false, fmt.Errorf("userAddress: security
passphrase not found")
}
ua := algorand.Account{
AccountAddress: accountAddress.(string),
PrivateKey: privateKey.(string),
SecurityPassphrase: securityPassphrase.(string),
}
return &ua, true, nil
}
Algorand proporciona varios soportes de SDK para generar direcciones y realizar diversas operaciones en la cadena de bloques.
type algo struct {
from *Account
apiAddress string
apiKey string
amountFactor uint64
minFee uint64
seedAlgo uint64
}
func (a *algo) GenerateAccount() (*Account, error) { account := crypto.GenerateAccount()
paraphrase, err := mnemonic.FromPrivateKey(account.PrivateKey)
if err != nil {
return nil, fmt.Errorf("generateAccount: error generating account: %w", err)
}
return &Account{
AccountAddress: account.Address.String(),
PrivateKey: string(account.PrivateKey),
SecurityPassphrase: paraphrase,
}, nil
}
Digitalización
Las NFT se representan como un activo estándar de Algorand con el parámetro de emisión establecido como 1. Esto crea de forma única una NFT y aquí está nuestra estructura para representar.
func (a *algo) CreateNFT(ctx context.Context, ac *Account) {
var headers []*algod.Header
headers = append(headers, &algod.Header{Key: "X-API-Key", Value: a.apiKey})
algodClient, err := algod.MakeClientWithHeaders(a.apiAddress, "", headers)
if err != nil {
return 0, fmt.Errorf("createAsset: error connecting to algo: %w", err)
}
txParams, err := algodClient.SuggestedParams()
if err != nil {
return 0, fmt.Errorf("createAsset: error getting suggested tx params: %w", err)
}
genID := txParams.GenesisID genHash := txParams.GenesisHash
firstValidRound := txParams.LastRound
lastValidRound := firstValidRound + 1000
// Create an asset // Set parameters for asset creation transaction
creator := ac.AccountAddress
assetName := "NAME"
unitName := "tickets"
assetURL := "URL"
assetMetadataHash := "thisIsSomeLength32HashCommitment"
defaultFrozen := false
decimals := uint32(0)
totalIssuance := uint64(1) //unique NFTs
manager := a.from.AccountAddress
reserve := a.from.AccountAddress
freeze := "" clawback := a.from.AccountAddress
note := []byte(nil)
txn, err := transaction.MakeAssetCreateTxn(creator, a.minFee, firstValidRound, lastValidRound, note,
genID, base64.StdEncoding.EncodeToString(genHash), totalIssuance, decimals,
defaultFrozen, manager, reserve, freeze, clawback,
unitName, assetName, assetURL, assetMetadataHash)
if err != nil {
return 0, fmt.Errorf("createAsset: failed to make asset: %w", err)
}
fmt.Printf("Asset created AssetName: %s\n", txn.AssetConfigTxnFields.AssetParams.AssetName)
privateKey, err := mnemonic.ToPrivateKey(ac.SecurityPassphrase)
if err != nil {
return 0, fmt.Errorf("createAsset: error getting private key from mnemonic: %w", err)
}
txid, stx, err := crypto.SignTransaction(privateKey, txn) if err != nil {
return 0, fmt.Errorf("createAsset: failed to sign transaction: %w", err)
}
logger.Infof(ctx, "Signed txid: %s", txid)
// Broadcast the transaction to the network
txHeaders := append([]*algod.Header{}, &algod.Header{Key: "Content-Type", Value: "application/x-binary"})
sendResponse, err := algodClient.SendRawTransaction(stx, txHeaders...)
if err != nil {
return 0, fmt.Errorf("createAsset: failed to send transaction: %w", err)
}
}
Las operaciones comerciales como comprar, vender, revender y reenviar se realizan utilizando varios mecanismos de transacción utilizando la API de Purestake para conectarse a la cadena de bloques Algorand.
func (a *algo) Send(ctx context.Context, to *Account, noOfAlgos uint64) error {
var headers []*algod.Header
headers = append(headers, &algod.Header{Key: "X-API-Key", Value: a.apiKey})
algodClient, err := algod.MakeClientWithHeaders(a.apiAddress, "", headers)
if err != nil {
return fmt.Errorf("send: error connecting to algo: %w", err)
}
txParams, err := algodClient.SuggestedParams()
if err != nil {
return fmt.Errorf("send: error getting suggested tx params: %w", err)
}
fromAddr := a.from.AccountAddress
toAddr := to.AccountAddress
amount := noOfAlgos * a.amountFactor
note := []byte(fmt.Sprintf("Transferring %d algos from %s", a.seedAlgo, a.from))
genID := txParams.GenesisID
genHash := txParams.GenesisHash
firstValidRound := txParams.LastRound
lastValidRound := firstValidRound + 1000
txn, err := transaction.MakePaymentTxnWithFlatFee(fromAddr, toAddr,
a.minFee, amount, firstValidRound,
lastValidRound, note, "", genID, genHash)
if err != nil {
return fmt.Errorf("send: error creating transaction: %w", err)
}
privateKey, err := mnemonic.ToPrivateKey(a.from.SecurityPassphrase)
if err != nil {
return fmt.Errorf("send: error getting private key from mnemonic: %w", err)
}
txId, bytes, err := crypto.SignTransaction(privateKey, txn)
if err != nil {
return fmt.Errorf("send: failed to sign transaction: %w", err)
}
logger.Infof(ctx, "Signed txid: %s", txId)
txHeaders := append([]*algod.Header{}, &algod.Header{Key: "Content-Type", Value: "application/x-binary"})
sendResponse, err := algodClient.SendRawTransaction(bytes, txHeaders...)
if err != nil {
return fmt.Errorf("send: failed to send transaction: %w", err)
}
logger.Infof(ctx, "send: submitted transaction %s", sendResponse.TxID)
return nil
}
Demostración
Aquí está la demostración de una aplicación de eventos que se conecta al administrador de canales y resuelve los problemas relacionados con el mundo de la venta de entradas.
La aplicación proporciona varias implementaciones de casos de uso en Java y Kotlin. La funcionalidad de cambio de clave y las funciones sin custodia también se implementan como parte del código en la aplicación de Android.
Ver video: https://youtu.be/kDnyFdpeyNs
Referencias
Aplicación de Android: https://play.google.com/store/apps/details?id=com.eventersapp.marketplace
Channel Manager Code (en Golang): https://github.com/eventers/Eventers-Marketplace-Backend
Android Código (en Kotlin + Java): https://github.com/eventers/Eventers-Marketplace-Android
Este artículo ha sido escrito originalmente por Akshay Kant en «Soluciones» del portal para desarrolladores de Algorand y traducido por AlgoLatam.
Original Article: https://developer.algorand.org/solutions/channel-manager-for-nfts/
Aviso de responsabilidad:
Este artículo no contiene consejos financieros, ni recomendaciones de inversión de ningún tipo. La información brindada se ofrece sólo con fines educativos y didácticos en cuanto a tecnología Web3 y análisis sobre sus casos de uso.
Las inversiones con criptomonedas, NFTs, tokens u otros activos digitales conllevan riesgos y no se encuentran regulados, por lo que los lectores deben realizar su propia investigación antes de tomar cualquier tipo de decisión bajo su entera responsabilidad, así como adaptarse y observar las diferentes regulaciones legales según su país de residencia.