Saltar al contenido principal

Integrar con Acceso a MoneyGram

Este documento guía al lector a través de los requisitos técnicos para integrar Acceso a MoneyGram en una aplicación existente. Acceso a MoneyGram es un producto de MoneyGram que permite a los usuarios de aplicaciones de terceros, como billeteras de criptomonedas y exchanges, depositar (cash-in) y retirar (cash-out) USDC Stellar.

MoneyGram requiere que las empresas pasen por un proceso de incorporación para obtener acceso a sus entornos de prueba y producción. Para comenzar con este proceso, contacta a [email protected].

Recursos

  • [Implementación MVP de Billetera de Acceso a MoneyGram]
    • Utiliza esta implementación MVP como referencia para construir tu propia integración. Muchos de los fragmentos de código compartidos en este documento se obtuvieron de este proyecto.
  • Documentación del SDK de Billetera Stellar
    • Utiliza este SDK de Billetera para facilitar la construcción de tu propia integración. Muchos de los fragmentos de código compartidos en este documento se obtuvieron del repositorio del SDK de Billetera Stellar.
  • Ancla de Prueba Stellar
    • Before getting access to MoneyGram's test environment, you can use the SDF's test anchor while developing your integration
  • [Billetera de Demostración Stellar]
    • This application visualizes the API calls necessary to connect to a Stellar Anchor
  • Propuesta del Ecosistema Stellar 24 (SEP-24)
    • The standardized API protocol for Stellar on & off ramps, implemented by MoneyGram
  • Propuesta del Ecosistema Stellar 10 (SEP-10)
    • The standardized API protocol for Stellar authentication, implemented by MoneyGram

Información sobre Activos

Antes de que obtengas acceso al entorno de prueba de MoneyGram, debes probar tu implementación con la Ancla de Prueba Stellar del SDF. Implementa las mismas APIs que el servicio de MoneyGram, pero utiliza un activo diferente. La información para cada activo está a continuación.

Token de Referencia Stellar

Este token está solo en testnet.

USD Coin

Testnet:

Pubnet:

Introducción

Las aplicaciones que buscan integrar Acceso a MoneyGram deben implementar el lado del cliente de Propuesta del Ecosistema Stellar 24 (SEP-24), un protocolo estandarizado definido para que las aplicaciones se conecten a empresas como MoneyGram, generalmente llamadas anclas, que ofrecen servicios de depósito y retiro Stellar utilizando rieles de pago locales.

Este documento te guiará a través de los pasos necesarios para desarrollar una implementación funcional de este estándar.

La guía asumirá que tu aplicación se está desarrollando primero en la red de prueba de Stellar y utilizando la implementación de prueba de MoneyGram de Acceso, pero no hay diferencias funcionales al desplegar la aplicación en la red pública de Stellar y utilizar la implementación de producción de MoneyGram.

Instalando el SDK de Billetera

Recomendamos encarecidamente usar el SDK de billetera para facilitar la construcción de tu integración. Encuentra más información en la Documentación del SDK de Billetera Stellar.

Puedes usar yarn para instalarlo:

yarn add @stellar/typescript-wallet-sdk

Aplicaciones Custodiales vs. No Custodiales

Algunas aplicaciones, como los exchanges centralizados, son custodiales, lo que significa que la aplicación tiene acceso a las claves privadas de las cuentas que contienen los fondos de sus usuarios en Stellar. Típicamente, las aplicaciones custodiales agrupan los fondos de los usuarios en un conjunto más pequeño de cuentas Stellar gestionadas, llamadas cuentas agrupadas, compartidas u omnibuses.

Otras aplicaciones son no custodiales, lo que significa que la aplicación no tiene acceso a las claves privadas de las cuentas que contienen los fondos de sus usuarios en Stellar. Típicamente, las aplicaciones no custodiales crean o importan una cuenta Stellar preexistente para cada usuario.

Estos dos enfoques requieren diferencias menores pero concretas en cómo las aplicaciones se integran con Acceso a MoneyGram. Las subsecciones a continuación describirán estas diferencias, pero el resto de este tutorial asumirá que la aplicación es custodial.

Autenticación

MoneyGram necesita autenticar tanto al usuario como a la aplicación que se está utilizando a través del protocolo SEP-10 de Stellar.

Las aplicaciones custodiales se identifican por la clave pública de la cuenta Stellar que registran con MoneyGram durante el proceso de incorporación. Al autenticarte, la aplicación debe pasar esta clave pública como el parámetro de consulta account, y para identificar al usuario, la aplicación debe pasar un ID entero único como el parámetro de consulta memo. MoneyGram devolverá una transacción Stellar que debe ser firmada por la clave privada de la aplicación y enviada de regreso para su verificación.

Dado que cada usuario de una aplicación no custodial tiene su propia cuenta Stellar, las aplicaciones no custodiales se identifican por el dominio de origen que registran con MoneyGram durante el proceso de incorporación. Al autenticarte, la aplicación debe pasar la clave pública del usuario como el parámetro de consulta account, y pasar su dominio de origen como el parámetro de consulta client_domain. MoneyGram buscará el valor SIGNING_KEY en https://<client_domain>/.well-known/stellar.toml, y devolverá una transacción Stellar que requiere firmas tanto de la clave privada del usuario como de la clave privada de la clave pública SIGNING_KEY en el archivo stellar.toml de la aplicación SEP-1. Un archivo de ejemplo se puede encontrar en https://vibrantapp.com/.well-known/stellar.toml.

Iniciación de Transacciones

Dado que los usuarios de aplicaciones custodiales no tienen cuentas Stellar individuales, solo la aplicación sabe cuánto dinero un usuario tiene para retirar. Debido a esto, MoneyGram requiere que las aplicaciones custodiales siempre pasen el campo amount en la solicitud para iniciar una nueva transacción. Las aplicaciones no custodiales no necesitan hacer esto, aunque pueden hacerlo si lo prefieren.

Fuente y Destino de Fondos

MoneyGram requiere que las aplicaciones custodiales proporcionen las cuentas Stellar que pueden ser utilizadas como fuente o destino de fondos durante el proceso de incorporación. Para las aplicaciones no custodiales, MoneyGram requiere que la fuente y el destino de los fondos para cada transacción sean la misma cuenta que fue autenticada a través de SEP-10.

Flujo de Aplicación y Arquitectura

Esta guía asumirá que la aplicación tiene una arquitectura básica cliente-servidor. El cliente de la aplicación solicitará recursos e iniciará acciones con el servidor de la aplicación, que se comunicará directamente con el servidor de MoneyGram.

A continuación se muestran los 7 pasos generales a seguir para facilitar una transacción de efectivo (retirada).

Billetera - Página 1 de MoneyGram

Después del Paso 4, la aplicación debería abrir la URL proporcionada por MoneyGram en una vista web móvil o pestaña del navegador. MoneyGram luego pedirá al usuario que proporcione información de KYC y de la transacción. Al completar este flujo, el cliente de la aplicación debería cerrar la pestaña o vista web de MoneyGram e iniciar la distribución de fondos.

Billetera - Página 2 de MoneyGram

El número de referencia proporcionado se llevaría a cualquier agente de efectivo de MoneyGram para recibir dinero en la moneda fiat del usuario. Estos pasos documentan el flujo de efectivo o de retiro. El flujo de depósito es similar y se detalla en los pasos a continuación.

Generar Keypairs de Stellar

En esta sección, generarás al menos dos keypairs de Stellar, uno que se utilizará para probar la identidad de tu aplicación al autenticarte con Acceso a MoneyGram, y otro que mantendrá, enviará y recibirá USDC en Stellar. Siempre debes usar un keypair para la autenticación, pero la aplicación puede usar muchos keypairs para enviar y recibir pagos. En esta guía, asumiremos que la aplicación utiliza un keypair para cada propósito.

Esta sección asume que tu aplicación no tiene soporte para la red Stellar. Si tu aplicación ya soporta depósitos y retiros de XLM, ya tienes uno o más cuentas Stellar que se pueden usar para estos propósitos, aunque se recomienda poner un nuevo keypair para autenticación.

Ve a [Stellar Lab] y genera 2 keypairs. Las claves secretas deben ser tratadas de forma segura, porque se utilizarán para autenticar y distribuir fondos a MoneyGram.

El primer keypair se llamará el keypair de “autenticación” (o clave pública / secreta). El segundo keypair será el keypair de “fondos” (o cuenta, clave pública, o clave secreta). A diferencia del keypair de autenticación, el keypair de fondos hará referencia a una cuenta financiada en la red Stellar. El keypair de autenticación no necesita estar financiado.

Proporciona las claves públicas (que comienzan con una G) de ambos keypairs de autenticación y de fondos a MoneyGram. Ellos añadirán estas claves a sus listas conocidas de claves, otorgándoles acceso a su implementación.

Obtener XLM y USDC

Muchos exchanges de criptomonedas soportan la compra de XLM o USDC en Stellar. El SDF también mantiene un Directorio de Anclajes que intenta listar todas las rampas y bajadas para la Red Stellar.

Cuando hayas comprado XLM y/o USDC en un exchange, puedes hacer un pago a una cuenta externa, específicamente a la clave pública de fondos que generaste en el paso anterior. Ten en cuenta que primero necesitarás enviar XLM para crear la cuenta, luego agregar una trustline de USDC, y luego enviar el USDC. Crear una trustline a USDC se puede hacer utilizando [Stellar Lab] o cualquier aplicación de billetera compatible con Stellar, como Lobstr.

Algunos exchanges soportan XLM pero no soportan USDC en Stellar. Esto no es un problema, porque siempre puedes vender XLM por USDC en el exchange descentralizado de Stellar (o SDEX).

Para hacer esto, envía tu XLM a la clave pública de fondos desde el exchange, añade una trustline de USDC, y vende XLM por USDC usando una oferta de venta.

Autenticarse

Esta sección engloba los pasos 1 y 2 del diagrama mostrado en la sección de Arquitectura arriba. El cliente de la aplicación debe solicitar una URL de transacción de MoneyGram desde el servidor de la aplicación al iniciar el usuario. Esto debería activar un proceso de autenticación entre el servidor de la aplicación y el servidor de MoneyGram. Este proceso está estandarizado en SEP-10.

Esta sección asume que el servidor de la aplicación tiene las siguientes piezas de información:

El flujo se puede describir con los siguientes pasos:

  1. La aplicación solicita un reto de autenticación
  2. El servidor (MoneyGram) proporciona el reto de autenticación
  3. La aplicación verifica que MoneyGram firmó la autenticación con su SIGNING_KEY
  4. La aplicación firma el reto de autenticación con su propia clave
  5. La aplicación envía de regreso el reto de autenticación al servidor
  6. El servidor verifica que la aplicación firmó el reto con la cuenta que usó inicialmente para solicitar el reto
  7. El servidor devuelve un token de sesión para la cuenta y memo utilizados en la solicitud de autenticación inicial

El siguiente código demuestra cómo implementar el lado de la aplicación de este flujo. Ten en cuenta que este código no maneja reintentos en caso de problemas de conexión de red. Tampoco maneja códigos de estado inesperados y no incluye registro o métricas.

import { Wallet, SigningKeypair } from "@stellar/typescript-wallet-sdk";

const wallet = Wallet.TestNet();

// Testnet
const MGI_ACCESS_HOST = "extmgxanchor.moneygram.com";
// Pubnet
// const MGI_ACCESS_HOST = "stellar.moneygram.com";

// First we create an anchor object with MoneyGram's home domain.
const anchor = wallet.anchor({ homeDomain: MGI_ACCESS_HOST });

// Then we create the sep10 object which handles all the athentication steps.
const sep10 = await anchor.sep10();

// Finally, we authenticate using the wallet's SIGNING_KEY secret.
const authKey = SigningKeypair.fromSecret(AUTH_SECRET_KEY);
const authToken = await sep10.authenticate({ accountKp: authKey });

Iniciar una Transacción

Esta sección engloba los pasos 3 y 4 del diagrama de la arquitectura mostrado arriba. El servidor de la aplicación hará una solicitud de iniciación de depósito o retiro al servidor de MoneyGram, y MoneyGram devolverá un ID de transacción, que se usará más adelante para consultar el estado de la transacción, y una URL de transacción, que debe ser devuelta al cliente de la aplicación y abierta para el usuario.

Con el propósito de esta guía, pasaremos por el caso de retiro.

Nota: MoneyGram requiere el campo amount en solicitudes tanto para depósitos como para transacciones de retiro si tu aplicación es custodial.

Necesitarás las siguientes piezas de información:

  • El token de autenticación proporcionado por MoneyGram. Este token solo se puede usar para acciones asociadas con el usuario identificado por el ID utilizado en los pasos anteriores.
  • La clave pública del keypair que la aplicación utilizará para enviar fondos
  • El código de idioma con el que MoneyGram debería renderizar el contenido de su interfaz de usuario
  • La cantidad que el usuario desea retirar / sacar en caso de que sea una billetera custodial
    • Esto debe ser recolectado del usuario antes de iniciar esta transacción

El siguiente código se puede usar como referencia para implementar esta lógica tú mismo.

import { IssuedAssetId } from "@stellar/typescript-wallet-sdk";

// First let's make sure Anchor supports the asset we want to withdraw.
const assetCode = "USDC";
const info = await anchor.getInfo();
const currency = info.currencies.find(({ code }) => code === assetCode);
if (!currency?.code || !currency?.issuer) {
throw new Error(
`Anchor does not support ${assetCode} asset or is not correctly configured on TOML file`,
);
}

// Use same "anchor" object from previous step.
const { url, id } = await anchor.sep24().withdraw({
authToken: authToken, // Use same "authToken" string from previous step
withdrawalAccount: FUNDS_STELLAR_KEYPAIR.public_key,
assetCode,
lang: "en", // "lang" is optional, defaults to "en" if ommited
extraFields: {
// "amount" is optional for non-custodial wallets and mandatory for custodial wallets
amount: "<amount to withdraw / cash-out>",
},
});

La lógica para iniciar una transacción de depósito se ve muy similar. Consulta la especificación estándar de SEP-24 para información detallada.

Escuchar la Notificación de Cierre

El siguiente paso es abrir la URL proporcionada en el cliente de la aplicación utilizando una vista web móvil, pestaña del navegador o popup. El usuario pasará por KYC si no lo ha hecho antes en una transacción anterior. En el caso de depósito, el usuario también puede seleccionar una ubicación de agente de MoneyGram a la que ir al proporcionar efectivo.

Finalmente, cuando el usuario termine con la interfaz de usuario de MoneyGram, el usuario seleccionará un botón mostrado en la interfaz de usuario de MoneyGram y MoneyGram enviará un [postMessage] a la ventana o aplicación que abrió su flujo inicialmente. El mensaje enviado será el objeto JSON de transacción SEP-24 que representa la transacción.

Si la transacción recibida en el mensaje [postMessage] está en un estado de pending_user_transfer_start, esto significa que el usuario ha terminado con la interfaz de usuario de MoneyGram y es seguro cerrar la ventana.

A continuación, se muestra un ejemplo simple en JavaScript escuchando por una notificación [postMessage].

webview = window.open(moneygramURL, "webview", "width=500,height=800");
window.addEventListener("message", closeWebView);

function closeWebView(e) {
const txJson = e.data.transaction;
console.log(`Transaction ${txJson.id} is ${txJson.status}`);

// If we get a postMessage event and the transaction status is
// "pending_user_transfer_start" let's interpret that as a signal to close
// the webview window and take user back to the application experience
if (txJson.status === "pending_user_transfer_start") {
webview.close();
}
}

Enviar o Recibir Fondos

En las transacciones de retiro (o cash-out), las aplicaciones deben enviar USDC a la cuenta Stellar que MoneyGram especifica. En las transacciones de depósito (cash-in), las aplicaciones deben monitorear su cuenta Stellar para un pago de MoneyGram.

En cada caso, la transacción presentada a Stellar debe tener un memo adjunto. Este memo es proporcionado por MoneyGram en el caso de la retirada de fondos, y proporcionado por la aplicación en el caso del depósito. El memo es un identificador que permite a las partes vincular el pago on-chain con el registro de la transacción en la base de datos de la aplicación o de MoneyGram.

Esperar hasta que MoneyGram esté listo

Antes de que la aplicación pueda enviar fondos o instruir al usuario a proporcionar efectivo a un agente de MoneyGram, la aplicación debe confirmar con el servidor de MoneyGram que la transacción está lista para proceder, lo cual se indica con el estado pending_user_transfer_start.

Necesitarás la siguiente información para hacerlo.

Este código utiliza un mecanismo simple de monitoreo (polling) sin condición de salida. El código de la aplicación debe ser más robusto.

// We can keep the transaction "id" from the withdraw() call,
// authToken and assetCode from previous steps.
const { url, id: transactionId } = await anchor.sep24().withdraw({
authToken,
assetCode,
// ...other params
});

// First, let's initialize a watcher object from the Wallet SDK.
let watcher = anchor.sep24().watcher();

// Then we have the option to watch for a particular transaction.
let { stop, refresh } = watcher.watchOneTransaction({
authToken,
assetCode,
id: transactionId,
onMessage: (transaction) => {
if (transaction.status === "pending_user_transfer_start") {
// begin transfer code
}
},
onSuccess: (transaction) => {
// transaction comes back as completed / refunded / expired
},
onError: (transaction) => {
// runtime error, or the transaction comes back as
// no_market / too_small / too_large / error
},
});

// We also have the option to watch for ALL transactions of a particular asset.
let { stop, refresh } = watcher.watchAllTransactions({
authToken,
assetCode,
onMessage: (transaction) => {
if (transaction.status === "pending_user_transfer_start") {
// begin transfer code
}
},
onError: (transaction) => {
// runtime error, or the transaction comes back as
// no_market / too_small / too_large / error
},
});

// While the Watcher class offers powerful tracking capabilities, sometimes
// it's required to just fetch a transaction (or transactions) once. The Anchor
// class allows you to fetch a transaction by ID, Stellar transaction ID, or
// external transaction ID like illustrated below.

// "id" is the actual Anchor transaction id, all transactions should have it.
const transaction = await anchor.sep24().getTransactionBy({
authToken,
id: transactionId,
});

// "stellarTransactionId" (aka "stellar_transaction_id" on the SEP spec)
// is the hash of the Stellar network transaction payment related to this
// Anchor transaction.
// The "stellarTransactionId" has a SHA256 hash format like the below:
// - "a35135d8ed4b29b66d821444f6760f8ca1e77bea1fb49541bebeb2c3d844364a"
// E.g. we'll only have this transaction id field AFTER the wallet sends funds
// to Anchor on the withdrawal flow or receives funds from Anchor on the
// deposit flow.
const transaction = await anchor.sep24().getTransactionBy({
authToken,
stellarTransactionId,
});

// "externalTransactionId" (aka "external_transaction_id" on the SEP spec)
// could refer to some ID of transaction on external network.
// E.g. for MoneyGram this is the "reference number" displayed to the user on
// the last step of MoneyGram's UI which the user should then use on a physical
// MoneyGram location to complete the cash out operation and pick-up the money.
const transaction = await anchor.sep24().getTransactionBy({
authToken,
externalTransactionId,
});

// It's also possible to fetch multiple transactions for an asset.
const transactions = await anchor.sep24().getTransactionsForAsset({
authToken,
assetCode,
});

Enviar fondos

Una vez que MoneyGram esté listo para recibir fondos, tu aplicación debe extraer la cuenta Stellar, el memo y el monto a usar en la transacción de pago, construir una transacción Stellar y enviarla a la red Stellar. Necesitarás:

  • Una copia del objeto de transacción de MoneyGram
  • La clave pública y secreta de fondos de la aplicación

El código para enviar transacciones a Stellar debe desarrollarse de manera cuidadosa. La SDF tiene una página de documentación dedicada a enviar transacciones y manejar errores de forma adecuada. Aquí hay varias cosas que debes tener en cuenta:

  • Ofrece una tarifa alta. Tu tarifa debe ser tan alta como la que ofrecerías antes de decidir que la transacción ya no vale la pena enviar. Stellar solo te cobrará lo mínimo necesario para ser incluido en el ledger; no te cobrarán la cantidad que ofreces a menos que todos los demás ofrezcan la misma cantidad o más. De lo contrario, pagarás la tarifa más pequeña ofrecida en el conjunto de transacciones incluidas en el ledger.
  • Establece un límite de tiempo máximo en la transacción. Esto asegura que si tu transacción no se incluye en el ledger antes del tiempo establecido, puedes reconstruir la transacción con una tarifa ofrecida más alta y volver a enviarla con mejores posibilidades de inclusión.
  • Reenvía la transacción cuando recibas códigos de estado 504. Los códigos de estado 504 simplemente te están indicando que tu transacción sigue pendiente; no que ha sido cancelada o que tu solicitud fue inválida. Simplemente deberías hacer la solicitud nuevamente con la misma transacción para obtener un estado final (ya sea incluido o caducado).

A continuación, se presenta un ejemplo de código Typescript para enviar una transacción de pago ("transferencia"). Utiliza límites de tiempo y maneja códigos de estado 504 (dentro de submitTransaction), pero no maneja la caducidad de una transacción.

Ten en cuenta que el código Python está muy simplificado. No utiliza límites de tiempo, no maneja códigos de estado 504 ni la caducidad de una transacción.

import { Wallet, IssuedAssetId } from "@stellar/typescript-wallet-sdk";
import { Horizon } from "@stellar/stellar-sdk";

const wallet = Wallet.TestNet();

// This creates a Stellar instance to manage the connection with Horizon.
const stellar = wallet.stellar();

// Let's make sure Anchor supports the token we want to withdraw.
const assetCode = "USDC";
const info = await anchor.getInfo();
const currency = info.currencies.find(({ code }) => code === assetCode);
if (!currency?.code || !currency?.issuer) {
throw new Error(
`Anchor does not support ${assetCode} asset or is not correctly configured on TOML file`,
);
}

// This creates the Stellar asset object which we'll need while creating the
// transfer withdrawal transaction below.
const asset = new IssuedAssetId(currency.code, currency.issuer);

// This creates a transaction builder which we'll be using to assemble
// our transfer withdrawal transaction as shown below.
const txBuilder = await stellar.transaction({
sourceAddress: FUNDS_STELLAR_KEYPAIR,
baseFee: 10000, // this is 0.001 XLM
timebounds: 180, // in seconds
});

// We can use the transaction object received on the onMessage callback from
// the watcher, or, we can also fetch the transaction object using either
// getTransactionBy or getTransactionsForAsset as illustrated in previous step.
onMessage: (transaction) => {
if (transaction.status === "pending_user_transfer_start") {
// Use the builder to assemble the transfer transaction. Behind the scenes
// it extracts the Stellar account (withdraw_anchor_account), memo (withdraw_memo)
// and amount (amount_in) to use in the Stellar payment transaction that will
// be submitted to the Stellar network.
const transferTransaction = txBuilder
.transferWithdrawalTransaction(transaction, asset)
.build();

// Signs it with the source (funds) account key pair
transferTransaction.sign(FUNDS_STELLAR_KEYPAIR);

// Finally submits it to the stellar network. This stellar.submitTransaction()
// function handles '504' status codes (timeout) by keep retrying it until
// submission succeeds or we get a different error.
try {
const response = await stellar.submitTransaction(transferTransaction);
console.log("Stellar-generated transaction ID: ", response.id);
} catch (error) {
/*
In case it's not a 504 (timeout) error, the application could try some
resolution strategy based on the error kind.

On Stellar docs you can find a page dedicated to error handling:
https://developers.stellar.org/docs/learn/encyclopedia/errors-and-debugging/error-handling

And status/result codes:
https://developers.stellar.org/docs/data/horizon/api-reference/errors
*/

// Let's illustrate here how we could handle an 'invalid sequence number' error.

// We can access all possible result codes through Horizon's API.
const sdkResultCodes = Horizon.HorizonApi.TransactionFailedResultCodes;

// We can access error's response data to check for useful error details.
const errorData = error.response?.data;
/*
Sample of errorData object returned by the Wallet SDK:
{
type: 'https://stellar.org/horizon-errors/transaction_failed',
title: 'Transaction Failed',
status: 400,
detail: 'The transaction failed when submitted to the stellar network.
The `extras.result_codes` field on this response contains further details.
Descriptions of each code can be found at:
https://developers.stellar.org/docs/data/horizon/api-reference/errors/http-status-codes/horizon-specific/transaction-failed',
extras: {
envelope_xdr: 'AAAAAgAAAADBjF7n9gfByOwlnyaJH...k4BRagf/////////8AAAAAAAAAAA==',
result_codes: { transaction: 'tx_bad_seq' },
result_xdr: 'AAAAAAAAAGT////6AAAAAA=='
}
}
*/

/*
Example scenario: invalid sequence numbers.

These errors typically occur when you have an outdated view of an account.
This could be because multiple devices are using this account, you have
concurrent submissions happening, or other reasons. The solution is relatively
simple: retrieve the account details and try again with an updated sequence number.
*/
if (
errorData?.status == 400 &&
errorData?.extras?.result_codes?.transaction ===
sdkResultCodes.TX_BAD_SEQ
) {
// Creating a new transaction builder means retrieving an updated sequence number.
const txBuilder2 = await stellar.transaction({
sourceAddress: FUNDS_STELLAR_KEYPAIR,
baseFee: 10000,
timebounds: 180,
});

// ...

// Repeat all the steps until submitting the transaction again.

// ...

const response2 = await stellar.submitTransaction(transferTransaction);
console.log(
"Stellar-generated transaction ID on retry: ",
response2.id,
);

// The application should take care to not resubmit the same transaction
// blindly with an updated sequence number as it could result in more than
// one payment being made when only one was intended.
}
}
}
};

Recibir fondos

Una vez que MoneyGram esté listo para que el usuario entregue efectivo a un agente de MGI (en casos de depósito o cash-in), el servidor de la aplicación debe comenzar a monitorear su cuenta Stellar en busca de un pago entrante de USDC enviado por MoneyGram.

La aplicación debe haber proporcionado un memo para que MoneyGram lo use cuando inicie el depósito. MoneyGram adjuntará este memo a la transacción utilizada para enviar el pago a la aplicación, y la aplicación debe utilizar esto para verificar el memo de las transacciones involucrando su cuenta para asociar el pago de regreso al usuario y a la transacción específica.

La mejor manera de monitorear los pagos realizados a una cuenta es transmitir eventos desde el endpoint de pagos de Stellar. El uso de cursores de transmisión puede ayudar a asegurarte de que nunca pierdas un evento, incluso si el proceso de transmisión de tu aplicación se cae por un período de tiempo.

Ten en cuenta que este código no maneja pagos de ruta o saldos reclamables, dos formas de pago ligeramente diferentes. En el momento de escribir esto, MoneyGram no utiliza ninguna de estas opciones, pero puede que desees agregar soporte para ellas en caso de que lo hagan en el futuro.

// The Wallet SDK does not support payments streaming yet so let's build
// it using the underlying Horizon SDK
import { Horizon } from "@stellar/stellar-sdk";
import { getTransactionByMemo } from "./queries";

const streamPayments = (account: string, cursor: string) => {
const server = new Horizon.Server("https://horizon-testnet.stellar.org");
server
.payments()
.forAccount(account)
.join("transactions")
.cursor(cursor)
.stream({
onmessage: (payment) => {
if (
payment["type"] !== "payment" ||
payment["from"] === account ||
payment["asset_type"] === "native" ||
payment["asset_code"] !== ASSET_CODE ||
payment["asset_issuer"] !== ASSET_ISSUER
) {
return;
}

const transaction = getTransactionByMemo(
payment["transaction_attr"]["memo"],
payment["transaction_attr"]["memo_type"],
); // this is your own DB query function

if (!transaction) {
return;
}

console.log(
`Payment for deposit transaction ${transaction.id}`,
`matched with Stellar transaction `,
`${payment["transaction_attr"]["id"]}`,
);
},
onerror: (error) => {
// handle error
},
});
};

Obtener el número de referencia

Para transacciones de depósito o cash-in, MoneyGram no proporciona números de referencia. Todo lo que el usuario necesita hacer es entregar efectivo en la ubicación del agente que eligió en la interfaz de usuario de MoneyGram más temprano en el flujo, y la aplicación debe completar la transacción cuando se detecte un pago coincidente en Stellar.

Para transacciones de retirada o cash-out, MoneyGram proporciona un número de referencia en su UI y API una vez que MoneyGram detecta el pago de USDC de la aplicación en Stellar. Los usuarios deberían poder usar la interfaz del cliente de la aplicación para ver el número de referencia directamente o encontrar la página de detalles de la transacción de MoneyGram y verlo allí.

Ten en cuenta que la página de detalles de transacciones de MoneyGram está protegida con un token JWT en la URL que caduca relativamente rápido después de ser recuperada. Esto significa que las aplicaciones deben recuperar la URL en el momento en que el usuario solicita la página, lo que potencialmente requeriría re-autenticación a través de SEP-10.

// Watcher's onMessage callback, see previous steps for more info on this
onMessage: (transaction) => {
if (transaction.status === "pending_user_transfer_complete") {
console.log(
`Transaction reference number ${transaction.external_transaction_id}`,
`also viewable at ${transaction.more_info_url}`,
);
}
};