Documentación
spare-sdk
Suma una microdonación en USDC por transacción a cualquier app de Stellar. La donación va directo a la cuenta de la fundación; Spare nunca retiene fondos. Solo USDC de Circle, solo fundaciones con dominio verificado.
Instalar
pnpm add spare-sdk @stellar/stellar-sdk@stellar/stellar-sdk es una peer dependency: instálala junto a spare-sdk (una sola copia compartida con tu app).
Transacción clásica: addDonation
import { addDonation, HorizonAccountPort } from "spare-sdk";
const result = await addDonation(unsignedTx, {
foundation: { account: "G...", domain: "foundation.org" }, // must be listed in its stellar.toml
amount: "0.50", // or: roundUp: true (only when the purchase is USDC)
appId: "my-app", // <= 22 ASCII bytes, memo becomes "spare:my-app"
maxAmount: "5", // your cap per donation
accounts: new HorizonAccountPort("https://horizon.stellar.org"),
});
switch (result.status) {
case "offered": // ask the user "Add US$<result.donation.amount>?", then sign result.transaction
case "not-offered": // sign the original tx; result.reason says why (e.g. "insufficient-balance")
case "passthrough": // signed / fee-bump / multisig / extra signers / Soroban: sign the original tx
}offered devuelve una transacción nueva sin firmar (hash nuevo, comisión subida en una operación, memo puesto solo si estaba vacío y ningún destino exige uno). No se agrega nada sin el sí explícito de la persona.
Redondeo
Solo cuando toda la transacción es una compra en USDC de Circle (pagos, pathPaymentStrictSend, ofertas de venta). El SDK informa lo que usó, así que muestra estos valores en vez de recalcular: donation.purchase / purchaseStroops (la compra en USDC) y roundedTotal / roundedTotalStroops (compra más donación). Solo vienen definidos en el redondeo.
- Ya es entero (por ejemplo 5.00):
round-up-already-whole. pathPaymentStrictReceive, operaciones en XLM u otro activo, o operaciones no modeladas en la misma transacción:round-up-needs-usdc-purchase(el gasto real no se conoce de antemano, así que Spare nunca redondeasendMax).
Llamada Soroban: donateAfter
Una transacción Soroban tiene una sola operación, así que la donación es un pago aparte después del éxito. Necesita una segunda firma: avísale a la persona antes de que acepte.
import { donateAfter } from "spare-sdk";
const follow = await donateAfter(
{ successful: true, sourceAccount: userAccount, hash },
{ foundation, amount: "0.50", appId: "my-app", maxAmount: "5",
accounts, networkPassphrase: Networks.PUBLIC },
);
if (follow.status === "offered") { /* confirm, then sign follow.transaction */ }El seguimiento es un único pago (umbral medio). Si la cuenta de la persona necesita más que su llave maestra para firmarlo, no se ofrece nada (multisig).
Resultados y códigos de motivo
| Estado | Significado |
|---|---|
offered | Una transaction nueva sin firmar, la información de donation y el fee. Pregunta a la persona y luego fírmala. |
not-offered | La transacción está bien pero no se debe ofrecer donación. reason dice por qué. Firma la original. |
passthrough | Spare no puede modificar la transacción de forma segura. Queda intacta. Firma la original. |
Motivos de passthrough
| Motivo | Significado |
|---|---|
fee-bump | La transacción es un fee-bump. |
already-signed | La transacción ya tiene firmas. |
soroban | Una transacción Soroban: usa donateAfter. |
multiple-sources | Más de una cuenta de origen. |
multisig | La llave maestra sola no alcanza el umbral de la transacción: medio, o alto con setOptions / accountMerge. |
extra-signers | Está puesta la precondición extraSigners de CAP-21. |
Motivos de not-offered
| Motivo | Significado |
|---|---|
invalid-options | Las opciones están mal formadas, incluido un baseFee mal formado. |
invalid-app-id | appId no es válido (como máximo 22 bytes ASCII). |
invalid-amount | El monto no es un monto USDC válido. |
invalid-foundation | La fundación está mal formada. |
amount-over-cap | La donación supera tu maxAmount. |
round-up-needs-usdc-purchase | El redondeo necesita una compra en USDC de Circle (ver arriba). |
round-up-already-whole | La compra ya es un monto entero. |
foundation-not-verified | La cuenta de la fundación no está listada en el stellar.toml de su sitio. |
foundation-trustline-missing | La fundación no tiene trustline de USDC. |
foundation-trustline-unauthorized | La trustline de USDC de la fundación no está autorizada. |
foundation-trustline-full | No queda espacio bajo el límite de la trustline de la fundación. |
user-trustline-missing | La persona no tiene trustline de USDC. |
user-trustline-unauthorized | La trustline de USDC de la persona no está autorizada. |
unsupported-operation | La transacción tiene operaciones que pueden gastar fondos de formas que Spare no modela, por ejemplo manageBuyOffer, createClaimableBalance, liquidityPoolDeposit, accountMerge. |
multisig | Solo desde donateAfter: el seguimiento necesita más que la llave maestra. |
insufficient-balance | No alcanza el USDC, o el XLM para la comisión más el XLM que envía la transacción. |
account-lookup-failed | No se pudo cargar la cuenta. |
main-tx-not-successful | Solo donateAfter: la transacción principal no resultó bien. |
DonationInfo
| Campo | Descripción |
|---|---|
amount | Monto en USDC, 7 decimales. Muéstraselo a la persona antes de firmar. |
amountStroops | El mismo monto en stroops (bigint). |
foundation | La cuenta de la fundación. |
attributed | Falso cuando la transacción ya tenía un memo, así que la donación no se puede etiquetar para la app. |
purchase, purchaseStroops | Solo redondeo: la compra en USDC que la transacción ya hace. |
roundedTotal, roundedTotalStroops | Solo redondeo: la compra más la donación. |
Opciones
| Opción | Descripción |
|---|---|
foundation | { account, domain }: la cuenta G... y el hostname cuyo stellar.toml debe listarla. |
appId | Como máximo 22 bytes ASCII. El memo queda como spare:<appId>. |
maxAmount | Tu tope por donación, en USDC. |
accounts | Un AccountPort (por ejemplo HorizonAccountPort). |
fetch | Opcional. Fetch inyectable, por defecto el global. |
baseFee | Opcional. Comisión por operación en stroops, solo dígitos, mínimo 100. |
Puerto de cuenta
AccountPort.loadAccount(id) devuelve un AccountSnapshot, o null cuando la cuenta no existe. HorizonAccountPort lo llena desde Horizon (headroom = límite - saldo - pasivos de compra; memoRequired desde la entrada de datos config.memo_required). Spare decide sobre múltiples firmas con masterWeight y thresholds por transacción.
| Campo | Descripción |
|---|---|
sequence | Número de secuencia actual (la próxima transacción usa sequence + 1). |
xlmAvailable | XLM disponible para comisiones: saldo menos reserva y pasivos de venta. |
usdc | Trustline de USDC de Circle { balance, authorized, headroom }, o null si no hay. |
masterWeight | Peso de la llave propia de la cuenta; 0 cuando está desactivada. |
thresholds | { low, medium, high }, de 0 a 255. |
memoRequired | SEP-29: la cuenta espera un memo en los pagos entrantes. |
Memo, SEP-29 y comisiones
Si el destino de un pago, pago con ruta o merge tiene config.memo_required, Spare no pone su memo, así que el checkMemoRequired de tu app sigue funcionando. La donación igual se ofrece, con donation.attributed === false. Un destino que no se puede leer se trata como memo requerido.
baseFee es por operación, solo dígitos, mínimo 100 stroops. Un valor mal formado da not-offered / invalid-options; nunca lanza error. Una transacción con comisión 0 sube a 100 por operación, y el mismo número se usa para la revisión de saldo y para la transacción construida.
Utilidades
verifyFoundation(foundation)ylistVerifiedFoundations(candidates): la revisión SEP-1 deACCOUNTS(solo https, sin redirecciones, 5 s de timeout, cuerpo limitado a 100 KB).parseUsdc,formatStroops,roundUpToWholeDollar: utilidades de montos.isValidAppId,memoFor: validación del app id y el memo.USDC_ISSUER,USDC_CODE: las constantes de USDC de Circle.- El acceso a la red (
fetch,AccountPort) es inyectable.