Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion backend/src/__tests__/eventIndexer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,14 @@ describe("EventIndexer", () => {
}

if (sql.includes("INSERT INTO scores")) {
scoreUpdates.push(params);
// Parse bulk insert params: [userId1, delta1, userId2, delta2, ...]
// Convert to format expected by test: [[userId, score, delta], ...]
for (let i = 0; i < params.length; i += 2) {
const userId = params[i];
const delta = params[i + 1];
const score = 500 + (delta as number);
scoreUpdates.push([userId, score, delta]);
}
return { rows: [], rowCount: 1 };
}

Expand Down
1 change: 1 addition & 0 deletions backend/src/__tests__/stellarConfig.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ describe("stellar config", () => {

it("rejects passphrase/network mismatches", () => {
process.env.STELLAR_NETWORK = "mainnet";
process.env.STELLAR_RPC_URL = "https://soroban-mainnet.stellar.org";
process.env.STELLAR_NETWORK_PASSPHRASE = Networks.TESTNET;

expect(() => getStellarConfig()).toThrow(
Expand Down
24 changes: 24 additions & 0 deletions backend/src/tests/jest.setup.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
// Set up environment variables for testing BEFORE any imports
process.env.DATABASE_URL =
process.env.DATABASE_URL ||
"postgresql://test:test@localhost:5432/remitlend_test";
process.env.REDIS_URL = process.env.REDIS_URL || "redis://localhost:6379/1";
process.env.JWT_SECRET =
process.env.JWT_SECRET || "test-secret-key-for-testing-only";
process.env.STELLAR_RPC_URL =
process.env.STELLAR_RPC_URL || "https://soroban-testnet.stellar.org:443";
process.env.STELLAR_NETWORK_PASSPHRASE =
process.env.STELLAR_NETWORK_PASSPHRASE || "Test SDF Network ; September 2015";
process.env.LOAN_MANAGER_CONTRACT_ID =
process.env.LOAN_MANAGER_CONTRACT_ID ||
"CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSC4";
process.env.LENDING_POOL_CONTRACT_ID =
process.env.LENDING_POOL_CONTRACT_ID ||
"CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSC4";
process.env.POOL_TOKEN_ADDRESS =
process.env.POOL_TOKEN_ADDRESS ||
"CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABSC4";
process.env.LOAN_MANAGER_ADMIN_SECRET =
process.env.LOAN_MANAGER_ADMIN_SECRET || "test-secret";
process.env.INTERNAL_API_KEY = process.env.INTERNAL_API_KEY || "test-api-key";

import { jest } from "@jest/globals";

// We've found that global mocks in ESM can be tricky and lead to 'read-only' errors.
Expand Down
96 changes: 96 additions & 0 deletions frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,101 @@
"Settings": {
"language": "Language",
"selectLanguage": "Select Language"
},
"SendRemittance": {
"title": "Send Remittance",
"description": "Transfer funds globally using the Stellar blockchain",
"backButton": "Back",
"walletNotConnected": "⚠️ Please connect your Stellar wallet to send remittances",
"successMessage": "✓ Remittance sent successfully! Redirecting to remittances page...",
"faq": {
"title": "Frequently Asked Questions",
"q1": "What is a Stellar address?",
"a1": "A Stellar address is a 56-character public key that uniquely identifies a Stellar account. It always starts with the letter 'G' and is used to receive payments on the Stellar network.",
"q2": "How long does a remittance take?",
"a2": "Stellar transactions are typically confirmed within 3-5 seconds. Your remittance will appear in the recipient's account almost instantly after blockchain confirmation.",
"q3": "Are there transaction fees?",
"a3": "Stellar network fees are minimal (typically 0.00001 XLM per operation). Additional fees may apply depending on your service provider. Review the transaction preview before confirming.",
"q4": "Do remittances improve my credit score?",
"a4": "Yes! Each successful remittance demonstrates financial activity and helps build your on-chain credit history, which can improve your credit score and loan eligibility.",
"q5": "What if I enter the wrong address?",
"a5": "Always verify the recipient address carefully before confirming. The transaction preview allows you to review the recipient address before sending. Once sent on the blockchain, transactions cannot be reversed."
},
"helpFooter": "Need help?",
"contactSupport": "Contact Support"
},
"RemittanceForm": {
"title": "Send Remittance",
"recipientAddress": "Recipient Address",
"recipientAddressPlaceholder": "G... (Stellar public key)",
"recipientAddressHelper": "Enter the recipient's Stellar public key (56 characters starting with G)",
"recipientRequired": "Recipient address is required",
"recipientInvalid": "Invalid Stellar address format (must be 56 characters starting with G)",
"token": "Token",
"tokenHelper": "Select the currency for remittance",
"amount": "Amount",
"amountPlaceholder": "0.00",
"amountRequired": "Amount is required",
"amountInvalid": "Amount must be greater than 0",
"memo": "Memo (Optional)",
"memoPlaceholder": "Add a note (optional)",
"memoHelper": "Memo must be 28 characters or less",
"reviewButton": "Review Remittance",
"sendingButton": "Sending...",
"validationError": "Validation Error",
"validationErrorDesc": "Please fix the errors in the form",
"successTitle": "Success!",
"successDesc": "Remittance sent successfully",
"errorTitle": "Error",
"resetForm": "Reset"
},
"LoanRepayment": {
"title": "Repay Loan #{loanId}",
"totalOwed": "Total Owed",
"minPaymentLabel": "Minimum Payment",
"repaymentAmount": "Repayment Amount",
"repaymentPlaceholder": "0.00",
"repaymentHelper": "Enter the amount you want to repay in USDC",
"payFullAmount": "Pay Full Amount ({amount} USDC)",
"infoMessage": "Repaying your loan on time improves your credit score and unlocks better rates for future loans.",
"validationError": "Please enter a valid amount",
"amountGreaterThanZero": "Amount must be greater than 0",
"minPaymentRequired": "Minimum payment is {amount} USDC",
"amountExceedsOwed": "Amount cannot exceed total owed ({amount} USDC)",
"reviewButton": "Review Repayment",
"processingButton": "Processing...",
"reviewRemittanceDesc": "Review Repayment"
},
"LendPage": {
"lenderPortal": "Lender Portal",
"title": "Lend",
"description": "Track pool performance, manage deposits, and monitor yield growth.",
"totalPoolSize": "Total Pool Size",
"utilizationRate": "Utilization Rate",
"currentApy": "Current APY",
"activeLoans": "Active Loans",
"errorMessage": "Failed to load lender dashboard data. Please try again.",
"walletNotConnected": "Connect your wallet to view your lending pool portfolio."
},
"RequestLoan": {
"title": "Loan Request Submitted",
"requestId": "Request ID: {id}",
"nextSteps": "Next steps: monitor approval status and prepare repayment before the due date.",
"viewLoans": "View Loans",
"errorLoadingScore": "Could not load your credit score",
"errorLoadingConfig": "Could not load loan eligibility config"
},
"Common": {
"required": "Required",
"optional": "Optional",
"back": "Back",
"cancel": "Cancel",
"confirm": "Confirm",
"submit": "Submit",
"loading": "Loading...",
"error": "Error",
"success": "Success",
"failed": "Failed to load loans. Please reconnect your wallet and try again.",
"walletNotConnected": "Wallet not connected"
}
}
96 changes: 96 additions & 0 deletions frontend/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,101 @@
"Settings": {
"language": "Idioma",
"selectLanguage": "Seleccione el idioma"
},
"SendRemittance": {
"title": "Enviar Remesa",
"description": "Transfiera fondos globalmente utilizando la cadena de bloques Stellar",
"backButton": "Atrás",
"walletNotConnected": "⚠️ Por favor, conecte su cartera Stellar para enviar remesas",
"successMessage": "✓ ¡Remesa enviada exitosamente! Redirigiendo a la página de remesas...",
"faq": {
"title": "Preguntas Frecuentes",
"q1": "¿Qué es una dirección de Stellar?",
"a1": "Una dirección de Stellar es una clave pública de 56 caracteres que identifica de forma única una cuenta de Stellar. Siempre comienza con la letra 'G' y se utiliza para recibir pagos en la red de Stellar.",
"q2": "¿Cuánto tiempo tarda una remesa?",
"a2": "Las transacciones de Stellar se confirman típicamente dentro de 3-5 segundos. Su remesa aparecerá en la cuenta del destinatario casi instantáneamente después de la confirmación de la cadena de bloques.",
"q3": "¿Hay comisiones de transacción?",
"a3": "Las comisiones de la red de Stellar son mínimas (típicamente 0.00001 XLM por operación). Pueden aplicarse comisiones adicionales dependiendo de su proveedor de servicios. Revise la vista previa de la transacción antes de confirmar.",
"q4": "¿Las remesas mejoran mi puntuación de crédito?",
"a4": "¡Sí! Cada remesa exitosa demuestra actividad financiera y ayuda a construir su historial de crédito en cadena, lo que puede mejorar su puntuación de crédito y elegibilidad de préstamo.",
"q5": "¿Qué pasa si ingreso la dirección incorrecta?",
"a5": "Siempre verifique cuidadosamente la dirección del destinatario antes de confirmar. La vista previa de la transacción le permite revisar la dirección del destinatario antes de enviar. Una vez enviado en la cadena de bloques, las transacciones no se pueden revertir."
},
"helpFooter": "¿Necesita ayuda?",
"contactSupport": "Contactar Soporte"
},
"RemittanceForm": {
"title": "Enviar Remesa",
"recipientAddress": "Dirección de Destinatario",
"recipientAddressPlaceholder": "G... (clave pública de Stellar)",
"recipientAddressHelper": "Ingrese la clave pública de Stellar del destinatario (56 caracteres comenzando con G)",
"recipientRequired": "La dirección de destinatario es requerida",
"recipientInvalid": "Formato de dirección de Stellar inválido (debe ser de 56 caracteres comenzando con G)",
"token": "Token",
"tokenHelper": "Seleccione la moneda para la remesa",
"amount": "Monto",
"amountPlaceholder": "0.00",
"amountRequired": "El monto es requerido",
"amountInvalid": "El monto debe ser mayor a 0",
"memo": "Nota (Opcional)",
"memoPlaceholder": "Agregue una nota (opcional)",
"memoHelper": "La nota debe ser de 28 caracteres o menos",
"reviewButton": "Revisar Remesa",
"sendingButton": "Enviando...",
"validationError": "Error de Validación",
"validationErrorDesc": "Por favor corrija los errores en el formulario",
"successTitle": "¡Éxito!",
"successDesc": "Remesa enviada exitosamente",
"errorTitle": "Error",
"resetForm": "Reiniciar"
},
"LoanRepayment": {
"title": "Pagar Préstamo #{loanId}",
"totalOwed": "Total Adeudado",
"minPaymentLabel": "Pago Mínimo",
"repaymentAmount": "Monto de Reembolso",
"repaymentPlaceholder": "0.00",
"repaymentHelper": "Ingrese el monto que desea pagar en USDC",
"payFullAmount": "Pagar Monto Completo ({amount} USDC)",
"infoMessage": "Pagar su préstamo a tiempo mejora su puntuación de crédito y desbloquea mejores tasas para futuros préstamos.",
"validationError": "Por favor ingrese un monto válido",
"amountGreaterThanZero": "El monto debe ser mayor a 0",
"minPaymentRequired": "El pago mínimo es {amount} USDC",
"amountExceedsOwed": "El monto no puede exceder lo adeudado ({amount} USDC)",
"reviewButton": "Revisar Reembolso",
"processingButton": "Procesando...",
"reviewRemittanceDesc": "Revisar Reembolso"
},
"LendPage": {
"lenderPortal": "Portal del Prestamista",
"title": "Prestar",
"description": "Rastrear el desempeño del fondo, administrar depósitos y monitorear el crecimiento de rendimiento.",
"totalPoolSize": "Tamaño Total del Fondo",
"utilizationRate": "Tasa de Utilización",
"currentApy": "APY Actual",
"activeLoans": "Préstamos Activos",
"errorMessage": "Error al cargar los datos del panel de control del prestamista. Por favor intente de nuevo.",
"walletNotConnected": "Conecte su cartera para ver su cartera de fondo de préstamos."
},
"RequestLoan": {
"title": "Solicitud de Préstamo Enviada",
"requestId": "ID de Solicitud: {id}",
"nextSteps": "Próximos pasos: monitoree el estado de aprobación y prepare el reembolso antes de la fecha de vencimiento.",
"viewLoans": "Ver Préstamos",
"errorLoadingScore": "No se pudo cargar su puntuación de crédito",
"errorLoadingConfig": "No se pudo cargar la configuración de elegibilidad de préstamo"
},
"Common": {
"required": "Requerido",
"optional": "Opcional",
"back": "Atrás",
"cancel": "Cancelar",
"confirm": "Confirmar",
"submit": "Enviar",
"loading": "Cargando...",
"error": "Error",
"success": "Éxito",
"failed": "No se pudo cargar los préstamos. Por favor reconecte su cartera e intente de nuevo.",
"walletNotConnected": "Cartera no conectada"
}
}
96 changes: 96 additions & 0 deletions frontend/messages/tl.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,101 @@
"Settings": {
"language": "Wika",
"selectLanguage": "Piliin ang Wika"
},
"SendRemittance": {
"title": "Magpadala ng Remittance",
"description": "Magpadala ng pondo sa buong mundo gamit ang Stellar blockchain",
"backButton": "Bumalik",
"walletNotConnected": "⚠️ Mangyaring i-connect ang iyong Stellar wallet upang magpadala ng remittance",
"successMessage": "✓ Ang remittance ay matagumpay na ipinadala! Ire-redirect sa remittance page...",
"faq": {
"title": "Mga Madalas na Itinatanong",
"q1": "Ano ang Stellar address?",
"a1": "Ang Stellar address ay isang 56-character public key na natatanging nakaidentify ng Stellar account. Laging nagsisimula sa letrang 'G' at ginagamit upang makatanggap ng mga pagbabayad sa Stellar network.",
"q2": "Gaano katagal ang remittance?",
"a2": "Ang mga transaksyon sa Stellar ay karaniwang napapatunayan sa loob ng 3-5 segundo. Ang iyong remittance ay lalitaw sa account ng tagatanggap halos kaagad pagkatapos ng blockchain confirmation.",
"q3": "May transaction fees ba?",
"a3": "Ang Stellar network fees ay minimal (karaniwan 0.00001 XLM per operation). Maaaring may karagdagang bayad depende sa iyong service provider. Suriin ang transaction preview bago kumpirmahin.",
"q4": "Ang mga remittance ba ay nagpapabuti ng aking credit score?",
"a4": "Oo! Bawat matagumpay na remittance ay nagpapakita ng financial activity at tumutulong na bumuo ng iyong on-chain credit history, na maaaring mapabuti ang iyong credit score at loan eligibility.",
"q5": "Paano kung magsulat ako ng maling address?",
"a5": "Laging i-verify nang mabuti ang recipient address bago kumpirmahin. Ang transaction preview ay nagpapahintulot sa iyo na suriin ang recipient address bago magpadala. Pagkatapos ipadala sa blockchain, ang mga transaksyon ay hindi na maibabalik."
},
"helpFooter": "Kailangan ng tulong?",
"contactSupport": "Makipag-ugnayan sa Support"
},
"RemittanceForm": {
"title": "Magpadala ng Remittance",
"recipientAddress": "Recipient Address",
"recipientAddressPlaceholder": "G... (Stellar public key)",
"recipientAddressHelper": "Ilagay ang Stellar public key ng tagatanggap (56 characters na nagsisimula sa G)",
"recipientRequired": "Ang recipient address ay kailangan",
"recipientInvalid": "Invalid Stellar address format (dapat 56 characters na nagsisimula sa G)",
"token": "Token",
"tokenHelper": "Piliin ang currency para sa remittance",
"amount": "Halaga",
"amountPlaceholder": "0.00",
"amountRequired": "Ang halaga ay kailangan",
"amountInvalid": "Ang halaga ay dapat higit sa 0",
"memo": "Memo (Opsyonal)",
"memoPlaceholder": "Magdagdag ng nota (opsyonal)",
"memoHelper": "Ang memo ay dapat 28 characters o mas kaunti",
"reviewButton": "Suriin ang Remittance",
"sendingButton": "Nagpapadala...",
"validationError": "Validation Error",
"validationErrorDesc": "Mangyaring ayusin ang mga error sa form",
"successTitle": "Tagumpay!",
"successDesc": "Ang remittance ay matagumpay na ipinadala",
"errorTitle": "Error",
"resetForm": "I-reset"
},
"LoanRepayment": {
"title": "Bayaran ang Loan #{loanId}",
"totalOwed": "Kabuuang Utang",
"minPaymentLabel": "Minimum Payment",
"repaymentAmount": "Repayment Amount",
"repaymentPlaceholder": "0.00",
"repaymentHelper": "Ilagay ang halaga na gusto mong bayaran sa USDC",
"payFullAmount": "Bayaran ang Buong Halaga ({amount} USDC)",
"infoMessage": "Ang pagbabayad ng iyong loan sa tamang oras ay nagpapabuti ng iyong credit score at nagbubukas ng mas magandang rates para sa mga susunod na loans.",
"validationError": "Mangyaring magbigay ng valid na halaga",
"amountGreaterThanZero": "Ang halaga ay dapat higit sa 0",
"minPaymentRequired": "Ang minimum payment ay {amount} USDC",
"amountExceedsOwed": "Ang halaga ay hindi dapat lampas sa total owed ({amount} USDC)",
"reviewButton": "Suriin ang Repayment",
"processingButton": "Nagpoproseso...",
"reviewRemittanceDesc": "Suriin ang Repayment"
},
"LendPage": {
"lenderPortal": "Lender Portal",
"title": "Magpautang",
"description": "Subaybayan ang pool performance, pamahalaan ang deposits, at subaybayan ang yield growth.",
"totalPoolSize": "Kabuuang Pool Size",
"utilizationRate": "Utilization Rate",
"currentApy": "Current APY",
"activeLoans": "Active Loans",
"errorMessage": "Nabigong mag-load ng lender dashboard data. Mangyaring subukan ulit.",
"walletNotConnected": "I-connect ang iyong wallet upang makita ang iyong lending pool portfolio."
},
"RequestLoan": {
"title": "Ang Loan Request ay Ipinadala Na",
"requestId": "Request ID: {id}",
"nextSteps": "Mga susunod na hakbang: subaybayan ang approval status at maghanda ng repayment bago ang due date.",
"viewLoans": "Tingnan ang Mga Loan",
"errorLoadingScore": "Hindi ma-load ang iyong credit score",
"errorLoadingConfig": "Hindi ma-load ang loan eligibility config"
},
"Common": {
"required": "Kailangan",
"optional": "Opsyonal",
"back": "Bumalik",
"cancel": "Kanselahin",
"confirm": "Kumpirmahin",
"submit": "Ipadala",
"loading": "Nag-load...",
"error": "Error",
"success": "Tagumpay",
"failed": "Nabigong mag-load ng loans. Mangyaring i-reconnect ang iyong wallet at subukan ulit.",
"walletNotConnected": "Wallet na hindi konektado"
}
}
2 changes: 1 addition & 1 deletion frontend/src/app/[locale]/loans/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export default function LoansPage() {
if (isError) {
return (
<section className="rounded-3xl border border-red-200 bg-red-50 p-6 text-red-800 dark:border-red-900/60 dark:bg-red-950/30 dark:text-red-200">
Failed to load loans. Please reconnect your wallet and try again.
{t("errorMessage")}
</section>
);
}
Expand Down
Loading
Loading