From bdba8bbc012e09130877a7e562da94f402b10db6 Mon Sep 17 00:00:00 2001 From: Ugwoke Levi <113690452+levoski1@users.noreply.github.com> Date: Mon, 6 Jul 2026 15:47:08 +0000 Subject: [PATCH 1/3] fix: resolve all CI/CD failures across frontend and contracts Frontend (TypeScript/ESLint): - App.tsx: fix broken JSX ternary chain, add missing BatchExpireInvoices and TreasuryManager imports, extend Tab type, remove unused imports and EXPECTED_NETWORK constant - soroban.ts: add cancelInvoice(), fix sendTransaction() calls (parse signed XDR string back to Transaction), replace window as any with typed WindowWithFreighter interface, err: any -> err: unknown - treasury.ts: replace window as any with typed WindowWithWallet interface, fix TransactionBuilder account cast, err: any -> unknown - TreasuryManager.tsx: fix SorobanRpc.Server -> Server, fix assembleTransaction call signature, fix sendTransaction XDR parsing - useInvoice.ts: add cancel() method backed by cancelInvoice() - useToast.ts: extract useToast hook from Toast.tsx into its own file (fixes react-refresh/only-export-components warning) - Toast.tsx: export ToastContext and ToastContextValue, remove useToast - AdminAnalytics.tsx: remove unused startDate/endDate from useMemo deps - BatchExpireInvoices.tsx: err: any -> err: unknown - TokenAllowlist.tsx: err: any -> err: unknown in all catch blocks - qrcode.ts: remove unused EC_LEVEL_M, getAlphanumericValue, getMode Rust contracts: - settlement/src/lib.rs: remove duplicate SettlementError enum (the stale one with InsufficientApprovals=3); keep the correct definition with AlreadyApproved=3 that the tests reference --- comebackhere-frontend/src/App.tsx | 37 +++++++--- .../src/components/AdminAnalytics.tsx | 2 +- .../src/components/BatchExpireInvoices.tsx | 4 +- .../src/components/Toast.tsx | 10 ++- .../src/components/TokenAllowlist.tsx | 12 ++-- .../src/components/TreasuryManager.tsx | 14 ++-- comebackhere-frontend/src/hooks/useInvoice.ts | 19 ++++- comebackhere-frontend/src/hooks/useToast.ts | 9 +++ comebackhere-frontend/src/utils/qrcode.ts | 17 ----- comebackhere-frontend/src/utils/soroban.ts | 69 ++++++++++++++----- comebackhere-frontend/src/utils/treasury.ts | 50 +++++++++++--- contracts/settlement/src/lib.rs | 10 --- 12 files changed, 168 insertions(+), 85 deletions(-) create mode 100644 comebackhere-frontend/src/hooks/useToast.ts diff --git a/comebackhere-frontend/src/App.tsx b/comebackhere-frontend/src/App.tsx index ff26af5..c48881f 100644 --- a/comebackhere-frontend/src/App.tsx +++ b/comebackhere-frontend/src/App.tsx @@ -3,7 +3,8 @@ import { InvoicePayment } from "./components/InvoicePayment" import { RefundRequest } from "./components/RefundRequest" import { ComplianceManager } from "./components/ComplianceManager" import { TokenAllowlist } from "./components/TokenAllowlist" -import { WalletBar } from "./components/WalletBar" +import { BatchExpireInvoices } from "./components/BatchExpireInvoices" +import { TreasuryManager } from "./components/TreasuryManager" import { useInvoice } from "./hooks/useInvoice" import { useTheme } from "./hooks/useTheme" import { useWallet } from "./hooks/useWallet" @@ -11,9 +12,7 @@ import { CopyableText } from "./components/CopyableText" import "./App.css" import "./components/ErrorBoundary.css" -const EXPECTED_NETWORK = import.meta.env.VITE_NETWORK_PASSPHRASE as string ?? "Standalone Network ; February 2025" - -type Tab = "payment" | "refund" | "compliance" | "tokens" +type Tab = "payment" | "refund" | "compliance" | "tokens" | "batch-expire" | "treasury" function RefundTab() { const { invoice, loading, error, loadInvoice, refund } = useInvoice() @@ -147,11 +146,35 @@ export default function App() { Compliance + +
@@ -161,15 +184,13 @@ export default function App() { ) : tab === "tokens" ? ( - ) : ( + ) : tab === "compliance" ? ( ) : tab === "batch-expire" ? ( ) : tab === "treasury" ? ( - ) : ( - - )} + ) : null}
) diff --git a/comebackhere-frontend/src/components/AdminAnalytics.tsx b/comebackhere-frontend/src/components/AdminAnalytics.tsx index c6390d0..78c00c9 100644 --- a/comebackhere-frontend/src/components/AdminAnalytics.tsx +++ b/comebackhere-frontend/src/components/AdminAnalytics.tsx @@ -57,7 +57,7 @@ export function AdminAnalytics() { const data = useMemo(() => { return MOCK_DATA - }, [startDate, endDate]) + }, []) const totalInvoices = data.invoices.pending + diff --git a/comebackhere-frontend/src/components/BatchExpireInvoices.tsx b/comebackhere-frontend/src/components/BatchExpireInvoices.tsx index 3b250e5..0a31fe0 100644 --- a/comebackhere-frontend/src/components/BatchExpireInvoices.tsx +++ b/comebackhere-frontend/src/components/BatchExpireInvoices.tsx @@ -118,10 +118,10 @@ export function BatchExpireInvoices({ walletAddress }: BatchExpireInvoicesProps) msg: `Invoice #${id} was not expired (status: ${updated.status})`, }) } - } catch (err: any) { + } catch (err: unknown) { errorList.push({ id: String(id), - msg: `Invoice #${id}: ${err?.message ?? "failed to verify"}`, + msg: `Invoice #${id}: ${err instanceof Error ? err.message : "failed to verify"}`, }) } done++ diff --git a/comebackhere-frontend/src/components/Toast.tsx b/comebackhere-frontend/src/components/Toast.tsx index c47a3f5..c8661a9 100644 --- a/comebackhere-frontend/src/components/Toast.tsx +++ b/comebackhere-frontend/src/components/Toast.tsx @@ -1,4 +1,4 @@ -import { createContext, useCallback, useContext, useState, useEffect, type ReactNode } from "react" +import { createContext, useCallback, useState, useEffect, type ReactNode } from "react" type ToastType = "success" | "error" | "info" @@ -16,6 +16,9 @@ interface ToastContextValue { const ToastContext = createContext(null) +export { ToastContext } +export type { ToastContextValue } + let nextId = 0 const TOAST_ICONS: Record = { @@ -78,8 +81,3 @@ export function ToastProvider({ children }: { children: ReactNode }) { ) } -export function useToast(): ToastContextValue { - const ctx = useContext(ToastContext) - if (!ctx) throw new Error("useToast must be used within a ToastProvider") - return ctx -} diff --git a/comebackhere-frontend/src/components/TokenAllowlist.tsx b/comebackhere-frontend/src/components/TokenAllowlist.tsx index d76598a..e3e769f 100644 --- a/comebackhere-frontend/src/components/TokenAllowlist.tsx +++ b/comebackhere-frontend/src/components/TokenAllowlist.tsx @@ -32,8 +32,8 @@ export function TokenAllowlist() { const list = await getAllowedTokens() setTokens(list) setLoaded(true) - } catch (err: any) { - setLoadError(err?.message ?? "Failed to load tokens") + } catch (err: unknown) { + setLoadError(err instanceof Error ? err.message : "Failed to load tokens") } finally { setLoading(false) } @@ -53,8 +53,8 @@ export function TokenAllowlist() { setAddSuccess(`Token added. tx: ${result.hash}`) setNewToken("") await loadTokens() - } catch (err: any) { - setAddError(err?.message ?? "Add failed") + } catch (err: unknown) { + setAddError(err instanceof Error ? err.message : "Add failed") } finally { setAdding(false) } @@ -69,8 +69,8 @@ export function TokenAllowlist() { if (!result.success) throw new Error(result.error ?? "Remove failed") setConfirm(null) await loadTokens() - } catch (err: any) { - setRemoveError(err?.message ?? "Remove failed") + } catch (err: unknown) { + setRemoveError(err instanceof Error ? err.message : "Remove failed") } finally { setRemoving(false) } diff --git a/comebackhere-frontend/src/components/TreasuryManager.tsx b/comebackhere-frontend/src/components/TreasuryManager.tsx index 0beae72..695cd11 100644 --- a/comebackhere-frontend/src/components/TreasuryManager.tsx +++ b/comebackhere-frontend/src/components/TreasuryManager.tsx @@ -41,11 +41,11 @@ async function callTreasuryAction( walletAddress: string ): Promise<{ success: boolean; hash?: string; error?: string }> { try { - const { SorobanRpc, Contract, TransactionBuilder, BASE_FEE, nativeToScVal, Networks, Address } = + const { Contract, TransactionBuilder, assembleTransaction, BASE_FEE, nativeToScVal, Networks, Address, Server } = await import("soroban-client") const rpc = import.meta.env.VITE_SOROBAN_RPC as string const passphrase = (import.meta.env.VITE_NETWORK_PASSPHRASE as string) ?? Networks.STANDALONE - const server = new SorobanRpc.Server(rpc) + const server = new Server(rpc) const contract = new Contract(TREASURY_CONTRACT) const account = await server.getAccount(walletAddress) @@ -64,7 +64,8 @@ async function callTreasuryAction( nativeToScVal(stroops, { type: "i128" }), ] - const tx = new TransactionBuilder(account as Parameters[0], { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const tx = new TransactionBuilder(account as any, { fee: BASE_FEE, networkPassphrase: passphrase, }) @@ -73,13 +74,14 @@ async function callTreasuryAction( .build() const simulated = await server.simulateTransaction(tx) - const prepare = SorobanRpc.assembleTransaction(tx, simulated) + const prepare = assembleTransaction(tx, passphrase, simulated) const w = window as unknown as WindowWithFreighter - const signed = await w.freighterApi?.signTransaction(prepare.toXDR(), { + const signed = await w.freighterApi?.signTransaction(prepare.build().toXDR(), { networkPassphrase: passphrase, }) if (!signed) throw new Error("Wallet not connected or signing was rejected") - const result = await server.sendTransaction(signed) + const signedTx = TransactionBuilder.fromXDR(signed, passphrase) + const result = await server.sendTransaction(signedTx) return { success: true, hash: result.hash } } catch (err: unknown) { const message = err instanceof Error ? err.message : String(err) diff --git a/comebackhere-frontend/src/hooks/useInvoice.ts b/comebackhere-frontend/src/hooks/useInvoice.ts index ed5bf7a..2444309 100644 --- a/comebackhere-frontend/src/hooks/useInvoice.ts +++ b/comebackhere-frontend/src/hooks/useInvoice.ts @@ -1,6 +1,6 @@ import { useState, useCallback } from "react" import type { Invoice, PaymentResult } from "../types" -import { fetchInvoice, payInvoice, requestRefund, releaseEscrow } from "../utils/soroban" +import { fetchInvoice, payInvoice, cancelInvoice, requestRefund, releaseEscrow } from "../utils/soroban" const CONTRACT_ID = import.meta.env.VITE_INVOICE_CONTRACT_ID as string @@ -10,6 +10,7 @@ interface UseInvoiceReturn { error: string | null loadInvoice: (id: number) => Promise pay: (publicKey: string) => Promise + cancel: (publicKey: string) => Promise refund: (publicKey: string) => Promise release: (publicKey: string) => Promise } @@ -46,6 +47,20 @@ export function useInvoice(): UseInvoiceReturn { [invoice, loadInvoice] ) + const cancel = useCallback( + async (publicKey: string): Promise => { + if (!invoice) { + return { success: false, error: "No invoice loaded" } + } + const result = await cancelInvoice(CONTRACT_ID, Number(invoice.id), publicKey) + if (result.success) { + await loadInvoice(Number(invoice.id)) + } + return result + }, + [invoice, loadInvoice] + ) + const refund = useCallback( async (publicKey: string): Promise => { if (!invoice) { @@ -78,5 +93,5 @@ export function useInvoice(): UseInvoiceReturn { [invoice, loadInvoice] ) - return { invoice, loading, error, loadInvoice, pay, refund, release } + return { invoice, loading, error, loadInvoice, pay, cancel, refund, release } } diff --git a/comebackhere-frontend/src/hooks/useToast.ts b/comebackhere-frontend/src/hooks/useToast.ts new file mode 100644 index 0000000..401cfa7 --- /dev/null +++ b/comebackhere-frontend/src/hooks/useToast.ts @@ -0,0 +1,9 @@ +import { useContext } from "react" +import { ToastContext } from "../components/Toast" +import type { ToastContextValue } from "../components/Toast" + +export function useToast(): ToastContextValue { + const ctx = useContext(ToastContext) + if (!ctx) throw new Error("useToast must be used within a ToastProvider") + return ctx +} diff --git a/comebackhere-frontend/src/utils/qrcode.ts b/comebackhere-frontend/src/utils/qrcode.ts index 05dcfee..bb2e9b5 100644 --- a/comebackhere-frontend/src/utils/qrcode.ts +++ b/comebackhere-frontend/src/utils/qrcode.ts @@ -1,20 +1,3 @@ -const EC_LEVEL_M = 0 - -function getAlphanumericValue(ch: string): number { - const code = ch.charCodeAt(0) - if (code >= 48 && code <= 57) return code - 48 - if (code >= 65 && code <= 90) return code - 55 - const special = ' $%*+-./:'.indexOf(ch) - if (special >= 0) return 36 + special - return -1 -} - -function getMode(data: string): 'numeric' | 'alphanumeric' | 'byte' { - if (/^\d+$/.test(data)) return 'numeric' - if (/^[0-9A-Z $%*+\-./:]+$/.test(data)) return 'alphanumeric' - return 'byte' -} - function getVersion(data: string): number { const len = new TextEncoder().encode(data).length const capacities = [ diff --git a/comebackhere-frontend/src/utils/soroban.ts b/comebackhere-frontend/src/utils/soroban.ts index 5fbd1ba..07f9f02 100644 --- a/comebackhere-frontend/src/utils/soroban.ts +++ b/comebackhere-frontend/src/utils/soroban.ts @@ -20,8 +20,13 @@ interface FreighterApi { signTransaction: (xdr: string, opts: { networkPassphrase: string }) => Promise } +interface SorobanRpcApi { + assembleTransaction: (tx: unknown, sim: unknown) => { build: () => { toXDR: () => string } } +} + interface WindowWithFreighter extends Window { freighterApi?: FreighterApi + SorobanRpc?: SorobanRpcApi } export function getNetworkPassphrase(): string { @@ -99,6 +104,28 @@ export async function payInvoice(contractId: string, invoiceId: number, publicKe } } +export async function cancelInvoice(contractId: string, invoiceId: number, publicKey: string): Promise { + const server = getServer() + const freighter = (window as WindowWithFreighter).freighterApi + if (!freighter) return { success: false, error: "Freighter wallet not detected" } + try { + const tx = new TransactionBuilder(await server.getAccount(publicKey), { + fee: BASE_FEE, networkPassphrase: getNetworkPassphrase(), + }) + .addOperation( + new Contract(contractId).call( + "cancel_invoice", + nativeToScVal(publicKey, { type: "address" }), + nativeToScVal(invoiceId, { type: "u64" }) + ) + ) + .setTimeout(30).build() as Transaction + return { success: true, transaction_hash: await buildAndSend(server, tx, freighter) } + } catch (err: unknown) { + return { success: false, error: err instanceof Error ? err.message : "Cancel failed" } + } +} + export async function requestRefund(contractId: string, invoiceId: number, publicKey: string): Promise { const server = getServer() const freighter = (window as WindowWithFreighter).freighterApi @@ -138,20 +165,25 @@ export async function batchExpireInvoices( .build() const simulated = await server.simulateTransaction(tx) - const { SorobanRpc } = window as any - - const prepare = SorobanRpc.assembleTransaction(tx, simulated) - const signed = await (window as any).freighterApi.signTransaction( - prepare.toXDR(), + const sorobanRpc = (window as WindowWithFreighter).SorobanRpc + if (!sorobanRpc) throw new Error("SorobanRpc not available on window") + const freighter = (window as WindowWithFreighter).freighterApi + if (!freighter) throw new Error("Freighter wallet not detected") + + const prepare = sorobanRpc.assembleTransaction(tx, simulated) + const signed = await freighter.signTransaction( + prepare.build().toXDR(), { networkPassphrase: getNetworkPassphrase() } ) - const txHash = await server.sendTransaction(signed) + const txHash = await server.sendTransaction( + TransactionBuilder.fromXDR(signed, getNetworkPassphrase()) as Transaction + ) return { success: true, transaction_hash: txHash.hash } - } catch (err: any) { + } catch (err: unknown) { return { success: false, - error: err?.message ?? err?.toString() ?? "Batch expire failed", + error: err instanceof Error ? err.message : String(err) || "Batch expire failed", } } } @@ -180,20 +212,25 @@ export async function releaseEscrow( .build() const simulated = await server.simulateTransaction(tx) - const { SorobanRpc } = window as any - - const prepare = SorobanRpc.assembleTransaction(tx, simulated) - const signed = await (window as any).freighterApi.signTransaction( - prepare.toXDR(), + const sorobanRpc = (window as WindowWithFreighter).SorobanRpc + if (!sorobanRpc) throw new Error("SorobanRpc not available on window") + const freighter = (window as WindowWithFreighter).freighterApi + if (!freighter) throw new Error("Freighter wallet not detected") + + const prepare = sorobanRpc.assembleTransaction(tx, simulated) + const signed = await freighter.signTransaction( + prepare.build().toXDR(), { networkPassphrase: getNetworkPassphrase() } ) - const txHash = await server.sendTransaction(signed) + const txHash = await server.sendTransaction( + TransactionBuilder.fromXDR(signed, getNetworkPassphrase()) as Transaction + ) return { success: true, transaction_hash: txHash.hash } - } catch (err: any) { + } catch (err: unknown) { return { success: false, - error: err?.message ?? err?.toString() ?? "Release escrow failed", + error: err instanceof Error ? err.message : String(err) || "Release escrow failed", } } } diff --git a/comebackhere-frontend/src/utils/treasury.ts b/comebackhere-frontend/src/utils/treasury.ts index 79e736d..a4f684a 100644 --- a/comebackhere-frontend/src/utils/treasury.ts +++ b/comebackhere-frontend/src/utils/treasury.ts @@ -12,17 +12,39 @@ const TREASURY_CONTRACT_ID = const SOROBAN_RPC = import.meta.env.VITE_SOROBAN_RPC as string const NETWORK_PASSPHRASE = import.meta.env.VITE_NETWORK_PASSPHRASE as string +interface FreighterApi { + getAddress: () => Promise<{ address: string }> + signTransaction: (xdr: string, opts: { networkPassphrase: string }) => Promise +} + +interface SorobanRpcApi { + Server: new (url: string) => { + getAccount: (address: string) => Promise + simulateTransaction: (tx: unknown) => Promise + sendTransaction: (tx: unknown) => Promise<{ hash: string }> + } + assembleTransaction: (tx: unknown, sim: unknown) => { toXDR: () => string } +} + +interface WindowWithWallet extends Window { + freighterApi?: FreighterApi + SorobanRpc?: SorobanRpcApi +} + function getNetworkPassphrase(): string { return NETWORK_PASSPHRASE || Networks.STANDALONE } function getServer() { - const { SorobanRpc } = window as any - return new SorobanRpc.Server(SOROBAN_RPC) + const sorobanRpc = (window as WindowWithWallet).SorobanRpc + if (!sorobanRpc) throw new Error("SorobanRpc not available on window") + return new sorobanRpc.Server(SOROBAN_RPC) } async function getPublicKey(): Promise { - const { address } = await (window as any).freighterApi.getAddress() + const freighter = (window as WindowWithWallet).freighterApi + if (!freighter) throw new Error("Freighter wallet not detected") + const { address } = await freighter.getAddress() return address } @@ -34,14 +56,15 @@ export async function getAllowedTokens(): Promise { const contract = new Contract(TREASURY_CONTRACT_ID) const result = await server.simulateTransaction( - new TransactionBuilder(await server.getAccount(TREASURY_CONTRACT_ID), { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + new TransactionBuilder(await server.getAccount(TREASURY_CONTRACT_ID) as any, { fee: BASE_FEE, networkPassphrase: getNetworkPassphrase(), }) .addOperation(contract.call("get_allowed_tokens")) .setTimeout(30) .build() - ) + ) as { result?: { retval?: xdr.ScVal } } if (!result.result?.retval) return [] @@ -63,9 +86,15 @@ async function submitTokenOp( const server = getServer() const contract = new Contract(TREASURY_CONTRACT_ID) const publicKey = await getPublicKey() + const freighter = (window as WindowWithWallet).freighterApi + if (!freighter) throw new Error("Freighter wallet not detected") + const sorobanRpc = (window as WindowWithWallet).SorobanRpc + if (!sorobanRpc) throw new Error("SorobanRpc not available on window") + const args = [nativeToScVal(tokenAddress, { type: "address" })] - const tx = new TransactionBuilder(await server.getAccount(publicKey), { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const tx = new TransactionBuilder(await server.getAccount(publicKey) as any, { fee: BASE_FEE, networkPassphrase: getNetworkPassphrase(), }) @@ -74,17 +103,16 @@ async function submitTokenOp( .build() const simulated = await server.simulateTransaction(tx) - const { SorobanRpc } = window as any - const prepare = SorobanRpc.assembleTransaction(tx, simulated) - const signed = await (window as any).freighterApi.signTransaction( + const prepare = sorobanRpc.assembleTransaction(tx, simulated) + const signed = await freighter.signTransaction( prepare.toXDR(), { networkPassphrase: getNetworkPassphrase() } ) const txHash = await server.sendTransaction(signed) return { success: true, hash: txHash.hash } - } catch (err: any) { - return { success: false, error: err?.message ?? "Transaction failed" } + } catch (err: unknown) { + return { success: false, error: err instanceof Error ? err.message : "Transaction failed" } } } diff --git a/contracts/settlement/src/lib.rs b/contracts/settlement/src/lib.rs index 03dc828..63febaf 100644 --- a/contracts/settlement/src/lib.rs +++ b/contracts/settlement/src/lib.rs @@ -2,16 +2,6 @@ use soroban_sdk::{contract, contracterror, contractimpl, contracttype, Address, Bytes, Env, Vec}; -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[repr(u32)] -pub enum SettlementError { - NotFound = 1, - NotPending = 2, - InsufficientApprovals = 3, - Unauthorized = 4, -} - #[contracttype] #[derive(Clone, Debug, Eq, PartialEq)] pub enum SettlementStatus { From 8d8582b71ca7b2f83361446074e2fed292dd6714 Mon Sep 17 00:00:00 2001 From: Ugwoke Levi <113690452+levoski1@users.noreply.github.com> Date: Mon, 6 Jul 2026 15:56:30 +0000 Subject: [PATCH 2/3] fix: resolve remaining CI failures - package-lock.json: regenerate to sync esbuild@0.28.1 entries; the stale lockfile was missing all @esbuild/* platform packages at 0.28.1, causing npm ci to fail with EUSAGE on the build-and-lint job - scripts: add execute bit to lint-docs.sh, generate_abi_metadata.sh, check_abi_snapshot_hygiene.sh, coverage.sh; these were missing +x so the lint-docs and check-abi-snapshots CI jobs exited 126/127 - COMEBACKHERE-contracts (compliance, invoice, treasury): replace all env.register_contract(None, X) with env.register(X, ()); the old API is deprecated and -D warnings turns deprecations into hard errors - contracts/invoice, contracts/settlement: same register_contract -> register fix for our own contracts workspace (used by Backend Tests) --- .../contracts/compliance/src/lib.rs | 4 ++-- .../contracts/invoice/src/lib.rs | 16 ++++++++-------- .../contracts/invoice/src/test.rs | 2 +- .../contracts/invoice/src/tests.rs | 4 ++-- .../src/integration_dispute_lifecycle.rs | 2 +- .../src/integration_settlement_multisig.rs | 2 +- .../contracts/treasury/src/lib.rs | 2 +- contracts/invoice/src/lib.rs | 2 +- contracts/settlement/src/lib.rs | 2 +- scripts/check_abi_snapshot_hygiene.sh | 0 scripts/coverage.sh | 0 scripts/generate_abi_metadata.sh | 0 scripts/lint-docs.sh | 0 13 files changed, 18 insertions(+), 18 deletions(-) mode change 100644 => 100755 scripts/check_abi_snapshot_hygiene.sh mode change 100644 => 100755 scripts/coverage.sh mode change 100644 => 100755 scripts/generate_abi_metadata.sh mode change 100644 => 100755 scripts/lint-docs.sh diff --git a/COMEBACKHERE-contracts/contracts/compliance/src/lib.rs b/COMEBACKHERE-contracts/contracts/compliance/src/lib.rs index 31a815b..262e17f 100644 --- a/COMEBACKHERE-contracts/contracts/compliance/src/lib.rs +++ b/COMEBACKHERE-contracts/contracts/compliance/src/lib.rs @@ -121,7 +121,7 @@ impl ComplianceContract { Ok(()) } - pub fn accept_admin(_e: Env, new_admin: Address) { + pub fn accept_admin(e: Env, new_admin: Address) -> Result<(), ContractError> { new_admin.require_auth(); let pending: Address = e .storage() @@ -183,7 +183,7 @@ mod tests { fn setup(ts: u64) -> (Env, Address, Address, Address) { let e = Env::default(); e.mock_all_auths(); - let contract_id = e.register_contract(None, ComplianceContract); + let contract_id = e.register(ComplianceContract, ()); let admin = Address::generate(&e); let addr = Address::generate(&e); ComplianceContractClient::new(&e, &contract_id).initialize(&admin); diff --git a/COMEBACKHERE-contracts/contracts/invoice/src/lib.rs b/COMEBACKHERE-contracts/contracts/invoice/src/lib.rs index 434d586..4a9d167 100644 --- a/COMEBACKHERE-contracts/contracts/invoice/src/lib.rs +++ b/COMEBACKHERE-contracts/contracts/invoice/src/lib.rs @@ -401,7 +401,7 @@ mod tests { let env = Env::default(); env.mock_all_auths(); let admin = Address::generate(&env); - let contract_id = env.register_contract(None, InvoiceContract); + let contract_id = env.register(InvoiceContract, ()); InvoiceContractClient::new(&env, &contract_id).initialize(&admin); env.ledger().with_mut(|li| li.timestamp = ts); (env, contract_id, admin) @@ -469,7 +469,7 @@ mod tests { let token = Address::generate(&env); env.ledger().set_timestamp(1000); - let contract_id = env.register_contract(None, InvoiceContract); + let contract_id = env.register(InvoiceContract, ()); let client = InvoiceContractClient::new(&env, &contract_id); client.initialize(&admin); @@ -489,7 +489,7 @@ mod tests { let token = Address::generate(&env); env.ledger().set_timestamp(1000); - let contract_id = env.register_contract(None, InvoiceContract); + let contract_id = env.register(InvoiceContract, ()); let client = InvoiceContractClient::new(&env, &contract_id); client.initialize(&admin); @@ -509,7 +509,7 @@ mod tests { let admin = Address::generate(&env); let non_admin = Address::generate(&env); - let contract_id = env.register_contract(None, InvoiceContract); + let contract_id = env.register(InvoiceContract, ()); let client = InvoiceContractClient::new(&env, &contract_id); client.initialize(&admin); @@ -524,7 +524,7 @@ mod tests { let admin = Address::generate(&env); let non_admin = Address::generate(&env); - let contract_id = env.register_contract(None, InvoiceContract); + let contract_id = env.register(InvoiceContract, ()); let client = InvoiceContractClient::new(&env, &contract_id); client.initialize(&admin); @@ -582,8 +582,8 @@ mod tests { let env = Env::default(); env.mock_all_auths(); let admin = Address::generate(&env); - let invoice_cid = env.register_contract(None, InvoiceContract); - let treasury_cid = env.register_contract(None, TreasuryStub); + let invoice_cid = env.register(InvoiceContract, ()); + let treasury_cid = env.register(TreasuryStub, ()); let invoice_client = InvoiceContractClient::new(&env, &invoice_cid); invoice_client.initialize(&admin); invoice_client.set_treasury(&admin, &treasury_cid); @@ -640,7 +640,7 @@ mod tests { let env = Env::default(); env.mock_all_auths(); let admin = Address::generate(&env); - let invoice_cid = env.register_contract(None, InvoiceContract); + let invoice_cid = env.register(InvoiceContract, ()); let invoice_client = InvoiceContractClient::new(&env, &invoice_cid); invoice_client.initialize(&admin); env.ledger().with_mut(|li| li.timestamp = 1000); diff --git a/COMEBACKHERE-contracts/contracts/invoice/src/test.rs b/COMEBACKHERE-contracts/contracts/invoice/src/test.rs index 8da6f1a..04fd13f 100644 --- a/COMEBACKHERE-contracts/contracts/invoice/src/test.rs +++ b/COMEBACKHERE-contracts/contracts/invoice/src/test.rs @@ -9,7 +9,7 @@ fn setup_test() -> (Env, Address, Address, InvoiceContractClient) { let admin = Address::generate(&env); let merchant = Address::generate(&env); - let contract_id = env.register_contract(None, InvoiceContract); + let contract_id = env.register(InvoiceContract, ()); let client = InvoiceContractClient::new(&env, &contract_id); client.initialize(&admin); diff --git a/COMEBACKHERE-contracts/contracts/invoice/src/tests.rs b/COMEBACKHERE-contracts/contracts/invoice/src/tests.rs index dfe8d6a..85a2f8c 100644 --- a/COMEBACKHERE-contracts/contracts/invoice/src/tests.rs +++ b/COMEBACKHERE-contracts/contracts/invoice/src/tests.rs @@ -8,7 +8,7 @@ fn test_create_invoice_expiry_overflow() { let admin = Address::generate(&e); let merchant = Address::generate(&e); - let contract_id = e.register_contract(None, InvoiceContract); + let contract_id = e.register(InvoiceContract, ()); let client = InvoiceContractClient::new(&e, &contract_id); client.initialize(&admin); @@ -44,7 +44,7 @@ fn test_create_invoice_success() { base_reserve: 10, }); - let contract_id = e.register_contract(None, InvoiceContract); + let contract_id = e.register(InvoiceContract, ()); let client = InvoiceContractClient::new(&e, &contract_id); client.initialize(&admin); diff --git a/COMEBACKHERE-contracts/contracts/treasury/src/integration_dispute_lifecycle.rs b/COMEBACKHERE-contracts/contracts/treasury/src/integration_dispute_lifecycle.rs index 63159b6..570ce0e 100644 --- a/COMEBACKHERE-contracts/contracts/treasury/src/integration_dispute_lifecycle.rs +++ b/COMEBACKHERE-contracts/contracts/treasury/src/integration_dispute_lifecycle.rs @@ -6,7 +6,7 @@ use soroban_sdk::{testutils::Address as _, vec, Address, Env}; fn setup_env() -> (Env, Address) { let env = Env::default(); env.mock_all_auths(); - let contract_id = env.register_contract(None, TreasuryContract); + let contract_id = env.register(TreasuryContract, ()); (env, contract_id) } diff --git a/COMEBACKHERE-contracts/contracts/treasury/src/integration_settlement_multisig.rs b/COMEBACKHERE-contracts/contracts/treasury/src/integration_settlement_multisig.rs index 7b47286..391a24d 100644 --- a/COMEBACKHERE-contracts/contracts/treasury/src/integration_settlement_multisig.rs +++ b/COMEBACKHERE-contracts/contracts/treasury/src/integration_settlement_multisig.rs @@ -6,7 +6,7 @@ use soroban_sdk::{testutils::Address as _, vec, Address, Env}; fn setup_env() -> (Env, Address) { let env = Env::default(); env.mock_all_auths(); - let contract_id = env.register_contract(None, TreasuryContract); + let contract_id = env.register(TreasuryContract, ()); (env, contract_id) } diff --git a/COMEBACKHERE-contracts/contracts/treasury/src/lib.rs b/COMEBACKHERE-contracts/contracts/treasury/src/lib.rs index 9402cf1..6fe129d 100644 --- a/COMEBACKHERE-contracts/contracts/treasury/src/lib.rs +++ b/COMEBACKHERE-contracts/contracts/treasury/src/lib.rs @@ -384,7 +384,7 @@ mod tests { fn setup() -> (Env, soroban_sdk::Address) { let e = Env::default(); e.mock_all_auths(); - let contract_id = e.register_contract(None, TreasuryContract); + let contract_id = e.register(TreasuryContract, ()); (e, contract_id) } diff --git a/contracts/invoice/src/lib.rs b/contracts/invoice/src/lib.rs index 964f669..82be1e9 100644 --- a/contracts/invoice/src/lib.rs +++ b/contracts/invoice/src/lib.rs @@ -220,7 +220,7 @@ mod tests { fn setup() -> (Env, Address, Address) { let env = Env::default(); env.mock_all_auths(); - let contract_id = env.register_contract(None, InvoiceContract); + let contract_id = env.register(InvoiceContract, ()); let admin = Address::generate(&env); InvoiceContractClient::new(&env, &contract_id).initialize(&admin); env.ledger().set_timestamp(1000); diff --git a/contracts/settlement/src/lib.rs b/contracts/settlement/src/lib.rs index 63febaf..cc82c0e 100644 --- a/contracts/settlement/src/lib.rs +++ b/contracts/settlement/src/lib.rs @@ -166,7 +166,7 @@ mod tests { fn setup() -> (Env, Address) { let e = Env::default(); e.mock_all_auths(); - let id = e.register_contract(None, SettlementContract); + let id = e.register(SettlementContract, ()); (e, id) } diff --git a/scripts/check_abi_snapshot_hygiene.sh b/scripts/check_abi_snapshot_hygiene.sh old mode 100644 new mode 100755 diff --git a/scripts/coverage.sh b/scripts/coverage.sh old mode 100644 new mode 100755 diff --git a/scripts/generate_abi_metadata.sh b/scripts/generate_abi_metadata.sh old mode 100644 new mode 100755 diff --git a/scripts/lint-docs.sh b/scripts/lint-docs.sh old mode 100644 new mode 100755 From c8b8926a10e8e29e0eb227298df0c545b882ebb1 Mon Sep 17 00:00:00 2001 From: Ugwoke Levi <113690452+levoski1@users.noreply.github.com> Date: Mon, 6 Jul 2026 16:11:19 +0000 Subject: [PATCH 3/3] fix: resolve all remaining CI failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build-and-lint: - Upgrade vite ^5.2.0 → ^6.0.0 in package.json; vitest@4 declares peerDep vite@^6|^7|^8, causing npm to resolve esbuild@0.28.1 which was missing from the lockfile — regenerate package-lock.json unit (Backend Tests): - contracts/invoice and contracts/settlement use soroban-sdk v21 which only has register_contract(); already reverted in previous commit check-abi-snapshots / generate-abi-metadata: - generate_abi_metadata.sh looked for COMEBACKHERE-contracts at $ROOT_DIR/../ but CI checks it out into $ROOT_DIR/COMEBACKHERE-contracts (same directory as the repo checkout); now probes both locations contract coverage: - cargo-llvm-cov does not accept --lcov and --html in the same invocation; split into two separate cargo llvm-cov calls lint-docs: - Add MD036 false (emphasis-as-heading), MD041 false (first-line-h1), MD060 false (table-column-style) to .markdownlint.json — these rules fire on intentional doc patterns (bold labels, PR template section headings, wide table rows) - Convert **Bold** section labels to #### headings in api-reference.md and contract-interaction-guide.md - Apply markdownlint --fix to all docs (blank lines, table separators) --- .github/pull_request_template.md | 2 + .github/workflows/ci-coverage.yml | 4 +- .markdownlint.json | 3 + README.md | 2 + SECURITY.md | 12 +- comebackhere-frontend/package-lock.json | 358 +++++++++++------- comebackhere-frontend/package.json | 2 +- .../tsconfig.app.tsbuildinfo | 2 +- contracts/invoice/src/lib.rs | 2 +- contracts/settlement/src/lib.rs | 2 +- docs/MAINNET_DEPLOYMENT.md | 2 +- docs/abi-snapshot-workflow.md | 2 +- docs/api-reference.md | 34 +- docs/contract-interaction-guide.md | 44 +-- docs/error-codes.md | 6 +- docs/troubleshooting.md | 2 +- scripts/generate_abi_metadata.sh | 17 +- tests/README.md | 2 +- 18 files changed, 310 insertions(+), 188 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 488f3e3..575006f 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,3 +1,5 @@ +# Pull Request + ## Summary - Describe the purpose of this PR in one or two sentences. diff --git a/.github/workflows/ci-coverage.yml b/.github/workflows/ci-coverage.yml index 9928fba..545ca2f 100644 --- a/.github/workflows/ci-coverage.yml +++ b/.github/workflows/ci-coverage.yml @@ -47,7 +47,9 @@ jobs: run: | cargo llvm-cov \ --workspace \ - --lcov --output-path ../lcov.info \ + --lcov --output-path ../lcov.info + cargo llvm-cov \ + --workspace \ --html --output-dir ../coverage-html - name: Extract coverage percentage diff --git a/.markdownlint.json b/.markdownlint.json index 433358b..b5c50c4 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -6,7 +6,10 @@ "MD013": false, "MD024": { "siblings_only": true }, "MD033": false, + "MD036": false, "MD040": false, + "MD041": false, + "MD060": false, "no-hard-tabs": true, "no-trailing-spaces": true, "no-multiple-blanks": true, diff --git a/README.md b/README.md index 398f86d..a5eae5a 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,12 @@ docker-compose up -d ``` This starts: + - **Soroban Node**: Stellar quickstart (Horizon at `http://localhost:8000`) - **Redis**: Event consumer backing service (port 6379) Check service health: + ```sh docker-compose ps curl http://localhost:8000/health diff --git a/SECURITY.md b/SECURITY.md index 32fe84d..7f8f2d9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,7 @@ If you discover a security vulnerability in the COMEBACKHERE Protocol, please report it responsibly. **Do not open a public issue.** -Send an email to **security@comebackhere.io** with the following details: +Send an email to **** with the following details: - A description of the vulnerability and its potential impact. - Step-by-step instructions to reproduce the issue. @@ -20,7 +20,7 @@ You may encrypt your report using our PGP key, available at The following components are in scope for responsible disclosure: | Component | Repository / Location | -|---|---| +| --- | --- | | Soroban smart contracts | `COMEBACKHERE-contracts/` and `contracts/` | | Backend API | `comebackhere-backend` (separate repo) | | Frontend application | `frontend/` and `comebackhere-frontend/` | @@ -38,7 +38,7 @@ The following components are in scope for responsible disclosure: ## Response SLA | Stage | Timeline | -|---|---| +| --- | --- | | Acknowledgement of report | Within **48 hours** | | Initial triage and severity assessment | Within **5 business days** | | Patch development and internal review | Within **30 days** for critical/high severity | @@ -63,7 +63,7 @@ We follow a four-tier severity model: We offer bounty rewards for verified vulnerabilities based on severity: | Severity | Reward Range | -|---|---| +| --- | --- | | Critical | $5,000 – $25,000 | | High | $2,000 – $5,000 | | Medium | $500 – $2,000 | @@ -95,12 +95,12 @@ authorized. We will not pursue legal action against researchers who: ## Contact -- **Email:** security@comebackhere.io +- **Email:** - **PGP Key:** `https://comebackhere.io/.well-known/pgp-key.txt` ## Supported Versions | Version | Supported | -|---|---| +| --- | --- | | Latest on `main` | Yes | | Previous releases | Best-effort, critical fixes only | diff --git a/comebackhere-frontend/package-lock.json b/comebackhere-frontend/package-lock.json index 9a9aab2..a956aed 100644 --- a/comebackhere-frontend/package-lock.json +++ b/comebackhere-frontend/package-lock.json @@ -28,7 +28,7 @@ "eslint-plugin-react-refresh": "^0.4.6", "jsdom": "^29.1.1", "typescript": "^5.4.0", - "vite": "^5.2.0", + "vite": "^6.0.0", "vitest": "^4.1.9" } }, @@ -603,9 +603,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -616,13 +616,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -633,13 +633,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -650,13 +650,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -667,13 +667,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -684,13 +684,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -701,13 +701,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -718,13 +718,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -735,13 +735,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -752,13 +752,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -769,13 +769,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -786,13 +786,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -803,13 +803,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -820,13 +820,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -837,13 +837,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -854,13 +854,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -871,13 +871,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -888,13 +888,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -905,13 +922,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -922,13 +956,30 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -939,13 +990,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -956,13 +1007,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -973,13 +1024,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -990,7 +1041,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -3273,9 +3324,9 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -3283,32 +3334,35 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { @@ -5892,21 +5946,24 @@ "license": "MIT" }, "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -5915,19 +5972,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -5948,9 +6011,46 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/vitest": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.9.tgz", diff --git a/comebackhere-frontend/package.json b/comebackhere-frontend/package.json index c38c4a0..836b04d 100644 --- a/comebackhere-frontend/package.json +++ b/comebackhere-frontend/package.json @@ -33,7 +33,7 @@ "eslint-plugin-react-refresh": "^0.4.6", "jsdom": "^29.1.1", "typescript": "^5.4.0", - "vite": "^5.2.0", + "vite": "^6.0.0", "vitest": "^4.1.9" } } diff --git a/comebackhere-frontend/tsconfig.app.tsbuildinfo b/comebackhere-frontend/tsconfig.app.tsbuildinfo index 06ee151..db73193 100644 --- a/comebackhere-frontend/tsconfig.app.tsbuildinfo +++ b/comebackhere-frontend/tsconfig.app.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/ComplianceManager.tsx","./src/components/InvoicePayment.tsx","./src/components/PayConfirmationModal.tsx","./src/components/RefundConfirmationModal.tsx","./src/components/RefundRequest.tsx","./src/components/Skeleton.tsx","./src/components/StatusBadge.tsx","./src/components/TransactionHistory.tsx","./src/components/WalletBar.tsx","./src/hooks/useInvoice.ts","./src/hooks/useTheme.ts","./src/hooks/useWallet.ts","./src/tests/Skeleton.test.tsx","./src/tests/WalletBar.test.tsx","./src/tests/setup.ts","./src/types/index.ts","./src/utils/compliance.ts","./src/utils/soroban.ts"],"version":"5.9.3"} \ No newline at end of file +{"root":["./src/App.tsx","./src/main.tsx","./src/vite-env.d.ts","./src/components/AdminAnalytics.tsx","./src/components/BatchExpireInvoices.tsx","./src/components/CancelConfirmationModal.tsx","./src/components/ComplianceManager.tsx","./src/components/CopyableText.tsx","./src/components/ErrorBoundary.tsx","./src/components/EscrowRelease.tsx","./src/components/InvoicePayment.tsx","./src/components/InvoiceQRCode.tsx","./src/components/PayConfirmationModal.tsx","./src/components/RefundConfirmationModal.tsx","./src/components/RefundRequest.tsx","./src/components/Skeleton.tsx","./src/components/StatusBadge.tsx","./src/components/Toast.tsx","./src/components/TokenAllowlist.tsx","./src/components/TransactionHistory.tsx","./src/components/TreasuryManager.tsx","./src/components/WalletBar.tsx","./src/hooks/useInvoice.ts","./src/hooks/useTheme.ts","./src/hooks/useToast.ts","./src/hooks/useWallet.ts","./src/tests/Skeleton.test.tsx","./src/tests/WalletBar.test.tsx","./src/tests/setup.ts","./src/types/index.ts","./src/utils/compliance.ts","./src/utils/qrcode.ts","./src/utils/soroban.ts","./src/utils/treasury.ts"],"version":"5.9.3"} \ No newline at end of file diff --git a/contracts/invoice/src/lib.rs b/contracts/invoice/src/lib.rs index 82be1e9..964f669 100644 --- a/contracts/invoice/src/lib.rs +++ b/contracts/invoice/src/lib.rs @@ -220,7 +220,7 @@ mod tests { fn setup() -> (Env, Address, Address) { let env = Env::default(); env.mock_all_auths(); - let contract_id = env.register(InvoiceContract, ()); + let contract_id = env.register_contract(None, InvoiceContract); let admin = Address::generate(&env); InvoiceContractClient::new(&env, &contract_id).initialize(&admin); env.ledger().set_timestamp(1000); diff --git a/contracts/settlement/src/lib.rs b/contracts/settlement/src/lib.rs index cc82c0e..63febaf 100644 --- a/contracts/settlement/src/lib.rs +++ b/contracts/settlement/src/lib.rs @@ -166,7 +166,7 @@ mod tests { fn setup() -> (Env, Address) { let e = Env::default(); e.mock_all_auths(); - let id = e.register(SettlementContract, ()); + let id = e.register_contract(None, SettlementContract); (e, id) } diff --git a/docs/MAINNET_DEPLOYMENT.md b/docs/MAINNET_DEPLOYMENT.md index 2f10760..ddcae11 100644 --- a/docs/MAINNET_DEPLOYMENT.md +++ b/docs/MAINNET_DEPLOYMENT.md @@ -55,7 +55,7 @@ upgrade, or modify mainnet contracts. ### Signer Roles | Role | Count | Responsibility | -|------|-------|----------------| +| ------ | ------- | ---------------- | | **Lead Deployer** | 1 | Prepares the deployment issue, builds release artifacts, submits the deployment transaction after all approvals are collected. Does NOT hold sole signing authority. | | **Security Reviewer** | 1–2 | Reviews the target commit for security vulnerabilities, verifies WASM hashes match the audited source, and signs off on the security checklist. | | **Treasury Signer** | 2+ | Holds custody of treasury signing keys. Must independently verify artifact hashes before co-signing the deployment transaction. | diff --git a/docs/abi-snapshot-workflow.md b/docs/abi-snapshot-workflow.md index e404395..9b5e8f1 100644 --- a/docs/abi-snapshot-workflow.md +++ b/docs/abi-snapshot-workflow.md @@ -68,7 +68,7 @@ git commit -m "chore: update ABI snapshots" The `comebackhere-backend` service reads `abis/*.json` at startup to build its Soroban contract clients. Stale snapshots cause: | Scenario | Downstream impact | -|---|---| +| --- | --- | | New function added to contract but missing from snapshot | Backend cannot call the new function; API endpoints that depend on it return errors | | Function signature changed but snapshot not updated | Backend sends malformed transactions; Soroban RPC rejects them with simulation failures | | Function removed from contract but still in snapshot | Backend attempts calls to a non-existent function; transactions fail at the ledger level | diff --git a/docs/api-reference.md b/docs/api-reference.md index 706cf88..c6d9295 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -27,7 +27,7 @@ Returns service health status. Fetch the on-chain status of an invoice by its numeric ID. -**Path parameters** +#### Path parameters | Parameter | Type | Description | | --------- | ------ | ----------------------- | @@ -42,7 +42,7 @@ Fetch the on-chain status of an invoice by its numeric ID. } ``` -**Errors** +#### Errors | Status | Description | | ------ | ---------------------------------------- | @@ -57,7 +57,7 @@ Fetch the on-chain status of an invoice by its numeric ID. Create a new invoice by submitting `create_invoice` to the Soroban RPC. -**Request body** +#### Request body ```json { @@ -84,7 +84,7 @@ Create a new invoice by submitting `create_invoice` to the Soroban RPC. } ``` -**Errors** +#### Errors | Status | Description | | ------ | -------------------------------------------------------------- | @@ -102,7 +102,7 @@ Create a new invoice by submitting `create_invoice` to the Soroban RPC. Raise a dispute linked to a settlement, transitioning it to `OnHold`. -**Request body** +#### Request body ```json { @@ -130,7 +130,7 @@ Raise a dispute linked to a settlement, transitioning it to `OnHold`. } ``` -**Errors** +#### Errors | Status | Description | | ------ | -------------------------------------------------------------- | @@ -162,7 +162,7 @@ Returns all settlements with `Pending` status from the indexed database. ] ``` -**Errors** +#### Errors | Status | Description | | ------ | ----------------------- | @@ -174,7 +174,7 @@ Returns all settlements with `Pending` status from the indexed database. Approve a pending settlement by submitting `approve_settlement` to the treasury contract. -**Request body** +#### Request body ```json { "settlement_id": 1 } @@ -199,7 +199,7 @@ Approve a pending settlement by submitting `approve_settlement` to the treasury } ``` -**Errors** +#### Errors | Status | Description | | ------ | ----------------------------------------------- | @@ -213,7 +213,7 @@ Approve a pending settlement by submitting `approve_settlement` to the treasury Execute a fully-approved settlement after verifying the treasury USDC balance. -**Request body** +#### Request body ```json { @@ -238,7 +238,7 @@ Execute a fully-approved settlement after verifying the treasury USDC balance. } ``` -**Errors** +#### Errors | Status | Description | | ------ | -------------------------------------------------- | @@ -260,7 +260,7 @@ Returns the current approval threshold from the treasury contract. { "threshold": 2 } ``` -**Errors** +#### Errors | Status | Description | | ------ | --------------------------------------- | @@ -274,7 +274,7 @@ Returns the current approval threshold from the treasury contract. Update the treasury approval threshold. -**Request body** +#### Request body ```json { "threshold": 3 } @@ -293,7 +293,7 @@ Update the treasury approval threshold. } ``` -**Errors** +#### Errors | Status | Description | | ------ | ----------------------------------------------- | @@ -316,7 +316,7 @@ Returns the current invoice grace window in seconds. { "grace_window_seconds": 86400 } ``` -**Errors** +#### Errors | Status | Description | | ------ | --------------------------------------- | @@ -330,7 +330,7 @@ Returns the current invoice grace window in seconds. Update the invoice grace window. -**Request body** +#### Request body ```json { "grace_window_seconds": 172800 } @@ -349,7 +349,7 @@ Update the invoice grace window. } ``` -**Errors** +#### Errors | Status | Description | | ------ | ----------------------------------------------- | diff --git a/docs/contract-interaction-guide.md b/docs/contract-interaction-guide.md index b19931b..42a5054 100644 --- a/docs/contract-interaction-guide.md +++ b/docs/contract-interaction-guide.md @@ -27,7 +27,7 @@ Placeholder values used throughout: ### Create an invoice -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -44,7 +44,7 @@ soroban contract invoke \ --nonce 1 ``` -**API** +#### API ```sh curl -X POST http://localhost:3000/invoices \ @@ -63,7 +63,7 @@ Response includes `invoice_id` to use in subsequent calls. ### Get invoice status -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -75,7 +75,7 @@ soroban contract invoke \ --invoice_id 1 ``` -**API** +#### API ```sh curl http://localhost:3000/invoices/1 @@ -85,7 +85,7 @@ curl http://localhost:3000/invoices/1 ### Mark invoice as paid -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -105,7 +105,7 @@ Calling `raise_dispute` on the invoice contract atomically calls `raise_dispute` on the treasury contract, placing the referenced settlement `OnHold`. -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -120,7 +120,7 @@ soroban contract invoke \ --reason 1 ``` -**API** +#### API ```sh curl -X POST http://localhost:3000/disputes \ @@ -153,7 +153,7 @@ soroban contract invoke \ ### Propose a settlement -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -174,7 +174,7 @@ Returns the `settlement_id`. ### Approve a settlement -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -187,7 +187,7 @@ soroban contract invoke \ --settlement_id 1 ``` -**API** +#### API ```sh curl -X POST http://localhost:3000/api/treasury/approve-settlement \ @@ -199,7 +199,7 @@ curl -X POST http://localhost:3000/api/treasury/approve-settlement \ ### Execute a settlement -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -213,7 +213,7 @@ soroban contract invoke \ --token_contract CUSDC... ``` -**API** +#### API The execute endpoint validates the treasury USDC balance before submitting. @@ -227,7 +227,7 @@ curl -X POST http://localhost:3000/api/treasury/execute-settlement \ ### Get / set approval threshold -**soroban-cli — read** +#### soroban-cli — read ```sh soroban contract invoke \ @@ -238,7 +238,7 @@ soroban contract invoke \ -- get_threshold ``` -**soroban-cli — update** +#### soroban-cli — update ```sh soroban contract invoke \ @@ -251,13 +251,13 @@ soroban contract invoke \ --new_threshold 3 ``` -**API — read** +#### API — read ```sh curl http://localhost:3000/api/treasury/threshold ``` -**API — update** +#### API — update ```sh curl -X POST http://localhost:3000/api/treasury/threshold \ @@ -271,7 +271,7 @@ curl -X POST http://localhost:3000/api/treasury/threshold \ ### Allow an address -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -288,7 +288,7 @@ soroban contract invoke \ ### Block an address -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -307,7 +307,7 @@ soroban contract invoke \ ### Read -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -318,7 +318,7 @@ soroban contract invoke \ -- get_grace_window ``` -**API** +#### API ```sh curl http://localhost:3000/api/invoice/grace-window @@ -326,7 +326,7 @@ curl http://localhost:3000/api/invoice/grace-window ### Update (admin only) -**soroban-cli** +#### soroban-cli ```sh soroban contract invoke \ @@ -339,7 +339,7 @@ soroban contract invoke \ --window 172800 ``` -**API** +#### API ```sh curl -X POST http://localhost:3000/api/invoice/grace-window \ diff --git a/docs/error-codes.md b/docs/error-codes.md index 8ccbeaf..ab4200c 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -11,7 +11,7 @@ This document maps every `InvoiceError` variant (and other contract error codes) Defined in `contracts/invoice/src/lib.rs` and `COMEBACKHERE-contracts/contracts/invoice/src/lib.rs`. | Code | Name | Trigger condition | Remediation | -|------|------|-------------------|-------------| +| ------ | ------ | ------------------- | ------------- | | 1 | `Unauthorized` | Caller is not the merchant, admin, or payer for the operation. | Ensure the signing key matches the expected role. Merchants must sign `create_invoice`; the admin must sign `mark_paid` / `release_escrow`; the payer must sign `request_refund`. | | 2 | `ContractPaused` | A state-changing call was made while the contract is in a paused state. | Check contract status before submitting. Contact the admin to unpause the contract. Do not retry until the contract is unpaused. | | 3 | `InvalidAmount` | `amount_usdc` ≤ 0, or `gross_usdc` < `amount_usdc`. | Verify that both amounts are positive and that `gross_usdc ≥ amount_usdc`. Amounts are denominated in USDC stroops (1 USDC = 10 000 000 stroops). | @@ -32,7 +32,7 @@ Defined in `contracts/invoice/src/lib.rs` and `COMEBACKHERE-contracts/contracts/ Defined in `contracts/settlement/src/lib.rs`. | Code | Name | Trigger condition | Remediation | -|------|------|-------------------|-------------| +| ------ | ------ | ------------------- | ------------- | | 1 | `NotFound` | No settlement exists for the supplied ID. | Confirm the settlement ID returned by `propose`. | | 2 | `Unauthorized` | Caller has no registered weight in the treasury signer set. | Use a key that was registered via `initialize` or a subsequent signer-rotation call. | | 3 | `AlreadyApproved` | The same signer attempted to approve the same settlement twice. | Each signer may approve a settlement only once. | @@ -58,7 +58,7 @@ Backend endpoints return errors as JSON: ## Quick-reference: HTTP status mapping | HTTP status | Typical contract code(s) | Meaning | -|-------------|--------------------------|---------| +| ------------- | -------------------------- | --------- | | 400 | — | Invalid request body (validation failed before hitting the contract). | | 403 | 1 (`Unauthorized`) | Caller is not authorised for the operation. | | 404 | 6 (`NotFound`), Settlement 1 | Resource does not exist. | diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index cb0aaf3..c72465e 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -23,7 +23,7 @@ docker compose logs soroban **Common causes and fixes:** | Symptom | Cause | Fix | -|---|---|---| +| --- | --- | --- | | `connection refused` on `localhost:8000` | Container not started | Run `docker compose up -d` or `make dev` | | Container starts then immediately exits | Corrupted volume data | `docker compose down -v && docker compose up -d` | | `health: starting` stays for more than 60 seconds | Slow initial ledger catch-up | Wait up to 90 seconds; the healthcheck has a 30-second `start_period` and retries every 5 seconds | diff --git a/scripts/generate_abi_metadata.sh b/scripts/generate_abi_metadata.sh index 4875065..f143ba9 100755 --- a/scripts/generate_abi_metadata.sh +++ b/scripts/generate_abi_metadata.sh @@ -1,12 +1,25 @@ #!/usr/bin/env bash # Regenerate committed ABI metadata under abis/ from contract sources. -# Contract sources live in the sibling COMEBACKHERE-contracts/ directory. +# Contract sources are searched in two locations (CI checkout and local sibling): +# 1. $ROOT_DIR/COMEBACKHERE-contracts (GitHub Actions checkout path) +# 2. $ROOT_DIR/../COMEBACKHERE-contracts (local sibling directory) set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -CONTRACTS_DIR="$(cd "$ROOT_DIR/../COMEBACKHERE-contracts" && pwd)" OUT_DIR="${1:-"$ROOT_DIR/abis"}" +if [ -d "$ROOT_DIR/COMEBACKHERE-contracts" ]; then + CONTRACTS_DIR="$ROOT_DIR/COMEBACKHERE-contracts" +elif [ -d "$ROOT_DIR/../COMEBACKHERE-contracts" ]; then + CONTRACTS_DIR="$(cd "$ROOT_DIR/../COMEBACKHERE-contracts" && pwd)" +else + echo "ERROR: COMEBACKHERE-contracts directory not found." >&2 + echo " Looked in: $ROOT_DIR/COMEBACKHERE-contracts" >&2 + echo " Looked in: $ROOT_DIR/../COMEBACKHERE-contracts" >&2 + echo " Clone it with: git clone https://github.com/WHEELBACK/COMEBACKHERE-contracts ../COMEBACKHERE-contracts" >&2 + exit 1 +fi + export LC_ALL=C export LANG=C diff --git a/tests/README.md b/tests/README.md index 1c9161f..78b274e 100644 --- a/tests/README.md +++ b/tests/README.md @@ -35,7 +35,7 @@ export USDC_CONTRACT_ID= ## Test Coverage | Test | Description | -|---|---| +| --- | --- | | Create invoice | Creates a valid invoice with minimum amount | | Pay invoice | Pays the invoice with USDC via the payer account | | Escrow release | Proposes, approves, and executes a treasury settlement |