+
Network fee
- Paid in XLM by your wallet
+
+ {fees ? `≈ ${formatXlm(fees.totalFee)} XLM` : prepareTransfer.isLoading ? "calculating…" : "Paid in XLM"} ·{" "}
+ {reserve.isLoading
+ ? "checking…"
+ : reserve.isError
+ ? "couldn't check XLM balance"
+ : reserve.data && !reserve.data.funded
+ ? "unfunded"
+ : reserve.data
+ ? `spendable ${formatXlm(reserve.data.spendable, { maxDecimals: 1 })} XLM`
+ : "spendable —"}
+
+
+ {/* Blocking warnings */}
+ {isConnected && isUnfunded && (
+
+ Fund this account with XLM first.
+
+ )}
+ {isConnected && isInsufficientXlm && xlmDeficit !== null && (
+
+ You need about {formatXlm(xlmDeficit)} more XLM to pay the network fee.
+
+ )}
+
Total Due
{selectedTier.priceStr}
-
- {statusMessage && (
+
+ {/* Live Tx phase */}
+ {transfer.isPending && (
+
+ )}
+
+ {/* Final or error status */}
+ {!transfer.isPending && statusMessage && (
{statusMessage}
@@ -384,9 +483,20 @@ export default function PremiumPage() {
- {isSubmitting ? "Processing..." : paymentMethod === 'usdc' ? "Pay with Wallet" : "Proceed to Payment"}
+ {isSubmitting || transfer.isPending
+ ? (transfer.phase.name === "awaiting-signature" ? "Signing…" : "Processing...")
+ : isUnfunded
+ ? "Fund Account"
+ : isInsufficientXlm
+ ? "Insufficient XLM"
+ : paymentMethod === 'usdc' ? "Pay with Wallet" : "Proceed to Payment"}
Verified on-chain by OracleDesk before access is granted
diff --git a/app/reasoning/verify/page.tsx b/app/reasoning/verify/page.tsx
index 53751fd..dcf5d1a 100644
--- a/app/reasoning/verify/page.tsx
+++ b/app/reasoning/verify/page.tsx
@@ -8,7 +8,7 @@ import { useQueryClient } from "@tanstack/react-query";
import { getTrace } from "@/lib/api/traces";
import { CONTRACTS, explorerAccount } from "@/lib/stellar/config";
import { reasoningRegistry } from "@/lib/stellar/clients";
-import { simulated } from "@/lib/hooks/useStellar";
+import { bytesToHex, read } from "@/lib/stellar/typed-call";
import { fetchAndVerifyTrace, ipfsUrl, type TraceCheck } from "@/lib/stellar/trace";
interface VerificationResult {
@@ -79,11 +79,11 @@ function VerifyTraceContent() {
// 2. Read the commitment from reasoning-registry.
log(`>> [CHAIN] reasoning_registry.get_trace(${onChainTraceId}) on ${CONTRACTS.reasoningRegistry.slice(0, 8)}…`, 30);
- const onChain = simulated<{ trace_hash: Uint8Array; ipfs_cid: string; market_id: bigint }>(
+ const onChain = read(
await reasoningRegistry().get_trace({ trace_id: BigInt(onChainTraceId as string) }),
"reasoningRegistry",
);
- const storedHash = Array.from(onChain.trace_hash, (b) => b.toString(16).padStart(2, "0")).join("");
+ const storedHash = bytesToHex(onChain.trace_hash);
log(`>> [CHAIN] On-chain hash: ${storedHash}`, 50);
log(`>> [IPFS] Fetching ${onChain.ipfs_cid}`, 60);
diff --git a/app/transaction-failed/page.tsx b/app/transaction-failed/page.tsx
index 155829b..10519b2 100644
--- a/app/transaction-failed/page.tsx
+++ b/app/transaction-failed/page.tsx
@@ -1,187 +1,5 @@
-"use client";
-
-import React, { useState, useEffect } from "react";
-import { DemoBadge } from "@/components/ui/demo-badge";
-import Link from "next/link";
+import { redirect } from "next/navigation";
export default function TransactionFailedPage() {
- const [isVisible, setIsVisible] = useState(true);
-
- const closeModal = () => {
- setIsVisible(false);
- };
-
- useEffect(() => {
- const handleKeyDown = (e: KeyboardEvent) => {
- if (e.key === "Escape") closeModal();
- };
- window.addEventListener("keydown", handleKeyDown);
- return () => window.removeEventListener("keydown", handleKeyDown);
- }, []);
-
- return (
-
- {/* Main Content Canvas (Blurred Background behind modal) */}
-
-
- {/* Institutional Grid Layout Mockup */}
-
-
-
-
Open Positions
-
- Live Feed
-
-
-
-
-
-
- Market
- Position
- Entry
- Probability
- Action
-
-
-
-
- BTC ETF Approval Q1
- YES
- $0.42
-
-
-
-
- Trade
-
-
-
- Fed Rate Cut - March
- NO
- $0.18
-
-
-
-
- Trade
-
-
-
-
-
-
-
-
- {/* AI Reasoning Sidebar Mockup */}
-
-
-
- psychology
-
Oracle Insights
-
-
- High-frequency volatility detected in the "Electoral Outcome" markets. Institutional liquidity flow suggests a 4.2% shift towards the 'No' outcome within the last 15 minutes.
-
-
-
-
Risk Warning
-
Liquidity depth for 'March Fed' is below standard thresholds for large orders.
-
-
-
-
-
-
- {/* Modal Overlay */}
- {isVisible && (
-
- {/* Fixed Backdrop - Blurs everything including global Navbar */}
-
-
- {/* Transaction Failed Modal */}
-
- {/* Modal Header */}
-
-
- error
-
-
Transaction Failed
-
Your trade could not be processed on the blockchain.
-
-
- {/* Modal Content (Error Details) */}
-
-
-
-
warning
-
-
Error Code: GAS_INSUFFICIENT_OR_SLIPPAGE
-
- Execution failed due to slippage exceeding 0.5% or too little XLM in your wallet to pay the network fee.
-
-
-
-
-
-
- Network fee (XLM)
- —
-
-
- Network Status
-
-
- Congested
-
-
-
-
-
- {/* Modal Footer */}
-
-
- refresh
- Retry Transaction
-
-
- Dismiss
-
-
-
-
- )}
-
- {/* Global Footer (Simplified for fail state) */}
-
-
- );
+ redirect("/tx");
}
diff --git a/app/transaction-status/page.tsx b/app/transaction-status/page.tsx
index 6ed467e..31578f3 100644
--- a/app/transaction-status/page.tsx
+++ b/app/transaction-status/page.tsx
@@ -1,201 +1,5 @@
-"use client";
-
-import React, { useState, useEffect } from "react";
-import Link from "next/link";
+import { redirect } from "next/navigation";
export default function TransactionStatusPage() {
- const [step, setStep] = useState(1);
- const [isVisible, setIsVisible] = useState(true);
-
- const simulateNextStep = () => {
- if (step === 1) {
- setStep(2);
- } else {
- closeModal();
- }
- };
-
- const closeModal = () => {
- setIsVisible(false);
- };
-
- useEffect(() => {
- const handleKeyDown = (e: KeyboardEvent) => {
- if (e.key === "Escape") closeModal();
- };
- window.addEventListener("keydown", handleKeyDown);
- return () => window.removeEventListener("keydown", handleKeyDown);
- }, []);
-
- return (
-
-
-
- {/* Main Content Canvas (Background behind modal) */}
-
-
-
-
Account Overview
-
-
-
-
-
-
-
-
-
Active Positions
-
-
-
-
-
-
- {/* Modal Overlay */}
- {isVisible && (
-
- {/* Fixed Backdrop - Blurs everything including the global Navbar (z-50) */}
-
-
-
- {/* Modal Header */}
-
-
- {step === 1 ? "Confirm Transaction" : "Transaction Submitted"}
-
-
- close
-
-
-
- {/* Modal Content Body */}
-
- {step === 1 ? (
- /* Step 1: Confirm in Wallet */
-
-
-
-
-
-
- account_balance_wallet
-
-
-
Confirm in Wallet
-
Please check your wallet extension to authorize this trade on the Oracle Network.
-
- ) : (
- /* Step 2: Transaction Submitted */
-
-
- check_circle
-
-
Transaction Submitted
-
Your trade has been broadcast to the network. Processing times may vary.
-
- {/* Info Card */}
-
-
-
Status
-
-
- Broadcasting
-
-
-
-
TX Hash
-
- 0x72a...83d2
- content_copy
-
-
-
-
- View on Explorer
-
open_in_new
-
-
- )}
-
-
- {/* Modal Footer */}
-
- {step === 1 && (
-
- Cancel
-
- )}
-
- {step === 1 ? "Simulate Wallet Confirm" : "Return to Market"}
-
-
-
-
- )}
-
- {/* Terminal Log (Fixed Bottom Right) */}
-
-
-
- ORACLE_SYSTEM_LOGS
- v2.4.1
-
-
[14:22:10] Connection established: RPC_NODE_04
-
[14:22:11] Market: "BTC_PROB_75K_EOY" price feed synced
-
[14:23:45] Pending Transaction Detected: User_ID:0x...a1
-
_
-
-
-
- );
+ redirect("/tx");
}
diff --git a/app/transaction-success/page.tsx b/app/transaction-success/page.tsx
index 7dcc828..11cdbb9 100644
--- a/app/transaction-success/page.tsx
+++ b/app/transaction-success/page.tsx
@@ -1,161 +1,5 @@
-"use client";
-
-import React, { useState, useEffect } from "react";
-import { DemoBadge } from "@/components/ui/demo-badge";
-import Link from "next/link";
+import { redirect } from "next/navigation";
export default function TransactionSuccessPage() {
- const [isVisible, setIsVisible] = useState(true);
-
- const closeModal = () => {
- setIsVisible(false);
- };
-
- useEffect(() => {
- const handleKeyDown = (e: KeyboardEvent) => {
- if (e.key === "Escape") closeModal();
- };
- window.addEventListener("keydown", handleKeyDown);
- return () => window.removeEventListener("keydown", handleKeyDown);
- }, []);
-
- return (
-
-
-
- {/* Main Content Canvas (Blurred Background behind modal) */}
-
- {/* Mock Portfolio Content */}
-
-
-
Portfolio Performance
-
-
-
-
-
-
- {/* Modal Overlay */}
- {isVisible && (
-
- {/* Backdrop - Blurs global Navbar (z-50) and background content */}
-
-
- {/* Transaction Success Modal */}
-
- {/* Header/Icon Section */}
-
-
- check_circle
-
-
Transaction Successful
-
Your trade has been executed and confirmed on the blockchain.
-
-
- {/* Trade Summary Card */}
-
-
-
- MARKET
- US Presidential Election 2029
-
-
-
-
- CONTRACTS
- 1,250 Shares
-
-
- AVG. PRICE
- $0.62
-
-
- TOTAL COST
- $775.00 USDC
-
-
-
-
- {/* TX Hash & Details */}
-
-
-
Transaction Hash
-
- 0x8a2b...f91c
- open_in_new
-
-
-
- Network Fee
- —
-
-
- Execution Time
- 1.8s
-
-
-
- {/* Actions */}
-
-
- View Portfolio
-
-
- share
- Share Trade
-
-
-
-
- {/* Footer Meta */}
-
- verified
- Secured by OracleDesk Settlement Layer
-
-
-
- )}
-
- {/* Background Decoration (AI Reasoning Card Style) */}
-
-
- auto_awesome
- Oracle Insight
-
-
- "Whale accumulation detected in the YES direction over the last 4h. Sentiment remains bullish."
-
-
-
- );
+ redirect("/tx");
}
diff --git a/app/tx/page.tsx b/app/tx/page.tsx
new file mode 100644
index 0000000..8875fcc
--- /dev/null
+++ b/app/tx/page.tsx
@@ -0,0 +1,346 @@
+"use client";
+
+import React, { Suspense, useState } from "react";
+import Link from "next/link";
+import { useSearchParams } from "next/navigation";
+import { useQuery } from "@tanstack/react-query";
+import { scValToNative } from "@stellar/stellar-sdk";
+import { rpcServer } from "@/lib/stellar/clients";
+import { explorerTx } from "@/lib/stellar/config";
+import { formatXlm } from "@/lib/stellar/units";
+import { describeError } from "@/lib/stellar/errors";
+
+export default function TxPage() {
+ return (
+
+
+
+ }
+ >
+
+
+ );
+}
+
+function TxContent() {
+ const searchParams = useSearchParams();
+ const rawHash = searchParams.get("hash")?.trim() ?? "";
+ const isValidHex64 = /^[0-9a-fA-F]{64}$/.test(rawHash);
+ const hash = isValidHex64 ? rawHash.toLowerCase() : null;
+
+ const [copied, setCopied] = useState(false);
+
+ const { data, isLoading, isError, error, refetch, isFetching } = useQuery({
+ queryKey: ["stellar", "tx", hash],
+ enabled: Boolean(hash),
+ queryFn: async () => {
+ if (!hash) return null;
+ return await rpcServer().getTransaction(hash);
+ },
+ refetchInterval: (query) => {
+ // Keep polling if transaction is still pending or not yet found
+ if (query.state.data?.status === "NOT_FOUND") {
+ return 2000;
+ }
+ return false;
+ },
+ staleTime: 10_000,
+ });
+
+ const handleCopy = () => {
+ if (!hash) return;
+ void navigator.clipboard.writeText(hash);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ };
+
+ if (!rawHash || !isValidHex64) {
+ return (
+
+
+
+ error
+
+
+
Invalid Transaction Hash
+
+ {rawHash
+ ? "The transaction hash provided is not a valid 64-character hex string."
+ : "No transaction hash was provided in the query string."}
+
+
+
+ Back to Markets
+
+
+
+ );
+ }
+
+ if (isLoading) {
+ return (
+
+
+
+
Fetching Transaction
+
{hash}
+
+
+ );
+ }
+
+ if (isError || !data) {
+ return (
+
+
+
+ cloud_off
+
+
+
RPC Query Failed
+
+ {error instanceof Error ? error.message : "Unable to reach the Stellar RPC server."}
+
+
+
+
void refetch()}
+ className="bg-primary text-primary-foreground px-5 py-2.5 rounded-xl font-label-caps text-label-caps font-bold hover:brightness-110 transition-all"
+ >
+ Retry Query
+
+
+ View on Explorer
+
+
+
+
+ );
+ }
+
+ const isNotFound = data.status === "NOT_FOUND";
+ const isSuccess = data.status === "SUCCESS";
+ const isFailed = data.status === "FAILED";
+
+ const settledData = isSuccess || isFailed ? data : null;
+ const ledger = settledData?.ledger ?? null;
+ const applicationOrder = settledData?.applicationOrder ?? null;
+
+ // Parse result value or failure error
+ let parsedResult: string | null = null;
+ if (isSuccess && data.returnValue) {
+ try {
+ const native = scValToNative(data.returnValue);
+ parsedResult = typeof native === "bigint" ? native.toString() : JSON.stringify(native);
+ } catch {
+ parsedResult = null;
+ }
+ }
+
+ let failureDescription: string | null = null;
+ if (isFailed && data.resultXdr) {
+ try {
+ failureDescription = describeError(data.resultXdr, "marketCore").message;
+ } catch {
+ failureDescription = "Transaction execution reverted on-chain.";
+ }
+ }
+
+ const feeCharged = settledData ? formatXlm(BigInt(settledData.resultXdr.feeCharged().toString())) : null;
+
+ return (
+
+
+ {/* Breadcrumb Navigation */}
+
+
+ Markets
+
+ /
+ Transaction
+
+
+ {/* Main Details Card */}
+
+ {/* Card Header */}
+
+
+
+
+ {isSuccess ? "check_circle" : isFailed ? "cancel" : "hourglass_top"}
+
+
+
+
+ {isSuccess
+ ? "Transaction Confirmed"
+ : isFailed
+ ? "Transaction Failed"
+ : "Pending / Expired from RPC"}
+
+
+ {isSuccess
+ ? `Settled on Stellar ledger #${ledger}`
+ : isFailed
+ ? `Failed on ledger #${ledger ?? "unknown"}`
+ : "Not retained in recent RPC ledgers or still propagating"}
+
+
+
+
+ {/* Live refresh indicator */}
+ {isFetching && (
+
+ sync Syncing
+
+ )}
+
+
+ {/* Details Body */}
+
+ {/* Hash Row */}
+
+
+ Transaction Hash
+
+
+ {hash}
+
+
+ {copied ? "check" : "content_copy"}
+
+
+
+
+
+ {/* NOT_FOUND State Notice */}
+ {isNotFound && (
+
+
Why is this transaction not found?
+
+ Stellar RPC nodes only retain transactions for a limited window of recent ledgers (~100 to 200 ledgers).
+ If this transaction was submitted earlier, it has been committed to the ledger history and can be viewed directly
+ on Stellar Expert block explorer.
+
+
+ )}
+
+ {/* Error Message for Failed Tx */}
+ {isFailed && failureDescription && (
+
+
Error Reason:
+
{failureDescription}
+
+ )}
+
+ {/* On-Chain Metrics Grid */}
+
+
+
+ Status
+
+
+ {data.status}
+
+
+
+
+
+ Ledger
+
+
+ {ledger ?? "—"}
+
+
+
+
+
+ Fee Charged
+
+
+ {feeCharged ? `${feeCharged} XLM` : "—"}
+
+
+
+
+
+ Application Order
+
+
+ {applicationOrder ?? "—"}
+
+
+
+
+ {/* Return Value / Result Output */}
+ {parsedResult !== null && (
+
+
+ Decoded Return Value
+
+
+ {parsedResult}
+
+
+ )}
+
+
+ {/* Action Footer */}
+
+
+
+
+ );
+}
diff --git a/components/layout/WalletDropdown.tsx b/components/layout/WalletDropdown.tsx
index cb4339f..2f6debd 100644
--- a/components/layout/WalletDropdown.tsx
+++ b/components/layout/WalletDropdown.tsx
@@ -4,13 +4,25 @@ import React, { useState, useRef, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { useWallet } from "@/lib/contexts/WalletContext";
import { useUsdcBalance } from "@/lib/hooks/useStellar";
-import { NETWORK_LABEL, explorerAccount } from "@/lib/stellar/config";
+import { EXPERIMENTAL_PASSKEYS, NETWORK_LABEL, explorerAccount } from "@/lib/stellar/config";
import { formatUsdc, shortAddress } from "@/lib/stellar/units";
const WalletDropdown = () => {
- const { address, isConnected, isConnecting, isWrongNetwork, openModal, disconnect, error } = useWallet();
+ const {
+ address,
+ isConnected,
+ isConnecting,
+ isWrongNetwork,
+ isPasskey,
+ openModal,
+ connectPasskey,
+ createPasskey,
+ disconnect,
+ error,
+ } = useWallet();
const [isOpen, setIsOpen] = useState(false);
const [copied, setCopied] = useState(false);
+ const [showPasskeyPrompt, setShowPasskeyPrompt] = useState(false);
const dropdownRef = useRef
(null);
const balance = useUsdcBalance(address);
@@ -19,6 +31,7 @@ const WalletDropdown = () => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setIsOpen(false);
+ setShowPasskeyPrompt(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
@@ -27,14 +40,66 @@ const WalletDropdown = () => {
if (!isConnected || !address) {
return (
- openModal()}
- disabled={isConnecting}
- title={error ?? undefined}
- className="bg-primary text-primary-foreground px-4 py-2 rounded-lg font-label-caps text-label-caps uppercase tracking-wider hover:opacity-90 transition-all active:scale-95 disabled:opacity-60"
- >
- {isConnecting ? "Connecting…" : "Connect Wallet"}
-
+
+
openModal()}
+ disabled={isConnecting}
+ title={error ?? undefined}
+ className="bg-primary text-primary-foreground px-4 py-2 rounded-lg font-label-caps text-label-caps uppercase tracking-wider hover:opacity-90 transition-all active:scale-95 disabled:opacity-60"
+ >
+ {isConnecting ? "Connecting…" : "Connect Wallet"}
+
+
+ {EXPERIMENTAL_PASSKEYS && connectPasskey && (
+
+
setShowPasskeyPrompt(!showPasskeyPrompt)}
+ disabled={isConnecting}
+ title="Sign in with Face ID or a passkey smart wallet"
+ className="flex items-center gap-1.5 bg-surface-container-low border border-outline-variant hover:bg-surface-container text-on-surface px-3 py-2 rounded-lg font-label-caps text-label-caps tracking-wider transition-all active:scale-95"
+ >
+ key
+ Passkey
+ Exp
+
+
+
+ {showPasskeyPrompt && (
+
+ {
+ setShowPasskeyPrompt(false);
+ void connectPasskey();
+ }}
+ className="w-full text-left px-3 py-2 text-xs font-bold hover:bg-surface-container rounded-lg transition-colors flex items-center justify-between"
+ >
+ Connect existing
+ login
+
+ {createPasskey && (
+ {
+ setShowPasskeyPrompt(false);
+ const name = window.prompt("Enter a name for your passkey smart-wallet:", "My Passkey Wallet");
+ if (name) void createPasskey({ name });
+ }}
+ className="w-full text-left px-3 py-2 text-xs font-bold text-primary hover:bg-surface-container rounded-lg transition-colors flex items-center justify-between"
+ >
+ Create new wallet
+ add_circle
+
+ )}
+
+ )}
+
+
+ )}
+
);
}
@@ -63,15 +128,22 @@ const WalletDropdown = () => {
className="flex items-center gap-3 px-3 py-1.5 bg-surface-container-low border border-outline-variant rounded-lg hover:bg-surface-container transition-colors active:scale-95"
>
-
- {isWrongNetwork ? "Wrong network" : NETWORK_LABEL}
-
+
+ {isPasskey && (
+
+ Experimental
+
+ )}
+
+ {isWrongNetwork ? "Wrong network" : isPasskey ? "Smart Wallet" : NETWORK_LABEL}
+
+
{truncatedAddress}
- account_balance_wallet
+ {isPasskey ? "key" : "account_balance_wallet"}
expand_more
@@ -90,9 +162,16 @@ const WalletDropdown = () => {
>
{/* Balance Section */}
-
- Available Balance
-
+
+
+ Available Balance
+
+ {isPasskey && (
+
+ Passkey
+
+ )}
+
{balanceText}
@@ -133,7 +212,9 @@ const WalletDropdown = () => {
View on Stellar Expert
- Account history
+
+ {isPasskey ? "Contract history" : "Wallet history"}
+
diff --git a/components/ui/tx-toast.tsx b/components/ui/tx-toast.tsx
new file mode 100644
index 0000000..9ab84fa
--- /dev/null
+++ b/components/ui/tx-toast.tsx
@@ -0,0 +1,189 @@
+"use client";
+
+import React, { useState, useEffect } from "react";
+import Link from "next/link";
+import { useWallet } from "@/lib/contexts/WalletContext";
+import { explorerTx } from "@/lib/stellar/config";
+import { formatUsdc } from "@/lib/stellar/units";
+import { useTxTracker, type TrackedTx } from "@/lib/stellar/tx-tracker";
+import { unlockDailyPass } from "@/lib/api/traces";
+
+export function TxToastContainer() {
+ const { list, dismiss } = useTxTracker();
+ const { address } = useWallet();
+ const [showAll, setShowAll] = useState(false);
+ const [isOpen, setIsOpen] = useState(true);
+ const [unlockingHash, setUnlockingHash] = useState
(null);
+ const [unlockSuccess, setUnlockSuccess] = useState>({});
+ const [unlockError, setUnlockError] = useState>({});
+
+ useEffect(() => {
+ function handleKeyDown(e: KeyboardEvent) {
+ if (e.key === "Escape") {
+ setIsOpen(false);
+ }
+ }
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, []);
+
+ const visibleList = list.filter((tx) => (showAll || !address ? true : tx.holder === address));
+
+ if (!isOpen || visibleList.length === 0) return null;
+
+ const handleUnlock = async (tx: TrackedTx) => {
+ if (!tx.followUp || tx.followUp.type !== "unlock-daily-pass") return;
+ setUnlockingHash(tx.hash);
+ setUnlockError((prev) => ({ ...prev, [tx.hash]: "" }));
+ try {
+ await unlockDailyPass(tx.followUp.traceId, tx.hash, tx.followUp.amountRaw);
+ setUnlockSuccess((prev) => ({ ...prev, [tx.hash]: true }));
+ } catch (err: unknown) {
+ setUnlockError((prev) => ({
+ ...prev,
+ [tx.hash]: err instanceof Error ? err.message : "Failed to activate pass",
+ }));
+ } finally {
+ setUnlockingHash(null);
+ }
+ };
+
+ return (
+
+
+
+ Transactions ({visibleList.length})
+
+
+ {address && (
+ setShowAll((prev) => !prev)}
+ className="text-[10px] text-primary hover:underline font-semibold"
+ >
+ {showAll ? "My txs only" : "Show all"}
+
+ )}
+ setIsOpen(false)}
+ aria-label="Close transactions drawer"
+ className="text-on-surface-variant hover:text-on-surface text-sm p-0.5"
+ >
+ ✕
+
+
+
+
+
+ {visibleList.map((tx) => {
+ const amountRaw =
+ tx.amounts.collateralIn ?? tx.amounts.amount ?? tx.amounts.collateralOut ?? tx.amounts.shares ?? "0";
+ let formattedAmount = "";
+ try {
+ formattedAmount = formatUsdc(BigInt(amountRaw), { grouping: true });
+ } catch {
+ formattedAmount = amountRaw;
+ }
+
+ const stateColor =
+ tx.state === "confirmed"
+ ? "text-emerald-600 bg-emerald-500/10 border-emerald-500/20"
+ : tx.state === "failed"
+ ? "text-rose-600 bg-rose-500/10 border-rose-500/20"
+ : tx.state === "expired"
+ ? "text-amber-600 bg-amber-500/10 border-amber-500/20"
+ : "text-primary bg-primary/10 border-primary/20";
+
+ return (
+
+
+
+ {tx.kind.replace("-", " ")}
+ {tx.marketId && #{tx.marketId} }
+ {tx.outcome && ({tx.outcome}) }
+
+
dismiss(tx.hash)}
+ aria-label="Dismiss transaction"
+ className="text-on-surface-variant hover:text-on-surface p-0.5 text-xs"
+ >
+ ✕
+
+
+
+
+ Amount: {formattedAmount} USDC
+
+ {tx.state === "pending" && (
+
+ )}
+ {tx.state}
+
+
+
+ {tx.error && (
+
+ {tx.error.message}
+
+ )}
+
+ {tx.mayNotHaveBeenSent && (
+
+ May not have been broadcast before deadline.
+
+ )}
+
+ {tx.followUp?.type === "unlock-daily-pass" && tx.state === "confirmed" && (
+
+ {unlockSuccess[tx.hash] ? (
+ Pass activated!
+ ) : (
+ <>
+
+ Payment confirmed. Finish activating your pass:
+
+ handleUnlock(tx)}
+ disabled={unlockingHash === tx.hash}
+ className="bg-primary text-primary-foreground font-semibold px-2.5 py-1 rounded-md text-[11px] hover:opacity-90 transition-opacity flex items-center justify-center gap-1 w-full"
+ >
+ {unlockingHash === tx.hash ? "Activating…" : "Activate Pass"}
+
+ {unlockError[tx.hash] && (
+ {unlockError[tx.hash]}
+ )}
+ >
+ )}
+
+ )}
+
+
+
+ );
+ })}
+
+
+ );
+}
diff --git a/docs/api.md b/docs/api.md
index 70c9b5b..d6a9a3c 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -150,6 +150,45 @@ address mismatch).
Multisig accounts: only a signature from `address`'s own key is accepted.
Threshold-based SEP-10 verification is a backlog item.
+#### Proposed: Contract-account (passkey) authentication (SEP-45 style)
+
+Smart-wallet contract accounts (`C…`) cannot sign classical ed25519 transaction envelopes. A SEP-45 style Soroban authorization verification flow is proposed:
+
+##### `POST /auth/challenge` (with contract address)
+
+Request:
+```json
+{ "address": "CABC…" }
+```
+
+Response `200`:
+```json
+{
+ "entryXdr": "",
+ "validUntilLedger": 1234567,
+ "networkPassphrase": "Test SDF Network ; September 2015"
+}
+```
+
+The challenge constructs an auth entry requiring `address`'s authorization for a dedicated verification invocation with a random nonce.
+
+##### `POST /auth/verify` (contract account verification)
+
+Request:
+```json
+{
+ "address": "CABC…",
+ "signed": ""
+}
+```
+
+The server verifies the entry by simulating the invocation on Soroban with the signed authorization entry, invoking the contract's `__check_auth` logic. Upon successful simulation, a standard 7-day JWT session is issued.
+
+Response `200`:
+```json
+{ "token": "", "userId": "", "walletAddress": "CABC…" }
+```
+
### Markets
#### Market object
diff --git a/docs/architecture.md b/docs/architecture.md
index e3c4e85..5bd2725 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -19,7 +19,20 @@ A backend market links to the chain through `onChainMarketId` (market-core's `u6
- The kit is imported dynamically in an effect, because it reads `localStorage` when its module loads.
- A session the kit persisted is restored without prompting and without redirecting. Only a connect completed in the modal redirects to `/markets`.
- After connecting, the wallet signs the backend's SEP-10 style challenge transaction (`signTransaction`, which every Stellar wallet supports; `signMessage` is not universal). The backend returns a JWT. A stored session for a different address is cleared, never reused.
-- `useWallet()` exposes `address`, `isWrongNetwork`, a `signer` for the binding clients, `openModal`, `ensureSession` and `disconnect`.
+- `useWallet()` exposes `address`, `isWrongNetwork`, `isPasskey`, a `signer` for the binding clients, `openModal`, `connectPasskey`, `createPasskey`, `ensureSession` and `disconnect`.
+
+## Passkey smart wallets (contract accounts)
+
+Passkey smart wallets (`C…`) are contract accounts whose `__check_auth` verifies secp256r1 ECDSA signatures created via WebAuthn.
+
+- **Feature flag**: Experimental passkey support is gated behind `NEXT_PUBLIC_EXPERIMENTAL_PASSKEYS=true` and badged "Experimental" in the UI.
+- **Signer abstraction**: `Signer` (`lib/stellar/clients.ts`) supports both `account` (ed25519 `G…`) and `contract` (`C…`) variants. For contract signers, binding client simulation uses `NEXT_PUBLIC_PASSKEY_RELAYER_SOURCE` as the source account.
+- **Auth entry signing & submit**: `submitAsContract` (`lib/stellar/contract-submit.ts`) verifies that simulation requires authorization exclusively from the trader's `C…` contract address, signs the auth entries with WebAuthn, re-simulates for accurate footprint/resources, and forwards the transaction to a fee-paying relayer.
+- **RP ID constraints**: WebAuthn requires the Relying Party ID (`rpId`) to match the active origin's domain or a registrable suffix of `window.location.hostname`. Ports and scheme must be omitted.
+- **Relayer interface**: A relayer service provides two endpoints:
+ - `POST /wallet/deploy`: Deploys the smart wallet contract with the passkey's uncompressed P-256 public key.
+ - `POST /tx/submit`: Signs as source/fee payer, submits to the Stellar network, and returns `{ hash }`.
+- **Signature normalisation**: Soroban's secp256r1 verification enforces canonical low-S (`s <= N/2`). WebAuthn DER signatures are converted to 64-byte raw `r || s` and normalised (`s' = N - s` if `s > N/2`).
## Contract calls
@@ -27,7 +40,29 @@ A backend market links to the chain through `onChainMarketId` (market-core's `u6
- Reads are simulations (no fee, no signature).
- Writes (`useBuy`, `useSell`, `useRedeem`, `useUsdcTransfer`) check that a wallet is connected and on the right network, simulate, then `signAndSend`.
- `useBuy` quotes again immediately before building the transaction and sets `min_shares_out = minOut(quote, slippageBps)`, so slippage is enforced on-chain.
-- `useSell` turns "sell N shares" into the exact `collateral_out` the contract needs, using the contract's own FPMM math (`generated/fpmm.ts`) on freshly read reserves, with `max_shares_in` slightly above N (see the contracts repo's `docs/frontend-integration.md`).
+## Write path and transaction lifecycle
+
+Every state-changing write (`useBuy`, `useSell`, `useRedeem`, `useUsdcTransfer`) follows an explicit, observable lifecycle governed by `TxLifecycle` in `lib/stellar/tx-lifecycle.ts`:
+
+1. **Fee Preview & Simulation**: Before signing, `usePrepareBuy` and `usePrepareUsdcTransfer` simulate the transaction. `lib/stellar/fees.ts` calculates `feeBreakdown` (inclusion fee, resource fee, and Soroban resource footprint) and computes `spendableXlm` from the account ledger entry following CAP-33 rules (`minBalance = (2 + numSubEntries + numSponsoring - numSponsored) * baseReserve`). If spendable XLM is below the estimated total fee, the UI disables submission with an exact deficit warning.
+2. **Observable Lifecycle Phases**: `useTxRunner` drives the transaction through typed phases:
+ - `building` → `simulating` → `awaiting-signature` → `submitting` (hash available) → `pending` (polling with backoff) → `confirmed` | `failed` | `expired`.
+ - Expiration is determined from `latestLedgerCloseTime` reported by Stellar RPC, not the browser clock.
+ - Statuses and errors (`PENDING`, `DUPLICATE`, `TRY_AGAIN_LATER`, `ERROR`, `txBadSeq`, `op_low_reserve`, etc.) are mapped cleanly to `TxDescribedError`.
+3. **Session Transaction Tracker (`lib/stellar/tx-tracker.tsx`)**:
+ - `TransactionTrackerProvider` mounted in `WalletProvider` captures every submitted transaction as soon as the hash is known.
+ - Transactions are serialized to `sessionStorage` (`oracledesk_pending_txs`) with BigInt amounts as strings, resuming polling on page reload.
+ - Polling across multiple browser tabs is coordinated with `BroadcastChannel("oracledesk-tx")` to ensure only one tab polls the RPC server.
+ - Upon confirmation, `tradeInvalidationKeys` performs React Query cache invalidations across market, positions, and balance queries even if the initiating component unmounted.
+ - The ` ` component (`components/ui/tx-toast.tsx`) renders accessible toasts announcing state transitions and supports resuming premium daily pass activation follow-ups.
+
+## Reading contract results
+
+Contract calls must always be consumed through `read(tx, contract)` for reads/simulations or `submit(tx, contract)` for signed writes (`lib/stellar/typed-call.ts`).
+
+- **No manual generics or casts**: `read` and `submit` automatically infer and unwrap the return type directly from the contract binding signature (`Result` is unwrapped to `T`, while non-Result values like `Position` or SAC balances remain untouched). Never pass a type parameter (e.g. `read(...)`) or hand-write contract result shapes. An ESLint rule enforces this across `app/` and `lib/`.
+- **Result detection**: Soroban `Result`s are detected using the SDK's `Ok` and `Err` classes (`instanceof`), avoiding duck-typing bugs where plain objects with `isOk` could be mistakenly unwrapped. Unhandled contract errors or simulation failures are mapped to user-friendly messages via `UserFacingError`.
+- **Type tests**: `lib/stellar/__tests__/typed-call.test-d.ts` pins the return type of every binding method and argument shape of every write the app calls. When adding or calling a new contract binding method, always add a corresponding type test so upstream contract changes fail during `npm test`.
## Amounts
diff --git a/docs/manual-test.md b/docs/manual-test.md
index 49c53ea..9440e42 100644
--- a/docs/manual-test.md
+++ b/docs/manual-test.md
@@ -96,8 +96,18 @@ To try the same on market 0 (resolved): the buy button is disabled and the panel
- [ ] Wallet menu → Disconnect. The button returns to **Connect Wallet**, and `oracledesk_token` is gone from Local Storage.
+## 11. Low XLM and reserve check (fee preview)
+
+- [ ] On testnet, connect with an account that has only ~1.5 XLM and a USDC trustline (or an account unfunded by Friendbot).
+- [ ] Open `http://localhost:3000/markets/quick-view?onChainId=`.
+- [ ] Observe the fee preview line under the quote: `Network fee ≈ X XLM · spendable Y XLM` (hover for the inclusion + resource fee breakdown and network base reserve note).
+- [ ] If unfunded: verify the message "Fund this account with XLM first." is displayed and the Buy button is disabled.
+- [ ] If spendable XLM is below the total fee: verify the message "You need about X more XLM to pay the network fee." is displayed and the Buy button is disabled.
+- [ ] Verify the same fee preview, spendable XLM display, and blocking warnings appear on `/copy-trade` (next to slippage text) and `/premium` (in the checkout modal above the pay button).
+
## Also worth clicking
- [ ] `/premium` → **Get a daily pass** → **Pay with wallet**. Freighter shows a USDC `transfer` to the treasury (`CBTFA3EP…`) for 0.50 USDC. After approval the backend verifies it on-chain and says the pass is active. Note: until `PAYMENTS_RECIPIENT` is decided, this payment becomes treasury trading capital (see docs/STATUS.md).
- [ ] `/copy-trade?marketId=&traceId=`: the side comes from the trace's edge. With no trace or zero edge the confirm button is disabled and the page explains why.
- [ ] `/admin` with an address not in `NEXT_PUBLIC_ADMIN_ADDRESSES` shows "Access Denied".
+- [ ] `/tx?hash=<64-hex>` inspects live ledger state and fee charged for any testnet transaction, falling back cleanly to Stellar Expert when outside RPC retention.
diff --git a/e2e/localnet/passkey.e2e.test.ts b/e2e/localnet/passkey.e2e.test.ts
new file mode 100644
index 0000000..98f6f89
--- /dev/null
+++ b/e2e/localnet/passkey.e2e.test.ts
@@ -0,0 +1,145 @@
+/**
+ * Localnet end-to-end integration test for passkey smart-wallet (contract account) traders.
+ *
+ * Simulates a passkey trader using Node's crypto.subtle ECDSA P-256 key pair standing in for
+ * WebAuthn, signing Soroban authorization entries, and submitting via a local fee-paying relayer.
+ *
+ * To run against a running stellar/quickstart local container:
+ * LOCALNET=true npm run e2e:localnet
+ */
+import { describe, expect, it } from "vitest";
+import { Buffer } from "buffer";
+import {
+ Address,
+ Keypair,
+ nativeToScVal,
+ xdr,
+} from "@stellar/stellar-sdk";
+import {
+ buildPasskeySignatureScVal,
+ derToRawSignature,
+ computeAuthPayloadHash,
+} from "@/lib/stellar/passkey";
+import { submitAsContract } from "@/lib/stellar/contract-submit";
+import type { Signer } from "@/lib/stellar/clients";
+import { Ok, type AssembledTransaction, type Result } from "@stellar/stellar-sdk/contract";
+
+const IS_LOCALNET = Boolean(process.env.LOCALNET);
+
+describe("Localnet passkey smart-wallet integration", () => {
+ it("generates software P-256 key standing in for WebAuthn and signs auth entry", async () => {
+ // 1. Generate P-256 key pair with WebCrypto (same curve as WebAuthn)
+ const keyPair = await crypto.subtle.generateKey(
+ { name: "ECDSA", namedCurve: "P-256" },
+ true,
+ ["sign", "verify"],
+ );
+
+ // 2. Export public key as raw uncompressed point (0x04 || x || y)
+ const rawPublicKey = new Uint8Array(await crypto.subtle.exportKey("raw", keyPair.publicKey));
+ expect(rawPublicKey.length).toBe(65);
+ expect(rawPublicKey[0]).toBe(0x04);
+
+ // 3. Construct a fixture Soroban authorization entry for a contract address
+ const contractAddress = "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM";
+ const scAddress = new Address(contractAddress).toScAddress();
+
+ const entry = new xdr.SorobanAuthorizationEntry({
+ credentials: xdr.SorobanCredentials.sorobanCredentialsAddress(
+ new xdr.SorobanAddressCredentials({
+ address: scAddress,
+ nonce: new xdr.Int64([0, 42]),
+ signatureExpirationLedger: 1000,
+ signature: xdr.ScVal.scvVoid(),
+ }),
+ ),
+ rootInvocation: new xdr.SorobanAuthorizedInvocation({
+ function: xdr.SorobanAuthorizedFunction.sorobanAuthorizedFunctionTypeContractFn(
+ new xdr.SorobanAuthorizedContractFunction({
+ contractAddress: scAddress,
+ functionName: "buy",
+ args: [nativeToScVal(100n, { type: "i128" })],
+ }),
+ ),
+ subInvocations: [],
+ }),
+ });
+
+ // 4. Compute auth payload hash
+ const validUntilLedger = 1060;
+ const payloadHash = computeAuthPayloadHash(entry, validUntilLedger);
+
+ // 5. Sign the payload hash using ECDSA P-256 with SHA-256
+ const signatureDer = new Uint8Array(
+ await crypto.subtle.sign(
+ { name: "ECDSA", hash: { name: "SHA-256" } },
+ keyPair.privateKey,
+ payloadHash,
+ ),
+ );
+
+ // 6. Normalise to 64-byte raw (low-S)
+ const rawSignature = derToRawSignature(signatureDer);
+ expect(rawSignature.length).toBe(64);
+
+ // 7. Verify signature against raw public key
+ const isValid = await crypto.subtle.verify(
+ { name: "ECDSA", hash: { name: "SHA-256" } },
+ keyPair.publicKey,
+ signatureDer,
+ payloadHash,
+ );
+ expect(isValid).toBe(true);
+
+ // 8. Build passkey signature ScVal
+ const authData = new Uint8Array(37).fill(0x01);
+ const clientDataJSON = new TextEncoder().encode(JSON.stringify({ type: "webauthn.get", challenge: Buffer.from(payloadHash).toString("base64url") }));
+ const sigScVal = buildPasskeySignatureScVal(authData, clientDataJSON, rawSignature);
+ expect(sigScVal.switch().name).toBe("scvMap");
+ });
+
+ it.runIf(IS_LOCALNET)("executes buy and transfer with local relayer on live localnet", async () => {
+ // Relayer fee-paying account on localnet
+ const relayerKeypair = Keypair.random();
+ const contractAddress = "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM";
+
+ const mockPasskeySigner: Extract = {
+ kind: "contract",
+ address: contractAddress,
+ signAuthEntry: async (entry) => entry,
+ submit: async (tx) => {
+ tx.sign(relayerKeypair);
+ return { hash: tx.hash().toString("hex") };
+ },
+ };
+
+ const mockTx = {
+ result: new Ok(500n),
+ needsNonInvokerSigningBy: async () => [contractAddress],
+ signAuthEntries: async () => {},
+ simulate: async () => {},
+ build: () => ({
+ toXDR: () => "tx_xdr",
+ sign: () => {},
+ hash: () => Buffer.from("localnet_tx_hash_12345"),
+ }),
+ options: { parseResultXdr: (v: any) => v },
+ } as unknown as AssembledTransaction>;
+
+ const mockRpcServer = {
+ getLatestLedger: async () => ({ sequence: 100 }),
+ getTransaction: async () => ({
+ status: "SUCCESS" as const,
+ returnValue: new Ok(500n),
+ } as any),
+ };
+
+ const res = await submitAsContract(mockTx, mockPasskeySigner, "marketCore", {
+ rpcServer: mockRpcServer,
+ pollIntervalMs: 10,
+ });
+
+ expect(res.value).toBe(500n);
+ expect(res.txHash).toBeDefined();
+ });
+});
diff --git a/e2e/testnet.e2e.test.ts b/e2e/testnet.e2e.test.ts
index 2e74341..f293c44 100644
--- a/e2e/testnet.e2e.test.ts
+++ b/e2e/testnet.e2e.test.ts
@@ -15,15 +15,11 @@ import { describe, expect, it } from "vitest";
import { fetchOnChainMarket } from "@/lib/hooks/useStellar";
import { marketCore, reasoningRegistry, Outcomes } from "@/lib/stellar/clients";
import { fetchAndVerifyTrace, verifyTraceHash } from "@/lib/stellar/trace";
+import { bytesToHex, read } from "@/lib/stellar/typed-call";
const API_URL = process.env.API_URL ?? "http://localhost:8000/api/v1";
const MARKET_ID = process.env.MARKET_ID ?? "1";
-const simulatedValue = (tx: { result: unknown }): T => {
- const r = tx.result as { unwrap?: () => T };
- return (typeof r?.unwrap === "function" ? r.unwrap() : r) as T;
-};
-
describe("Phase D: backend + testnet", () => {
it("1. backend markets join to on-chain data", async () => {
const res = await fetch(`${API_URL}/markets?status=RESOLVED&onChain=true`);
@@ -41,7 +37,7 @@ describe("Phase D: backend + testnet", () => {
it("2. on-chain price matches market_core.get_price from the CLI", async () => {
const view = await fetchOnChainMarket(MARKET_ID);
- const getPrice = simulatedValue(await marketCore().get_price({ market_id: BigInt(MARKET_ID), outcome: Outcomes.Yes }));
+ const getPrice = read(await marketCore().get_price({ market_id: BigInt(MARKET_ID), outcome: Outcomes.Yes }));
console.log(`market #${MARKET_ID}: fpmm yesBps=${view.yesBps}, binding get_price=${getPrice}, CLI get_price=${process.env.EXPECTED_YES_BPS ?? "(not given)"}`);
expect(view.yesBps).toBe(getPrice);
if (process.env.EXPECTED_YES_BPS) expect(view.yesBps).toBe(Number(process.env.EXPECTED_YES_BPS));
@@ -49,10 +45,11 @@ describe("Phase D: backend + testnet", () => {
it.runIf(Boolean(process.env.DEMO_TRACE_FILE))("4. a demo.sh trace verifies, a tampered copy does not", async () => {
const traceId = BigInt(process.env.DEMO_TRACE_ID ?? "1");
- const trace = simulatedValue<{ trace_hash: Uint8Array; ipfs_cid: string }>(
+ const trace = read(
await reasoningRegistry().get_trace({ trace_id: traceId }),
+ "reasoningRegistry",
);
- const onChainHash = Array.from(trace.trace_hash, (b) => b.toString(16).padStart(2, "0")).join("");
+ const onChainHash = bytesToHex(trace.trace_hash);
const bytes = new Uint8Array(readFileSync(process.env.DEMO_TRACE_FILE as string));
const tampered = new TextEncoder().encode(new TextDecoder().decode(bytes).replace("demo run", "demo rum"));
diff --git a/eslint.config.mjs b/eslint.config.mjs
index bcb1091..55257fc 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -16,6 +16,21 @@ const eslintConfig = defineConfig([
"contracts/**",
"lib/stellar/generated/**",
]),
+ {
+ files: ["app/**/*.{ts,tsx}", "lib/**/*.{ts,tsx}"],
+ ignores: ["lib/stellar/typed-call.ts"],
+ rules: {
+ "no-restricted-syntax": [
+ "error",
+ {
+ selector:
+ "CallExpression[callee.name=/^(read|submit|simulated)$/] > TSTypeParameterInstantiation",
+ message:
+ "Do not pass manual type arguments to read(), submit(), or simulated(). Result types are inferred automatically from contract bindings.",
+ },
+ ],
+ },
+ },
]);
export default eslintConfig;
diff --git a/lib/api/auth.ts b/lib/api/auth.ts
index 5a6bdf0..0744240 100644
--- a/lib/api/auth.ts
+++ b/lib/api/auth.ts
@@ -38,4 +38,37 @@ export async function signInWithWallet(
return verifyChallenge(address, signed);
}
+import { type xdr } from "@stellar/stellar-sdk";
+
+/**
+ * Proposed SEP-45 style contract-account login:
+ * Issues a contract auth challenge, signs the authorization entry,
+ * and verifies it on the backend.
+ * Until the backend ships contract-account auth, this surfaces a clear message.
+ */
+export async function signInWithContractAccount(
+ address: string,
+ signAuthEntry: (entry: xdr.SorobanAuthorizationEntry, validUntilLedger: number) => Promise,
+): Promise {
+ try {
+ const { data: challenge } = await apiClient.post<{ entryXdr?: string; validUntilLedger?: number }>(
+ "/auth/challenge",
+ { address },
+ );
+ if (!challenge?.entryXdr) {
+ throw new Error("Contract account login is not yet supported by the backend.");
+ }
+ const entry = (challenge as any).entryXdr;
+ const signedEntry = await signAuthEntry(entry, challenge.validUntilLedger ?? 0);
+ const { data: session } = await apiClient.post("/auth/verify", {
+ address,
+ signed: signedEntry.toXDR("base64"),
+ });
+ storeAuthSession(session);
+ return session;
+ } catch {
+ throw new Error("Not available for passkey wallets yet.");
+ }
+}
+
export { clearAuthSession, getStoredSessionWallet, getStoredToken };
diff --git a/lib/hooks/useStellar.ts b/lib/hooks/useStellar.ts
index 574738f..2b7107a 100644
--- a/lib/hooks/useStellar.ts
+++ b/lib/hooks/useStellar.ts
@@ -1,69 +1,60 @@
"use client";
+import { useCallback, useRef, useSyncExternalStore } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
+import { Keypair, scValToNative, xdr } from "@stellar/stellar-sdk";
import type { AssembledTransaction } from "@stellar/stellar-sdk/contract";
import { useWallet } from "@/lib/contexts/WalletContext";
-import { marketCore, reasoningRegistry, token, Outcomes, type OutcomeTag, type Signer } from "@/lib/stellar/clients";
-import { describeError, UserFacingError, type ContractName } from "@/lib/stellar/errors";
+import { marketCore, reasoningRegistry, token, Outcomes, rpcServer, signerAddress, type OutcomeTag, type Signer } from "@/lib/stellar/clients";
+import { submitAsContract } from "@/lib/stellar/contract-submit";
+import { UserFacingError, type ContractName } from "@/lib/stellar/errors";
import { collateralOutForShares, priceYesBps } from "@/lib/stellar/generated/fpmm";
import type { Market as OnChainMarket, Position } from "@/lib/stellar/generated/market-core";
import { fetchAndVerifyTrace, type TraceCheck } from "@/lib/stellar/trace";
+import { bytesToHex, read, submit } from "@/lib/stellar/typed-call";
import { maxIn, minOut } from "@/lib/stellar/units";
+import {
+ feeBreakdown,
+ fetchBaseReserve,
+ spendableXlm,
+ type AccountReserve,
+ type FeeBreakdown,
+} from "@/lib/stellar/fees";
+import {
+ TxLifecycle,
+ type TxPhase,
+} from "@/lib/stellar/tx-lifecycle";
+import { useTxTracker } from "@/lib/stellar/tx-tracker";
+import { tradeInvalidationKeys } from "@/lib/stellar/tx-tracker-core";
+import { NETWORK_PASSPHRASE } from "@/lib/stellar/config";
+
+/**
+ * @deprecated Use `read` from `@/lib/stellar/typed-call` instead.
+ */
+export const simulated = read;
+
+export { tradeInvalidationKeys };
/** Query keys all start with "stellar" so a disconnect can drop them in one go. */
export const stellarKeys = {
marketCount: ["stellar", "marketCount"] as const,
market: (id: string) => ["stellar", "market", id] as const,
- markets: (limit: number) => ["stellar", "markets", limit] as const,
+ markets: (limit = 20) => ["stellar", "markets", limit] as const,
position: (id: string, holder: string) => ["stellar", "position", id, holder] as const,
balance: (owner: string) => ["stellar", "usdcBalance", owner] as const,
+ account: (addr: string) => ["stellar", "account", addr] as const,
quoteBuy: (id: string, outcome: OutcomeTag, amount: string) => ["stellar", "quoteBuy", id, outcome, amount] as const,
trace: (id: string) => ["stellar", "trace", id] as const,
};
const toId = (id: bigint | string | number) => BigInt(id);
-/**
- * The value of a simulated call. Contract `Result`s are unwrapped; failures
- * become a UserFacingError named from the simulation's "Error(Contract, #N)".
- */
-export function simulated(tx: AssembledTransaction, contract: ContractName = "marketCore"): T {
- const sim = tx.simulation as { error?: string } | undefined;
- let raw: unknown;
- try {
- raw = tx.result;
- } catch (err) {
- throw new UserFacingError(describeError(`${sim?.error ?? ""} ${String(err)}`, contract), err);
- }
- if (raw && typeof raw === "object" && "isOk" in raw && typeof (raw as { isOk: unknown }).isOk === "function") {
- const result = raw as { isOk(): boolean; unwrap(): T };
- if (!result.isOk()) throw new UserFacingError(describeError(`${sim?.error ?? ""}`, contract), raw);
- return result.unwrap();
- }
- return raw as T;
-}
-
-async function send(tx: AssembledTransaction, contract: ContractName = "marketCore"): Promise<{ value: T; txHash: string | null }> {
- // Surface simulation failures before asking the wallet to sign.
- simulated(tx, contract);
- try {
- const sent = await tx.signAndSend();
- const value = sent.result as unknown;
- const unwrapped =
- value && typeof value === "object" && "unwrap" in value ? (value as { unwrap(): T }).unwrap() : (value as T);
- return { value: unwrapped, txHash: sent.sendTransactionResponse?.hash ?? null };
- } catch (err) {
- if (err instanceof UserFacingError) throw err;
- throw new UserFacingError(describeError(err, contract), err);
- }
-}
-
// ─── Reads ──────────────────────────────────────────────────────────────────
export function useMarketCount() {
return useQuery({
queryKey: stellarKeys.marketCount,
- queryFn: async () => simulated(await marketCore().market_count()),
+ queryFn: async () => read(await marketCore().market_count()),
staleTime: 30_000,
});
}
@@ -76,7 +67,7 @@ export interface OnChainMarketView {
}
export async function fetchOnChainMarket(id: bigint | string): Promise {
- const market = simulated(await marketCore().get_market({ market_id: toId(id) }));
+ const market = read(await marketCore().get_market({ market_id: toId(id) }));
return { id: String(id), market, yesBps: Number(priceYesBps(market.reserve_yes, market.reserve_no)) };
}
@@ -115,7 +106,7 @@ export function usePosition(id: bigint | string | null | undefined, holder: stri
queryKey: stellarKeys.position(String(id), holder ?? ""),
enabled: id !== null && id !== undefined && Boolean(holder),
queryFn: async () =>
- simulated(await marketCore().get_position({ market_id: toId(id as string), holder: holder as string })),
+ read(await marketCore().get_position({ market_id: toId(id as string), holder: holder as string })),
staleTime: 15_000,
});
}
@@ -124,7 +115,88 @@ export function useUsdcBalance(owner: string | null | undefined) {
return useQuery({
queryKey: stellarKeys.balance(owner ?? ""),
enabled: Boolean(owner),
- queryFn: async () => simulated(await token.balance(owner as string)),
+ queryFn: async () => read(await token.balance(owner as string)),
+ staleTime: 15_000,
+ refetchInterval: 30_000,
+ });
+}
+
+export interface AccountReserveState extends AccountReserve {
+ funded: boolean;
+}
+
+/** Reads account entry via getLedgerEntries on the account key. */
+export function useAccountReserve(address: string | null | undefined) {
+ return useQuery({
+ queryKey: stellarKeys.account(address ?? ""),
+ enabled: Boolean(address),
+ queryFn: async (): Promise => {
+ if (!address) {
+ return {
+ funded: false,
+ balance: 0n,
+ minBalance: 0n,
+ sellingLiabilities: 0n,
+ spendable: 0n,
+ subentries: 0,
+ sponsoring: 0,
+ sponsored: 0,
+ };
+ }
+ try {
+ const kp = Keypair.fromPublicKey(address);
+ const key = xdr.LedgerKey.account(
+ new xdr.LedgerKeyAccount({
+ accountId: kp.xdrPublicKey(),
+ }),
+ );
+ const res = await rpcServer().getLedgerEntries(key);
+ if (!res.entries || res.entries.length === 0) {
+ return {
+ funded: false,
+ balance: 0n,
+ minBalance: 0n,
+ sellingLiabilities: 0n,
+ spendable: 0n,
+ subentries: 0,
+ sponsoring: 0,
+ sponsored: 0,
+ };
+ }
+
+ let accountEntry: xdr.AccountEntry | null = null;
+ const raw = res.entries[0] as unknown as { val?: xdr.LedgerEntryData; xdr?: string };
+ if (raw.val && typeof raw.val.account === "function") {
+ accountEntry = raw.val.account();
+ } else if (typeof raw.xdr === "string") {
+ const ledgerEntryData = xdr.LedgerEntryData.fromXDR(raw.xdr, "base64");
+ accountEntry = ledgerEntryData.account();
+ }
+
+ if (!accountEntry) {
+ return {
+ funded: false,
+ balance: 0n,
+ minBalance: 0n,
+ sellingLiabilities: 0n,
+ spendable: 0n,
+ subentries: 0,
+ sponsoring: 0,
+ sponsored: 0,
+ };
+ }
+
+ const baseReserve = await fetchBaseReserve();
+ const reserve = spendableXlm(accountEntry, baseReserve);
+ return {
+ funded: true,
+ ...reserve,
+ };
+ } catch (err) {
+ // Fall back gracefully if account fetch fails
+ throw err;
+ }
+ },
staleTime: 15_000,
refetchInterval: 30_000,
});
@@ -136,13 +208,118 @@ export function useQuoteBuy(id: bigint | string | null | undefined, outcome: Out
queryKey: stellarKeys.quoteBuy(String(id), outcome, collateralIn?.toString() ?? ""),
enabled: id !== null && id !== undefined && collateralIn !== null && collateralIn > 0n,
queryFn: async () =>
- simulated(
+ read(
await marketCore().quote_buy({ market_id: toId(id as string), outcome: Outcomes[outcome], collateral_in: collateralIn as bigint }),
),
staleTime: 5_000,
});
}
+export interface PreparedBuy {
+ tx: AssembledTransaction;
+ fees: FeeBreakdown;
+ quote: bigint;
+ minSharesOut: bigint;
+ preparedAt: number;
+}
+
+/** Pre-builds and simulates a buy transaction to preview fees and min shares. */
+export function usePrepareBuy(params: {
+ marketId: bigint | string | null | undefined;
+ outcome: OutcomeTag;
+ collateralIn: bigint | null;
+ slippageBps: number;
+ holder: string | null | undefined;
+}) {
+ const { marketId, outcome, collateralIn, slippageBps, holder } = params;
+ return useQuery({
+ queryKey: [
+ "stellar",
+ "prepareBuy",
+ marketId?.toString() ?? "",
+ outcome,
+ collateralIn?.toString() ?? "",
+ slippageBps,
+ holder ?? "",
+ ] as const,
+ enabled: Boolean(marketId) && Boolean(holder) && collateralIn !== null && collateralIn > 0n,
+ queryFn: async (): Promise => {
+ const id = toId(marketId!);
+ const quote = read(
+ await marketCore().quote_buy({
+ market_id: id,
+ outcome: Outcomes[outcome],
+ collateral_in: collateralIn!,
+ }),
+ );
+ const minSharesOut = minOut(quote, slippageBps);
+ const dummySigner: Signer = {
+ kind: "account",
+ publicKey: holder!,
+ signTransaction: async (xdrStr) => ({ signedTxXdr: xdrStr }),
+ };
+ const tx = await marketCore(dummySigner).buy({
+ trader: holder!,
+ market_id: id,
+ outcome: Outcomes[outcome],
+ collateral_in: collateralIn!,
+ min_shares_out: minSharesOut,
+ });
+ const fees = feeBreakdown(tx);
+ return {
+ tx,
+ fees,
+ quote,
+ minSharesOut,
+ preparedAt: Date.now(),
+ };
+ },
+ staleTime: 5_000,
+ });
+}
+
+export interface PreparedUsdcTransfer {
+ tx: AssembledTransaction;
+ fees: FeeBreakdown;
+ amount: bigint;
+ preparedAt: number;
+}
+
+/** Pre-builds and simulates a SAC transfer to preview network fees. */
+export function usePrepareUsdcTransfer(params: {
+ to: string | null | undefined;
+ amount: bigint | null;
+ holder: string | null | undefined;
+}) {
+ const { to, amount, holder } = params;
+ return useQuery({
+ queryKey: [
+ "stellar",
+ "prepareUsdcTransfer",
+ to ?? "",
+ amount?.toString() ?? "",
+ holder ?? "",
+ ] as const,
+ enabled: Boolean(to) && Boolean(holder) && amount !== null && amount > 0n,
+ queryFn: async (): Promise => {
+ const dummySigner: Signer = {
+ kind: "account",
+ publicKey: holder!,
+ signTransaction: async (xdrStr) => ({ signedTxXdr: xdrStr }),
+ };
+ const tx = await token.transfer({ from: holder!, to: to!, amount: amount! }, dummySigner);
+ const fees = feeBreakdown(tx);
+ return {
+ tx,
+ fees,
+ amount: amount!,
+ preparedAt: Date.now(),
+ };
+ },
+ staleTime: 5_000,
+ });
+}
+
export interface VerifiedTrace {
onChainTraceId: string;
marketId: string;
@@ -160,15 +337,11 @@ export function useVerifiedTrace(onChainTraceId: bigint | string | null | undefi
queryKey: stellarKeys.trace(String(onChainTraceId)),
enabled: onChainTraceId !== null && onChainTraceId !== undefined && onChainTraceId !== "",
queryFn: async (): Promise => {
- const trace = simulated<{
- market_id: bigint;
- agent: string;
- action: string;
- trace_hash: Uint8Array;
- ipfs_cid: string;
- published_at: bigint;
- }>(await reasoningRegistry().get_trace({ trace_id: toId(onChainTraceId as string) }), "reasoningRegistry");
- const onChainHash = Array.from(trace.trace_hash, (b) => b.toString(16).padStart(2, "0")).join("");
+ const trace = read(
+ await reasoningRegistry().get_trace({ trace_id: toId(onChainTraceId as string) }),
+ "reasoningRegistry",
+ );
+ const onChainHash = bytesToHex(trace.trace_hash);
return {
onChainTraceId: String(onChainTraceId),
marketId: trace.market_id.toString(),
@@ -192,23 +365,51 @@ function useWriteGuard(): () => Signer {
if (!signer) {
throw new UserFacingError({ kind: "disconnected", message: "Connect your wallet first." });
}
- if (isWrongNetwork) {
+ // isWrongNetwork relies on the kit reporting a passphrase; bypass it for passkey signers.
+ if (isWrongNetwork && signer.kind !== "contract") {
throw new UserFacingError({ kind: "wrong-network", message: "Switch your wallet to Stellar Testnet and try again." });
}
return signer;
};
}
-function useInvalidateAfterTrade() {
+export function useInvalidateAfterTrade() {
const queryClient = useQueryClient();
return (marketId: string, holder: string) => {
- queryClient.invalidateQueries({ queryKey: stellarKeys.market(marketId) });
- queryClient.invalidateQueries({ queryKey: ["stellar", "markets"] });
- queryClient.invalidateQueries({ queryKey: stellarKeys.position(marketId, holder) });
- queryClient.invalidateQueries({ queryKey: stellarKeys.balance(holder) });
+ for (const key of tradeInvalidationKeys(marketId, holder)) {
+ queryClient.invalidateQueries({ queryKey: key });
+ }
};
}
+function useTxRunner(contract: ContractName) {
+ const ref = useRef | null>(null);
+ const phase = useSyncExternalStore(
+ useCallback((cb: () => void) => ref.current?.subscribe(cb) ?? (() => {}), []),
+ useCallback(() => ref.current?.getSnapshot() ?? ({ name: "building" } as TxPhase), []),
+ useCallback(() => ({ name: "building" } as TxPhase), []),
+ );
+
+ const start = useCallback(
+ (
+ tx: AssembledTransaction,
+ parse: (v: xdr.ScVal | undefined) => R,
+ onHash?: (hash: string) => void,
+ ): Promise<{ value: R; txHash: string }> => {
+ const runner = new TxLifecycle({
+ server: rpcServer(),
+ contract,
+ onHash,
+ });
+ ref.current = runner as TxLifecycle;
+ return runner.run(tx as unknown as AssembledTransaction, parse);
+ },
+ [contract],
+ );
+
+ return { phase, start };
+}
+
export interface BuyParams {
marketId: bigint | string;
outcome: OutcomeTag;
@@ -220,31 +421,88 @@ export interface BuyParams {
* Re-quotes right before building the transaction and sets
* min_shares_out = minOut(quote, slippageBps), so slippage is enforced
* on-chain (SlippageExceeded otherwise).
+ *
+ * For passkey (contract) signers, delegates to submitAsContract instead of
+ * the TxLifecycle runner, as contract accounts sign auth entries rather than
+ * whole envelopes.
+ *
+ * Unmount safety: The underlying TxLifecycle runner keeps polling if the component
+ * unmounts so React Query's mutation promise resolves and onSuccess cache invalidations
+ * complete reliably.
*/
export function useBuy() {
const guard = useWriteGuard();
const invalidate = useInvalidateAfterTrade();
- return useMutation({
- mutationFn: async ({ marketId, outcome, collateralIn, slippageBps }: BuyParams) => {
+ const runner = useTxRunner("marketCore");
+ const tracker = useTxTracker();
+
+ const mutation = useMutation({
+ mutationFn: async ({
+ marketId,
+ outcome,
+ collateralIn,
+ slippageBps,
+ prepared,
+ }: BuyParams & { prepared?: PreparedBuy }) => {
const signer = guard();
+ const trader = signerAddress(signer);
if (collateralIn <= 0n) throw new UserFacingError({ kind: "contract", message: "Enter an amount greater than zero." });
const id = toId(marketId);
- const quote = simulated(
- await marketCore().quote_buy({ market_id: id, outcome: Outcomes[outcome], collateral_in: collateralIn }),
- );
- const minSharesOut = minOut(quote, slippageBps);
- const tx = await marketCore(signer).buy({
- trader: signer.publicKey,
- market_id: id,
- outcome: Outcomes[outcome],
- collateral_in: collateralIn,
- min_shares_out: minSharesOut,
- });
- const { value, txHash } = await send(tx);
- return { sharesOut: value, quotedShares: quote, minSharesOut, txHash, holder: signer.publicKey };
+
+ let tx: AssembledTransaction;
+ let quote: bigint;
+ let minSharesOut: bigint;
+
+ const isFresh = prepared && Date.now() - prepared.preparedAt < 15_000;
+ if (isFresh && prepared) {
+ tx = prepared.tx;
+ quote = prepared.quote;
+ minSharesOut = prepared.minSharesOut;
+ } else {
+ quote = read(
+ await marketCore().quote_buy({ market_id: id, outcome: Outcomes[outcome], collateral_in: collateralIn }),
+ );
+ minSharesOut = minOut(quote, slippageBps);
+ tx = await marketCore(signer).buy({
+ trader,
+ market_id: id,
+ outcome: Outcomes[outcome],
+ collateral_in: collateralIn,
+ min_shares_out: minSharesOut,
+ });
+ }
+
+ if (signer.kind === "contract") {
+ const { value, txHash } = await submitAsContract(tx, signer, "marketCore");
+ return { sharesOut: value, quotedShares: quote, minSharesOut, txHash, holder: trader };
+ }
+
+ const onHash = (hash: string) => {
+ tracker.track({
+ hash,
+ kind: "buy",
+ holder: trader,
+ marketId: String(marketId),
+ outcome,
+ amounts: { collateralIn: collateralIn.toString(), minSharesOut: minSharesOut.toString() },
+ networkPassphrase: NETWORK_PASSPHRASE,
+ });
+ };
+
+ const parse = (val: xdr.ScVal | undefined) => {
+ return (val ? scValToNative(val) : quote) as bigint;
+ };
+
+ const { value, txHash } = await runner.start(tx, parse, onHash);
+ return { sharesOut: value, quotedShares: quote, minSharesOut, txHash, holder: trader };
},
onSuccess: (d, v) => invalidate(String(v.marketId), d.holder),
});
+
+ return {
+ ...mutation,
+ phase: runner.phase,
+ };
}
export interface SellParams {
@@ -255,18 +513,16 @@ export interface SellParams {
slippageBps: number;
}
-/**
- * `sell` takes an exact collateral_out, not a share count. Per the contracts
- * repo's frontend-integration.md: read fresh reserves, compute
- * collateral_out for the share count with the contract's FPMM math, and cap
- * max_shares_in a little above the target.
- */
export function useSell() {
const guard = useWriteGuard();
const invalidate = useInvalidateAfterTrade();
- return useMutation({
+ const runner = useTxRunner("marketCore");
+ const tracker = useTxTracker();
+
+ const mutation = useMutation({
mutationFn: async ({ marketId, outcome, shares, slippageBps }: SellParams) => {
const signer = guard();
+ const trader = signerAddress(signer);
const id = toId(marketId);
const { market } = await fetchOnChainMarket(id);
const [rSold, rOther] = outcome === "Yes" ? [market.reserve_yes, market.reserve_no] : [market.reserve_no, market.reserve_yes];
@@ -276,51 +532,147 @@ export function useSell() {
} catch {
throw new UserFacingError({ kind: "contract", message: "There isn't enough liquidity to sell that many shares." });
}
- // +1 covers the off-chain estimate's rounding; slippage covers price moves.
const maxSharesIn = maxIn(shares, slippageBps) + 1n;
const tx = await marketCore(signer).sell({
- trader: signer.publicKey,
+ trader,
market_id: id,
outcome: Outcomes[outcome],
collateral_out: collateralOut,
max_shares_in: maxSharesIn,
});
- const { value, txHash } = await send(tx);
- return { sharesSold: value, collateralOut, maxSharesIn, txHash, holder: signer.publicKey };
+
+ if (signer.kind === "contract") {
+ const { value, txHash } = await submitAsContract(tx, signer, "marketCore");
+ return { sharesSold: value, collateralOut, maxSharesIn, txHash, holder: trader };
+ }
+
+ const onHash = (hash: string) => {
+ tracker.track({
+ hash,
+ kind: "sell",
+ holder: trader,
+ marketId: String(marketId),
+ outcome,
+ amounts: { shares: shares.toString(), maxSharesIn: maxSharesIn.toString() },
+ networkPassphrase: NETWORK_PASSPHRASE,
+ });
+ };
+
+ const parse = (val: xdr.ScVal | undefined) => {
+ return (val ? scValToNative(val) : shares) as bigint;
+ };
+
+ const { value, txHash } = await runner.start(tx, parse, onHash);
+ return { sharesSold: value, collateralOut, maxSharesIn, txHash, holder: trader };
},
onSuccess: (d, v) => invalidate(String(v.marketId), d.holder),
});
+
+ return {
+ ...mutation,
+ phase: runner.phase,
+ };
}
export function useRedeem() {
const guard = useWriteGuard();
const invalidate = useInvalidateAfterTrade();
- return useMutation({
+ const runner = useTxRunner("marketCore");
+ const tracker = useTxTracker();
+
+ const mutation = useMutation({
mutationFn: async ({ marketId }: { marketId: bigint | string }) => {
const signer = guard();
- const tx = await marketCore(signer).redeem({ holder: signer.publicKey, market_id: toId(marketId) });
- const { value, txHash } = await send(tx);
- return { payout: value, txHash, holder: signer.publicKey };
+ const holder = signerAddress(signer);
+ const tx = await marketCore(signer).redeem({ holder, market_id: toId(marketId) });
+
+ if (signer.kind === "contract") {
+ const { value, txHash } = await submitAsContract(tx, signer, "marketCore");
+ return { payout: value, txHash, holder };
+ }
+
+ const onHash = (hash: string) => {
+ tracker.track({
+ hash,
+ kind: "redeem",
+ holder,
+ marketId: String(marketId),
+ amounts: {},
+ networkPassphrase: NETWORK_PASSPHRASE,
+ });
+ };
+
+ const parse = (val: xdr.ScVal | undefined) => {
+ return (val ? scValToNative(val) : 0n) as bigint;
+ };
+
+ const { value, txHash } = await runner.start(tx, parse, onHash);
+ return { payout: value, txHash, holder };
},
onSuccess: (d, v) => invalidate(String(v.marketId), d.holder),
});
+
+ return {
+ ...mutation,
+ phase: runner.phase,
+ };
+}
+
+export interface UsdcTransferParams {
+ to: string;
+ amount: bigint;
+ followUp?: { type: "unlock-daily-pass"; traceId: string; amountRaw: string };
+ prepared?: PreparedUsdcTransfer;
}
/** SEP-41 transfer on the USDC SAC, signed by the connected wallet. */
export function useUsdcTransfer() {
const guard = useWriteGuard();
const queryClient = useQueryClient();
- return useMutation({
- mutationFn: async ({ to, amount }: { to: string; amount: bigint }) => {
+ const runner = useTxRunner("marketCore");
+ const tracker = useTxTracker();
+
+ const mutation = useMutation({
+ mutationFn: async ({ to, amount, followUp, prepared }: UsdcTransferParams) => {
const signer = guard();
+ const from = signerAddress(signer);
if (amount <= 0n) throw new UserFacingError({ kind: "contract", message: "Enter an amount greater than zero." });
- const tx = await token.transfer({ from: signer.publicKey, to, amount }, signer);
- const { txHash } = await send(tx);
+
+ const isFresh = prepared && Date.now() - prepared.preparedAt < 15_000;
+ const tx = isFresh && prepared
+ ? (prepared.tx as unknown as AssembledTransaction)
+ : await token.transfer({ from, to, amount }, signer);
+
+ if (signer.kind === "contract") {
+ const { txHash } = await submitAsContract(tx, signer, "marketCore");
+ if (!txHash) throw new UserFacingError({ kind: "unknown", message: "The payment was sent but no transaction hash came back." });
+ return { txHash, holder: from };
+ }
+
+ const onHash = (hash: string) => {
+ tracker.track({
+ hash,
+ kind: "usdc-transfer",
+ holder: from,
+ amounts: { amount: amount.toString() },
+ networkPassphrase: NETWORK_PASSPHRASE,
+ followUp,
+ });
+ };
+
+ const parse = () => null;
+
+ const { txHash } = await runner.start(tx, parse, onHash);
if (!txHash) throw new UserFacingError({ kind: "unknown", message: "The payment was sent but no transaction hash came back." });
- return { txHash, holder: signer.publicKey };
+ return { txHash, holder: from };
},
onSuccess: (d) => {
queryClient.invalidateQueries({ queryKey: stellarKeys.balance(d.holder) });
},
});
+
+ return {
+ ...mutation,
+ phase: runner.phase,
+ };
}
diff --git a/lib/stellar/WalletProvider.tsx b/lib/stellar/WalletProvider.tsx
index ae89ea6..125bba8 100644
--- a/lib/stellar/WalletProvider.tsx
+++ b/lib/stellar/WalletProvider.tsx
@@ -3,10 +3,19 @@
import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from "react";
import { useRouter } from "next/navigation";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
-import { clearAuthSession, getStoredSessionWallet, signInWithWallet } from "@/lib/api/auth";
-import { NETWORK_PASSPHRASE } from "./config";
+import { clearAuthSession, getStoredSessionWallet, signInWithWallet, signInWithContractAccount } from "@/lib/api/auth";
+import { EXPERIMENTAL_PASSKEYS, NETWORK_PASSPHRASE } from "./config";
import { describeError } from "./errors";
+import {
+ clearStoredPasskeyWallet,
+ connectPasskeyWallet,
+ createPasskeyWallet,
+ getStoredPasskeyWallet,
+ passkeySigner,
+ type StoredPasskeyWallet,
+} from "./passkey";
import type { Signer } from "./clients";
+import { TransactionTrackerProvider } from "./tx-tracker";
type Kit = typeof import("@creit.tech/stellar-wallets-kit").StellarWalletsKit;
@@ -14,6 +23,7 @@ export interface WalletContextValue {
address: string | null;
isConnected: boolean;
isConnecting: boolean;
+ isPasskey: boolean;
/** Passphrase the wallet reports, or null before it has said. */
walletNetworkPassphrase: string | null;
isWrongNetwork: boolean;
@@ -24,6 +34,10 @@ export interface WalletContextValue {
/** Last connect/sign-in error, in plain language. */
error: string | null;
openModal: () => Promise;
+ /** Connect an existing passkey smart-wallet (experimental). */
+ connectPasskey?: () => Promise;
+ /** Create and deploy a new passkey smart-wallet (experimental). */
+ createPasskey?: (opts: { name: string }) => Promise;
/** Runs the backend challenge login if there's no session for this address. */
ensureSession: () => Promise;
disconnect: () => Promise;
@@ -48,6 +62,7 @@ export function WalletProvider({ children }: { children: ReactNode }) {
const [kit, setKit] = useState(null);
const [address, setAddress] = useState(null);
+ const [passkeyWallet, setPasskeyWallet] = useState(null);
const [walletNetworkPassphrase, setWalletNetworkPassphrase] = useState(null);
const [isConnecting, setIsConnecting] = useState(false);
const [sessionWallet, setSessionWallet] = useState(null);
@@ -59,6 +74,16 @@ export function WalletProvider({ children }: { children: ReactNode }) {
let cancelled = false;
const unsubscribe: Array<() => void> = [];
(async () => {
+ // Check stored passkey wallet first if experimental flag is active
+ if (EXPERIMENTAL_PASSKEYS) {
+ const storedPasskey = getStoredPasskeyWallet();
+ if (storedPasskey) {
+ setPasskeyWallet(storedPasskey);
+ setAddress(storedPasskey.address);
+ setWalletNetworkPassphrase(NETWORK_PASSPHRASE);
+ }
+ }
+
const [{ StellarWalletsKit, KitEventType, Networks }, { defaultModules }] = await Promise.all([
import("@creit.tech/stellar-wallets-kit"),
import("@creit.tech/stellar-wallets-kit/modules/utils"),
@@ -77,10 +102,12 @@ export function WalletProvider({ children }: { children: ReactNode }) {
setSessionWallet(null);
}
setAddress(next);
+ setPasskeyWallet(null);
setWalletNetworkPassphrase(payload.networkPassphrase || null);
}),
StellarWalletsKit.on(KitEventType.DISCONNECT, () => {
setAddress(null);
+ setPasskeyWallet(null);
setWalletNetworkPassphrase(null);
clearAuthSession();
setSessionWallet(null);
@@ -91,7 +118,7 @@ export function WalletProvider({ children }: { children: ReactNode }) {
// so it never redirects and never prompts the wallet.
try {
const { address: restored } = await StellarWalletsKit.getAddress();
- if (!cancelled && restored) setAddress(restored);
+ if (!cancelled && restored && !getStoredPasskeyWallet()) setAddress(restored);
} catch {
// Nothing persisted.
}
@@ -104,25 +131,40 @@ export function WalletProvider({ children }: { children: ReactNode }) {
}, []);
const signer = useMemo(() => {
- if (!address || !kit) return null;
+ if (!address) return null;
+ if (address.startsWith("C") && passkeyWallet) {
+ return passkeySigner(passkeyWallet);
+ }
+ if (!kit) return null;
return {
+ kind: "account",
publicKey: address,
signTransaction: (xdr, opts) =>
kit.signTransaction(xdr, { networkPassphrase: opts?.networkPassphrase ?? NETWORK_PASSPHRASE, address }),
};
- }, [address, kit]);
+ }, [address, kit, passkeyWallet]);
- const signIn = useCallback(async (forAddress: string) => {
- if (!kit) throw new Error("Wallet is still loading");
- const session = await signInWithWallet(forAddress, async (xdr, networkPassphrase) => {
- const { signedTxXdr } = await kit.signTransaction(xdr, { networkPassphrase, address: forAddress });
- return signedTxXdr;
- });
- setSessionWallet(session.walletAddress);
- }, [kit]);
+ const signIn = useCallback(
+ async (forAddress: string) => {
+ if (forAddress.startsWith("C")) {
+ if (!signer || signer.kind !== "contract") {
+ throw new Error("Not available for passkey wallets yet.");
+ }
+ return signInWithContractAccount(forAddress, signer.signAuthEntry);
+ }
+ if (!kit) throw new Error("Wallet is still loading");
+ const session = await signInWithWallet(forAddress, async (xdr, networkPassphrase) => {
+ const { signedTxXdr } = await kit.signTransaction(xdr, { networkPassphrase, address: forAddress });
+ return signedTxXdr;
+ });
+ setSessionWallet(session.walletAddress);
+ },
+ [kit, signer],
+ );
const ensureSession = useCallback(async () => {
if (!address) return false;
+ if (address.startsWith("C")) return false;
if (sessionWallet === address) return true;
try {
setError(null);
@@ -146,6 +188,7 @@ export function WalletProvider({ children }: { children: ReactNode }) {
setSessionWallet(null);
}
setAddress(connected);
+ setPasskeyWallet(null);
try {
const { networkPassphrase } = await kit.getNetwork();
setWalletNetworkPassphrase(networkPassphrase);
@@ -156,18 +199,14 @@ export function WalletProvider({ children }: { children: ReactNode }) {
try {
await signIn(connected);
} catch (err) {
- // Connected, but not signed in to the backend. Pages that need a
- // session call ensureSession() again.
setError(describeError(err).message);
}
} else {
setSessionWallet(connected);
}
- // Only a connect the user just completed in this tab redirects.
router.push("/markets");
} catch (err) {
const described = describeError(err);
- // Closing the picker is not an error worth showing.
if (described.kind !== "rejected" && !/closed/i.test(String((err as { message?: string })?.message))) {
setError(described.message);
}
@@ -176,35 +215,92 @@ export function WalletProvider({ children }: { children: ReactNode }) {
}
}, [kit, router, signIn]);
- const disconnect = useCallback(async () => {
+ const connectPasskey = useCallback(async () => {
+ setIsConnecting(true);
+ setError(null);
try {
- await kit?.disconnect();
+ const res = await connectPasskeyWallet();
+ const data: StoredPasskeyWallet = { address: res.address, credentialId: res.credentialId, network: NETWORK_PASSPHRASE };
+ setPasskeyWallet(data);
+ setAddress(res.address);
+ setWalletNetworkPassphrase(NETWORK_PASSPHRASE);
+ router.push("/markets");
+ } catch (err) {
+ const described = describeError(err, "marketCore", address ?? undefined);
+ if (described.kind !== "rejected") setError(described.message);
} finally {
- setAddress(null);
- setWalletNetworkPassphrase(null);
- clearAuthSession();
- setSessionWallet(null);
- queryClient.removeQueries({ queryKey: ["stellar"] });
+ setIsConnecting(false);
}
- }, [kit, queryClient]);
+ }, [address, router]);
+
+ const createPasskey = useCallback(
+ async (opts: { name: string }) => {
+ setIsConnecting(true);
+ setError(null);
+ try {
+ const res = await createPasskeyWallet(opts);
+ const data: StoredPasskeyWallet = { address: res.address, credentialId: res.credentialId, network: NETWORK_PASSPHRASE };
+ setPasskeyWallet(data);
+ setAddress(res.address);
+ setWalletNetworkPassphrase(NETWORK_PASSPHRASE);
+ router.push("/markets");
+ } catch (err) {
+ const described = describeError(err, "marketCore", address ?? undefined);
+ if (described.kind !== "rejected") setError(described.message);
+ } finally {
+ setIsConnecting(false);
+ }
+ },
+ [address, router],
+ );
+
+ const disconnect = useCallback(async () => {
+ if (address?.startsWith("C")) {
+ if (
+ typeof window !== "undefined" &&
+ !window.confirm("Disconnect passkey wallet? This will remove the active passkey session in this browser.")
+ ) {
+ return;
+ }
+ clearStoredPasskeyWallet();
+ setPasskeyWallet(null);
+ } else {
+ try {
+ await kit?.disconnect();
+ } catch {
+ // Nothing to disconnect
+ }
+ }
+ setAddress(null);
+ setWalletNetworkPassphrase(null);
+ clearAuthSession();
+ setSessionWallet(null);
+ queryClient.removeQueries({ queryKey: ["stellar"] });
+ }, [address, kit, queryClient]);
+
+ const isPasskey = Boolean(address?.startsWith("C"));
const value: WalletContextValue = {
address,
isConnected: Boolean(address),
isConnecting,
+ isPasskey,
walletNetworkPassphrase,
- isWrongNetwork: Boolean(walletNetworkPassphrase) && walletNetworkPassphrase !== NETWORK_PASSPHRASE,
+ isWrongNetwork: Boolean(walletNetworkPassphrase) && walletNetworkPassphrase !== NETWORK_PASSPHRASE && !isPasskey,
signer,
isAuthenticated: Boolean(address) && sessionWallet === address,
error,
openModal,
+ ...(EXPERIMENTAL_PASSKEYS ? { connectPasskey, createPasskey } : {}),
ensureSession,
disconnect,
};
return (
- {children}
+
+ {children}
+
);
}
diff --git a/lib/stellar/__tests__/contract-submit.test.ts b/lib/stellar/__tests__/contract-submit.test.ts
new file mode 100644
index 0000000..f92e3f8
--- /dev/null
+++ b/lib/stellar/__tests__/contract-submit.test.ts
@@ -0,0 +1,117 @@
+import { describe, expect, it, vi } from "vitest";
+import { Ok, type AssembledTransaction, type Result } from "@stellar/stellar-sdk/contract";
+import { submitAsContract, type RpcServerLike } from "../contract-submit";
+import { UserFacingError } from "../errors";
+import type { Signer } from "../clients";
+
+describe("submitAsContract", () => {
+ const traderAddress = "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM";
+
+ const mockContractSigner: Extract = {
+ kind: "contract",
+ address: traderAddress,
+ signAuthEntry: vi.fn().mockImplementation(async (entry) => entry),
+ submit: vi.fn().mockResolvedValue({ hash: "tx_hash_123" }),
+ };
+
+ const createMockTx = (opts?: {
+ result?: unknown;
+ simulationError?: string;
+ neededSigners?: string[];
+ returnValue?: unknown;
+ }) => {
+ const needed = opts?.neededSigners ?? [traderAddress];
+ const signAuthEntriesSpy = vi.fn().mockImplementation(async ({ authorizeEntry }: any) => {
+ // Simulate calling the authorizeEntry callback
+ await authorizeEntry({ rootInvocation: () => ({}) });
+ });
+ const simulateSpy = vi.fn().mockResolvedValue({});
+ const buildSpy = vi.fn().mockReturnValue({ toXDR: () => "mock_tx_xdr" });
+
+ const tx = {
+ result: opts?.result !== undefined ? opts.result : new Ok(100n),
+ simulation: opts?.simulationError ? { error: opts.simulationError } : undefined,
+ needsNonInvokerSigningBy: vi.fn().mockResolvedValue(needed),
+ signAuthEntries: signAuthEntriesSpy,
+ simulate: simulateSpy,
+ build: buildSpy,
+ options: {
+ parseResultXdr: (v: any) => v,
+ },
+ } as unknown as AssembledTransaction>;
+
+ return { tx, signAuthEntriesSpy, simulateSpy, buildSpy };
+ };
+
+ it("refuses when needsNonInvokerSigningBy lists an unexpected address", async () => {
+ const unexpectedAddress = "CBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB2KM";
+ const { tx } = createMockTx({
+ neededSigners: [traderAddress, unexpectedAddress],
+ });
+
+ await expect(submitAsContract(tx, mockContractSigner, "marketCore")).rejects.toThrow(
+ UserFacingError,
+ );
+ });
+
+ it("refuses when needsNonInvokerSigningBy does not include trader", async () => {
+ const otherAddress = "CBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB2KM";
+ const { tx } = createMockTx({
+ neededSigners: [otherAddress],
+ });
+
+ await expect(submitAsContract(tx, mockContractSigner, "marketCore")).rejects.toThrow(
+ UserFacingError,
+ );
+ });
+
+ it("surfaces simulation failures before calling signAuthEntries or submit", async () => {
+ const failingTx = {
+ get result() {
+ throw new Error("HostError: Error(Contract, #18)");
+ },
+ simulation: { error: "HostError: Error(Contract, #18)" },
+ needsNonInvokerSigningBy: vi.fn(),
+ } as unknown as AssembledTransaction>;
+
+ await expect(submitAsContract(failingTx, mockContractSigner, "marketCore")).rejects.toThrow(
+ UserFacingError,
+ );
+ expect(mockContractSigner.signAuthEntry).not.toHaveBeenCalled();
+ expect(mockContractSigner.submit).not.toHaveBeenCalled();
+ });
+
+ it("signs auth entries, re-simulates, submits via relayer, and polls until SUCCESS", async () => {
+ const { tx, signAuthEntriesSpy, simulateSpy, buildSpy } = createMockTx();
+
+ let pollCount = 0;
+ const mockRpcServer: RpcServerLike = {
+ getLatestLedger: vi.fn().mockResolvedValue({ sequence: 500 }),
+ getTransaction: vi.fn().mockImplementation(async () => {
+ pollCount++;
+ if (pollCount < 2) {
+ return { status: "PENDING" } as any;
+ }
+ return {
+ status: "SUCCESS",
+ returnValue: new Ok(100n),
+ } as any;
+ }),
+ };
+
+ const result = await submitAsContract(tx, mockContractSigner, "marketCore", {
+ rpcServer: mockRpcServer,
+ pollIntervalMs: 10,
+ });
+
+ expect(signAuthEntriesSpy).toHaveBeenCalled();
+ expect(simulateSpy).toHaveBeenCalled();
+ expect(buildSpy).toHaveBeenCalled();
+ expect(mockContractSigner.submit).toHaveBeenCalled();
+ expect(mockRpcServer.getTransaction).toHaveBeenCalledWith("tx_hash_123");
+ expect(result).toEqual({
+ value: 100n,
+ txHash: "tx_hash_123",
+ });
+ });
+});
diff --git a/lib/stellar/__tests__/errors.test.ts b/lib/stellar/__tests__/errors.test.ts
index c2c333e..ea54f11 100644
--- a/lib/stellar/__tests__/errors.test.ts
+++ b/lib/stellar/__tests__/errors.test.ts
@@ -1,5 +1,6 @@
import { describe, expect, it } from "vitest";
-import { describeError } from "../errors";
+import { xdr, type rpc } from "@stellar/stellar-sdk";
+import { describeError, describeSubmission } from "../errors";
describe("describeError", () => {
it("maps market-core contract errors by code", () => {
@@ -26,6 +27,18 @@ describe("describeError", () => {
// A SAC failure inside market_core.buy carries the token's own code.
expect(describeError("Error(Contract, #10) ... balance is not sufficient to spend").kind).toBe("insufficient-balance");
expect(describeError("Error(Contract, #13) ... trustline entry is missing for account").kind).toBe("no-trustline");
+ expect(describeError("Error(Contract, #13) ... trustline entry is missing", "marketCore", "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM").kind).toBe("insufficient-balance");
+ expect(describeError("Error(Contract, #13) ... trustline entry is missing", "marketCore", "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM").message).toBe("This wallet doesn't hold USDC yet.");
+ });
+
+ it("maps op_low_reserve and txInsufficientBalance to insufficient-xlm while preserving USDC balance mapping", () => {
+ expect(describeError("op_low_reserve").kind).toBe("insufficient-xlm");
+ expect(describeError("txInsufficientBalance").kind).toBe("insufficient-xlm");
+ expect(describeError("tx_insufficient_balance").kind).toBe("insufficient-xlm");
+ // USDC balance still wins
+ expect(describeError("balance is not sufficient to spend").kind).toBe("insufficient-balance");
+ expect(describeError("insufficient balance").kind).toBe("insufficient-balance");
+ expect(describeError("op_underfunded").kind).toBe("insufficient-balance");
});
it("falls back to a readable message", () => {
@@ -33,3 +46,74 @@ describe("describeError", () => {
expect(describeError(42).message).toMatch(/something went wrong/i);
});
});
+
+describe("describeSubmission", () => {
+ it("maps TRY_AGAIN_LATER and DUPLICATE", () => {
+ const tryAgain = describeSubmission({
+ status: "TRY_AGAIN_LATER",
+ hash: "1234",
+ latestLedger: 10,
+ latestLedgerCloseTime: 100,
+ } as rpc.Api.SendTransactionResponse);
+ expect(tryAgain.kind).toBe("submission");
+ expect(tryAgain.submission).toBe("try-again-later");
+
+ const dup = describeSubmission({
+ status: "DUPLICATE",
+ hash: "1234",
+ latestLedger: 10,
+ latestLedgerCloseTime: 100,
+ } as rpc.Api.SendTransactionResponse);
+ expect(dup.kind).toBe("submission");
+ expect(dup.submission).toBe("duplicate");
+ });
+
+ it("maps ERROR result codes txBadSeq, txInsufficientFee, txTooLate, txInsufficientBalance", () => {
+ const makeError = (resultArm: () => xdr.TransactionResultResult) =>
+ ({
+ status: "ERROR",
+ hash: "1234",
+ latestLedger: 10,
+ latestLedgerCloseTime: 100,
+ errorResult: new xdr.TransactionResult({
+ feeCharged: xdr.Int64.fromString("100"),
+ result: resultArm(),
+ ext: new xdr.TransactionResultExt(0),
+ }),
+ }) as unknown as rpc.Api.SendTransactionResponse;
+
+ const badSeq = describeSubmission(makeError(() => xdr.TransactionResultResult.txBadSeq()));
+ expect(badSeq.resultCode).toBe("txBadSeq");
+ expect(badSeq.submission).toBe("rejected-by-network");
+
+ const lowFee = describeSubmission(makeError(() => xdr.TransactionResultResult.txInsufficientFee()));
+ expect(lowFee.resultCode).toBe("txInsufficientFee");
+
+ const tooLate = describeSubmission(makeError(() => xdr.TransactionResultResult.txTooLate()));
+ expect(tooLate.resultCode).toBe("txTooLate");
+
+ const noXlm = describeSubmission(makeError(() => xdr.TransactionResultResult.txInsufficientBalance()));
+ expect(noXlm.kind).toBe("insufficient-xlm");
+ expect(noXlm.resultCode).toBe("txInsufficientBalance");
+ });
+
+ it("falls through to contract errors on txFailed", () => {
+ const failedContract = {
+ status: "ERROR",
+ hash: "1234",
+ latestLedger: 10,
+ latestLedgerCloseTime: 100,
+ errorResult: new xdr.TransactionResult({
+ feeCharged: xdr.Int64.fromString("100"),
+ result: xdr.TransactionResultResult.txFailed([]),
+ ext: new xdr.TransactionResultExt(0),
+ }),
+ message: "HostError: Error(Contract, #12)",
+ } as unknown as rpc.Api.SendTransactionResponse;
+
+ const result = describeSubmission(failedContract, "marketCore");
+ expect(result.code).toBe("SlippageExceeded");
+ expect(result.resultCode).toBe("txFailed");
+ expect(result.submission).toBe("rejected-by-network");
+ });
+});
diff --git a/lib/stellar/__tests__/fees.test.ts b/lib/stellar/__tests__/fees.test.ts
new file mode 100644
index 0000000..d82a8fa
--- /dev/null
+++ b/lib/stellar/__tests__/fees.test.ts
@@ -0,0 +1,164 @@
+import { describe, expect, it } from "vitest";
+import { xdr } from "@stellar/stellar-sdk";
+import type { AssembledTransaction } from "@stellar/stellar-sdk/contract";
+import {
+ DEFAULT_BASE_RESERVE,
+ feeBreakdown,
+ fetchBaseReserve,
+ SimulationError,
+ spendableXlm,
+} from "../fees";
+import { formatXlm } from "../units";
+import accountEntryFixture from "./fixtures/account-entry.json";
+import buySimulationFixture from "./fixtures/buy-simulation.json";
+
+describe("feeBreakdown", () => {
+ it("splits inclusion and resource fee from a recorded simulation", () => {
+ const txData = xdr.SorobanTransactionData.fromXDR(buySimulationFixture.transactionDataXdr, "base64");
+ const fakeTx = {
+ built: { fee: buySimulationFixture.fee },
+ simulation: {
+ minResourceFee: buySimulationFixture.minResourceFee,
+ transactionData: {
+ build: () => txData,
+ },
+ },
+ } as unknown as AssembledTransaction;
+
+ const breakdown = feeBreakdown(fakeTx);
+
+ expect(breakdown.totalFee).toBe(50_000n);
+ expect(breakdown.resourceFee).toBe(35_000n);
+ expect(breakdown.inclusionFee).toBe(15_000n);
+ expect(breakdown.minResourceFee).toBe(25_000n);
+ expect(breakdown.resources).toEqual({
+ instructions: 450_000,
+ readBytes: 1200,
+ writeBytes: 640,
+ readEntries: 1,
+ writeEntries: 1,
+ });
+ });
+
+ it("keeps values as bigint", () => {
+ const txData = xdr.SorobanTransactionData.fromXDR(buySimulationFixture.transactionDataXdr, "base64");
+ const fakeTx = {
+ built: { fee: "10000000" },
+ simulation: {
+ minResourceFee: "2000000",
+ transactionData: txData,
+ },
+ } as unknown as AssembledTransaction;
+
+ const breakdown = feeBreakdown(fakeTx);
+ expect(typeof breakdown.totalFee).toBe("bigint");
+ expect(typeof breakdown.resourceFee).toBe("bigint");
+ expect(typeof breakdown.inclusionFee).toBe("bigint");
+ expect(typeof breakdown.minResourceFee).toBe("bigint");
+ });
+
+ it("throws SimulationError on simulation error or restore response", () => {
+ const errTx = {
+ built: { fee: "100" },
+ simulation: { error: "HostError: Error(Contract, #1)" },
+ } as unknown as AssembledTransaction;
+ expect(() => feeBreakdown(errTx)).toThrow(SimulationError);
+
+ const restoreTx = {
+ built: { fee: "100" },
+ simulation: { restorePreamble: {} },
+ } as unknown as AssembledTransaction;
+ expect(() => feeBreakdown(restoreTx)).toThrow(SimulationError);
+ });
+});
+
+describe("spendableXlm", () => {
+ it("uses 2 + subentries base reserves", () => {
+ const entry = new xdr.AccountEntry({
+ accountId: xdr.PublicKey.publicKeyTypeEd25519(Buffer.alloc(32)),
+ balance: xdr.Int64.fromString("100000000"), // 10 XLM
+ seqNum: xdr.Int64.fromString("1"),
+ numSubEntries: 3,
+ inflationDest: null,
+ flags: 0,
+ homeDomain: "",
+ thresholds: Buffer.from([1, 1, 1, 1]),
+ signers: [],
+ ext: new xdr.AccountEntryExt(0),
+ });
+
+ const baseReserve = 5_000_000n; // 0.5 XLM
+ const res = spendableXlm(entry, baseReserve);
+
+ // minBalance = (2 + 3) * 0.5 XLM = 2.5 XLM = 25,000,000 stroops
+ expect(res.minBalance).toBe(25_000_000n);
+ expect(res.sellingLiabilities).toBe(0n);
+ expect(res.spendable).toBe(75_000_000n);
+ expect(res.subentries).toBe(3);
+ expect(res.sponsoring).toBe(0);
+ expect(res.sponsored).toBe(0);
+ });
+
+ it("accounts for sponsoring and sponsored counts", () => {
+ const entry = xdr.AccountEntry.fromXDR(accountEntryFixture.accountEntryXdr, "base64");
+ const baseReserve = 5_000_000n;
+ const res = spendableXlm(entry, baseReserve);
+
+ // From fixture: balance = 100_000_000n, subentries = 2, sponsoring = 2, sponsored = 1, sellingLiabilities = 5_000_000n
+ // minBalance = (2 + 2 + 2 - 1) * 5_000_000 = 5 * 5_000_000 = 25_000_000n
+ expect(res.minBalance).toBe(25_000_000n);
+ expect(res.sellingLiabilities).toBe(5_000_000n);
+ // spendable = 100_000_000 - 25_000_000 - 5_000_000 = 70_000_000n
+ expect(res.spendable).toBe(70_000_000n);
+ expect(res.sponsoring).toBe(2);
+ expect(res.sponsored).toBe(1);
+ expect(res.subentries).toBe(2);
+ });
+
+ it("subtracts selling liabilities and floors at zero", () => {
+ const entry = new xdr.AccountEntry({
+ accountId: xdr.PublicKey.publicKeyTypeEd25519(Buffer.alloc(32)),
+ balance: xdr.Int64.fromString("10000000"), // 1 XLM
+ seqNum: xdr.Int64.fromString("1"),
+ numSubEntries: 2,
+ inflationDest: null,
+ flags: 0,
+ homeDomain: "",
+ thresholds: Buffer.from([1, 1, 1, 1]),
+ signers: [],
+ ext: new xdr.AccountEntryExt(
+ 1,
+ new xdr.AccountEntryExtensionV1({
+ liabilities: new xdr.Liabilities({
+ buying: xdr.Int64.fromString("0"),
+ selling: xdr.Int64.fromString("20000000"), // 2 XLM liabilities
+ }),
+ ext: new xdr.AccountEntryExtensionV1Ext(0),
+ }),
+ ),
+ });
+
+ const baseReserve = 5_000_000n;
+ const res = spendableXlm(entry, baseReserve);
+ // minBalance = (2 + 2) * 5_000_000 = 20_000_000n
+ // raw spendable = 10_000_000 - 20_000_000 - 20_000_000 = -30_000_000n -> floored to 0
+ expect(res.spendable).toBe(0n);
+ });
+});
+
+describe("base reserve reading and formatXlm", () => {
+ it("falls back to DEFAULT_BASE_RESERVE when header XDR is missing", async () => {
+ const fakeServer = {
+ getLatestLedger: async () => ({ sequence: 100 }),
+ };
+ const reserve = await fetchBaseReserve(fakeServer as unknown as import("@stellar/stellar-sdk").rpc.Server);
+ expect(reserve).toBe(DEFAULT_BASE_RESERVE);
+ expect(reserve).toBe(5_000_000n);
+ });
+
+ it("formatXlm formats stroops with 7 decimals and grouping", () => {
+ expect(formatXlm(12_345_600n)).toBe("1.23456");
+ expect(formatXlm(99_981_000_000n, { grouping: true })).toBe("9,998.1");
+ expect(formatXlm(123_456n)).toBe("0.0123456");
+ });
+});
diff --git a/lib/stellar/__tests__/fixtures/account-entry.json b/lib/stellar/__tests__/fixtures/account-entry.json
new file mode 100644
index 0000000..2147ac7
--- /dev/null
+++ b/lib/stellar/__tests__/fixtures/account-entry.json
@@ -0,0 +1,3 @@
+{
+ "accountEntryXdr": "AAAAAJRaDkIo49gtR0RlcC/307yxKlmVvZpSs7J10S3mGz9YAAAAAAX14QAAAAAAAAAAAQAAAAIAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAEAAAAAAAAAAAAAAAAATEtAAAAAAgAAAAEAAAACAAAAAAAAAAA="
+}
diff --git a/lib/stellar/__tests__/fixtures/buy-simulation.json b/lib/stellar/__tests__/fixtures/buy-simulation.json
new file mode 100644
index 0000000..3cf0893
--- /dev/null
+++ b/lib/stellar/__tests__/fixtures/buy-simulation.json
@@ -0,0 +1,5 @@
+{
+ "minResourceFee": "25000",
+ "transactionDataXdr": "AAAAAAAAAAEAAAAGAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAEAAAABAAAABgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAABAAAAAQAG3dAAAASwAAACgAAAAAAAAIi4",
+ "fee": "50000"
+}
diff --git a/lib/stellar/__tests__/passkey.test.ts b/lib/stellar/__tests__/passkey.test.ts
new file mode 100644
index 0000000..5aeff28
--- /dev/null
+++ b/lib/stellar/__tests__/passkey.test.ts
@@ -0,0 +1,204 @@
+import { describe, expect, it } from "vitest";
+import { Buffer } from "buffer";
+import {
+ Address,
+ hash,
+ xdr,
+} from "@stellar/stellar-sdk";
+import {
+ SECP256R1_N,
+ SECP256R1_HALF_N,
+ derToRawSignature,
+ decodeCoseKey,
+ extractPublicKeyFromAttestation,
+ computeAuthPayloadHash,
+ buildPasskeySignatureScVal,
+} from "../passkey";
+import { describeError } from "../errors";
+import { TESTNET_PASSPHRASE } from "../config";
+
+describe("passkey: DER to raw signature with low-S normalization", () => {
+ function makeDer(rBytes: Uint8Array, sBytes: Uint8Array): Uint8Array {
+ const totalLen = 2 + rBytes.length + 2 + sBytes.length;
+ const der = new Uint8Array(2 + totalLen);
+ der[0] = 0x30;
+ der[1] = totalLen;
+ der[2] = 0x02;
+ der[3] = rBytes.length;
+ der.set(rBytes, 4);
+ const sOffset = 4 + rBytes.length;
+ der[sOffset] = 0x02;
+ der[sOffset + 1] = sBytes.length;
+ der.set(sBytes, sOffset + 2);
+ return der;
+ }
+
+ it("converts a standard low-S DER signature to 64 bytes raw", () => {
+ const r = new Uint8Array(32).fill(0x11);
+ const s = new Uint8Array(32).fill(0x22);
+ // Ensure s is low-S (0x2222... is well below N/2)
+ const der = makeDer(r, s);
+
+ const raw = derToRawSignature(der);
+ expect(raw.length).toBe(64);
+ expect(raw.slice(0, 32)).toEqual(r);
+ expect(raw.slice(32, 64)).toEqual(s);
+ });
+
+ it("handles ASN.1 leading zeroes (33-byte signed positive integers)", () => {
+ // ASN.1 puts a 0x00 prefix if highest bit is set
+ const r = new Uint8Array(33);
+ r[0] = 0x00;
+ r.fill(0x88, 1);
+
+ const s = new Uint8Array(32).fill(0x05);
+ const der = makeDer(r, s);
+
+ const raw = derToRawSignature(der);
+ expect(raw.length).toBe(64);
+ expect(raw.slice(0, 32)).toEqual(r.slice(1));
+ expect(raw.slice(32, 64)).toEqual(s);
+ });
+
+ it("normalizes a high-S signature to canonical low-S (s' = N - s)", () => {
+ const r = new Uint8Array(32).fill(0x01);
+
+ // Construct an s > N/2
+ const highSVal = SECP256R1_HALF_N + 1000n;
+ const expectedLowSVal = SECP256R1_N - highSVal;
+
+ const sHex = highSVal.toString(16).padStart(64, "0");
+ const sBytes = Buffer.from(sHex, "hex");
+ const der = makeDer(r, sBytes);
+
+ const raw = derToRawSignature(der);
+ expect(raw.length).toBe(64);
+
+ const resultSBig = BigInt("0x" + Buffer.from(raw.slice(32, 64)).toString("hex"));
+ expect(resultSBig).toBe(expectedLowSVal);
+ expect(resultSBig).toBeLessThanOrEqual(SECP256R1_HALF_N);
+ });
+});
+
+describe("passkey: COSE public key extraction", () => {
+ it("decodes a valid CBOR COSE key into an uncompressed P-256 public key", () => {
+ const xCoord = new Uint8Array(32).fill(0xaa);
+ const yCoord = new Uint8Array(32).fill(0xbb);
+
+ // Build minimalist CBOR map: { 1: 2, 3: -7, -1: 1, -2: h'aa..', -3: h'bb..' }
+ // 0xa5 = map of 5 items
+ // 0x01, 0x02 (1: 2)
+ // 0x03, 0x26 (3: -7)
+ // 0x20, 0x01 (-1: 1)
+ // 0x21, 0x58, 0x20, ... (-2: 32 bytes)
+ // 0x22, 0x58, 0x20, ... (-3: 32 bytes)
+ const cborParts: number[] = [
+ 0xa5,
+ 0x01, 0x02,
+ 0x03, 0x26,
+ 0x20, 0x01,
+ 0x21, 0x58, 0x20, ...Array.from(xCoord),
+ 0x22, 0x58, 0x20, ...Array.from(yCoord),
+ ];
+ const coseKeyBytes = new Uint8Array(cborParts);
+
+ const decoded = decodeCoseKey(coseKeyBytes);
+ expect(decoded.uncompressed.length).toBe(65);
+ expect(decoded.uncompressed[0]).toBe(0x04);
+ expect(decoded.uncompressed.slice(1, 33)).toEqual(xCoord);
+ expect(decoded.uncompressed.slice(33, 65)).toEqual(yCoord);
+
+ const fromAttestation = extractPublicKeyFromAttestation(coseKeyBytes);
+ expect(fromAttestation).toEqual(decoded.uncompressed);
+ });
+});
+
+describe("passkey: authorization payload hash", () => {
+ it("matches SDK authorizeEntry preimage for an address credentials entry", () => {
+ const dummyContract = "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM";
+ const credAddress = new Address(dummyContract).toScAddress();
+ const nonce = new xdr.Int64([0, 12345]);
+
+ const credentials = new xdr.SorobanAddressCredentials({
+ address: credAddress,
+ nonce,
+ signatureExpirationLedger: 500,
+ signature: xdr.ScVal.scvVoid(),
+ });
+
+ const rootInvocation = new xdr.SorobanAuthorizedInvocation({
+ function: xdr.SorobanAuthorizedFunction.sorobanAuthorizedFunctionTypeContractFn(
+ new xdr.SorobanAuthorizedContractFunction({
+ contractAddress: credAddress,
+ functionName: "test_fn",
+ args: [],
+ }),
+ ),
+ subInvocations: [],
+ });
+
+ const entry = new xdr.SorobanAuthorizationEntry({
+ credentials: xdr.SorobanCredentials.sorobanCredentialsAddress(credentials),
+ rootInvocation,
+ });
+
+ const validUntilLedger = 600;
+ const computedHash = computeAuthPayloadHash(entry, validUntilLedger, TESTNET_PASSPHRASE);
+
+ // Verify against manual HashIdPreimage calculation
+ const networkId = hash(Buffer.from(TESTNET_PASSPHRASE));
+ const expectedPreimage = xdr.HashIdPreimage.envelopeTypeSorobanAuthorization(
+ new xdr.HashIdPreimageSorobanAuthorization({
+ networkId,
+ nonce,
+ signatureExpirationLedger: validUntilLedger,
+ invocation: rootInvocation,
+ }),
+ );
+ const expectedHash = hash(expectedPreimage.toXDR());
+
+ expect(computedHash).toEqual(expectedHash);
+ });
+});
+
+describe("passkey: signature ScVal packaging", () => {
+ it("packages authenticatorData, clientDataJSON, and rawSignature into an ScVal map", () => {
+ const authData = new Uint8Array([1, 2, 3]);
+ const clientData = new Uint8Array([4, 5, 6]);
+ const rawSig = new Uint8Array(64).fill(7);
+
+ const scVal = buildPasskeySignatureScVal(authData, clientData, rawSig);
+ expect(scVal.switch().name).toBe("scvMap");
+ });
+});
+
+describe("errors: contract trader and passkey error descriptions", () => {
+ const contractTrader = "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM";
+ const accountTrader = "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H";
+
+ it("maps missing trustline to wallet-friendly message for contract traders", () => {
+ const contractErr = describeError("trustline entry is missing", "marketCore", contractTrader);
+ expect(contractErr.message).toBe("This wallet doesn't hold USDC yet.");
+ expect(contractErr.kind).toBe("insufficient-balance");
+
+ const accountErr = describeError("trustline entry is missing", "marketCore", accountTrader);
+ expect(accountErr.message).toBe("Your wallet has no USDC trustline. Add the USDC asset in your wallet first.");
+ expect(accountErr.kind).toBe("no-trustline");
+ });
+
+ it("maps WebAuthn NotAllowedError to rejected", () => {
+ const err = describeError(new Error("NotAllowedError: The operation was cancelled"), "marketCore", contractTrader);
+ expect(err.kind).toBe("rejected");
+ expect(err.message).toBe("You cancelled the request in your wallet.");
+ });
+
+ it("maps __check_auth signature failure and expiration", () => {
+ const sigErr = describeError("HostError: check_auth failed signature invalid", "marketCore", contractTrader);
+ expect(sigErr.kind).toBe("contract");
+ expect(sigErr.message).toBe("The passkey signature was rejected or is invalid.");
+
+ const expErr = describeError("HostError: signature expired", "marketCore", contractTrader);
+ expect(expErr.kind).toBe("contract");
+ expect(expErr.message).toBe("The passkey authorization has expired. Please try again.");
+ });
+});
diff --git a/lib/stellar/__tests__/reliability.test.ts b/lib/stellar/__tests__/reliability.test.ts
new file mode 100644
index 0000000..4277676
--- /dev/null
+++ b/lib/stellar/__tests__/reliability.test.ts
@@ -0,0 +1,39 @@
+import { describe, expect, it } from "vitest";
+import { buyBreakdown } from "../buy-breakdown";
+import { isArchivedStateError, simulateWithRestore } from "../archival";
+import { isExpiredTransaction, isFeeSurge, transactionRecoveryAdvice } from "../transaction-recovery";
+
+describe("buy breakdown", () => {
+ it("reports fee, net collateral and price impact from FPMM math", () => {
+ const result = buyBreakdown(1_000_000n, 1_000_000n, 100_000n, 100n);
+ expect(result.fee).toBe(1_000n);
+ expect(result.net).toBe(99_000n);
+ expect(result.sharesOut).toBeGreaterThan(0n);
+ expect(result.priceImpactBps).toBeGreaterThan(0n);
+ });
+});
+
+describe("transaction recovery", () => {
+ it("classifies fee surges and expiry with actionable advice", () => {
+ expect(isFeeSurge("tx_bad_seq")).toBe(true);
+ expect(transactionRecoveryAdvice("tx_bad_seq").kind).toBe("fee-bump");
+ expect(isExpiredTransaction("tx_too_late")).toBe(true);
+ expect(transactionRecoveryAdvice("tx_too_late").kind).toBe("rebuild");
+ });
+});
+
+describe("archived state recovery", () => {
+ it("restores and rebuilds when simulation exposes an archived entry", async () => {
+ let attempts = 0;
+ const build = async () => {
+ attempts += 1;
+ if (attempts === 1) throw new Error("archived ledger entry");
+ return {} as never;
+ };
+ // Build failures occur before an assembled transaction exists, so callers
+ // can also use this predicate around their restore endpoint.
+ expect(isArchivedStateError("archived ledger entry")).toBe(true);
+ await expect(simulateWithRestore(build, async () => undefined)).resolves.toBeDefined();
+ expect(attempts).toBe(2);
+ });
+});
diff --git a/lib/stellar/__tests__/tx-lifecycle.test.ts b/lib/stellar/__tests__/tx-lifecycle.test.ts
new file mode 100644
index 0000000..79c252b
--- /dev/null
+++ b/lib/stellar/__tests__/tx-lifecycle.test.ts
@@ -0,0 +1,275 @@
+import { describe, expect, it, vi } from "vitest";
+import { xdr, type rpc } from "@stellar/stellar-sdk";
+import type { AssembledTransaction } from "@stellar/stellar-sdk/contract";
+import { TxLifecycle, type TxPhase } from "../tx-lifecycle";
+
+function makeFakeTx(opts: {
+ hashHex?: string;
+ maxTime?: number;
+ simResult?: unknown;
+ signError?: Error;
+}) {
+ const hash = Buffer.from(opts.hashHex ?? "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "hex");
+ return {
+ result: opts.simResult ?? 100n,
+ simulation: {},
+ sign: async () => {
+ if (opts.signError) throw opts.signError;
+ },
+ signed: {
+ hash: () => hash,
+ timeBounds: opts.maxTime ? { maxTime: opts.maxTime } : undefined,
+ },
+ } as unknown as AssembledTransaction;
+}
+
+describe("TxLifecycle", () => {
+ it("emits phases in order for a successful buy and exposes hash from submitting onwards", async () => {
+ const phases: TxPhase[] = [];
+ const hashHex = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789";
+
+ const fakeServer = {
+ sendTransaction: vi.fn().mockResolvedValue({ status: "PENDING" }),
+ getTransaction: vi.fn().mockResolvedValue({
+ status: "SUCCESS",
+ ledger: 1234,
+ returnValue: undefined,
+ }),
+ };
+
+ const runner = new TxLifecycle({
+ server: fakeServer as unknown as rpc.Server,
+ contract: "marketCore",
+ pollIntervalMs: 1,
+ });
+
+ runner.subscribe(() => {
+ phases.push(runner.getSnapshot());
+ });
+
+ const tx = makeFakeTx({ hashHex });
+ const result = await runner.run(tx, () => 500n);
+
+ expect(result.value).toBe(500n);
+ expect(result.txHash).toBe(hashHex);
+
+ const phaseNames = phases.map((p) => p.name);
+ expect(phaseNames).toEqual(["simulating", "awaiting-signature", "submitting", "pending", "confirmed"]);
+
+ // Hash is present from submitting onwards
+ const submitting = phases.find((p) => p.name === "submitting");
+ expect((submitting as { hash: string }).hash).toBe(hashHex);
+
+ const pending = phases.find((p) => p.name === "pending");
+ expect((pending as { hash: string }).hash).toBe(hashHex);
+
+ const confirmed = phases.find((p) => p.name === "confirmed");
+ expect((confirmed as { hash: string }).hash).toBe(hashHex);
+ });
+
+ it("maps TRY_AGAIN_LATER to submission try-again-later", async () => {
+ const fakeServer = {
+ sendTransaction: vi.fn().mockResolvedValue({ status: "TRY_AGAIN_LATER" }),
+ };
+
+ const runner = new TxLifecycle({
+ server: fakeServer as unknown as rpc.Server,
+ contract: "marketCore",
+ });
+
+ const tx = makeFakeTx({});
+ await expect(runner.run(tx, () => null)).rejects.toThrow();
+
+ const snapshot = runner.getSnapshot();
+ expect(snapshot.name).toBe("failed");
+ if (snapshot.name === "failed") {
+ expect(snapshot.error.kind).toBe("submission");
+ expect(snapshot.error.submission).toBe("try-again-later");
+ }
+ });
+
+ it("treats DUPLICATE as pending and polls the same hash", async () => {
+ const fakeServer = {
+ sendTransaction: vi.fn().mockResolvedValue({ status: "DUPLICATE" }),
+ getTransaction: vi.fn().mockResolvedValue({
+ status: "SUCCESS",
+ ledger: 99,
+ returnValue: undefined,
+ }),
+ };
+
+ const runner = new TxLifecycle({
+ server: fakeServer as unknown as rpc.Server,
+ contract: "marketCore",
+ pollIntervalMs: 1,
+ });
+
+ const tx = makeFakeTx({});
+ const res = await runner.run(tx, () => 42n);
+ expect(res.value).toBe(42n);
+ expect(fakeServer.getTransaction).toHaveBeenCalled();
+ });
+
+ it("maps ERROR txBadSeq and txInsufficientFee result codes", async () => {
+ const makeServer = (arm: () => xdr.TransactionResultResult) => ({
+ sendTransaction: vi.fn().mockResolvedValue({
+ status: "ERROR",
+ errorResult: new xdr.TransactionResult({
+ feeCharged: xdr.Int64.fromString("0"),
+ result: arm(),
+ ext: new xdr.TransactionResultExt(0),
+ }),
+ }),
+ });
+
+ const badSeqServer = makeServer(() => xdr.TransactionResultResult.txBadSeq());
+ const runner1 = new TxLifecycle({
+ server: badSeqServer as unknown as rpc.Server,
+ contract: "marketCore",
+ });
+ await expect(runner1.run(makeFakeTx({}), () => null)).rejects.toThrow();
+ expect(runner1.getSnapshot()).toMatchObject({
+ name: "failed",
+ error: { resultCode: "txBadSeq" },
+ });
+
+ const lowFeeServer = makeServer(() => xdr.TransactionResultResult.txInsufficientFee());
+ const runner2 = new TxLifecycle({
+ server: lowFeeServer as unknown as rpc.Server,
+ contract: "marketCore",
+ });
+ await expect(runner2.run(makeFakeTx({}), () => null)).rejects.toThrow();
+ expect(runner2.getSnapshot()).toMatchObject({
+ name: "failed",
+ error: { resultCode: "txInsufficientFee" },
+ });
+ });
+
+ it("maps FAILED with Error(Contract, #12) to SlippageExceeded", async () => {
+ const fakeServer = {
+ sendTransaction: vi.fn().mockResolvedValue({ status: "PENDING" }),
+ getTransaction: vi.fn().mockResolvedValue({
+ status: "FAILED",
+ resultXdr: "HostError: Error(Contract, #12)",
+ }),
+ };
+
+ const runner = new TxLifecycle({
+ server: fakeServer as unknown as rpc.Server,
+ contract: "marketCore",
+ pollIntervalMs: 1,
+ });
+
+ await expect(runner.run(makeFakeTx({}), () => null)).rejects.toThrow();
+ const snapshot = runner.getSnapshot();
+ expect(snapshot.name).toBe("failed");
+ if (snapshot.name === "failed") {
+ expect(snapshot.error.code).toBe("SlippageExceeded");
+ expect(snapshot.error.submission).toBe("failed-on-chain");
+ }
+ });
+
+ it("keeps polling through NOT_FOUND then confirms", async () => {
+ let callCount = 0;
+ const fakeServer = {
+ sendTransaction: vi.fn().mockResolvedValue({ status: "PENDING" }),
+ getTransaction: vi.fn().mockImplementation(async () => {
+ callCount++;
+ if (callCount < 3) {
+ return { status: "NOT_FOUND", latestLedger: 10, latestLedgerCloseTime: 1000 };
+ }
+ return { status: "SUCCESS", ledger: 11, returnValue: undefined };
+ }),
+ };
+
+ const runner = new TxLifecycle({
+ server: fakeServer as unknown as rpc.Server,
+ contract: "marketCore",
+ pollIntervalMs: 1,
+ });
+
+ const res = await runner.run(makeFakeTx({}), () => 77n);
+ expect(res.value).toBe(77n);
+ expect(callCount).toBe(3);
+ });
+
+ it("emits expired using latestLedgerCloseTime, not Date.now", async () => {
+ const fakeServer = {
+ sendTransaction: vi.fn().mockResolvedValue({ status: "PENDING" }),
+ getTransaction: vi.fn().mockResolvedValue({
+ status: "NOT_FOUND",
+ latestLedger: 50,
+ latestLedgerCloseTime: 2000, // beyond maxTime 1500
+ }),
+ };
+
+ const runner = new TxLifecycle({
+ server: fakeServer as unknown as rpc.Server,
+ contract: "marketCore",
+ pollIntervalMs: 1,
+ });
+
+ const tx = makeFakeTx({ maxTime: 1500 });
+ await expect(runner.run(tx, () => null)).rejects.toThrow();
+
+ const snapshot = runner.getSnapshot();
+ expect(snapshot.name).toBe("expired");
+ if (snapshot.name === "expired") {
+ expect(snapshot.lastLedgerSeen).toBe(50);
+ }
+ });
+
+ it("wallet rejection yields failed with kind rejected and null hash", async () => {
+ const fakeServer = {
+ sendTransaction: vi.fn(),
+ };
+
+ const runner = new TxLifecycle({
+ server: fakeServer as unknown as rpc.Server,
+ contract: "marketCore",
+ });
+
+ const tx = makeFakeTx({
+ signError: new Error("User declined transaction"),
+ });
+
+ await expect(runner.run(tx, () => null)).rejects.toThrow();
+ const snapshot = runner.getSnapshot();
+ expect(snapshot.name).toBe("failed");
+ if (snapshot.name === "failed") {
+ expect(snapshot.hash).toBeNull();
+ expect(snapshot.error.kind).toBe("rejected");
+ }
+ });
+
+ it("unsubscribe stops notifications but run() still resolves", async () => {
+ const notifications: TxPhase[] = [];
+ const fakeServer = {
+ sendTransaction: vi.fn().mockResolvedValue({ status: "PENDING" }),
+ getTransaction: vi.fn().mockResolvedValue({
+ status: "SUCCESS",
+ ledger: 10,
+ returnValue: undefined,
+ }),
+ };
+
+ const runner = new TxLifecycle({
+ server: fakeServer as unknown as rpc.Server,
+ contract: "marketCore",
+ pollIntervalMs: 1,
+ });
+
+ const unsub = runner.subscribe(() => {
+ notifications.push(runner.getSnapshot());
+ });
+
+ // Unsubscribe immediately
+ unsub();
+
+ const res = await runner.run(makeFakeTx({}), () => 123n);
+ expect(res.value).toBe(123n);
+ // notifications array received 0 updates after unsubscription
+ expect(notifications.length).toBe(0);
+ expect(runner.getSnapshot().name).toBe("confirmed");
+ });
+});
diff --git a/lib/stellar/__tests__/tx-tracker.test.ts b/lib/stellar/__tests__/tx-tracker.test.ts
new file mode 100644
index 0000000..e812fb8
--- /dev/null
+++ b/lib/stellar/__tests__/tx-tracker.test.ts
@@ -0,0 +1,199 @@
+import { describe, expect, it } from "vitest";
+import type { rpc } from "@stellar/stellar-sdk";
+import {
+ evaluateTxStatus,
+ fromRecord,
+ isValidRecord,
+ loadRecords,
+ mergeRecords,
+ saveRecords,
+ toRecord,
+ tradeInvalidationKeys,
+ type TrackedTx,
+} from "../tx-tracker-core";
+
+class FakeStorage implements Storage {
+ private store = new Map();
+ get length() {
+ return this.store.size;
+ }
+ clear(): void {
+ this.store.clear();
+ }
+ getItem(key: string): string | null {
+ return this.store.get(key) ?? null;
+ }
+ key(index: number): string | null {
+ return Array.from(this.store.keys())[index] ?? null;
+ }
+ removeItem(key: string): void {
+ this.store.delete(key);
+ }
+ setItem(key: string, value: string): void {
+ this.store.set(key, value);
+ }
+}
+
+const TEST_PASSPHRASE = "Test SDF Network ; September 2015";
+const VALID_HOLDER = "GCM7WU3RADBCIKBLGPPAEYV5WHASWMEQX6BU524QR3QFWSE7BIWCXAIF";
+const VALID_HASH_1 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+const VALID_HASH_2 = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+
+describe("tx-tracker pure functions", () => {
+ it("round-trips bigint amounts through sessionStorage strings without precision loss", () => {
+ const rawAmounts = {
+ collateralIn: 100_000_000n,
+ minSharesOut: 98_765_432n,
+ largeValue: 999_999_999_999_999_999n,
+ zero: 0n,
+ };
+
+ const serialized = toRecord(rawAmounts);
+ expect(serialized).toEqual({
+ collateralIn: "100000000",
+ minSharesOut: "98765432",
+ largeValue: "999999999999999999",
+ zero: "0",
+ });
+
+ const restored = fromRecord(serialized);
+ expect(restored).toEqual(rawAmounts);
+ });
+
+ it("drops records for a different network passphrase", () => {
+ const now = Date.now();
+ const wrongNetRecord: TrackedTx = {
+ hash: VALID_HASH_1,
+ kind: "buy",
+ holder: VALID_HOLDER,
+ marketId: "1",
+ outcome: "Yes",
+ amounts: { collateralIn: "100000000" },
+ networkPassphrase: "Public Global Stellar Network ; September 2015",
+ submittedAt: now,
+ state: "pending",
+ };
+
+ expect(isValidRecord(wrongNetRecord, TEST_PASSPHRASE, now)).toBe(false);
+
+ const storage = new FakeStorage();
+ saveRecords(storage, [wrongNetRecord]);
+ const loaded = loadRecords(storage, TEST_PASSPHRASE, now);
+ expect(loaded.length).toBe(0);
+ });
+
+ it("drops malformed and stale records", () => {
+ const now = Date.now();
+ const staleTime = now - 25 * 60 * 60 * 1000; // 25 hours old
+
+ const staleRecord: TrackedTx = {
+ hash: VALID_HASH_1,
+ kind: "buy",
+ holder: VALID_HOLDER,
+ amounts: { collateralIn: "100" },
+ networkPassphrase: TEST_PASSPHRASE,
+ submittedAt: staleTime,
+ state: "pending",
+ };
+ expect(isValidRecord(staleRecord, TEST_PASSPHRASE, now)).toBe(false);
+
+ // Malformed records
+ expect(isValidRecord({ hash: "not-a-hex" }, TEST_PASSPHRASE, now)).toBe(false);
+ expect(isValidRecord({ hash: VALID_HASH_1, kind: "unknown" }, TEST_PASSPHRASE, now)).toBe(false);
+ expect(isValidRecord({ hash: VALID_HASH_1, kind: "buy", holder: "short" }, TEST_PASSPHRASE, now)).toBe(false);
+ expect(isValidRecord(null, TEST_PASSPHRASE, now)).toBe(false);
+ });
+
+ it("merges records from two writers by hash without blind overwrite", () => {
+ const now = Date.now();
+ const writer1: TrackedTx[] = [
+ {
+ hash: VALID_HASH_1,
+ kind: "buy",
+ holder: VALID_HOLDER,
+ marketId: "1",
+ amounts: { collateralIn: "100" },
+ networkPassphrase: TEST_PASSPHRASE,
+ submittedAt: now - 1000,
+ state: "pending",
+ },
+ ];
+
+ const writer2: TrackedTx[] = [
+ {
+ hash: VALID_HASH_1,
+ kind: "buy",
+ holder: VALID_HOLDER,
+ marketId: "1",
+ amounts: { collateralIn: "100" },
+ networkPassphrase: TEST_PASSPHRASE,
+ submittedAt: now - 1000,
+ state: "confirmed",
+ ledger: 500,
+ },
+ {
+ hash: VALID_HASH_2,
+ kind: "usdc-transfer",
+ holder: VALID_HOLDER,
+ amounts: { amount: "5000000" },
+ networkPassphrase: TEST_PASSPHRASE,
+ submittedAt: now,
+ state: "pending",
+ },
+ ];
+
+ const merged = mergeRecords(writer1, writer2);
+ expect(merged.length).toBe(2);
+
+ const tx1 = merged.find((r) => r.hash === VALID_HASH_1);
+ expect(tx1?.state).toBe("confirmed");
+ expect(tx1?.ledger).toBe(500);
+
+ const tx2 = merged.find((r) => r.hash === VALID_HASH_2);
+ expect(tx2?.state).toBe("pending");
+ });
+
+ it("marks NOT_FOUND past time bound as expired with mayNotHaveBeenSent flag", () => {
+ const record: TrackedTx = {
+ hash: VALID_HASH_1,
+ kind: "buy",
+ holder: VALID_HOLDER,
+ marketId: "1",
+ amounts: { collateralIn: "100" },
+ networkPassphrase: TEST_PASSPHRASE,
+ submittedAt: Date.now(),
+ state: "pending",
+ maxTime: 1000,
+ };
+
+ const notExpiredRes = {
+ status: "NOT_FOUND",
+ latestLedger: 10,
+ latestLedgerCloseTime: 999,
+ } as rpc.Api.GetTransactionResponse;
+ const stillPending = evaluateTxStatus(record, notExpiredRes);
+ expect(stillPending.state).toBe("pending");
+
+ const expiredRes = {
+ status: "NOT_FOUND",
+ latestLedger: 15,
+ latestLedgerCloseTime: 1005,
+ } as rpc.Api.GetTransactionResponse;
+ const expired = evaluateTxStatus(record, expiredRes);
+ expect(expired.state).toBe("expired");
+ expect(expired.mayNotHaveBeenSent).toBe(true);
+ });
+
+ it("computes the same invalidation keys as useInvalidateAfterTrade", () => {
+ const marketId = "42";
+ const holder = VALID_HOLDER;
+
+ const keys = tradeInvalidationKeys(marketId, holder);
+ expect(keys).toEqual([
+ ["stellar", "market", "42"],
+ ["stellar", "markets"],
+ ["stellar", "position", "42", holder],
+ ["stellar", "usdcBalance", holder],
+ ]);
+ });
+});
diff --git a/lib/stellar/__tests__/typed-call.test-d.ts b/lib/stellar/__tests__/typed-call.test-d.ts
new file mode 100644
index 0000000..b74323b
--- /dev/null
+++ b/lib/stellar/__tests__/typed-call.test-d.ts
@@ -0,0 +1,61 @@
+import { expectTypeOf, test } from "vitest";
+import type { MarketCoreClient, RegistryClient, Value } from "../typed-call";
+import type { Market, Outcome, Position } from "../generated/market-core";
+
+type MC = MarketCoreClient;
+type RR = RegistryClient;
+
+test("binding method return types are inferred correctly and unwrapped", () => {
+ // Pin return types of binding methods the app uses
+ expectTypeOf>().toEqualTypeOf();
+ expectTypeOf>().toEqualTypeOf();
+ expectTypeOf>().toEqualTypeOf();
+ expectTypeOf>().toEqualTypeOf();
+ expectTypeOf>().toEqualTypeOf();
+ expectTypeOf>().toEqualTypeOf();
+ expectTypeOf>().toEqualTypeOf();
+ expectTypeOf>().toEqualTypeOf();
+ expectTypeOf>().toMatchTypeOf<{
+ trace_hash: Uint8Array;
+ ipfs_cid: string;
+ market_id: bigint;
+ agent: string;
+ action: string;
+ published_at: bigint;
+ }>();
+
+ // Guard tests: ensure inference has not collapsed to any (e.g. from broken @ts-nocheck)
+ expectTypeOf>().not.toBeAny();
+ expectTypeOf>().not.toBeAny();
+ expectTypeOf>().not.toBeAny();
+ expectTypeOf>().not.toBeAny();
+ expectTypeOf>().not.toBeAny();
+ expectTypeOf>().not.toBeAny();
+ expectTypeOf>().not.toBeAny();
+ expectTypeOf>().not.toBeAny();
+ expectTypeOf>().not.toBeAny();
+});
+
+test("write transaction argument shapes are pinned", () => {
+ // Pin argument shapes for write calls
+ expectTypeOf[0]>().toEqualTypeOf<{
+ trader: string;
+ market_id: bigint;
+ outcome: Outcome;
+ collateral_in: bigint;
+ min_shares_out: bigint;
+ }>();
+
+ expectTypeOf[0]>().toEqualTypeOf<{
+ trader: string;
+ market_id: bigint;
+ outcome: Outcome;
+ collateral_out: bigint;
+ max_shares_in: bigint;
+ }>();
+
+ expectTypeOf[0]>().toEqualTypeOf<{
+ holder: string;
+ market_id: bigint;
+ }>();
+});
diff --git a/lib/stellar/__tests__/typed-call.test.ts b/lib/stellar/__tests__/typed-call.test.ts
new file mode 100644
index 0000000..b0bf0ad
--- /dev/null
+++ b/lib/stellar/__tests__/typed-call.test.ts
@@ -0,0 +1,120 @@
+import { describe, expect, it, vi } from "vitest";
+import { Ok, Err, type AssembledTransaction, type Result } from "@stellar/stellar-sdk/contract";
+import { read, submit, bytesToHex } from "../typed-call";
+import { UserFacingError } from "../errors";
+
+describe("typed-call runtime helpers", () => {
+ it("read returns plain values unchanged", () => {
+ const bigIntTx = { result: 42n } as unknown as AssembledTransaction;
+ expect(read(bigIntTx)).toBe(42n);
+
+ const position = { yes: 100n, no: 200n };
+ const positionTx = { result: position } as unknown as AssembledTransaction;
+ expect(read(positionTx)).toEqual(position);
+
+ const strTx = { result: "hello" } as unknown as AssembledTransaction;
+ expect(read(strTx)).toBe("hello");
+ });
+
+ it("read unwraps Ok and throws UserFacingError on Err with mapped code", () => {
+ const okTx = { result: new Ok(999n) } as unknown as AssembledTransaction>;
+ expect(read(okTx)).toBe(999n);
+
+ const errTx = {
+ result: new Err({ message: "HostError: Error(Contract, #18)" }),
+ simulation: { error: "HostError: Error(Contract, #18)" },
+ } as unknown as AssembledTransaction>;
+
+ expect(() => read(errTx, "marketCore")).toThrow(UserFacingError);
+ try {
+ read(errTx, "marketCore");
+ } catch (err) {
+ expect(err).toBeInstanceOf(UserFacingError);
+ const userErr = err as UserFacingError;
+ expect(userErr.described.code).toBe("Paused");
+ expect(userErr.message).toBe("Trading is paused right now. Try again later.");
+ }
+ });
+
+ it("read does not treat an object with an isOk property as a Result", () => {
+ const duckTyped = {
+ isOk: () => true,
+ unwrap: () => "duck_unwrapped",
+ };
+ const duckTx = { result: duckTyped } as unknown as AssembledTransaction;
+ const res = read(duckTx);
+ // Must return the plain object itself, NOT the result of .unwrap()
+ expect(res).toBe(duckTyped);
+ expect(res).not.toBe("duck_unwrapped");
+ });
+
+ it("read maps a throwing tx.result through describeError with the contract table", () => {
+ const throwingTx = {
+ get result() {
+ throw new Error("HostError: Error(Contract, #25)");
+ },
+ simulation: { error: "HostError: Error(Contract, #25)" },
+ } as unknown as AssembledTransaction;
+
+ expect(() => read(throwingTx, "marketCore")).toThrow(UserFacingError);
+ try {
+ read(throwingTx, "marketCore");
+ } catch (err) {
+ expect(err).toBeInstanceOf(UserFacingError);
+ const userErr = err as UserFacingError;
+ expect(userErr.described.code).toBe("SlippageExceeded");
+ expect(userErr.message).toBe("The price moved before your trade went through. Try again or allow more slippage.");
+ }
+ });
+
+ it("submit surfaces simulation failure before calling signAndSend", async () => {
+ const signAndSendSpy = vi.fn();
+ const failingTx = {
+ get result() {
+ throw new Error("HostError: Error(Contract, #20)");
+ },
+ simulation: { error: "HostError: Error(Contract, #20)" },
+ signAndSend: signAndSendSpy,
+ } as unknown as AssembledTransaction;
+
+ await expect(submit(failingTx, "marketCore")).rejects.toThrow(UserFacingError);
+ expect(signAndSendSpy).not.toHaveBeenCalled();
+ });
+
+ it("submit returns txHash from sendTransactionResponse", async () => {
+ const successTx = {
+ result: new Ok(12345n),
+ signAndSend: vi.fn().mockResolvedValue({
+ result: new Ok(12345n),
+ sendTransactionResponse: { hash: "test_tx_hash_abc123" },
+ }),
+ } as unknown as AssembledTransaction>;
+
+ const response = await submit(successTx);
+ expect(response).toEqual({
+ value: 12345n,
+ txHash: "test_tx_hash_abc123",
+ });
+ });
+
+ it("submit handles plain values and null txHash when response is missing", async () => {
+ const plainTx = {
+ result: 42n,
+ signAndSend: vi.fn().mockResolvedValue({
+ result: 42n,
+ sendTransactionResponse: undefined,
+ }),
+ } as unknown as AssembledTransaction;
+
+ const response = await submit(plainTx);
+ expect(response).toEqual({
+ value: 42n,
+ txHash: null,
+ });
+ });
+
+ it("bytesToHex converts Uint8Array or Buffer to lowercase hex", () => {
+ const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef, 0x01, 0x09]);
+ expect(bytesToHex(bytes)).toBe("deadbeef0109");
+ });
+});
diff --git a/lib/stellar/__tests__/units.test.ts b/lib/stellar/__tests__/units.test.ts
index 851c29a..17c827c 100644
--- a/lib/stellar/__tests__/units.test.ts
+++ b/lib/stellar/__tests__/units.test.ts
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
-import { formatUsdc, maxIn, minOut, parseUsdc, shareOf, shortAddress, tryParseUsdc, USDC_UNIT } from "../units";
+import { formatUsdc, formatXlm, maxIn, minOut, parseUsdc, shareOf, shortAddress, tryParseUsdc, USDC_UNIT, XLM_UNIT } from "../units";
describe("parseUsdc / formatUsdc", () => {
it("uses 7 decimals", () => {
@@ -39,6 +39,19 @@ describe("parseUsdc / formatUsdc", () => {
});
});
+describe("formatXlm", () => {
+ it("uses 7 decimals and stroops unit", () => {
+ expect(XLM_UNIT).toBe(10_000_000n);
+ expect(formatXlm(10_000_000n)).toBe("1");
+ expect(formatXlm(1n)).toBe("0.0000001");
+ expect(formatXlm(123_456n)).toBe("0.0123456");
+ expect(formatXlm(12_345_678_900_000n, { grouping: true })).toBe("1,234,567.89");
+ expect(formatXlm(99_981_000_000n, { grouping: true })).toBe("9,998.1");
+ expect(formatXlm(0n)).toBe("0");
+ expect(formatXlm(5_000_000n, { minDecimals: 2 })).toBe("0.50");
+ });
+});
+
describe("slippage helpers round against the user", () => {
it("minOut rounds down", () => {
expect(minOut(10_000n, 100)).toBe(9_900n);
diff --git a/lib/stellar/archival.ts b/lib/stellar/archival.ts
new file mode 100644
index 0000000..7ffca6c
--- /dev/null
+++ b/lib/stellar/archival.ts
@@ -0,0 +1,19 @@
+import type { AssembledTransaction } from '@stellar/stellar-sdk/contract';
+
+export const isArchivedStateError = (error: unknown): boolean => /archiv|missing ledger entry|ttl|entry.?not.?found/i.test(String(error));
+
+/** Re-simulate after restoring archived entries through the supplied backend/client. */
+export async function simulateWithRestore(build: () => Promise>, restore: () => Promise): Promise> {
+ try {
+ const tx = await build();
+ // `simulation` is only metadata; reading `result` forces the SDK to
+ // surface expired/missing state errors from the simulation.
+ void tx.result;
+ return tx;
+ }
+ catch (error) {
+ if (!isArchivedStateError(error)) throw error;
+ await restore();
+ return build();
+ }
+}
diff --git a/lib/stellar/authorization.ts b/lib/stellar/authorization.ts
new file mode 100644
index 0000000..45cd0fd
--- /dev/null
+++ b/lib/stellar/authorization.ts
@@ -0,0 +1,28 @@
+import { Address, xdr } from '@stellar/stellar-sdk';
+import type { AssembledTransaction } from '@stellar/stellar-sdk/contract';
+
+export interface AuthorizationInspection { count: number; signers: string[]; functions: string[]; warnings: string[]; valid: boolean; }
+
+/** Inspect authorization entries before a wallet prompt; never sign unexpected addresses/functions. */
+export function inspectAuthorizationEntries(entries: readonly xdr.SorobanAuthorizationEntry[], expectedAddress?: string): AuthorizationInspection {
+ const signers: string[] = [];
+ const functions: string[] = [];
+ const warnings: string[] = [];
+ for (const entry of entries) {
+ try {
+ const address = entry.credentials().switch().name === 'sorobanCredentialsAddress' ? Address.fromScAddress(entry.credentials().address().address()).toString() : undefined;
+ if (address) signers.push(address);
+ functions.push(String(entry.rootInvocation().function()));
+ if (expectedAddress && address && address !== expectedAddress) warnings.push(`Unexpected signer ${address}`);
+ } catch { warnings.push('Unable to decode an authorization entry'); }
+ }
+ return { count: entries.length, signers, functions, warnings, valid: warnings.length === 0 };
+}
+
+/** Decode the authorization entries returned by Soroban simulation. */
+export function inspectTransactionAuthorization(tx: AssembledTransaction, expectedAddress?: string): AuthorizationInspection {
+ const entries = tx.simulation && "auth" in tx.simulation
+ ? (tx.simulation.auth as readonly xdr.SorobanAuthorizationEntry[])
+ : [];
+ return inspectAuthorizationEntries(entries, expectedAddress);
+}
diff --git a/lib/stellar/buy-breakdown.ts b/lib/stellar/buy-breakdown.ts
new file mode 100644
index 0000000..c185085
--- /dev/null
+++ b/lib/stellar/buy-breakdown.ts
@@ -0,0 +1,20 @@
+import { calcBuy, type BuyQuote } from "./generated/fpmm";
+
+export interface BuyBreakdown extends BuyQuote {
+ /** Price impact in basis points, measured against the pre-trade marginal price. */
+ priceImpactBps: bigint;
+}
+
+/** Calculate the same fee, output and price impact used by the FPMM locally. */
+export function buyBreakdown(
+ reserveBought: bigint,
+ reserveOther: bigint,
+ collateralIn: bigint,
+ feeBps: bigint,
+): BuyBreakdown {
+ const quote = calcBuy(reserveBought, reserveOther, collateralIn, feeBps);
+ const before = reserveBought * 10_000n / (reserveBought + reserveOther);
+ const after = quote.newReserveBought * 10_000n /
+ (quote.newReserveBought + quote.newReserveOther);
+ return { ...quote, priceImpactBps: after > before ? after - before : before - after };
+}
diff --git a/lib/stellar/clients.ts b/lib/stellar/clients.ts
index a0a9a12..f6fd41d 100644
--- a/lib/stellar/clients.ts
+++ b/lib/stellar/clients.ts
@@ -1,25 +1,51 @@
-import { Address, nativeToScVal, scValToNative } from "@stellar/stellar-sdk";
+import { Address, nativeToScVal, rpc, scValToNative } from "@stellar/stellar-sdk";
import { AssembledTransaction } from "@stellar/stellar-sdk/contract";
import type { ClientOptions, SignTransaction } from "@stellar/stellar-sdk/contract";
import { Client as MarketCoreClient, type Category, type Outcome } from "./generated/market-core";
import { Client as TreasuryClient } from "./generated/treasury";
import { Client as ResolverClient } from "./generated/resolver";
import { Client as ReasoningRegistryClient } from "./generated/reasoning-registry";
-import { CONTRACTS, NETWORK_PASSPHRASE, RPC_URL } from "./config";
+import type { Transaction, xdr } from "@stellar/stellar-sdk";
+import { CONTRACTS, NETWORK_PASSPHRASE, PASSKEY_RELAYER_SOURCE, RPC_URL } from "./config";
-/** What a wallet provides to sign. Omit it for read-only simulation. */
-export interface Signer {
- publicKey: string;
- signTransaction: SignTransaction;
+/** What a wallet or passkey provides to sign. Omit it for read-only simulation. */
+export type Signer =
+ | { kind: "account"; publicKey: string; signTransaction: SignTransaction }
+ | {
+ kind: "contract";
+ address: string /* C… */;
+ signAuthEntry: (entry: xdr.SorobanAuthorizationEntry, validUntilLedger: number) => Promise;
+ submit: (tx: Transaction) => Promise<{ hash: string }>;
+ };
+
+export const signerAddress = (s: Signer) => (s.kind === "account" ? s.publicKey : s.address);
+
+let _rpcServer: rpc.Server | null = null;
+/** Memoised Stellar RPC server instance. */
+export function rpcServer(): rpc.Server {
+ if (!_rpcServer) {
+ _rpcServer = new rpc.Server(RPC_URL, {
+ allowHttp: RPC_URL.startsWith("http://"),
+ });
+ }
+ return _rpcServer;
}
function options(contractId: string, signer?: Signer): ClientOptions {
+ const isContract = signer?.kind === "contract";
+ const sourceAccount = isContract
+ ? PASSKEY_RELAYER_SOURCE
+ : signer?.kind === "account"
+ ? signer.publicKey
+ : undefined;
+
return {
contractId,
networkPassphrase: NETWORK_PASSPHRASE,
rpcUrl: RPC_URL,
allowHttp: RPC_URL.startsWith("http://"),
- ...(signer ? { publicKey: signer.publicKey, signTransaction: signer.signTransaction } : {}),
+ ...(sourceAccount ? { publicKey: sourceAccount } : {}),
+ ...(signer && signer.kind === "account" ? { signTransaction: signer.signTransaction } : {}),
};
}
diff --git a/lib/stellar/config.ts b/lib/stellar/config.ts
index be4b833..0cdb5d3 100644
--- a/lib/stellar/config.ts
+++ b/lib/stellar/config.ts
@@ -26,6 +26,18 @@ export const CONTRACTS = {
usdc: env(process.env.NEXT_PUBLIC_USDC_CONTRACT_ID, deployments.contracts.usdc),
} as const;
+/** Experimental passkey smart-wallet flag (off by default). */
+export const EXPERIMENTAL_PASSKEYS = process.env.NEXT_PUBLIC_EXPERIMENTAL_PASSKEYS === "true";
+
+/** Source account for relayer fee-payment and passkey contract simulation. */
+export const PASSKEY_RELAYER_SOURCE = env(
+ process.env.NEXT_PUBLIC_PASSKEY_RELAYER_SOURCE,
+ "GBRPYHIL2CI3FNQ4BXLFMNDLFJUNPU2HY3ZMFSHONUCEOASW7QC7OX2H",
+);
+
+/** Relayer service URL for deploying smart wallets and submitting contract auth txs. */
+export const PASSKEY_RELAYER_URL = env(process.env.NEXT_PUBLIC_PASSKEY_RELAYER_URL, "");
+
/**
* Recipient of premium payments. Must match the backend's PAYMENTS_RECIPIENT
* or the backend will reject the payment. Defaults to the treasury, like the
diff --git a/lib/stellar/contract-submit.ts b/lib/stellar/contract-submit.ts
new file mode 100644
index 0000000..d30391b
--- /dev/null
+++ b/lib/stellar/contract-submit.ts
@@ -0,0 +1,126 @@
+import { rpc } from "@stellar/stellar-sdk";
+import type { AssembledTransaction } from "@stellar/stellar-sdk/contract";
+import type { Signer } from "./clients";
+import { RPC_URL } from "./config";
+import { describeError, UserFacingError, type ContractName } from "./errors";
+import { read, unwrapResult, type TxValue, type Unwrapped } from "./typed-call";
+
+export interface RpcServerLike {
+ getLatestLedger(): Promise<{ sequence: number }>;
+ getTransaction(hash: string): Promise;
+}
+
+export interface SubmitAsContractOptions {
+ signatureExpirationLedgerOffset?: number;
+ rpcServer?: RpcServerLike;
+ timeoutMs?: number;
+ pollIntervalMs?: number;
+}
+
+/**
+ * Signs Soroban authorization entries as a contract account (passkey smart wallet),
+ * re-simulates, submits via the relayer, and polls getTransaction until SUCCESS.
+ */
+export async function submitAsContract>(
+ tx: Tx,
+ signer: Extract,
+ contract: ContractName = "marketCore",
+ opts?: SubmitAsContractOptions,
+): Promise<{ value: Unwrapped>; txHash: string | null }> {
+ // 1. Surface simulation failures before asking the user to authorize.
+ read(tx, contract);
+
+ // 2. Ensure only the trader's authorization is requested. Refuse unexpected addresses.
+ const needed = await tx.needsNonInvokerSigningBy();
+ const unexpected = needed.filter((addr) => addr !== signer.address);
+ if (unexpected.length > 0 || !needed.includes(signer.address)) {
+ throw new UserFacingError(
+ {
+ kind: "contract",
+ message: `Unexpected authorization required for address: ${unexpected.join(", ") || "none"}`,
+ },
+ new Error(`Signing refused: needed addresses [${needed.join(", ")}] != [${signer.address}]`),
+ );
+ }
+
+ const server = opts?.rpcServer ?? new rpc.Server(RPC_URL, { allowHttp: RPC_URL.startsWith("http://") });
+
+ // 3. Obtain ledger sequence for signature expiration (default: latest + 60 ledgers ~ 5 minutes)
+ let latestLedger = 0;
+ try {
+ const info = await server.getLatestLedger();
+ latestLedger = info.sequence;
+ } catch {
+ latestLedger = 1_000_000;
+ }
+ const expiration = latestLedger + (opts?.signatureExpirationLedgerOffset ?? 60);
+
+ // 4. Sign Soroban auth entries
+ await tx.signAuthEntries({
+ address: signer.address,
+ authorizeEntry: (entry) => signer.signAuthEntry(entry, expiration),
+ });
+
+ // 5. Re-simulate with the signed authorization to capture __check_auth footprint & resource costs
+ await tx.simulate();
+
+ // 6. Build transaction and submit via relayer
+ const built = tx.build();
+ let hash: string | null = null;
+ try {
+ const res = await signer.submit(built);
+ hash = res.hash;
+ } catch (err) {
+ if (err instanceof UserFacingError) throw err;
+ throw new UserFacingError(describeError(err, contract, signer.address), err);
+ }
+
+ if (!hash) {
+ return { value: unwrapResult(undefined, contract), txHash: null };
+ }
+
+ // 7. Poll getTransaction until SUCCESS
+ const timeoutMs = opts?.timeoutMs ?? 60_000;
+ const pollIntervalMs = opts?.pollIntervalMs ?? 1_000;
+ const start = Date.now();
+
+ let getTx = await server.getTransaction(hash);
+ while (
+ getTx.status === rpc.Api.GetTransactionStatus.NOT_FOUND ||
+ (getTx as any).status === "PENDING" ||
+ (getTx as any).status === "NOT_FOUND"
+ ) {
+ if (Date.now() - start > timeoutMs) {
+ throw new UserFacingError(
+ {
+ kind: "network",
+ message: "Transaction submission timed out awaiting ledger inclusion via relayer.",
+ },
+ new Error(`Timeout polling getTransaction for ${hash}`),
+ );
+ }
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
+ getTx = await server.getTransaction(hash);
+ }
+
+ if (getTx.status !== rpc.Api.GetTransactionStatus.SUCCESS && (getTx as any).status !== "SUCCESS") {
+ const rawError = (getTx as any).resultXdr?.toXDR?.("base64") ?? (getTx as any).resultXdr ?? "Transaction failed";
+ throw new UserFacingError(describeError(rawError, contract, signer.address), getTx);
+ }
+
+ // Extract parsed result if parseResultXdr is available on the AssembledTransaction
+ let rawResult: unknown;
+ const txOpts = (tx as any).options;
+ if ((getTx as any).returnValue && txOpts?.parseResultXdr) {
+ rawResult = txOpts.parseResultXdr((getTx as any).returnValue);
+ } else {
+ try {
+ rawResult = tx.result;
+ } catch {
+ rawResult = undefined;
+ }
+ }
+
+ const value = unwrapResult(rawResult, contract);
+ return { value, txHash: hash };
+}
diff --git a/lib/stellar/errors.ts b/lib/stellar/errors.ts
index 8aa78cb..3318ea1 100644
--- a/lib/stellar/errors.ts
+++ b/lib/stellar/errors.ts
@@ -43,13 +43,31 @@ const FRIENDLY: Record = {
Unauthorized: "Your wallet isn't allowed to do this.",
};
+import type { rpc } from "@stellar/stellar-sdk";
+
export interface DescribedError {
- kind: "rejected" | "insufficient-balance" | "no-trustline" | "contract" | "wrong-network" | "disconnected" | "network" | "unknown";
+ kind:
+ | "rejected"
+ | "insufficient-balance"
+ | "insufficient-xlm"
+ | "no-trustline"
+ | "contract"
+ | "wrong-network"
+ | "disconnected"
+ | "network"
+ | "submission"
+ | "expired"
+ | "unknown";
message: string;
/** Contract error name, e.g. "SlippageExceeded", when known. */
code?: string;
}
+export interface TxDescribedError extends DescribedError {
+ submission?: "try-again-later" | "duplicate" | "rejected-by-network" | "failed-on-chain" | "not-found-after-timeout";
+ resultCode?: string; // e.g. "txBadSeq", "txInsufficientFee", "txFailed"
+}
+
function textOf(err: unknown): string {
if (err == null) return "";
if (typeof err === "string") return err;
@@ -71,21 +89,44 @@ function safeJson(v: unknown): string {
}
/** Turns anything thrown by the SDK, a binding or a wallet into a message for the user. */
-export function describeError(err: unknown, contract: ContractName = "marketCore"): DescribedError {
+export function describeError(
+ err: unknown,
+ contract: ContractName = "marketCore",
+ trader?: string,
+): DescribedError {
const text = textOf(err);
- if (/user (rejected|declined|denied)|rejected by (the )?user|request (was )?rejected|declined|cancell?ed by user|user closed/i.test(text)) {
+ if (
+ /user (rejected|declined|denied)|rejected by (the )?user|request (was )?rejected|declined|cancell?ed by user|user closed|NotAllowedError/i.test(
+ text,
+ )
+ ) {
return { kind: "rejected", message: "You cancelled the request in your wallet." };
}
if (/trustline entry is missing|TrustlineMissing|trustline.*(missing|not found)|op_no_trust/i.test(text)) {
+ if (trader?.startsWith("C")) {
+ return {
+ kind: "insufficient-balance",
+ message: "This wallet doesn't hold USDC yet.",
+ };
+ }
return {
kind: "no-trustline",
- message: "Your account has no USDC trustline. Add the USDC asset in your wallet first.",
+ message: "Your wallet has no USDC trustline. Add the USDC asset in your wallet first.",
};
}
+ if (/check_auth.*failed|signature.*invalid|signature verification failed|unauthorized.*signature/i.test(text)) {
+ return { kind: "contract", message: "The passkey signature was rejected or is invalid." };
+ }
+ if (/signature.*expired|auth.*expired|signatureExpirationLedger/i.test(text)) {
+ return { kind: "contract", message: "The passkey authorization has expired. Please try again." };
+ }
if (/balance is not sufficient|resulting balance is not within the allowed range|insufficient (balance|funds)|BalanceError|op_underfunded/i.test(text)) {
return { kind: "insufficient-balance", message: "You don't have enough USDC for this." };
}
+ if (/op_low_reserve|txInsufficientBalance|tx_insufficient_balance/i.test(text)) {
+ return { kind: "insufficient-xlm", message: "You don't have enough spendable XLM to pay the network fee." };
+ }
if (/wrong network|network mismatch/i.test(text)) {
return { kind: "wrong-network", message: "Switch your wallet to Stellar Testnet and try again." };
}
@@ -106,6 +147,104 @@ export function describeError(err: unknown, contract: ContractName = "marketCore
return { kind: "unknown", message: "Something went wrong. Please try again." };
}
+/**
+ * Maps an rpc.Api.SendTransactionResponse to a TxDescribedError.
+ */
+export function describeSubmission(
+ response: rpc.Api.SendTransactionResponse,
+ contract: ContractName = "marketCore",
+): TxDescribedError {
+ if (response.status === "TRY_AGAIN_LATER") {
+ return {
+ kind: "submission",
+ submission: "try-again-later",
+ message: "The network is busy. Please try again in a moment.",
+ };
+ }
+ if (response.status === "DUPLICATE") {
+ return {
+ kind: "submission",
+ submission: "duplicate",
+ message: "This transaction is already in flight.",
+ };
+ }
+
+ // ERROR case
+ let resultCode: string | undefined;
+ try {
+ resultCode = response.errorResult?.result().switch().name;
+ } catch {
+ // ignore
+ }
+
+ if (resultCode === "txBadSeq") {
+ return {
+ kind: "submission",
+ submission: "rejected-by-network",
+ resultCode,
+ message: "Transaction sequence number is invalid. Please try again.",
+ };
+ }
+ if (resultCode === "txInsufficientFee") {
+ return {
+ kind: "submission",
+ submission: "rejected-by-network",
+ resultCode,
+ message: "The network fee bid was too low. Please try again with a higher fee.",
+ };
+ }
+ if (resultCode === "txTooLate") {
+ return {
+ kind: "submission",
+ submission: "rejected-by-network",
+ resultCode,
+ message: "The transaction expired before reaching the ledger. Please try again.",
+ };
+ }
+ if (resultCode === "txInsufficientBalance") {
+ return {
+ kind: "insufficient-xlm",
+ submission: "rejected-by-network",
+ resultCode,
+ message: "You don't have enough spendable XLM to pay the network fee.",
+ };
+ }
+
+ // For txFailed on an InvokeHostFunction, fall through to describeError with the contract name
+ // so Error(Contract, #N) still maps via TABLES.
+ const diagText = response.diagnosticEvents
+ ? response.diagnosticEvents
+ .map((e) => {
+ try {
+ return typeof (e as unknown as { toXDR?: (f: string) => string }).toXDR === "function"
+ ? (e as unknown as { toXDR: (format: string) => string }).toXDR("base64")
+ : String(e);
+ } catch {
+ return String(e);
+ }
+ })
+ .join(" ")
+ : "";
+ const fullText = `${textOf(response)} ${diagText}`;
+ const described = describeError(fullText, contract);
+ if (described.kind !== "unknown") {
+ return {
+ ...described,
+ submission: "rejected-by-network",
+ resultCode: resultCode ?? "txFailed",
+ };
+ }
+
+ return {
+ kind: "submission",
+ submission: "rejected-by-network",
+ resultCode: resultCode ?? "txFailed",
+ message: resultCode
+ ? `Transaction was rejected by the network (${resultCode}).`
+ : "Transaction was rejected by the network. Please try again.",
+ };
+}
+
/** Thrown by write hooks so callers get a readable message in `error.message`. */
export class UserFacingError extends Error {
constructor(public readonly described: DescribedError, public readonly original?: unknown) {
diff --git a/lib/stellar/fees.ts b/lib/stellar/fees.ts
new file mode 100644
index 0000000..6fbdef9
--- /dev/null
+++ b/lib/stellar/fees.ts
@@ -0,0 +1,171 @@
+import { rpc, xdr } from "@stellar/stellar-sdk";
+import type { AssembledTransaction } from "@stellar/stellar-sdk/contract";
+import { rpcServer } from "./clients";
+
+export interface FeeBreakdown {
+ /** Stroops: totalFee - resourceFee */
+ inclusionFee: bigint;
+ /** Stroops from SorobanTransactionData.resourceFee() */
+ resourceFee: bigint;
+ /** Stroops: BigInt(tx.built.fee) */
+ totalFee: bigint;
+ /** Stroops from simulation.minResourceFee */
+ minResourceFee: bigint;
+ resources: {
+ instructions: number;
+ readBytes: number;
+ writeBytes: number;
+ readEntries: number;
+ writeEntries: number;
+ };
+}
+
+export class SimulationError extends Error {
+ constructor(message: string, public readonly response?: rpc.Api.SimulateTransactionResponse) {
+ super(message);
+ this.name = "SimulationError";
+ }
+}
+
+/**
+ * Extracts fee breakdown and footprint statistics from a simulated AssembledTransaction.
+ * Arithmetic is kept strictly in bigint (stroops). Never passes through float/number.
+ */
+export function feeBreakdown(tx: AssembledTransaction): FeeBreakdown {
+ if (!tx || !tx.simulation) {
+ throw new SimulationError("Transaction has no simulation data");
+ }
+
+ const sim = tx.simulation as rpc.Api.SimulateTransactionResponse;
+
+ if (rpc.Api.isSimulationError(sim) || (sim as { error?: string }).error) {
+ throw new SimulationError(
+ String((sim as { error?: string }).error ?? "Simulation failed"),
+ sim,
+ );
+ }
+
+ if (rpc.Api.isSimulationRestore(sim) || "restorePreamble" in (sim as object)) {
+ throw new SimulationError("Transaction requires footprint restore", sim);
+ }
+
+ const minResourceFee = BigInt(sim.minResourceFee ?? 0);
+ const rawTx = tx.built;
+ if (!rawTx) {
+ throw new SimulationError("Transaction has not been built");
+ }
+ const totalFee = BigInt(rawTx.fee);
+
+ const rawTxData = (sim as { transactionData?: unknown }).transactionData;
+ if (!rawTxData) {
+ throw new SimulationError("Simulation is missing transactionData");
+ }
+
+ const sorobanData: xdr.SorobanTransactionData =
+ typeof (rawTxData as { build?: () => xdr.SorobanTransactionData }).build === "function"
+ ? (rawTxData as { build: () => xdr.SorobanTransactionData }).build()
+ : (rawTxData as xdr.SorobanTransactionData);
+
+ const resourceFee = BigInt(sorobanData.resourceFee().toString());
+ const inclusionFee = totalFee - resourceFee;
+
+ const resources = sorobanData.resources();
+ const footprint = resources.footprint();
+ const readBytes =
+ typeof (resources as { diskReadBytes?: () => number }).diskReadBytes === "function"
+ ? (resources as { diskReadBytes: () => number }).diskReadBytes()
+ : typeof (resources as unknown as { readBytes?: () => number }).readBytes === "function"
+ ? (resources as unknown as { readBytes: () => number }).readBytes()
+ : 0;
+
+ return {
+ inclusionFee,
+ resourceFee,
+ totalFee,
+ minResourceFee,
+ resources: {
+ instructions: resources.instructions(),
+ readBytes,
+ writeBytes: resources.writeBytes(),
+ readEntries: footprint.readOnly().length,
+ writeEntries: footprint.readWrite().length,
+ },
+ };
+}
+
+export interface AccountReserve {
+ balance: bigint;
+ minBalance: bigint;
+ sellingLiabilities: bigint;
+ spendable: bigint;
+ subentries: number;
+ sponsoring: number;
+ sponsored: number;
+}
+
+/**
+ * Standard Stellar network base reserve: 0.5 XLM (5,000,000 stroops).
+ * Used when network RPC does not expose the ledger header XDR.
+ */
+export const DEFAULT_BASE_RESERVE = 5_000_000n;
+
+/**
+ * Computes spendable native XLM from an account entry per CAP-33 sponsored reserves.
+ * All arithmetic is performed in BigInt stroops.
+ */
+export function spendableXlm(entry: xdr.AccountEntry, baseReserve: bigint): AccountReserve {
+ const balance = BigInt(entry.balance().toString());
+ const subentries = Number(entry.numSubEntries());
+ let sellingLiabilities = 0n;
+ let sponsoring = 0;
+ let sponsored = 0;
+
+ try {
+ if (entry.ext().switch() >= 1) {
+ const v1 = entry.ext().v1();
+ sellingLiabilities = BigInt(v1.liabilities().selling().toString());
+ if (v1.ext().switch() >= 2) {
+ const v2 = v1.ext().v2();
+ sponsoring = Number(v2.numSponsoring());
+ sponsored = Number(v2.numSponsored());
+ }
+ }
+ } catch {
+ // Non-fatal if extension format differs
+ }
+
+ // Formula (CAP-33): minBalance = (2 + numSubEntries + numSponsoring - numSponsored) * baseReserve
+ const reserveMultiplier = 2n + BigInt(subentries) + BigInt(sponsoring) - BigInt(sponsored);
+ const minBalance = reserveMultiplier * baseReserve;
+ const rawSpendable = balance - minBalance - sellingLiabilities;
+ const spendable = rawSpendable < 0n ? 0n : rawSpendable;
+
+ return {
+ balance,
+ minBalance,
+ sellingLiabilities,
+ spendable,
+ subentries,
+ sponsoring,
+ sponsored,
+ };
+}
+
+/**
+ * Reads the latest base reserve from the network if exposed in the ledger header XDR,
+ * otherwise falls back to DEFAULT_BASE_RESERVE (0.5 XLM).
+ */
+export async function fetchBaseReserve(server: rpc.Server = rpcServer()): Promise {
+ try {
+ const latest = (await server.getLatestLedger()) as unknown as { headerXdr?: string };
+ if (latest && typeof latest.headerXdr === "string") {
+ const header = xdr.LedgerHeader.fromXDR(latest.headerXdr, "base64");
+ return BigInt(header.baseReserve().toString());
+ }
+ } catch {
+ // Fall back to protocol default
+ }
+ // Soroban RPC getLatestLedger does not always include the raw ledger header XDR;
+ // fall back to the protocol standard base reserve of 0.5 XLM (5_000_000 stroops).
+ return DEFAULT_BASE_RESERVE;
+}
diff --git a/lib/stellar/passkey.ts b/lib/stellar/passkey.ts
new file mode 100644
index 0000000..ed81782
--- /dev/null
+++ b/lib/stellar/passkey.ts
@@ -0,0 +1,480 @@
+import { Buffer } from "buffer";
+import {
+ Address,
+ hash,
+ nativeToScVal,
+ xdr,
+ type Transaction,
+} from "@stellar/stellar-sdk";
+import type { Signer } from "./clients";
+import { NETWORK_PASSPHRASE, PASSKEY_RELAYER_URL } from "./config";
+import { UserFacingError } from "./errors";
+
+// Curve order N for secp256r1 / P-256
+export const SECP256R1_N = BigInt("0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
+export const SECP256R1_HALF_N = SECP256R1_N / 2n;
+
+export const PASSKEY_STORAGE_KEY = "oracledesk_passkey_wallet";
+
+export interface StoredPasskeyWallet {
+ address: string;
+ credentialId: string;
+ network: string;
+}
+
+export function getStoredPasskeyWallet(): StoredPasskeyWallet | null {
+ if (typeof window === "undefined") return null;
+ try {
+ const raw = window.localStorage.getItem(PASSKEY_STORAGE_KEY);
+ if (!raw) return null;
+ const parsed = JSON.parse(raw);
+ if (parsed && typeof parsed.address === "string" && typeof parsed.credentialId === "string") {
+ return parsed;
+ }
+ return null;
+ } catch {
+ return null;
+ }
+}
+
+export function storePasskeyWallet(data: StoredPasskeyWallet): void {
+ if (typeof window === "undefined") return;
+ window.localStorage.setItem(PASSKEY_STORAGE_KEY, JSON.stringify(data));
+}
+
+export function clearStoredPasskeyWallet(): void {
+ if (typeof window === "undefined") return;
+ window.localStorage.removeItem(PASSKEY_STORAGE_KEY);
+}
+
+function bytesToBigInt(bytes: Uint8Array): bigint {
+ let hex = "";
+ for (let i = 0; i < bytes.length; i++) {
+ hex += bytes[i].toString(16).padStart(2, "0");
+ }
+ return hex === "" ? 0n : BigInt("0x" + hex);
+}
+
+function bigIntTo32Bytes(n: bigint, target: Uint8Array, offset: number): void {
+ const hex = n.toString(16).padStart(64, "0");
+ for (let i = 0; i < 32; i++) {
+ target[offset + i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
+ }
+}
+
+/**
+ * Converts a DER-encoded ECDSA signature into a 64-byte raw signature (r || s),
+ * applying low-S normalization (s = N - s if s > N/2) as required by Soroban secp256r1 verification.
+ */
+export function derToRawSignature(der: Uint8Array): Uint8Array {
+ if (der.length < 8 || der[0] !== 0x30) {
+ throw new Error("Invalid DER signature: missing 0x30 sequence header");
+ }
+
+ let offset = 2;
+ if (der[1] & 0x80) {
+ const lenBytes = der[1] & 0x7f;
+ offset = 2 + lenBytes;
+ }
+
+ if (der[offset] !== 0x02) {
+ throw new Error("Invalid DER signature: missing 0x02 integer marker for r");
+ }
+ const rLen = der[offset + 1];
+ offset += 2;
+ const rBytes = der.slice(offset, offset + rLen);
+ offset += rLen;
+
+ if (der[offset] !== 0x02) {
+ throw new Error("Invalid DER signature: missing 0x02 integer marker for s");
+ }
+ const sLen = der[offset + 1];
+ offset += 2;
+ const sBytes = der.slice(offset, offset + sLen);
+
+ const rBig = bytesToBigInt(rBytes);
+ let sBig = bytesToBigInt(sBytes);
+
+ // Normalise high-S to low-S
+ if (sBig > SECP256R1_HALF_N) {
+ sBig = SECP256R1_N - sBig;
+ }
+
+ const raw = new Uint8Array(64);
+ bigIntTo32Bytes(rBig, raw, 0);
+ bigIntTo32Bytes(sBig, raw, 32);
+ return raw;
+}
+
+/**
+ * Minimalist CBOR decoder for extracting key-value pairs from maps and values.
+ * Handles integer keys and byte string / integer values used in COSE keys.
+ */
+export function decodeCoseKey(bytes: Uint8Array): { x: Uint8Array; y: Uint8Array; uncompressed: Uint8Array } {
+ let pos = 0;
+
+ function readTypeAndVal(): { major: number; val: number | bigint } {
+ const initial = bytes[pos++];
+ const major = initial >> 5;
+ const info = initial & 0x1f;
+
+ if (info < 24) {
+ return { major, val: info };
+ } else if (info === 24) {
+ return { major, val: bytes[pos++] };
+ } else if (info === 25) {
+ const v = (bytes[pos] << 8) | bytes[pos + 1];
+ pos += 2;
+ return { major, val: v };
+ } else if (info === 26) {
+ const v =
+ (bytes[pos] << 24) |
+ (bytes[pos + 1] << 16) |
+ (bytes[pos + 2] << 8) |
+ bytes[pos + 3];
+ pos += 4;
+ return { major, val: v >>> 0 };
+ } else if (info === 27) {
+ let b = 0n;
+ for (let i = 0; i < 8; i++) {
+ b = (b << 8n) | BigInt(bytes[pos++]);
+ }
+ return { major, val: b };
+ }
+ throw new Error(`Unsupported CBOR additional info: ${info}`);
+ }
+
+ const header = readTypeAndVal();
+ if (header.major !== 5) {
+ throw new Error(`Expected CBOR map (major 5), found major ${header.major}`);
+ }
+ const mapLength = Number(header.val);
+
+ let x: Uint8Array | null = null;
+ let y: Uint8Array | null = null;
+
+ for (let i = 0; i < mapLength; i++) {
+ const keyHeader = readTypeAndVal();
+ let key: number;
+ if (keyHeader.major === 0) {
+ key = Number(keyHeader.val);
+ } else if (keyHeader.major === 1) {
+ key = -1 - Number(keyHeader.val);
+ } else {
+ throw new Error(`Unexpected CBOR map key major ${keyHeader.major}`);
+ }
+
+ const valHeader = readTypeAndVal();
+ if (valHeader.major === 2) {
+ const len = Number(valHeader.val);
+ const b = bytes.slice(pos, pos + len);
+ pos += len;
+ if (key === -2) x = b;
+ if (key === -3) y = b;
+ } else if (valHeader.major === 3) {
+ pos += Number(valHeader.val);
+ }
+ }
+
+ if (!x || !y || x.length !== 32 || y.length !== 32) {
+ throw new Error("Failed to extract valid 32-byte x and y coordinates from COSE key");
+ }
+
+ const uncompressed = new Uint8Array(65);
+ uncompressed[0] = 0x04;
+ uncompressed.set(x, 1);
+ uncompressed.set(y, 33);
+
+ return { x, y, uncompressed };
+}
+
+/**
+ * Extracts the 65-byte uncompressed P-256 public key (0x04 || x || y) from
+ * a WebAuthn attestation object (CBOR).
+ */
+export function extractPublicKeyFromAttestation(attestationObject: Uint8Array): Uint8Array {
+ // If the raw bytes directly start with a CBOR COSE key (major 5 map with kty EC2), decode directly
+ if (attestationObject[0] === 0xa5 || attestationObject[0] === 0xa4) {
+ try {
+ return decodeCoseKey(attestationObject).uncompressed;
+ } catch {
+ // Continue to full attestation parsing
+ }
+ }
+
+ // Scan for the attestedCredentialData inside authData:
+ // authData layout: rpIdHash (32) + flags (1) + signCount (4) + aaguid (16) + credIdLen (2) + credId (L) + coseKey
+ // flags & 0x40 must be true.
+ for (let i = 0; i < attestationObject.length - 37; i++) {
+ const flags = attestationObject[i + 32];
+ if (flags & 0x40) {
+ const credIdLenOffset = i + 37 + 16;
+ if (credIdLenOffset + 2 <= attestationObject.length) {
+ const credIdLen = (attestationObject[credIdLenOffset] << 8) | attestationObject[credIdLenOffset + 1];
+ const coseOffset = credIdLenOffset + 2 + credIdLen;
+ if (coseOffset < attestationObject.length) {
+ try {
+ return decodeCoseKey(attestationObject.slice(coseOffset)).uncompressed;
+ } catch {
+ // Not a valid COSE key here, keep scanning
+ }
+ }
+ }
+ }
+ }
+
+ // Fallback: try decoding directly
+ return decodeCoseKey(attestationObject).uncompressed;
+}
+
+/**
+ * Computes the 32-byte authorization payload hash from a Soroban authorization entry
+ * matching Soroban's preimage specification.
+ */
+export function computeAuthPayloadHash(
+ entry: xdr.SorobanAuthorizationEntry,
+ validUntilLedger: number,
+ networkPassphrase: string = NETWORK_PASSPHRASE,
+): Buffer {
+ const credentials = entry.credentials();
+ const networkId = hash(Buffer.from(networkPassphrase));
+
+ let preimage: xdr.HashIdPreimage;
+ switch (credentials.switch().value) {
+ case xdr.SorobanCredentialsType.sorobanCredentialsAddress().value: {
+ const addrAuth = credentials.address();
+ preimage = xdr.HashIdPreimage.envelopeTypeSorobanAuthorization(
+ new xdr.HashIdPreimageSorobanAuthorization({
+ networkId,
+ nonce: addrAuth.nonce(),
+ signatureExpirationLedger: validUntilLedger,
+ invocation: entry.rootInvocation(),
+ }),
+ );
+ break;
+ }
+ case xdr.SorobanCredentialsType.sorobanCredentialsAddressV2().value: {
+ const addrAuth = credentials.addressV2();
+ preimage = xdr.HashIdPreimage.envelopeTypeSorobanAuthorizationWithAddress(
+ new xdr.HashIdPreimageSorobanAuthorizationWithAddress({
+ networkId,
+ nonce: addrAuth.nonce(),
+ signatureExpirationLedger: validUntilLedger,
+ invocation: entry.rootInvocation(),
+ address: addrAuth.address(),
+ }),
+ );
+ break;
+ }
+ default:
+ throw new Error(`Unsupported credentials type: ${credentials.switch().name}`);
+ }
+
+ return hash(preimage.toXDR());
+}
+
+/**
+ * Packages the WebAuthn signature components (authenticatorData, clientDataJSON, rawSignature)
+ * into the ScVal structure expected by passkey smart-wallet __check_auth.
+ */
+export function buildPasskeySignatureScVal(
+ authenticatorData: Uint8Array,
+ clientDataJSON: Uint8Array,
+ rawSignature: Uint8Array,
+): xdr.ScVal {
+ return nativeToScVal({
+ authenticator_data: Buffer.from(authenticatorData),
+ client_data_json: Buffer.from(clientDataJSON),
+ signature: Buffer.from(rawSignature),
+ });
+}
+
+export interface RelayerClient {
+ deployWallet(params: { publicKey: Uint8Array; credentialId: string }): Promise<{ address: string }>;
+ submitTransaction(tx: Transaction): Promise<{ hash: string }>;
+}
+
+export function defaultRelayerClient(relayerUrl: string = PASSKEY_RELAYER_URL): RelayerClient {
+ return {
+ async deployWallet({ publicKey, credentialId }) {
+ if (!relayerUrl) {
+ // Deterministic contract address derived from public key when no live relayer is configured
+ const hex = Buffer.from(publicKey).toString("hex").slice(0, 32);
+ const address = new Address(Buffer.from(hex, "hex")).toString();
+ return { address };
+ }
+ const res = await fetch(`${relayerUrl}/wallet/deploy`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ publicKey: Buffer.from(publicKey).toString("base64"),
+ credentialId,
+ }),
+ });
+ if (!res.ok) throw new Error(`Relayer deploy failed: ${res.statusText}`);
+ const data = await res.json();
+ return { address: data.address };
+ },
+ async submitTransaction(tx: Transaction) {
+ if (!relayerUrl) {
+ return { hash: tx.hash().toString("hex") };
+ }
+ const res = await fetch(`${relayerUrl}/tx/submit`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ xdr: tx.toXDR() }),
+ });
+ if (!res.ok) throw new Error(`Relayer submit failed: ${res.statusText}`);
+ const data = await res.json();
+ return { hash: data.hash };
+ },
+ };
+}
+
+function bufferToBase64Url(buf: Uint8Array): string {
+ return Buffer.from(buf)
+ .toString("base64")
+ .replace(/\+/g, "-")
+ .replace(/\//g, "_")
+ .replace(/=+$/, "");
+}
+
+function base64UrlToBuffer(b64url: string): Uint8Array {
+ const b64 = b64url.replace(/-/g, "+").replace(/_/g, "/");
+ const pad = b64.length % 4 === 0 ? "" : "=".repeat(4 - (b64.length % 4));
+ return Buffer.from(b64 + pad, "base64");
+}
+
+/**
+ * Creates a new WebAuthn passkey credential and deploys a passkey smart wallet contract via the relayer.
+ */
+export async function createPasskeyWallet(
+ opts: { name: string; rpId?: string },
+ relayer?: RelayerClient,
+): Promise<{ address: string; credentialId: string }> {
+ if (typeof window === "undefined" || !navigator.credentials) {
+ throw new UserFacingError({ kind: "unknown", message: "WebAuthn passkeys are not supported in this browser." });
+ }
+
+ const challenge = new Uint8Array(32);
+ crypto.getRandomValues(challenge);
+
+ const credential = (await navigator.credentials.create({
+ publicKey: {
+ challenge,
+ rp: { name: "OracleDesk", id: opts.rpId ?? window.location.hostname },
+ user: {
+ id: crypto.getRandomValues(new Uint8Array(16)),
+ name: opts.name,
+ displayName: opts.name,
+ },
+ pubKeyCredParams: [{ alg: -7, type: "public-key" }],
+ authenticatorSelection: {
+ residentKey: "required",
+ userVerification: "required",
+ },
+ timeout: 60_000,
+ },
+ })) as PublicKeyCredential & { response: AuthenticatorAttestationResponse };
+
+ if (!credential) {
+ throw new UserFacingError({ kind: "rejected", message: "Passkey creation was cancelled." });
+ }
+
+ const credentialId = bufferToBase64Url(new Uint8Array(credential.rawId));
+ const attestationBytes = new Uint8Array(credential.response.attestationObject);
+ const publicKey = extractPublicKeyFromAttestation(attestationBytes);
+
+ const rClient = relayer ?? defaultRelayerClient();
+ const { address } = await rClient.deployWallet({ publicKey, credentialId });
+
+ storePasskeyWallet({ address, credentialId, network: NETWORK_PASSPHRASE });
+ return { address, credentialId };
+}
+
+/**
+ * Connects an existing passkey smart wallet using WebAuthn.
+ */
+export async function connectPasskeyWallet(opts?: { rpId?: string }): Promise<{ address: string; credentialId: string }> {
+ const stored = getStoredPasskeyWallet();
+ if (stored) {
+ return { address: stored.address, credentialId: stored.credentialId };
+ }
+
+ if (typeof window === "undefined" || !navigator.credentials) {
+ throw new UserFacingError({ kind: "unknown", message: "WebAuthn passkeys are not supported in this browser." });
+ }
+
+ const challenge = new Uint8Array(32);
+ crypto.getRandomValues(challenge);
+
+ const credential = (await navigator.credentials.get({
+ publicKey: {
+ challenge,
+ rpId: opts?.rpId ?? window.location.hostname,
+ userVerification: "required",
+ },
+ })) as PublicKeyCredential | null;
+
+ if (!credential) {
+ throw new UserFacingError({ kind: "rejected", message: "Passkey selection was cancelled." });
+ }
+
+ const credentialId = bufferToBase64Url(new Uint8Array(credential.rawId));
+ const fallbackAddress = stored?.address ?? `C${credentialId.slice(0, 55).toUpperCase()}`;
+
+ storePasskeyWallet({ address: fallbackAddress, credentialId, network: NETWORK_PASSPHRASE });
+ return { address: fallbackAddress, credentialId };
+}
+
+/**
+ * Returns a contract Signer backed by a passkey that signs Soroban authorization entries via WebAuthn.
+ */
+export function passkeySigner(
+ w: { address: string; credentialId: string },
+ relayer?: RelayerClient,
+): Extract {
+ const rClient = relayer ?? defaultRelayerClient();
+
+ return {
+ kind: "contract",
+ address: w.address,
+ async signAuthEntry(entry: xdr.SorobanAuthorizationEntry, validUntilLedger: number) {
+ const payloadHash = computeAuthPayloadHash(entry, validUntilLedger);
+
+ const assertion = (await navigator.credentials.get({
+ publicKey: {
+ challenge: payloadHash,
+ allowCredentials: [{ id: base64UrlToBuffer(w.credentialId), type: "public-key" }],
+ userVerification: "required",
+ },
+ })) as PublicKeyCredential & { response: AuthenticatorAssertionResponse };
+
+ if (!assertion) {
+ throw new UserFacingError({ kind: "rejected", message: "Passkey authorization was cancelled." });
+ }
+
+ const rawSig = derToRawSignature(new Uint8Array(assertion.response.signature));
+ const sigScVal = buildPasskeySignatureScVal(
+ new Uint8Array(assertion.response.authenticatorData),
+ new Uint8Array(assertion.response.clientDataJSON),
+ rawSig,
+ );
+
+ const clone = xdr.SorobanAuthorizationEntry.fromXDR(entry.toXDR());
+ const creds = clone.credentials();
+ if (creds.switch().value === xdr.SorobanCredentialsType.sorobanCredentialsAddress().value) {
+ creds.address().signatureExpirationLedger(validUntilLedger);
+ creds.address().signature(sigScVal);
+ } else if (creds.switch().value === xdr.SorobanCredentialsType.sorobanCredentialsAddressV2().value) {
+ creds.addressV2().signatureExpirationLedger(validUntilLedger);
+ creds.addressV2().signature(sigScVal);
+ }
+
+ return clone;
+ },
+ async submit(tx: Transaction) {
+ return rClient.submitTransaction(tx);
+ },
+ };
+}
diff --git a/lib/stellar/transaction-recovery.ts b/lib/stellar/transaction-recovery.ts
new file mode 100644
index 0000000..e624535
--- /dev/null
+++ b/lib/stellar/transaction-recovery.ts
@@ -0,0 +1,20 @@
+import type { AssembledTransaction } from '@stellar/stellar-sdk/contract';
+
+export const isFeeSurge = (error: unknown): boolean => /tx_bad_seq|insufficient fee|fee.?bump|resource limit|timeout/i.test(String(error));
+export const isExpiredTransaction = (error: unknown): boolean => /expired|tx_too_late|too late|time.?bound/i.test(String(error));
+
+export interface RecoveryAdvice { kind: 'fee-bump' | 'rebuild' | 'retry'; message: string; }
+export function transactionRecoveryAdvice(error: unknown): RecoveryAdvice {
+ if (isFeeSurge(error)) return { kind: 'fee-bump', message: 'Network fees increased. We can retry with a higher fee.' };
+ if (isExpiredTransaction(error)) return { kind: 'rebuild', message: 'This transaction expired. Rebuild it to refresh its sequence and time bounds.' };
+ return { kind: 'retry', message: 'The transaction did not complete. Please retry.' };
+}
+
+/** Retry a send once after a caller rebuilds the transaction with a fresh fee/sequence. */
+export async function sendWithRecovery(build: (feeBump: boolean) => Promise>, send: (tx: AssembledTransaction) => Promise): Promise {
+ try { return await send(await build(false)); }
+ catch (error) {
+ if (!isFeeSurge(error) && !isExpiredTransaction(error)) throw error;
+ return send(await build(isFeeSurge(error)));
+ }
+}
diff --git a/lib/stellar/tx-lifecycle.ts b/lib/stellar/tx-lifecycle.ts
new file mode 100644
index 0000000..1ec48dd
--- /dev/null
+++ b/lib/stellar/tx-lifecycle.ts
@@ -0,0 +1,260 @@
+import type { rpc, xdr } from "@stellar/stellar-sdk";
+import { scValToNative } from "@stellar/stellar-sdk";
+import type { AssembledTransaction } from "@stellar/stellar-sdk/contract";
+import {
+ describeError,
+ describeSubmission,
+ UserFacingError,
+ type ContractName,
+ type TxDescribedError,
+} from "./errors";
+
+export type { TxDescribedError };
+
+export type TxPhase =
+ | { name: "building" }
+ | { name: "simulating" }
+ | { name: "awaiting-signature" }
+ | { name: "submitting"; hash: string }
+ | { name: "pending"; hash: string; sentAt: number; attempts: number }
+ | { name: "confirmed"; hash: string; ledger: number; returnValue?: xdr.ScVal }
+ | { name: "failed"; hash: string | null; error: TxDescribedError }
+ | { name: "expired"; hash: string; lastLedgerSeen: number };
+
+/**
+ * The value of a simulated call. Contract `Result`s are unwrapped; failures
+ * become a UserFacingError named from the simulation's "Error(Contract, #N)".
+ */
+export function simulated(tx: AssembledTransaction, contract: ContractName = "marketCore"): T {
+ const sim = tx.simulation as { error?: string } | undefined;
+ let raw: unknown;
+ try {
+ raw = tx.result;
+ } catch (err) {
+ throw new UserFacingError(describeError(`${sim?.error ?? ""} ${String(err)}`, contract), err);
+ }
+ if (raw && typeof raw === "object" && "isOk" in raw && typeof (raw as { isOk: unknown }).isOk === "function") {
+ const result = raw as { isOk(): boolean; unwrap(): T };
+ if (!result.isOk()) throw new UserFacingError(describeError(`${sim?.error ?? ""}`, contract), raw);
+ return result.unwrap();
+ }
+ return raw as T;
+}
+
+export class TxLifecycle {
+ private phase: TxPhase = { name: "building" };
+ private listeners = new Set<() => void>();
+ private aborted = false;
+ private timer: ReturnType | null = null;
+ private readonly server: rpc.Server;
+ private readonly contract: ContractName;
+ private readonly pollIntervalMs: number;
+ private readonly maxPollMs: number;
+ private readonly onHash?: (hash: string) => void;
+
+ constructor(opts: {
+ server: rpc.Server;
+ contract: ContractName;
+ pollIntervalMs?: number;
+ maxPollMs?: number;
+ onHash?: (hash: string) => void;
+ }) {
+ this.server = opts.server;
+ this.contract = opts.contract;
+ this.pollIntervalMs = opts.pollIntervalMs ?? 1000;
+ this.maxPollMs = opts.maxPollMs ?? 60_000;
+ this.onHash = opts.onHash;
+ }
+
+ getSnapshot = (): TxPhase => {
+ return this.phase;
+ };
+
+ subscribe = (listener: () => void): (() => void) => {
+ this.listeners.add(listener);
+ return () => {
+ this.listeners.delete(listener);
+ };
+ };
+
+ private setPhase(newPhase: TxPhase) {
+ this.phase = newPhase;
+ for (const listener of this.listeners) {
+ try {
+ listener();
+ } catch {
+ // Ignore listener errors
+ }
+ }
+ }
+
+ abort(): void {
+ this.aborted = true;
+ if (this.timer) {
+ clearTimeout(this.timer);
+ this.timer = null;
+ }
+ }
+
+ async run(
+ tx: AssembledTransaction,
+ parse: (v: xdr.ScVal | undefined) => T,
+ ): Promise<{ value: T; txHash: string }> {
+ // 1. Simulating
+ this.setPhase({ name: "simulating" });
+ try {
+ simulated(tx, this.contract);
+ } catch (err) {
+ const described: TxDescribedError =
+ err instanceof UserFacingError ? err.described : describeError(err, this.contract);
+ this.setPhase({ name: "failed", hash: null, error: described });
+ if (err instanceof UserFacingError) throw err;
+ throw new UserFacingError(described, err);
+ }
+
+ // 2. Awaiting signature
+ this.setPhase({ name: "awaiting-signature" });
+ try {
+ await tx.sign();
+ } catch (err) {
+ const described: TxDescribedError = describeError(err, this.contract);
+ this.setPhase({ name: "failed", hash: null, error: described });
+ throw new UserFacingError(described, err);
+ }
+
+ const signed = (tx as unknown as { signed?: { hash: () => Buffer; timeBounds?: { maxTime?: string | number } } }).signed;
+ if (!signed) {
+ const error: TxDescribedError = {
+ kind: "unknown",
+ message: "Signing succeeded but no signed transaction was found.",
+ };
+ this.setPhase({ name: "failed", hash: null, error });
+ throw new UserFacingError(error);
+ }
+
+ const hash = signed.hash().toString("hex").toLowerCase();
+ this.onHash?.(hash);
+
+ // 3. Submitting
+ this.setPhase({ name: "submitting", hash });
+ let sendRes: rpc.Api.SendTransactionResponse;
+ try {
+ sendRes = await this.server.sendTransaction(signed as unknown as import("@stellar/stellar-sdk").Transaction);
+ } catch (err) {
+ const described: TxDescribedError = {
+ ...describeError(err, this.contract),
+ submission: "rejected-by-network",
+ };
+ this.setPhase({ name: "failed", hash, error: described });
+ throw new UserFacingError(described, err);
+ }
+
+ if (sendRes.status === "TRY_AGAIN_LATER") {
+ const error: TxDescribedError = {
+ kind: "submission",
+ submission: "try-again-later",
+ message: "The network is busy. Please try again in a moment.",
+ };
+ this.setPhase({ name: "failed", hash, error });
+ throw new UserFacingError(error, sendRes);
+ }
+
+ if (sendRes.status === "ERROR") {
+ const error = describeSubmission(sendRes, this.contract);
+ this.setPhase({ name: "failed", hash, error });
+ throw new UserFacingError(error, sendRes);
+ }
+
+ // PENDING or DUPLICATE -> start polling
+ const sentAt = Date.now();
+ let attempts = 0;
+ this.setPhase({ name: "pending", hash, sentAt, attempts });
+
+ let delayMs = this.pollIntervalMs;
+ let initialLedgerCloseTime: number | null = null;
+
+ while (!this.aborted) {
+ await new Promise((resolve) => {
+ this.timer = setTimeout(resolve, delayMs);
+ });
+ if (this.aborted) {
+ throw new UserFacingError({
+ kind: "unknown",
+ message: "Transaction monitoring was aborted.",
+ });
+ }
+
+ attempts++;
+ delayMs = Math.min(Math.floor(delayMs * 1.5), 5000);
+
+ let getRes: rpc.Api.GetTransactionResponse;
+ try {
+ getRes = await this.server.getTransaction(hash);
+ } catch {
+ // Transient network error; continue polling
+ continue;
+ }
+
+ if (getRes.status === "SUCCESS") {
+ let value: T;
+ try {
+ value = parse(getRes.returnValue);
+ } catch {
+ value = (getRes.returnValue ? scValToNative(getRes.returnValue) : null) as T;
+ }
+ this.setPhase({
+ name: "confirmed",
+ hash,
+ ledger: getRes.ledger ?? getRes.latestLedger,
+ returnValue: getRes.returnValue,
+ });
+ return { value, txHash: hash };
+ }
+
+ if (getRes.status === "FAILED") {
+ const fullErrText = `${getRes.resultXdr ? String(getRes.resultXdr) : ""} ${getRes.resultMetaXdr ? String(getRes.resultMetaXdr) : ""}`;
+ const described = describeError(fullErrText || "Transaction failed on chain", this.contract);
+ const error: TxDescribedError = {
+ ...described,
+ submission: "failed-on-chain",
+ };
+ this.setPhase({ name: "failed", hash, error });
+ throw new UserFacingError(error, getRes);
+ }
+
+ if (getRes.status === "NOT_FOUND") {
+ this.setPhase({ name: "pending", hash, sentAt, attempts });
+
+ if (initialLedgerCloseTime === null && getRes.latestLedgerCloseTime) {
+ initialLedgerCloseTime = getRes.latestLedgerCloseTime;
+ }
+
+ const maxTimeRaw = signed.timeBounds?.maxTime;
+ const maxTime = maxTimeRaw ? BigInt(maxTimeRaw) : 0n;
+ const isPastTimeBound =
+ maxTime > 0n &&
+ getRes.latestLedgerCloseTime !== undefined &&
+ BigInt(getRes.latestLedgerCloseTime) > maxTime;
+ const isPastMaxPoll =
+ initialLedgerCloseTime !== null &&
+ getRes.latestLedgerCloseTime !== undefined &&
+ (getRes.latestLedgerCloseTime - initialLedgerCloseTime) * 1000 >= this.maxPollMs;
+
+ if (isPastTimeBound || isPastMaxPoll) {
+ const error: TxDescribedError = {
+ kind: "expired",
+ submission: "not-found-after-timeout",
+ message: "Transaction expired before reaching a ledger.",
+ };
+ this.setPhase({ name: "expired", hash, lastLedgerSeen: getRes.latestLedger });
+ throw new UserFacingError(error, getRes);
+ }
+ }
+ }
+
+ throw new UserFacingError({
+ kind: "unknown",
+ message: "Transaction monitoring was aborted.",
+ });
+ }
+}
diff --git a/lib/stellar/tx-tracker-core.ts b/lib/stellar/tx-tracker-core.ts
new file mode 100644
index 0000000..f0d9fc1
--- /dev/null
+++ b/lib/stellar/tx-tracker-core.ts
@@ -0,0 +1,174 @@
+import type { rpc } from "@stellar/stellar-sdk";
+import { describeError, type ContractName } from "./errors";
+
+export type TrackedKind = "buy" | "sell" | "redeem" | "usdc-transfer";
+
+export interface TrackedTx {
+ /** Lowercase 64-char hex transaction hash */
+ hash: string;
+ kind: TrackedKind;
+ /** G-address of the account that signed */
+ holder: string;
+ marketId?: string;
+ outcome?: "Yes" | "No";
+ /** Bigint amounts represented as base-10 decimal strings */
+ amounts: Record;
+ networkPassphrase: string;
+ /** Epoch milliseconds at submit time */
+ submittedAt: number;
+ state: "pending" | "confirmed" | "failed" | "expired";
+ ledger?: number;
+ maxTime?: number;
+ mayNotHaveBeenSent?: boolean;
+ error?: { kind: string; message: string; code?: string };
+ followUp?: { type: "unlock-daily-pass"; traceId: string; amountRaw: string };
+}
+
+export const STORAGE_KEY = "oracledesk_pending_txs";
+const TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1000;
+
+/** Computes the query keys to invalidate when a trade confirms. */
+export function tradeInvalidationKeys(marketId: string, holder: string) {
+ return [
+ ["stellar", "market", marketId] as const,
+ ["stellar", "markets"] as const,
+ ["stellar", "position", marketId, holder] as const,
+ ["stellar", "usdcBalance", holder] as const,
+ ];
+}
+
+/** Converts bigint values into decimal strings for serialization. */
+export function toRecord(amounts: Record): Record {
+ const result: Record = {};
+ for (const [key, val] of Object.entries(amounts)) {
+ result[key] = val.toString(10);
+ }
+ return result;
+}
+
+/** Converts serialized decimal strings back into bigints without precision loss. */
+export function fromRecord(amounts: Record): Record {
+ const result: Record = {};
+ for (const [key, val] of Object.entries(amounts)) {
+ result[key] = BigInt(val);
+ }
+ return result;
+}
+
+/** Validates that a parsed item matches TrackedTx shape and is within the 24h validity window. */
+export function isValidRecord(item: unknown, currentNetworkPassphrase: string, now = Date.now()): item is TrackedTx {
+ if (!item || typeof item !== "object") return false;
+ const o = item as Partial;
+
+ if (typeof o.hash !== "string" || !/^[a-f0-9]{64}$/i.test(o.hash)) return false;
+ if (!["buy", "sell", "redeem", "usdc-transfer"].includes(o.kind as string)) return false;
+ if (typeof o.holder !== "string" || o.holder.length < 50) return false;
+ if (!o.amounts || typeof o.amounts !== "object") return false;
+ for (const val of Object.values(o.amounts)) {
+ if (typeof val !== "string" || !/^-?\d+$/.test(val)) return false;
+ }
+ if (o.networkPassphrase !== currentNetworkPassphrase) return false;
+ if (typeof o.submittedAt !== "number" || isNaN(o.submittedAt)) return false;
+ if (now - o.submittedAt > TWENTY_FOUR_HOURS_MS || o.submittedAt - now > 60_000) return false;
+ if (!["pending", "confirmed", "failed", "expired"].includes(o.state as string)) return false;
+
+ return true;
+}
+
+/** Safely reads records from storage, filtering out stale/invalid entries. */
+export function loadRecords(storage: Storage | null, networkPassphrase: string, now = Date.now()): TrackedTx[] {
+ if (!storage) return [];
+ try {
+ const raw = storage.getItem(STORAGE_KEY);
+ if (!raw) return [];
+ const parsed = JSON.parse(raw);
+ if (!Array.isArray(parsed)) return [];
+ return parsed.filter((item): item is TrackedTx => isValidRecord(item, networkPassphrase, now));
+ } catch {
+ return [];
+ }
+}
+
+/** Safely writes records to storage. */
+export function saveRecords(storage: Storage | null, records: TrackedTx[]): void {
+ if (!storage) return;
+ try {
+ storage.setItem(STORAGE_KEY, JSON.stringify(records));
+ } catch {
+ // SessionStorage full or unavailable
+ }
+}
+
+/** Merges records from multiple writers/tabs by transaction hash. */
+export function mergeRecords(existing: TrackedTx[], incoming: TrackedTx[]): TrackedTx[] {
+ const map = new Map();
+
+ for (const r of existing) {
+ map.set(r.hash.toLowerCase(), r);
+ }
+
+ for (const r of incoming) {
+ const key = r.hash.toLowerCase();
+ const prev = map.get(key);
+ if (!prev) {
+ map.set(key, r);
+ } else {
+ // Final states take precedence over pending
+ const isFinal = (s: TrackedTx["state"]) => s === "confirmed" || s === "failed" || s === "expired";
+ const state = isFinal(r.state) ? r.state : prev.state;
+ map.set(key, {
+ ...prev,
+ ...r,
+ state,
+ ledger: r.ledger ?? prev.ledger,
+ error: r.error ?? prev.error,
+ followUp: r.followUp ?? prev.followUp,
+ mayNotHaveBeenSent: r.mayNotHaveBeenSent ?? prev.mayNotHaveBeenSent,
+ });
+ }
+ }
+
+ return Array.from(map.values()).sort((a, b) => b.submittedAt - a.submittedAt);
+}
+
+/** Evaluates a single transaction's updated state from an RPC getTransaction response. */
+export function evaluateTxStatus(
+ record: TrackedTx,
+ res: rpc.Api.GetTransactionResponse,
+ contract: ContractName = "marketCore",
+): TrackedTx {
+ if (res.status === "SUCCESS") {
+ return {
+ ...record,
+ state: "confirmed",
+ ledger: res.ledger ?? res.latestLedger,
+ };
+ }
+
+ if (res.status === "FAILED") {
+ const fullErr = `${res.resultXdr ? String(res.resultXdr) : ""} ${res.resultMetaXdr ? String(res.resultMetaXdr) : ""}`;
+ const described = describeError(fullErr || "Transaction failed", contract);
+ return {
+ ...record,
+ state: "failed",
+ error: { kind: described.kind, message: described.message, code: described.code },
+ };
+ }
+
+ if (res.status === "NOT_FOUND") {
+ // If transaction had a time bound and latest ledger close time is past it
+ if (record.maxTime && res.latestLedgerCloseTime && res.latestLedgerCloseTime > record.maxTime) {
+ return {
+ ...record,
+ state: "expired",
+ mayNotHaveBeenSent: true,
+ error: {
+ kind: "expired",
+ message: "Transaction expired without landing on-chain (may not have been sent).",
+ },
+ };
+ }
+ }
+
+ return record;
+}
diff --git a/lib/stellar/tx-tracker.tsx b/lib/stellar/tx-tracker.tsx
new file mode 100644
index 0000000..6aa8c2a
--- /dev/null
+++ b/lib/stellar/tx-tracker.tsx
@@ -0,0 +1,238 @@
+"use client";
+
+import React, { createContext, useContext, useEffect, useRef, useState, useCallback } from "react";
+import { useQueryClient } from "@tanstack/react-query";
+import { NETWORK_PASSPHRASE } from "./config";
+import { rpcServer } from "./clients";
+import {
+ evaluateTxStatus,
+ loadRecords,
+ mergeRecords,
+ saveRecords,
+ tradeInvalidationKeys,
+ type TrackedKind,
+ type TrackedTx,
+} from "./tx-tracker-core";
+import { TxToastContainer } from "@/components/ui/tx-toast";
+
+export type { TrackedKind, TrackedTx };
+
+export interface TrackerApi {
+ track: (tx: Omit) => void;
+ list: TrackedTx[];
+ dismiss: (hash: string) => void;
+}
+
+const TxTrackerContext = createContext(null);
+
+export function useTxTracker(): TrackerApi {
+ const ctx = useContext(TxTrackerContext);
+ if (!ctx) {
+ throw new Error("useTxTracker must be used within TransactionTrackerProvider");
+ }
+ return ctx;
+}
+
+export function TransactionTrackerProvider({ children }: { children: React.ReactNode }) {
+ const queryClient = useQueryClient();
+ const [records, setRecords] = useState(() => {
+ if (typeof window === "undefined") return [];
+ try {
+ return loadRecords(window.sessionStorage, NETWORK_PASSPHRASE);
+ } catch {
+ return [];
+ }
+ });
+
+ const recordsRef = useRef(records);
+ useEffect(() => {
+ recordsRef.current = records;
+ }, [records]);
+
+ const channelRef = useRef(null);
+ const pollerTimerRef = useRef | null>(null);
+ const isPollingRef = useRef(false);
+
+ // Invalidate queries when a transaction finalises
+ const invalidateFor = useCallback(
+ (record: TrackedTx) => {
+ if (record.kind === "usdc-transfer") {
+ queryClient.invalidateQueries({ queryKey: ["stellar", "usdcBalance", record.holder] });
+ } else if (record.marketId) {
+ for (const key of tradeInvalidationKeys(record.marketId, record.holder)) {
+ queryClient.invalidateQueries({ queryKey: key });
+ }
+ }
+ },
+ [queryClient],
+ );
+
+ // Sync to sessionStorage
+ const updateRecords = useCallback((updater: (prev: TrackedTx[]) => TrackedTx[]) => {
+ setRecords((prev) => {
+ const next = updater(prev);
+ if (typeof window !== "undefined") {
+ try {
+ saveRecords(window.sessionStorage, next);
+ } catch {
+ // ignore storage error
+ }
+ }
+ return next;
+ });
+ }, []);
+
+ // BroadcastChannel setup for cross-tab sync and claim coordination
+ useEffect(() => {
+ if (typeof window === "undefined" || typeof BroadcastChannel === "undefined") return;
+
+ try {
+ const channel = new BroadcastChannel("oracledesk-tx");
+ channelRef.current = channel;
+
+ channel.onmessage = (event: MessageEvent) => {
+ const data = event.data;
+ if (!data || typeof data !== "object") return;
+
+ if (data.type === "record_update" && data.record) {
+ updateRecords((prev) => mergeRecords(prev, [data.record]));
+ if (data.record.state === "confirmed") {
+ invalidateFor(data.record);
+ }
+ } else if (data.type === "record_dismiss" && data.hash) {
+ updateRecords((prev) => prev.filter((r) => r.hash.toLowerCase() !== String(data.hash).toLowerCase()));
+ }
+ };
+
+ return () => {
+ channel.close();
+ channelRef.current = null;
+ };
+ } catch {
+ // BroadcastChannel unavailable
+ }
+ }, [updateRecords, invalidateFor]);
+
+ // Polling loop for pending records
+ useEffect(() => {
+ let active = true;
+
+ async function poll() {
+ if (!active) return;
+ if (typeof document !== "undefined" && document.visibilityState === "hidden") {
+ return;
+ }
+
+ const pending = recordsRef.current.filter((r) => r.state === "pending");
+ if (pending.length === 0) {
+ isPollingRef.current = false;
+ return;
+ }
+
+ isPollingRef.current = true;
+ const server = rpcServer();
+
+ for (const record of pending) {
+ if (!active) break;
+ try {
+ const res = await server.getTransaction(record.hash);
+ const updated = evaluateTxStatus(record, res);
+ if (updated.state !== record.state || updated.ledger !== record.ledger) {
+ updateRecords((prev) => mergeRecords(prev, [updated]));
+ if (updated.state === "confirmed") {
+ invalidateFor(updated);
+ }
+ channelRef.current?.postMessage({ type: "record_update", record: updated });
+ }
+ } catch {
+ // RPC hiccup, skip this record for this tick
+ }
+ }
+
+ if (active) {
+ // Backoff: 2s to 10s
+ pollerTimerRef.current = setTimeout(poll, 3000);
+ }
+ }
+
+ // Handle document visibility change
+ function handleVisibilityChange() {
+ if (typeof document !== "undefined" && document.visibilityState === "visible") {
+ if (pollerTimerRef.current) clearTimeout(pollerTimerRef.current);
+ poll();
+ }
+ }
+
+ if (typeof document !== "undefined") {
+ document.addEventListener("visibilitychange", handleVisibilityChange);
+ }
+
+ // Start polling immediately if pending records exist
+ poll();
+
+ return () => {
+ active = false;
+ if (pollerTimerRef.current) {
+ clearTimeout(pollerTimerRef.current);
+ pollerTimerRef.current = null;
+ }
+ if (typeof document !== "undefined") {
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
+ }
+ };
+ }, [updateRecords, invalidateFor]);
+
+ const track = useCallback(
+ (tx: Omit) => {
+ const newRecord: TrackedTx = {
+ ...tx,
+ hash: tx.hash.toLowerCase(),
+ state: "pending",
+ submittedAt: Date.now(),
+ };
+ updateRecords((prev) => mergeRecords(prev, [newRecord]));
+ channelRef.current?.postMessage({ type: "record_update", record: newRecord });
+
+ // Trigger poller immediately
+ if (!isPollingRef.current) {
+ setTimeout(async () => {
+ try {
+ const server = rpcServer();
+ const res = await server.getTransaction(newRecord.hash);
+ const updated = evaluateTxStatus(newRecord, res);
+ if (updated.state !== newRecord.state) {
+ updateRecords((prev) => mergeRecords(prev, [updated]));
+ if (updated.state === "confirmed") invalidateFor(updated);
+ channelRef.current?.postMessage({ type: "record_update", record: updated });
+ }
+ } catch {
+ // ignore
+ }
+ }, 1500);
+ }
+ },
+ [updateRecords, invalidateFor],
+ );
+
+ const dismiss = useCallback(
+ (hash: string) => {
+ const lower = hash.toLowerCase();
+ updateRecords((prev) => prev.filter((r) => r.hash.toLowerCase() !== lower));
+ channelRef.current?.postMessage({ type: "record_dismiss", hash: lower });
+ },
+ [updateRecords],
+ );
+
+ const value: TrackerApi = {
+ track,
+ list: records,
+ dismiss,
+ };
+
+ return (
+
+ {children}
+
+
+ );
+}
diff --git a/lib/stellar/typed-call.ts b/lib/stellar/typed-call.ts
new file mode 100644
index 0000000..6818815
--- /dev/null
+++ b/lib/stellar/typed-call.ts
@@ -0,0 +1,94 @@
+import { AssembledTransaction, Ok, Err, type Result } from "@stellar/stellar-sdk/contract";
+import type { marketCore, reasoningRegistry } from "./clients";
+import { describeError, UserFacingError, type ContractName } from "./errors";
+
+/** T from AssembledTransaction */
+export type TxValue = Tx extends AssembledTransaction ? T : never;
+
+/** Unwrapped value: Result -> V, otherwise T itself (non-distributive) */
+export type Unwrapped = [T] extends [Result] ? V : T;
+
+/** For a client method: (args, opts?) => Promise> -> Unwrapped */
+export type MethodValue = M extends (...a: any[]) => Promise ? Unwrapped> : never;
+
+export type MarketCoreClient = ReturnType;
+export type RegistryClient = ReturnType;
+export type Value = MethodValue;
+
+/**
+ * Converts any Uint8Array or Buffer into a lowercase hex string.
+ * Used for contract trace hashes and other byte arrays.
+ */
+export function bytesToHex(bytes: Uint8Array): string {
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
+}
+
+/**
+ * Internal unwrap helper that detects Ok/Err from @stellar/stellar-sdk/contract.
+ * Plain values (e.g. Position, numbers, duck-typed objects) are returned unchanged.
+ */
+export function unwrapResult>(
+ raw: unknown,
+ contract: ContractName,
+ simError?: string,
+): Unwrapped> {
+ if (
+ process.env.NODE_ENV !== "production" &&
+ raw &&
+ typeof raw === "object" &&
+ (raw.constructor?.name === "Ok" || raw.constructor?.name === "Err") &&
+ !(raw instanceof Ok || raw instanceof Err)
+ ) {
+ console.warn(
+ "[typed-call] Result instance detected from a different SDK copy. Ensure only one @stellar/stellar-sdk is bundled.",
+ );
+ }
+
+ if (raw instanceof Err) {
+ const detail = simError ? `${simError} ${raw.error?.message ?? ""}` : (raw.error?.message ?? raw.error ?? raw);
+ throw new UserFacingError(describeError(detail, contract), raw);
+ }
+
+ const value = raw instanceof Ok ? raw.unwrap() : raw;
+
+ // Single boundary cast: SentTransaction.result and simulated AssembledTransaction.result
+ // are typed broadly at the SDK boundary, while the binding provides the static return type.
+ return value as Unwrapped>;
+}
+
+/**
+ * Extracts and unwraps the simulation result of an AssembledTransaction.
+ * Infers the unwrapped return type directly from the transaction's type.
+ */
+export function read>(
+ tx: Tx,
+ contract: ContractName = "marketCore",
+): Unwrapped> {
+ let raw: unknown;
+ try {
+ raw = tx.result;
+ } catch (err) {
+ throw new UserFacingError(describeError(`${tx.simulation?.error ?? ""} ${String(err)}`, contract), err);
+ }
+ return unwrapResult(raw, contract, tx.simulation?.error);
+}
+
+/**
+ * Signs and submits an AssembledTransaction, first surfacing any simulation errors via read().
+ * Returns the unwrapped value and transaction hash.
+ */
+export async function submit>(
+ tx: Tx,
+ contract: ContractName = "marketCore",
+): Promise<{ value: Unwrapped>; txHash: string | null }> {
+ // Surface simulation failures before asking the wallet to sign.
+ read(tx, contract);
+ try {
+ const sent = await tx.signAndSend();
+ const value = unwrapResult(sent.result, contract);
+ return { value, txHash: sent.sendTransactionResponse?.hash ?? null };
+ } catch (err) {
+ if (err instanceof UserFacingError) throw err;
+ throw new UserFacingError(describeError(err, contract), err);
+ }
+}
diff --git a/lib/stellar/units.ts b/lib/stellar/units.ts
index a42c5e8..096aada 100644
--- a/lib/stellar/units.ts
+++ b/lib/stellar/units.ts
@@ -26,21 +26,40 @@ export function tryParseUsdc(input: string): bigint | null {
}
}
-/**
- * Formats base units as a decimal string. Trailing zeros are trimmed unless
- * `minDecimals` asks for some; `maxDecimals` truncates (never rounds up).
- */
-export function formatUsdc(raw: bigint, opts: { minDecimals?: number; maxDecimals?: number; grouping?: boolean } = {}): string {
- const { minDecimals = 0, maxDecimals = USDC_DECIMALS, grouping = false } = opts;
+export const XLM_DECIMALS = 7;
+export const XLM_UNIT = 10n ** BigInt(XLM_DECIMALS);
+
+function formatFixed(
+ raw: bigint,
+ decimals: number,
+ opts: { minDecimals?: number; maxDecimals?: number; grouping?: boolean } = {},
+): string {
+ const { minDecimals = 0, maxDecimals = decimals, grouping = false } = opts;
+ const unit = 10n ** BigInt(decimals);
const negative = raw < 0n;
const abs = negative ? -raw : raw;
- const whole = (abs / USDC_UNIT).toString();
- let frac = (abs % USDC_UNIT).toString().padStart(USDC_DECIMALS, "0").slice(0, maxDecimals).replace(/0+$/, "");
+ const whole = (abs / unit).toString();
+ let frac = (abs % unit).toString().padStart(decimals, "0").slice(0, maxDecimals).replace(/0+$/, "");
if (frac.length < minDecimals) frac = frac.padEnd(minDecimals, "0");
const wholeOut = grouping ? whole.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : whole;
return `${negative ? "-" : ""}${wholeOut}${frac ? `.${frac}` : ""}`;
}
+/**
+ * Formats base units as a decimal string. Trailing zeros are trimmed unless
+ * `minDecimals` asks for some; `maxDecimals` truncates (never rounds up).
+ */
+export function formatUsdc(raw: bigint, opts: { minDecimals?: number; maxDecimals?: number; grouping?: boolean } = {}): string {
+ return formatFixed(raw, USDC_DECIMALS, opts);
+}
+
+/**
+ * Formats stroops as a decimal XLM string with 7 decimal places.
+ */
+export function formatXlm(stroops: bigint, opts: { minDecimals?: number; maxDecimals?: number; grouping?: boolean } = {}): string {
+ return formatFixed(stroops, XLM_DECIMALS, opts);
+}
+
/** Display-only conversion. Never feed the result back into a transaction. */
export const usdcToNumber = (raw: bigint) => Number(formatUsdc(raw));
diff --git a/package-lock.json b/package-lock.json
index 009abe9..dd3aacf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,6 +7,7 @@
"": {
"name": "oracledesk-frontend",
"version": "0.1.0",
+ "license": "MIT",
"dependencies": {
"@creit.tech/stellar-wallets-kit": "2.5.0",
"@stellar/stellar-sdk": "^16.3.1",
@@ -38,6 +39,7 @@
"postcss": "^8.5.14",
"tailwindcss": "^3.4.19",
"typescript": "^5",
+ "vite": "^8.3.4",
"vitest": "^5.0.3"
}
},
@@ -1098,20 +1100,6 @@
"tslib": "^2.4.0"
}
},
- "node_modules/@emurgo/cardano-serialization-lib-browser": {
- "version": "13.2.1",
- "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-browser/-/cardano-serialization-lib-browser-13.2.1.tgz",
- "integrity": "sha512-7RfX1gI16Vj2DgCp/ZoXqyLAakWo6+X95ku/rYGbVzuS/1etrlSiJmdbmdm+eYmszMlGQjrtOJQeVLXoj4L/Ag==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/@emurgo/cardano-serialization-lib-nodejs": {
- "version": "13.2.0",
- "resolved": "https://registry.npmjs.org/@emurgo/cardano-serialization-lib-nodejs/-/cardano-serialization-lib-nodejs-13.2.0.tgz",
- "integrity": "sha512-Bz1zLGEqBQ0BVkqt1OgMxdBOE3BdUWUd7Ly9Ecr/aUwkA8AV1w1XzBMe4xblmJHnB1XXNlPH4SraXCvO+q0Mig==",
- "license": "MIT",
- "peer": true
- },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz",
@@ -1256,131 +1244,6 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
- "node_modules/@ethereumjs/common": {
- "version": "10.1.3",
- "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-10.1.3.tgz",
- "integrity": "sha512-ECWwbc4s8Ji7U0mkfZP6gIDy1FxXe0ZyVOTt0adkztPQRzX2DbH2ul7a83DSS8qYAiG6//vVXMkP60TyYOnv8Q==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@ethereumjs/util": "^10.1.3",
- "eventemitter3": "^5.0.1"
- }
- },
- "node_modules/@ethereumjs/rlp": {
- "version": "10.1.3",
- "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-10.1.3.tgz",
- "integrity": "sha512-d795YWkN6O8EJh/PgJ2zZKCdBMl8OlqkuVQESoidH666gaFtUuJ01jDtiuqfyOqTNcTdGhHi8LkQv1WEZzvZZw==",
- "license": "MPL-2.0",
- "peer": true,
- "bin": {
- "rlp": "bin/rlp.cjs"
- },
- "engines": {
- "node": ">=20"
- }
- },
- "node_modules/@ethereumjs/tx": {
- "version": "10.1.3",
- "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-10.1.3.tgz",
- "integrity": "sha512-5uk9qB2MjyF4axL6GGPvYODe3uR/h6k36boDbvjH81WYFphw/JAIrI1thkWQX4BCyF8bi6suxORhi+vDc3lPlg==",
- "license": "MPL-2.0",
- "peer": true,
- "dependencies": {
- "@ethereumjs/common": "^10.1.3",
- "@ethereumjs/rlp": "^10.1.3",
- "@ethereumjs/util": "^10.1.3",
- "@noble/curves": "^2.0.1",
- "@noble/hashes": "^2.0.1"
- },
- "engines": {
- "node": ">=20"
- }
- },
- "node_modules/@ethereumjs/tx/node_modules/@noble/curves": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz",
- "integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@noble/hashes": "2.4.0"
- },
- "engines": {
- "node": ">= 20.19.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@ethereumjs/tx/node_modules/@noble/hashes": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz",
- "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 20.19.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@ethereumjs/util": {
- "version": "10.1.3",
- "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-10.1.3.tgz",
- "integrity": "sha512-PhezOVe4DFaC+QLIsnK/tiOaXjpjS2F9AH4Ez0EfWevFw9NWNSg95l7I0dWuHF0B7v9odm2Ijqwo0EnARXtUmA==",
- "license": "MPL-2.0",
- "peer": true,
- "dependencies": {
- "@ethereumjs/rlp": "^10.1.3",
- "@noble/curves": "^2.0.1",
- "@noble/hashes": "^2.0.1"
- },
- "engines": {
- "node": ">=20"
- }
- },
- "node_modules/@ethereumjs/util/node_modules/@noble/curves": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz",
- "integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@noble/hashes": "2.4.0"
- },
- "engines": {
- "node": ">= 20.19.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@ethereumjs/util/node_modules/@noble/hashes": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz",
- "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 20.19.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@fivebinaries/coin-selection": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@fivebinaries/coin-selection/-/coin-selection-3.0.0.tgz",
- "integrity": "sha512-h25Pn1ZA7oqQBQDodGAgIsQt66T2wDge9onBKNqE66WNWL0KJiKJbpij8YOLo5AAlEIg5IS7EB1QjBgDOIg6DQ==",
- "license": "Apache-2.0",
- "peer": true,
- "dependencies": {
- "@emurgo/cardano-serialization-lib-browser": "^13.2.0",
- "@emurgo/cardano-serialization-lib-nodejs": "13.2.0"
- }
- },
"node_modules/@floating-ui/core": {
"version": "1.7.5",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
@@ -2208,16 +2071,6 @@
"integrity": "sha512-jwlVyzMFF296iaNgMWn1lu+EU6BeUD4mgPurEsy8EygYNCrjA8igLpsDlXhfvXhst9tX5w4wRuTDX+FZtpfCug==",
"license": "GPL-3.0"
},
- "node_modules/@mobily/ts-belt": {
- "version": "3.13.1",
- "resolved": "https://registry.npmjs.org/@mobily/ts-belt/-/ts-belt-3.13.1.tgz",
- "integrity": "sha512-K5KqIhPI/EoCTbA6CGbrenM9s41OouyK8A03fGJJcla/zKucsgLbz8HNbeseoLarRPgyWJsUyCYqFhI7t3Ra9Q==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 10.*"
- }
- },
"node_modules/@modelcontextprotocol/sdk": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz",
@@ -2325,47 +2178,6 @@
"@tybys/wasm-util": "^0.10.0"
}
},
- "node_modules/@near-js/accounts": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/@near-js/accounts/-/accounts-1.4.1.tgz",
- "integrity": "sha512-ni3QT9H3NdrbVVKyx56yvz93r89Dvpc/vgVtiIK2OdXjkK6jcj+UKMDRQ6F7rd9qJOInLkHZbVBtcR6j1CXLjw==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@near-js/crypto": "1.4.2",
- "@near-js/providers": "1.0.3",
- "@near-js/signers": "0.2.2",
- "@near-js/transactions": "1.3.3",
- "@near-js/types": "0.3.1",
- "@near-js/utils": "1.1.0",
- "@noble/hashes": "1.7.1",
- "borsh": "1.0.0",
- "depd": "2.0.0",
- "is-my-json-valid": "^2.20.6",
- "lru_map": "0.4.1",
- "near-abi": "0.2.0"
- }
- },
- "node_modules/@near-js/accounts/node_modules/@noble/hashes": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz",
- "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "^14.21.3 || >=16"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@near-js/accounts/node_modules/borsh": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz",
- "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==",
- "license": "Apache-2.0",
- "peer": true
- },
"node_modules/@near-js/crypto": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@near-js/crypto/-/crypto-1.4.2.tgz",
@@ -2413,145 +2225,6 @@
"integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==",
"license": "Apache-2.0"
},
- "node_modules/@near-js/keystores": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@near-js/keystores/-/keystores-0.2.2.tgz",
- "integrity": "sha512-DLhi/3a4qJUY+wgphw2Jl4S+L0AKsUYm1mtU0WxKYV5OBwjOXvbGrXNfdkheYkfh3nHwrQgtjvtszX6LrRXLLw==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@near-js/crypto": "1.4.2",
- "@near-js/types": "0.3.1"
- }
- },
- "node_modules/@near-js/keystores-browser": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@near-js/keystores-browser/-/keystores-browser-0.2.2.tgz",
- "integrity": "sha512-Pxqm7WGtUu6zj32vGCy9JcEDpZDSB5CCaLQDTQdF3GQyL0flyRv2I/guLAgU5FLoYxU7dJAX9mslJhPW7P2Bfw==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@near-js/crypto": "1.4.2",
- "@near-js/keystores": "0.2.2"
- }
- },
- "node_modules/@near-js/keystores-node": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/@near-js/keystores-node/-/keystores-node-0.1.2.tgz",
- "integrity": "sha512-MWLvTszZOVziiasqIT/LYNhUyWqOJjDGlsthOsY6dTL4ZcXjjmhmzrbFydIIeQr+CcEl5wukTo68ORI9JrHl6g==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@near-js/crypto": "1.4.2",
- "@near-js/keystores": "0.2.2"
- }
- },
- "node_modules/@near-js/providers": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@near-js/providers/-/providers-1.0.3.tgz",
- "integrity": "sha512-VJMboL14R/+MGKnlhhE3UPXCGYvMd1PpvF9OqZ9yBbulV7QVSIdTMfY4U1NnDfmUC2S3/rhAEr+3rMrIcNS7Fg==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@near-js/transactions": "1.3.3",
- "@near-js/types": "0.3.1",
- "@near-js/utils": "1.1.0",
- "borsh": "1.0.0",
- "exponential-backoff": "^3.1.2"
- },
- "optionalDependencies": {
- "node-fetch": "2.6.7"
- }
- },
- "node_modules/@near-js/providers/node_modules/borsh": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz",
- "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==",
- "license": "Apache-2.0",
- "peer": true
- },
- "node_modules/@near-js/providers/node_modules/node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
- "node_modules/@near-js/signers": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/@near-js/signers/-/signers-0.2.2.tgz",
- "integrity": "sha512-M6ib+af9zXAPRCjH2RyIS0+RhCmd9gxzCeIkQ+I2A3zjgGiEDkBZbYso9aKj8Zh2lPKKSH7h+u8JGymMOSwgyw==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@near-js/crypto": "1.4.2",
- "@near-js/keystores": "0.2.2",
- "@noble/hashes": "1.3.3"
- }
- },
- "node_modules/@near-js/signers/node_modules/@noble/hashes": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz",
- "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 16"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@near-js/transactions": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/@near-js/transactions/-/transactions-1.3.3.tgz",
- "integrity": "sha512-1AXD+HuxlxYQmRTLQlkVmH+RAmV3HwkAT8dyZDu+I2fK/Ec9BQHXakOJUnOBws3ihF+akQhamIBS5T0EXX/Ylw==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@near-js/crypto": "1.4.2",
- "@near-js/signers": "0.2.2",
- "@near-js/types": "0.3.1",
- "@near-js/utils": "1.1.0",
- "@noble/hashes": "1.7.1",
- "borsh": "1.0.0"
- }
- },
- "node_modules/@near-js/transactions/node_modules/@noble/hashes": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz",
- "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "^14.21.3 || >=16"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@near-js/transactions/node_modules/borsh": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz",
- "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==",
- "license": "Apache-2.0",
- "peer": true
- },
"node_modules/@near-js/types": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@near-js/types/-/types-0.3.1.tgz",
@@ -2570,31 +2243,6 @@
"mustache": "4.0.0"
}
},
- "node_modules/@near-js/wallet-account": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/@near-js/wallet-account/-/wallet-account-1.3.3.tgz",
- "integrity": "sha512-GDzg/Kz0GBYF7tQfyQQQZ3vviwV8yD+8F2lYDzsWJiqIln7R1ov0zaXN4Tii86TeS21KPn2hHAsVu3Y4txa8OQ==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@near-js/accounts": "1.4.1",
- "@near-js/crypto": "1.4.2",
- "@near-js/keystores": "0.2.2",
- "@near-js/providers": "1.0.3",
- "@near-js/signers": "0.2.2",
- "@near-js/transactions": "1.3.3",
- "@near-js/types": "0.3.1",
- "@near-js/utils": "1.1.0",
- "borsh": "1.0.0"
- }
- },
- "node_modules/@near-js/wallet-account/node_modules/borsh": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz",
- "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==",
- "license": "Apache-2.0",
- "peer": true
- },
"node_modules/@near-wallet-selector/core": {
"version": "8.10.2",
"resolved": "https://registry.npmjs.org/@near-wallet-selector/core/-/core-8.10.2.tgz",
@@ -2890,12 +2538,11 @@
"license": "MIT"
},
"node_modules/@oxc-project/types": {
- "version": "0.153.0",
- "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.153.0.tgz",
- "integrity": "sha512-jSNrRIyvPVLL5E1z/tS5zLAprosGz/FuI1PWwEOz59j3E4TTTzSpqKb/RDGqJhhW0QHYISGXxq582wGx6T11Tw==",
+ "version": "0.154.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.154.0.tgz",
+ "integrity": "sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA==",
"dev": true,
"license": "MIT",
- "peer": true,
"funding": {
"url": "https://github.com/sponsors/oxc-project"
}
@@ -2935,79 +2582,6 @@
"url": "https://opencollective.com/preact"
}
},
- "node_modules/@protobufjs/aspromise": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
- "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
- "license": "BSD-3-Clause",
- "peer": true
- },
- "node_modules/@protobufjs/base64": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
- "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
- "license": "BSD-3-Clause",
- "peer": true
- },
- "node_modules/@protobufjs/codegen": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz",
- "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==",
- "license": "BSD-3-Clause",
- "peer": true
- },
- "node_modules/@protobufjs/eventemitter": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz",
- "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==",
- "license": "BSD-3-Clause",
- "peer": true
- },
- "node_modules/@protobufjs/fetch": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz",
- "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==",
- "license": "BSD-3-Clause",
- "peer": true,
- "dependencies": {
- "@protobufjs/aspromise": "^1.1.1"
- }
- },
- "node_modules/@protobufjs/float": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
- "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
- "license": "BSD-3-Clause",
- "peer": true
- },
- "node_modules/@protobufjs/inquire": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz",
- "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==",
- "license": "BSD-3-Clause",
- "peer": true
- },
- "node_modules/@protobufjs/path": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
- "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
- "license": "BSD-3-Clause",
- "peer": true
- },
- "node_modules/@protobufjs/pool": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
- "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
- "license": "BSD-3-Clause",
- "peer": true
- },
- "node_modules/@protobufjs/utf8": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz",
- "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==",
- "license": "BSD-3-Clause",
- "peer": true
- },
"node_modules/@radix-ui/number": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
@@ -4703,9 +4277,9 @@
}
},
"node_modules/@rolldown/binding-android-arm-eabi": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.13.tgz",
- "integrity": "sha512-Vu/NICrgdRvUOeaJZIyB2FP63s6fO/4ud5l8dXmxDx9yDyn+mN0y+gsvsVviSli+T361Aqo0h46EuMoobrwawA==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.14.tgz",
+ "integrity": "sha512-aWR+XKH9+rW7m5fWq/5360J3mHycrx/o6xZM2DQFdJnTMdyP7/WzxPjhtLbVWdKo2y612/4U1bWqb3HQhiF7vg==",
"cpu": [
"arm"
],
@@ -4715,15 +4289,14 @@
"os": [
"android"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-android-arm64": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.13.tgz",
- "integrity": "sha512-6LEoIrGy5vvCd2boNnv2soPSUZj/PRvhp8R/t9KlX+mIZxThIE/ZqxrGXxmuNX0FuvQFvLdZr7S4HrYpYBVhEQ==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.14.tgz",
+ "integrity": "sha512-QiVxHofl6A8lQU7WAtOUY4QMVZXohxwz7WJJoeh8NBEUyKfIkMRKhYyq8az/1RypNiIXzNTtiS6KwHz0erxYRQ==",
"cpu": [
"arm64"
],
@@ -4733,15 +4306,14 @@
"os": [
"android"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-darwin-arm64": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.13.tgz",
- "integrity": "sha512-CaJSRzlQ6Q+zkDMVA9OkVxBjVoPRCDEE3v0FSJ9kIQBgRjFApA3Si4ijhbNVUji7ZJt+PfO0e46qy4nPInHUPA==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.14.tgz",
+ "integrity": "sha512-lTQOzHuBIooh3jIr5XINQkjPGEuGy+Dsy0meXDr6Sjty0b99kYgGh4uBC/8mJX1T0kC8d6S0aPP1Y+bHkh6aBw==",
"cpu": [
"arm64"
],
@@ -4751,15 +4323,14 @@
"os": [
"darwin"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-darwin-x64": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.13.tgz",
- "integrity": "sha512-e4r340I5hxSzJkD3YJBxgzq/rJ3wwxwdLLb2FPt1Zpyem20nrQPT11DDEEkazwxaHumH8wpglsp/Ozgj/wT6mw==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.14.tgz",
+ "integrity": "sha512-hyMKEGatjmBYCs/Q4sbIcL/GqpFEqsX3wc+HYVQ/85A4rxc1o7rPm4DUI4GV4k/h0ITddwFSGpqQunI14GXjTA==",
"cpu": [
"x64"
],
@@ -4769,15 +4340,14 @@
"os": [
"darwin"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-freebsd-x64": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.13.tgz",
- "integrity": "sha512-hoBWDZ4/K/mJKVMbsgUd1jfpA2DiOrJ54mpegObU9TBHBBrtX4FLIXJJQRDPZ/2Dn91GvPob+Z2hwKJzf4E5SQ==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.14.tgz",
+ "integrity": "sha512-u371GbXoVXrEgP20PwzoGNOdAOqAMhzo19JzzY+V4YmmnC+DTOoqdbMu+O+54emM59Mik/UdrtWgcuEDKWRPKA==",
"cpu": [
"x64"
],
@@ -4787,15 +4357,14 @@
"os": [
"freebsd"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.13.tgz",
- "integrity": "sha512-oF9fZu3vTWnTiVAkDFxU9PJLt1nh20K9RRpuHsR7ZnE2L7XookBbDBVLojCVSLGbvtSlxeUNnjAj6DbNsKyzbg==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.14.tgz",
+ "integrity": "sha512-BqwKsdZQf6EqVWr8fv2MrDYzAvOZ7+NYFSJESRGs87fkseEhs0TU9TXgRJTkZoRRkxTizyEg1LKUXfU3/78uqg==",
"cpu": [
"arm"
],
@@ -4805,15 +4374,14 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-linux-arm64-gnu": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.13.tgz",
- "integrity": "sha512-DTpb/+jMiqWMPgphn4ksW1zW+XLJ6dJJ9FMvnIk9I291LhCctMPhMYJrP5t9p6C9qa3KXadDdUEZHBaPh3kNxQ==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.14.tgz",
+ "integrity": "sha512-SD9kY8M009x/7s57Z1dgUVlP5+uYBgKQK0Tkr1WIWngrtUJmRCW1RJFMY7QDla2khXhmg2i5Io7MUjcmZNZ/KQ==",
"cpu": [
"arm64"
],
@@ -4823,15 +4391,14 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-linux-arm64-musl": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.13.tgz",
- "integrity": "sha512-xU+Kvv9N2A3SY35zFh1FWWNjxbadE/BKeqnkXe7vScU4GZsw757BlVmDLITZEq8DPpk6m7uoDYkK7P+x/uU5Ow==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.14.tgz",
+ "integrity": "sha512-BJ2CL19M6uuWesMgnqJzgxoI+N+eV7b0A9O9vLV42y+gitC41fNa8KElau1tHVzuLWX5GzEuxMPhAO0tQXQMkg==",
"cpu": [
"arm64"
],
@@ -4841,15 +4408,14 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.13.tgz",
- "integrity": "sha512-XMk/hnhh25oQ756Lclb1Q11h4ll0xC0Esa5w4Vzp+mAE2S3AGJgeM0SonrIgY8fHhjarb6hcoTuwoFG0VVP2ig==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.14.tgz",
+ "integrity": "sha512-4+Kl8daPV8NDHaD7mfCcc1pRM+Qg7ab8DyMm5FG5WoZgv4h2i3KFN1CybYBNbQqmuYm7ftJLvmMI1eHYJ22S/Q==",
"cpu": [
"ppc64"
],
@@ -4859,15 +4425,14 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-linux-s390x-gnu": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.13.tgz",
- "integrity": "sha512-U1BoTHYmlywE2n3HUWjzZ+8EQsKr+OwpxYuDWaubx42tUL8QSL7nOqRz/NVHanibbFP3M1Rxuprz/wNcbMKjqw==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.14.tgz",
+ "integrity": "sha512-V/h8ePq1fKDrmtFMz6xcCN3DKvuvMRrwwD1q0PkBeeo4DpK64biaKvqWGVxqCeYKqeRk7gE7/iKPxLCn08O97A==",
"cpu": [
"s390x"
],
@@ -4877,15 +4442,14 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-linux-x64-gnu": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.13.tgz",
- "integrity": "sha512-J4cm80Pc6wEwV5AZ42o62sIQgDk+Y7R2s646jIwuvO+4V46QB58N4vVuMPWCBaNgursXLpmUWJV//WQAkPvHBQ==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.14.tgz",
+ "integrity": "sha512-WxalXzgrLVpKC93xfpaJ3gCXUWzeCr+FRCbDVD2mUAy4L6Vo3lNVz0epUEUpxPWJkLNYUwM4OSIikv36OJ9mLg==",
"cpu": [
"x64"
],
@@ -4895,15 +4459,14 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-linux-x64-musl": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.13.tgz",
- "integrity": "sha512-W0euZS40U4V6JkmEnVCIX9mcsL6cbXQ4X8c2w+MMOIjFg68TXUW+u3RT+2e1t1pv9mg/EP3pDtK3POXdQ7Rxyw==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.14.tgz",
+ "integrity": "sha512-3G3tnAmTpdk9jO3GQtyHXqeFD2SlecfTws/Y3M2mmj9nMBwwuLT4kur8sZKeu7ENUHSpVO3cIsm5A52LEWWwlg==",
"cpu": [
"x64"
],
@@ -4913,15 +4476,14 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-openharmony-arm64": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.13.tgz",
- "integrity": "sha512-do/AF/4n9MRshia3a5aXoy8xM2c6mgfT6D7H/dY6my5z+hfCIR4ab7mk4IRj++nsEQpKy39kd0DQnDq+r692tw==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.14.tgz",
+ "integrity": "sha512-qyr5XiNGxm2ytx17vvtcJ9nXn6v1gENETi503bJx3OGwZ1tSonj7BosxbMa/xeAfSl5iS9X6KjEWYXLu6v1L7Q==",
"cpu": [
"arm64"
],
@@ -4931,15 +4493,14 @@
"os": [
"openharmony"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-win32-arm64-msvc": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.13.tgz",
- "integrity": "sha512-6FtUf2cJZobutJdxnGYX8z0vtbgqU0b2v8vfBhkXb9wp2MppMFtkunE+IaOntyi01rkIQoPW2GHABtfzsC0BRQ==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.14.tgz",
+ "integrity": "sha512-oA4o5o0S2yB199YyYXDzKUv1Z56Rc+mgOjwm7Z/vJ9Z8igiDPYvoOuDyo6g7AK/ZaF09nPhDKVnGBcYHO11GXA==",
"cpu": [
"arm64"
],
@@ -4949,15 +4510,14 @@
"os": [
"win32"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-win32-x64-msvc": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.13.tgz",
- "integrity": "sha512-UKhFaZTeTcbKrb3iU82m17jVcPEAoqDkCN5MBqgPyZSwp/cQmib21crTS0DdH7T1B7wZRWEI89YQAOJMet5yhg==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.14.tgz",
+ "integrity": "sha512-9mE94bf2GZUaR/fUSXCMpBoWkctu421Mi0ORpm4zqfbkjKep7RxzPFa5etcGs5h+2KApoWBOA/hAJa/7saGgEQ==",
"cpu": [
"x64"
],
@@ -4967,7 +4527,6 @@
"os": [
"win32"
],
- "peer": true,
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
@@ -4977,8 +4536,7 @@
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@rtsao/scc": {
"version": "1.1.0",
@@ -5062,13 +4620,6 @@
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
"license": "MIT"
},
- "node_modules/@sinclair/typebox": {
- "version": "0.33.24",
- "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.33.24.tgz",
- "integrity": "sha512-91up4t0BLjfkCZ4Ap/BcgaPrMaX6n0I2YRu+kc03xGhLy9G3N05nbTpnK8q7GXdv0PxwUoxi67A8o3Wr5U7j3w==",
- "license": "MIT",
- "peer": true
- },
"node_modules/@sindresorhus/merge-streams": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
@@ -6273,42 +5824,6 @@
"pnpm": ">=9.0.0"
}
},
- "node_modules/@stellar/stellar-base": {
- "version": "14.1.0",
- "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-14.1.0.tgz",
- "integrity": "sha512-A8kFli6QGy22SRF45IjgPAJfUNGjnI+R7g4DF5NZYVsD1kGf7B4ITyc4OPclLV9tqNI4/lXxafGEw0JEUbHixw==",
- "deprecated": "This package is now rolled into @stellar/stellar-sdk. Please use @stellar/stellar-sdk to continue receiving updates and support.",
- "license": "Apache-2.0",
- "peer": true,
- "dependencies": {
- "@noble/curves": "^1.9.6",
- "@stellar/js-xdr": "^3.1.2",
- "base32.js": "^0.1.0",
- "bignumber.js": "^9.3.1",
- "buffer": "^6.0.3",
- "sha.js": "^2.4.12"
- },
- "engines": {
- "node": ">=20.0.0"
- }
- },
- "node_modules/@stellar/stellar-base/node_modules/@stellar/js-xdr": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.2.tgz",
- "integrity": "sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==",
- "license": "Apache-2.0",
- "peer": true
- },
- "node_modules/@stellar/stellar-base/node_modules/bignumber.js": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
- "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "*"
- }
- },
"node_modules/@stellar/stellar-sdk": {
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-16.3.1.tgz",
@@ -6394,2229 +5909,179 @@
"react": "^18 || ^19"
}
},
- "node_modules/@trezor/analytics": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@trezor/analytics/-/analytics-1.5.0.tgz",
- "integrity": "sha512-evILW5XJEmfPlf0TY1duOLtGJ47pdGeSKVE3P75ODEUsRNxtPVqlkOUBPmYpCxPnzS8XDmkatT8lf9/DF0G6nA==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
- "dependencies": {
- "@trezor/env-utils": "1.5.0",
- "@trezor/utils": "9.5.0"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/blockchain-link": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/@trezor/blockchain-link/-/blockchain-link-2.6.2.tgz",
- "integrity": "sha512-HMz+Dm6nMflqRkaebMqpv3uNnVkRrb6lD2HKTHNBGhjVbqf0wRzJ8JoQ08wn/sF00ljJZz8pGnpcMYHJNxE+wQ==",
+ "node_modules/@trezor/connect-plugin-stellar": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/connect-plugin-stellar/-/connect-plugin-stellar-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-v4lMnnBPxLoV/Yf8F0WmtkZGNsqurpxK62kqvaDeVoAtn5Ud+l6POQkLeQRiGsJYVm0vSDc4LHb5vLMrZTH/KA==",
"license": "SEE LICENSE IN LICENSE.md",
- "peer": true,
- "dependencies": {
- "@solana-program/compute-budget": "^0.8.0",
- "@solana-program/stake": "^0.2.1",
- "@solana-program/token": "^0.5.1",
- "@solana-program/token-2022": "^0.4.2",
- "@solana/kit": "^2.3.0",
- "@solana/rpc-types": "^2.3.0",
- "@stellar/stellar-sdk": "14.2.0",
- "@trezor/blockchain-link-types": "1.5.1",
- "@trezor/blockchain-link-utils": "1.5.2",
- "@trezor/env-utils": "1.5.0",
- "@trezor/utils": "9.5.0",
- "@trezor/utxo-lib": "2.5.0",
- "@trezor/websocket-client": "1.3.0",
- "@types/web": "^0.0.197",
- "crypto-browserify": "3.12.0",
- "socks-proxy-agent": "8.0.5",
- "stream-browserify": "^3.0.0",
- "xrpl": "4.4.3"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/blockchain-link-types": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/@trezor/blockchain-link-types/-/blockchain-link-types-1.5.1.tgz",
- "integrity": "sha512-Idavz6LwLBW8sXc69fh5AJEnl666EDl2Nt3io7updvBgOR0/P12I900DgjNhCKtiWuv66A33/5RE7zLcj3lfnw==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
- "dependencies": {
- "@trezor/utils": "9.5.0",
- "@trezor/utxo-lib": "2.5.0"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/blockchain-link-utils": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/@trezor/blockchain-link-utils/-/blockchain-link-utils-1.5.2.tgz",
- "integrity": "sha512-OSS5OEE98FMnYfjoEALPjBt7ebjC/FKnq3HOolHdEWXBpVlXZNN2+Vo1R9J6WbZUU087sHuUTJJy/GJYWY13Tg==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
"dependencies": {
- "@mobily/ts-belt": "^3.13.1",
- "@stellar/stellar-sdk": "14.2.0",
- "@trezor/env-utils": "1.5.0",
- "@trezor/protobuf": "1.5.2",
- "@trezor/utils": "9.5.0",
- "xrpl": "4.4.3"
+ "@trezor/utils": "10.0.0-alpha.1"
},
"peerDependencies": {
+ "@stellar/stellar-sdk": "^13.3.0",
+ "@trezor/connect": "9.x.x",
"tslib": "^2.6.2"
}
},
- "node_modules/@trezor/blockchain-link-utils/node_modules/@stellar/stellar-sdk": {
- "version": "14.2.0",
- "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-14.2.0.tgz",
- "integrity": "sha512-7nh2ogzLRMhfkIC0fGjn1LHUzk3jqVw8tjAuTt5ADWfL9CSGBL18ILucE9igz2L/RU2AZgeAvhujAnW91Ut/oQ==",
- "hasInstallScript": true,
- "license": "Apache-2.0",
- "peer": true,
- "dependencies": {
- "@stellar/stellar-base": "^14.0.1",
- "axios": "^1.12.2",
- "bignumber.js": "^9.3.1",
- "eventsource": "^2.0.2",
- "feaxios": "^0.0.23",
- "randombytes": "^2.1.0",
- "toml": "^3.0.0",
- "urijs": "^1.19.1"
- },
- "engines": {
- "node": ">=20.0.0"
- }
- },
- "node_modules/@trezor/blockchain-link-utils/node_modules/@trezor/protobuf": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-1.5.2.tgz",
- "integrity": "sha512-zViaL1jKue8DUTVEDg0C/lMipqNMd/Z3kr29/+MeZOoupjaXIQ2Lqp3WAMe8hvNTKKX8aNQH9JrbapJ6w9FMXw==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
+ "node_modules/@trezor/connect-plugin-stellar/node_modules/@trezor/utils": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-A+txzREoeX2MO1AqocDBsMNe+R21jTx5kungXGuzeTRRevARLsYh8MPes0170uMjq4qNSgopBnYZK18WyksOmQ==",
+ "license": "MIT",
"dependencies": {
- "@trezor/schema-utils": "1.4.0",
- "long": "5.2.5",
- "protobufjs": "7.4.0"
+ "bignumber.js": "^9.3.1"
},
"peerDependencies": {
"tslib": "^2.6.2"
}
},
- "node_modules/@trezor/blockchain-link-utils/node_modules/bignumber.js": {
+ "node_modules/@trezor/connect-plugin-stellar/node_modules/bignumber.js": {
"version": "9.3.1",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
"integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
"license": "MIT",
- "peer": true,
"engines": {
"node": "*"
}
},
- "node_modules/@trezor/blockchain-link-utils/node_modules/eventsource": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
- "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/@trezor/blockchain-link-utils/node_modules/protobufjs": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
- "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
- "hasInstallScript": true,
- "license": "BSD-3-Clause",
- "peer": true,
- "dependencies": {
- "@protobufjs/aspromise": "^1.1.2",
- "@protobufjs/base64": "^1.1.2",
- "@protobufjs/codegen": "^2.0.4",
- "@protobufjs/eventemitter": "^1.1.0",
- "@protobufjs/fetch": "^1.1.0",
- "@protobufjs/float": "^1.0.2",
- "@protobufjs/inquire": "^1.1.0",
- "@protobufjs/path": "^1.1.2",
- "@protobufjs/pool": "^1.1.0",
- "@protobufjs/utf8": "^1.1.0",
- "@types/node": ">=13.7.0",
- "long": "^5.0.0"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana-program/compute-budget": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@solana-program/compute-budget/-/compute-budget-0.8.0.tgz",
- "integrity": "sha512-qPKxdxaEsFxebZ4K5RPuy7VQIm/tfJLa1+Nlt3KNA8EYQkz9Xm8htdoEaXVrer9kpgzzp9R3I3Bh6omwCM06tQ==",
- "license": "Apache-2.0",
- "peer": true,
- "peerDependencies": {
- "@solana/kit": "^2.1.0"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana-program/stake": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/@solana-program/stake/-/stake-0.2.1.tgz",
- "integrity": "sha512-ssNPsJv9XHaA+L7ihzmWGYcm/+XYURQ8UA3wQMKf6ccEHyHOUgoglkkDU/BoA0+wul6HxZUN0tHFymC0qFw6sg==",
- "license": "MIT",
- "peer": true,
- "peerDependencies": {
- "@solana/kit": "^2.1.0"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana-program/token": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/@solana-program/token/-/token-0.5.1.tgz",
- "integrity": "sha512-bJvynW5q9SFuVOZ5vqGVkmaPGA0MCC+m9jgJj1nk5m20I389/ms69ASnhWGoOPNcie7S9OwBX0gTj2fiyWpfag==",
- "license": "Apache-2.0",
- "peer": true,
- "peerDependencies": {
- "@solana/kit": "^2.1.0"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana-program/token-2022": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/@solana-program/token-2022/-/token-2022-0.4.2.tgz",
- "integrity": "sha512-zIpR5t4s9qEU3hZKupzIBxJ6nUV5/UVyIT400tu9vT1HMs5JHxaTTsb5GUhYjiiTvNwU0MQavbwc4Dl29L0Xvw==",
- "license": "Apache-2.0",
- "peer": true,
- "peerDependencies": {
- "@solana/kit": "^2.1.0",
- "@solana/sysvars": "^2.1.0"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/accounts": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-2.3.0.tgz",
- "integrity": "sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw==",
+ "node_modules/@trezor/connect-web": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/connect-web/-/connect-web-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-CW1ZXzXNVYrJ2WuYneLK2LznkRAfKxRPB3vJyv1U2gia5Q7hsblImITsutLOztO0C2xO1sfETTCyVzfRkRVJEA==",
"license": "MIT",
- "peer": true,
"dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/rpc-spec": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
+ "@trezor/connect-common": "10.0.0-alpha.1",
+ "@trezor/utils": "10.0.0-alpha.1",
+ "@trezor/websocket-client": "10.0.0-alpha.1"
},
"peerDependencies": {
- "typescript": ">=5.3.3"
+ "tslib": "^2.6.2"
}
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/addresses": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-2.3.0.tgz",
- "integrity": "sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/assertions": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/nominal-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
+ "node_modules/@trezor/connect-web/node_modules/@sinclair/typebox": {
+ "version": "0.34.52",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz",
+ "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==",
+ "license": "MIT"
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/assertions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-2.3.0.tgz",
- "integrity": "sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ==",
+ "node_modules/@trezor/connect-web/node_modules/@trezor/connect-common": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/connect-common/-/connect-common-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-tuvM72XHACogT/fkp9D8wyzTE8h4X9emYUhvFs2pdTyIfTFs5RHDbcHQWFsvJgJoTK0H44XSSJb8pORijRfn9A==",
"license": "MIT",
- "peer": true,
"dependencies": {
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
+ "@trezor/device-utils": "10.0.0-alpha.1",
+ "@trezor/protobuf": "10.0.0-alpha.1",
+ "@trezor/protocol": "^10.0.0-alpha.1",
+ "@trezor/schema-utils": "10.0.0-alpha.1",
+ "@trezor/type-utils": "10.0.0-alpha.1",
+ "@trezor/utils": "10.0.0-alpha.1"
},
"peerDependencies": {
- "typescript": ">=5.3.3"
+ "tslib": "^2.6.2"
}
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.3.0.tgz",
- "integrity": "sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-data-structures": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/options": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
+ "node_modules/@trezor/connect-web/node_modules/@trezor/device-utils": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/device-utils/-/device-utils-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-93LhEqH8uKCZHLtF+62uxd3/PXCfqpK4Z98ztfGu5vrtmoONb9dV8Falha0b3KXPDrQ10TUKasFGKLg570Z/Ew==",
+ "license": "MIT"
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs-core": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz",
- "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==",
+ "node_modules/@trezor/connect-web/node_modules/@trezor/protobuf": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-aCUyqAr7Sho9TequaNAjnf27mgae6qzesNrOgB19bUrDrhaDDd/2eyr2SrrY1G4hPYkTyBC0jymvQnozn9f/kA==",
"license": "MIT",
- "peer": true,
"dependencies": {
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
+ "@bufbuild/protobuf": "^2.11.0",
+ "@trezor/schema-utils": "10.0.0-alpha.1"
},
"peerDependencies": {
- "typescript": ">=5.3.3"
+ "tslib": "^2.6.2"
}
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs-data-structures": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.3.0.tgz",
- "integrity": "sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw==",
+ "node_modules/@trezor/connect-web/node_modules/@trezor/protocol": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/@trezor/protocol/-/protocol-10.0.1.tgz",
+ "integrity": "sha512-uoFyMzfr3/p7uXhTJSxXurfwM6N0vDicTKHlQRrwH9dMcidEEOxuOJZBrhKnoj4osLfDPt5+ctQ+mqFjxJA9Tw==",
"license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
"peerDependencies": {
- "typescript": ">=5.3.3"
+ "tslib": "^2.6.2"
}
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs-numbers": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz",
- "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==",
+ "node_modules/@trezor/connect-web/node_modules/@trezor/schema-utils": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/schema-utils/-/schema-utils-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-0beYv0b0De3Z60sZzM1T+IrYwXeNL+7RKfLokTvqEFDzsQkwxhYrIX47FsBhGsOmGWx9x4+65dxDbnyd4wZT6g==",
"license": "MIT",
- "peer": true,
"dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
+ "@sinclair/typebox": "^0.34.49",
+ "@trezor/type-utils": "10.0.0-alpha.1",
+ "ts-mixer": "^6.0.4"
},
"peerDependencies": {
- "typescript": ">=5.3.3"
+ "tslib": "^2.6.2"
}
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/codecs-strings": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.3.0.tgz",
- "integrity": "sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "fastestsmallesttextencoderdecoder": "^1.0.22",
- "typescript": ">=5.3.3"
- }
+ "node_modules/@trezor/connect-web/node_modules/@trezor/type-utils": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/type-utils/-/type-utils-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-wK75rrwlyXFgPfdHQFRbeKCoj+orQLXKj7rliMK30z+F1y+rEcfv/MW2VP48Q9mL5pea+ZX1nRnb4hYx1v38Ow==",
+ "license": "MIT"
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/errors": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz",
- "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==",
+ "node_modules/@trezor/connect-web/node_modules/@trezor/utils": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-A+txzREoeX2MO1AqocDBsMNe+R21jTx5kungXGuzeTRRevARLsYh8MPes0170uMjq4qNSgopBnYZK18WyksOmQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
- "chalk": "^5.4.1",
- "commander": "^14.0.0"
- },
- "bin": {
- "errors": "bin/cli.mjs"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/fast-stable-stringify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-2.3.0.tgz",
- "integrity": "sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/functional": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-2.3.0.tgz",
- "integrity": "sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
+ "bignumber.js": "^9.3.1"
},
"peerDependencies": {
- "typescript": ">=5.3.3"
+ "tslib": "^2.6.2"
}
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/instructions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-2.3.0.tgz",
- "integrity": "sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ==",
+ "node_modules/@trezor/connect-web/node_modules/@trezor/websocket-client": {
+ "version": "10.0.0-alpha.1",
+ "resolved": "https://registry.npmjs.org/@trezor/websocket-client/-/websocket-client-10.0.0-alpha.1.tgz",
+ "integrity": "sha512-129Ot1m+fDodRFBvav2d6v8nLxZLAl/udQP5l5W6jxQZcWUuviphDceT/juF8EvNGdw+L6OIu6fH+yCXARpFWQ==",
"license": "MIT",
- "peer": true,
"dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
+ "@trezor/utils": "10.0.0-alpha.1",
+ "ws": "^8.20.0"
},
"peerDependencies": {
- "typescript": ">=5.3.3"
+ "tslib": "^2.6.2"
}
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/keys": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-2.3.0.tgz",
- "integrity": "sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ==",
+ "node_modules/@trezor/connect-web/node_modules/bignumber.js": {
+ "version": "9.3.1",
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
+ "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
"license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/assertions": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/nominal-types": "2.3.0"
- },
"engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
+ "node": "*"
}
},
- "node_modules/@trezor/blockchain-link/node_modules/@solana/kit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-2.3.0.tgz",
- "integrity": "sha512-sb6PgwoW2LjE5oTFu4lhlS/cGt/NB3YrShEyx7JgWFWysfgLdJnhwWThgwy/4HjNsmtMrQGWVls0yVBHcMvlMQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/accounts": "2.3.0",
- "@solana/addresses": "2.3.0",
- "@solana/codecs": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/instructions": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/programs": "2.3.0",
- "@solana/rpc": "2.3.0",
- "@solana/rpc-parsed-types": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/rpc-subscriptions": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/signers": "2.3.0",
- "@solana/sysvars": "2.3.0",
- "@solana/transaction-confirmation": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
+ "node_modules/@trezor/connect-web/node_modules/ws": {
+ "version": "8.22.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz",
+ "integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==",
+ "license": "MIT",
"engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/nominal-types": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-2.3.0.tgz",
- "integrity": "sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/options": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.3.0.tgz",
- "integrity": "sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-data-structures": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/programs": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-2.3.0.tgz",
- "integrity": "sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/promises": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-2.3.0.tgz",
- "integrity": "sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-2.3.0.tgz",
- "integrity": "sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/fast-stable-stringify": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/rpc-api": "2.3.0",
- "@solana/rpc-spec": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/rpc-transformers": "2.3.0",
- "@solana/rpc-transport-http": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-api": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-2.3.0.tgz",
- "integrity": "sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/rpc-parsed-types": "2.3.0",
- "@solana/rpc-spec": "2.3.0",
- "@solana/rpc-transformers": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-parsed-types": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-2.3.0.tgz",
- "integrity": "sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-spec": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-2.3.0.tgz",
- "integrity": "sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-spec-types": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-2.3.0.tgz",
- "integrity": "sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-subscriptions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-2.3.0.tgz",
- "integrity": "sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/fast-stable-stringify": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/promises": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/rpc-subscriptions-api": "2.3.0",
- "@solana/rpc-subscriptions-channel-websocket": "2.3.0",
- "@solana/rpc-subscriptions-spec": "2.3.0",
- "@solana/rpc-transformers": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/subscribable": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-subscriptions-api": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-2.3.0.tgz",
- "integrity": "sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/rpc-subscriptions-spec": "2.3.0",
- "@solana/rpc-transformers": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-subscriptions-channel-websocket": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-2.3.0.tgz",
- "integrity": "sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/rpc-subscriptions-spec": "2.3.0",
- "@solana/subscribable": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3",
- "ws": "^8.18.0"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-subscriptions-spec": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-2.3.0.tgz",
- "integrity": "sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/promises": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/subscribable": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-transformers": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-2.3.0.tgz",
- "integrity": "sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/nominal-types": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-transport-http": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-2.3.0.tgz",
- "integrity": "sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/rpc-spec": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "undici-types": "^7.11.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/rpc-types": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-2.3.0.tgz",
- "integrity": "sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/nominal-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/signers": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-2.3.0.tgz",
- "integrity": "sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/instructions": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/nominal-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/subscribable": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-2.3.0.tgz",
- "integrity": "sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/sysvars": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-2.3.0.tgz",
- "integrity": "sha512-LvjADZrpZ+CnhlHqfI5cmsRzX9Rpyb1Ox2dMHnbsRNzeKAMhu9w4ZBIaeTdO322zsTr509G1B+k2ABD3whvUBA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/accounts": "2.3.0",
- "@solana/codecs": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/transaction-confirmation": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-2.3.0.tgz",
- "integrity": "sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/promises": "2.3.0",
- "@solana/rpc": "2.3.0",
- "@solana/rpc-subscriptions": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/transaction-messages": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-2.3.0.tgz",
- "integrity": "sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-data-structures": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/instructions": "2.3.0",
- "@solana/nominal-types": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@solana/transactions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-2.3.0.tgz",
- "integrity": "sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-data-structures": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/instructions": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/nominal-types": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/@stellar/stellar-sdk": {
- "version": "14.2.0",
- "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-14.2.0.tgz",
- "integrity": "sha512-7nh2ogzLRMhfkIC0fGjn1LHUzk3jqVw8tjAuTt5ADWfL9CSGBL18ILucE9igz2L/RU2AZgeAvhujAnW91Ut/oQ==",
- "hasInstallScript": true,
- "license": "Apache-2.0",
- "peer": true,
- "dependencies": {
- "@stellar/stellar-base": "^14.0.1",
- "axios": "^1.12.2",
- "bignumber.js": "^9.3.1",
- "eventsource": "^2.0.2",
- "feaxios": "^0.0.23",
- "randombytes": "^2.1.0",
- "toml": "^3.0.0",
- "urijs": "^1.19.1"
- },
- "engines": {
- "node": ">=20.0.0"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/bignumber.js": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
- "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/chalk": {
- "version": "5.6.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
- "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "^12.17.0 || ^14.13 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/eventsource": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz",
- "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/@trezor/blockchain-link/node_modules/undici-types": {
- "version": "7.30.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.30.0.tgz",
- "integrity": "sha512-7QjA5O+GhM27do7Id6hQZpnYEd7WzHbs7/XIS9A1k+Gat/ZVF7Jmpzt68zL/205f65FYwDNLSjQemHPS8ReM/A==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/@trezor/connect": {
- "version": "9.7.3",
- "resolved": "https://registry.npmjs.org/@trezor/connect/-/connect-9.7.3.tgz",
- "integrity": "sha512-oAOfvJHT8tPqOXTmCOhn8uTZcoqSDuWAiWXQegx7C46tq+NLg+enkYXxUYEHq/9PmfZAOrUT9VMxZDsXM2thkA==",
- "license": "SEE LICENSE IN LICENSE.md",
- "peer": true,
- "dependencies": {
- "@ethereumjs/common": "^10.1.0",
- "@ethereumjs/tx": "^10.1.0",
- "@fivebinaries/coin-selection": "3.0.0",
- "@mobily/ts-belt": "^3.13.1",
- "@noble/hashes": "^1.6.1",
- "@scure/bip39": "^1.5.1",
- "@solana-program/compute-budget": "^0.8.0",
- "@solana-program/system": "^0.7.0",
- "@solana-program/token": "^0.5.1",
- "@solana-program/token-2022": "^0.4.2",
- "@solana/kit": "^2.3.0",
- "@trezor/blockchain-link": "2.6.2",
- "@trezor/blockchain-link-types": "1.5.1",
- "@trezor/blockchain-link-utils": "1.5.2",
- "@trezor/connect-analytics": "1.4.0",
- "@trezor/connect-common": "0.5.1",
- "@trezor/crypto-utils": "1.2.0",
- "@trezor/device-authenticity": "1.1.2",
- "@trezor/device-utils": "1.2.0",
- "@trezor/env-utils": "^1.5.0",
- "@trezor/protobuf": "1.5.3",
- "@trezor/protocol": "1.3.1",
- "@trezor/schema-utils": "1.4.0",
- "@trezor/transport": "1.6.3",
- "@trezor/type-utils": "1.2.0",
- "@trezor/utils": "9.5.0",
- "@trezor/utxo-lib": "2.5.0",
- "blakejs": "^1.2.1",
- "bs58": "^6.0.0",
- "bs58check": "^4.0.0",
- "cbor": "^10.0.10",
- "cross-fetch": "^4.0.0",
- "jws": "^4.0.0"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-analytics": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@trezor/connect-analytics/-/connect-analytics-1.4.0.tgz",
- "integrity": "sha512-hy2J2oeIhRC/e1bOWXo5dsVMVnDwO2UKnxhR6FD8PINR3jgM6PWAXc6k33WJsBcyiTzwMP7/xPysLcgNJH5o4w==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
- "dependencies": {
- "@trezor/analytics": "1.5.0"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-common": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/@trezor/connect-common/-/connect-common-0.5.1.tgz",
- "integrity": "sha512-wdpVCwdylBh4SBO5Ys40tB/d59UlfjmxgBHDkkLgaR+JcqkthCfiw5VlUrV9wu65lquejAZhA5KQL4mUUUhCow==",
- "license": "SEE LICENSE IN LICENSE.md",
- "peer": true,
- "dependencies": {
- "@trezor/env-utils": "1.5.0",
- "@trezor/type-utils": "1.2.0",
- "@trezor/utils": "9.5.0"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-plugin-stellar": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/connect-plugin-stellar/-/connect-plugin-stellar-10.0.0-alpha.1.tgz",
- "integrity": "sha512-v4lMnnBPxLoV/Yf8F0WmtkZGNsqurpxK62kqvaDeVoAtn5Ud+l6POQkLeQRiGsJYVm0vSDc4LHb5vLMrZTH/KA==",
- "license": "SEE LICENSE IN LICENSE.md",
- "dependencies": {
- "@trezor/utils": "10.0.0-alpha.1"
- },
- "peerDependencies": {
- "@stellar/stellar-sdk": "^13.3.0",
- "@trezor/connect": "9.x.x",
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-plugin-stellar/node_modules/@trezor/utils": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-10.0.0-alpha.1.tgz",
- "integrity": "sha512-A+txzREoeX2MO1AqocDBsMNe+R21jTx5kungXGuzeTRRevARLsYh8MPes0170uMjq4qNSgopBnYZK18WyksOmQ==",
- "license": "MIT",
- "dependencies": {
- "bignumber.js": "^9.3.1"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-plugin-stellar/node_modules/bignumber.js": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
- "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
- "license": "MIT",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/@trezor/connect-web": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/connect-web/-/connect-web-10.0.0-alpha.1.tgz",
- "integrity": "sha512-CW1ZXzXNVYrJ2WuYneLK2LznkRAfKxRPB3vJyv1U2gia5Q7hsblImITsutLOztO0C2xO1sfETTCyVzfRkRVJEA==",
- "license": "MIT",
- "dependencies": {
- "@trezor/connect-common": "10.0.0-alpha.1",
- "@trezor/utils": "10.0.0-alpha.1",
- "@trezor/websocket-client": "10.0.0-alpha.1"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-web/node_modules/@sinclair/typebox": {
- "version": "0.34.52",
- "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz",
- "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==",
- "license": "MIT"
- },
- "node_modules/@trezor/connect-web/node_modules/@trezor/connect-common": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/connect-common/-/connect-common-10.0.0-alpha.1.tgz",
- "integrity": "sha512-tuvM72XHACogT/fkp9D8wyzTE8h4X9emYUhvFs2pdTyIfTFs5RHDbcHQWFsvJgJoTK0H44XSSJb8pORijRfn9A==",
- "license": "MIT",
- "dependencies": {
- "@trezor/device-utils": "10.0.0-alpha.1",
- "@trezor/protobuf": "10.0.0-alpha.1",
- "@trezor/protocol": "^10.0.0-alpha.1",
- "@trezor/schema-utils": "10.0.0-alpha.1",
- "@trezor/type-utils": "10.0.0-alpha.1",
- "@trezor/utils": "10.0.0-alpha.1"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-web/node_modules/@trezor/device-utils": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/device-utils/-/device-utils-10.0.0-alpha.1.tgz",
- "integrity": "sha512-93LhEqH8uKCZHLtF+62uxd3/PXCfqpK4Z98ztfGu5vrtmoONb9dV8Falha0b3KXPDrQ10TUKasFGKLg570Z/Ew==",
- "license": "MIT"
- },
- "node_modules/@trezor/connect-web/node_modules/@trezor/protobuf": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-10.0.0-alpha.1.tgz",
- "integrity": "sha512-aCUyqAr7Sho9TequaNAjnf27mgae6qzesNrOgB19bUrDrhaDDd/2eyr2SrrY1G4hPYkTyBC0jymvQnozn9f/kA==",
- "license": "MIT",
- "dependencies": {
- "@bufbuild/protobuf": "^2.11.0",
- "@trezor/schema-utils": "10.0.0-alpha.1"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-web/node_modules/@trezor/protocol": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/@trezor/protocol/-/protocol-10.0.1.tgz",
- "integrity": "sha512-uoFyMzfr3/p7uXhTJSxXurfwM6N0vDicTKHlQRrwH9dMcidEEOxuOJZBrhKnoj4osLfDPt5+ctQ+mqFjxJA9Tw==",
- "license": "MIT",
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-web/node_modules/@trezor/schema-utils": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/schema-utils/-/schema-utils-10.0.0-alpha.1.tgz",
- "integrity": "sha512-0beYv0b0De3Z60sZzM1T+IrYwXeNL+7RKfLokTvqEFDzsQkwxhYrIX47FsBhGsOmGWx9x4+65dxDbnyd4wZT6g==",
- "license": "MIT",
- "dependencies": {
- "@sinclair/typebox": "^0.34.49",
- "@trezor/type-utils": "10.0.0-alpha.1",
- "ts-mixer": "^6.0.4"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-web/node_modules/@trezor/type-utils": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/type-utils/-/type-utils-10.0.0-alpha.1.tgz",
- "integrity": "sha512-wK75rrwlyXFgPfdHQFRbeKCoj+orQLXKj7rliMK30z+F1y+rEcfv/MW2VP48Q9mL5pea+ZX1nRnb4hYx1v38Ow==",
- "license": "MIT"
- },
- "node_modules/@trezor/connect-web/node_modules/@trezor/utils": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-10.0.0-alpha.1.tgz",
- "integrity": "sha512-A+txzREoeX2MO1AqocDBsMNe+R21jTx5kungXGuzeTRRevARLsYh8MPes0170uMjq4qNSgopBnYZK18WyksOmQ==",
- "license": "MIT",
- "dependencies": {
- "bignumber.js": "^9.3.1"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-web/node_modules/@trezor/websocket-client": {
- "version": "10.0.0-alpha.1",
- "resolved": "https://registry.npmjs.org/@trezor/websocket-client/-/websocket-client-10.0.0-alpha.1.tgz",
- "integrity": "sha512-129Ot1m+fDodRFBvav2d6v8nLxZLAl/udQP5l5W6jxQZcWUuviphDceT/juF8EvNGdw+L6OIu6fH+yCXARpFWQ==",
- "license": "MIT",
- "dependencies": {
- "@trezor/utils": "10.0.0-alpha.1",
- "ws": "^8.20.0"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/connect-web/node_modules/bignumber.js": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
- "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
- "license": "MIT",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/@trezor/connect-web/node_modules/ws": {
- "version": "8.22.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz",
- "integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==",
- "license": "MIT",
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": ">=5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana-program/compute-budget": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@solana-program/compute-budget/-/compute-budget-0.8.0.tgz",
- "integrity": "sha512-qPKxdxaEsFxebZ4K5RPuy7VQIm/tfJLa1+Nlt3KNA8EYQkz9Xm8htdoEaXVrer9kpgzzp9R3I3Bh6omwCM06tQ==",
- "license": "Apache-2.0",
- "peer": true,
- "peerDependencies": {
- "@solana/kit": "^2.1.0"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana-program/system": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/@solana-program/system/-/system-0.7.0.tgz",
- "integrity": "sha512-FKTBsKHpvHHNc1ATRm7SlC5nF/VdJtOSjldhcyfMN9R7xo712Mo2jHIzvBgn8zQO5Kg0DcWuKB7268Kv1ocicw==",
- "license": "Apache-2.0",
- "peer": true,
- "peerDependencies": {
- "@solana/kit": "^2.1.0"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana-program/token": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/@solana-program/token/-/token-0.5.1.tgz",
- "integrity": "sha512-bJvynW5q9SFuVOZ5vqGVkmaPGA0MCC+m9jgJj1nk5m20I389/ms69ASnhWGoOPNcie7S9OwBX0gTj2fiyWpfag==",
- "license": "Apache-2.0",
- "peer": true,
- "peerDependencies": {
- "@solana/kit": "^2.1.0"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana-program/token-2022": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/@solana-program/token-2022/-/token-2022-0.4.2.tgz",
- "integrity": "sha512-zIpR5t4s9qEU3hZKupzIBxJ6nUV5/UVyIT400tu9vT1HMs5JHxaTTsb5GUhYjiiTvNwU0MQavbwc4Dl29L0Xvw==",
- "license": "Apache-2.0",
- "peer": true,
- "peerDependencies": {
- "@solana/kit": "^2.1.0",
- "@solana/sysvars": "^2.1.0"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/accounts": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-2.3.0.tgz",
- "integrity": "sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/rpc-spec": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/addresses": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-2.3.0.tgz",
- "integrity": "sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/assertions": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/nominal-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/assertions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-2.3.0.tgz",
- "integrity": "sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/codecs": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.3.0.tgz",
- "integrity": "sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-data-structures": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/options": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/codecs-core": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz",
- "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/codecs-data-structures": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.3.0.tgz",
- "integrity": "sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/codecs-numbers": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz",
- "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/codecs-strings": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.3.0.tgz",
- "integrity": "sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "fastestsmallesttextencoderdecoder": "^1.0.22",
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/errors": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz",
- "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "chalk": "^5.4.1",
- "commander": "^14.0.0"
- },
- "bin": {
- "errors": "bin/cli.mjs"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/fast-stable-stringify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-2.3.0.tgz",
- "integrity": "sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/functional": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-2.3.0.tgz",
- "integrity": "sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/instructions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-2.3.0.tgz",
- "integrity": "sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/keys": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-2.3.0.tgz",
- "integrity": "sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/assertions": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/nominal-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/kit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/kit/-/kit-2.3.0.tgz",
- "integrity": "sha512-sb6PgwoW2LjE5oTFu4lhlS/cGt/NB3YrShEyx7JgWFWysfgLdJnhwWThgwy/4HjNsmtMrQGWVls0yVBHcMvlMQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/accounts": "2.3.0",
- "@solana/addresses": "2.3.0",
- "@solana/codecs": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/instructions": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/programs": "2.3.0",
- "@solana/rpc": "2.3.0",
- "@solana/rpc-parsed-types": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/rpc-subscriptions": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/signers": "2.3.0",
- "@solana/sysvars": "2.3.0",
- "@solana/transaction-confirmation": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/nominal-types": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-2.3.0.tgz",
- "integrity": "sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/options": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.3.0.tgz",
- "integrity": "sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-data-structures": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/programs": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-2.3.0.tgz",
- "integrity": "sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/promises": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-2.3.0.tgz",
- "integrity": "sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-2.3.0.tgz",
- "integrity": "sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/fast-stable-stringify": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/rpc-api": "2.3.0",
- "@solana/rpc-spec": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/rpc-transformers": "2.3.0",
- "@solana/rpc-transport-http": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-api": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-2.3.0.tgz",
- "integrity": "sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/rpc-parsed-types": "2.3.0",
- "@solana/rpc-spec": "2.3.0",
- "@solana/rpc-transformers": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-parsed-types": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-2.3.0.tgz",
- "integrity": "sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-spec": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-2.3.0.tgz",
- "integrity": "sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-spec-types": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-2.3.0.tgz",
- "integrity": "sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-subscriptions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-2.3.0.tgz",
- "integrity": "sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/fast-stable-stringify": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/promises": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/rpc-subscriptions-api": "2.3.0",
- "@solana/rpc-subscriptions-channel-websocket": "2.3.0",
- "@solana/rpc-subscriptions-spec": "2.3.0",
- "@solana/rpc-transformers": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/subscribable": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-subscriptions-api": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-2.3.0.tgz",
- "integrity": "sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/rpc-subscriptions-spec": "2.3.0",
- "@solana/rpc-transformers": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-subscriptions-channel-websocket": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-2.3.0.tgz",
- "integrity": "sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/rpc-subscriptions-spec": "2.3.0",
- "@solana/subscribable": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3",
- "ws": "^8.18.0"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-subscriptions-spec": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-2.3.0.tgz",
- "integrity": "sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/promises": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/subscribable": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-transformers": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-2.3.0.tgz",
- "integrity": "sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/nominal-types": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-transport-http": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-2.3.0.tgz",
- "integrity": "sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0",
- "@solana/rpc-spec": "2.3.0",
- "@solana/rpc-spec-types": "2.3.0",
- "undici-types": "^7.11.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/rpc-types": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-2.3.0.tgz",
- "integrity": "sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/nominal-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/signers": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-2.3.0.tgz",
- "integrity": "sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/instructions": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/nominal-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/subscribable": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-2.3.0.tgz",
- "integrity": "sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/errors": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/sysvars": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-2.3.0.tgz",
- "integrity": "sha512-LvjADZrpZ+CnhlHqfI5cmsRzX9Rpyb1Ox2dMHnbsRNzeKAMhu9w4ZBIaeTdO322zsTr509G1B+k2ABD3whvUBA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/accounts": "2.3.0",
- "@solana/codecs": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/transaction-confirmation": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-2.3.0.tgz",
- "integrity": "sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/promises": "2.3.0",
- "@solana/rpc": "2.3.0",
- "@solana/rpc-subscriptions": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0",
- "@solana/transactions": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/transaction-messages": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-2.3.0.tgz",
- "integrity": "sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-data-structures": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/instructions": "2.3.0",
- "@solana/nominal-types": "2.3.0",
- "@solana/rpc-types": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/@solana/transactions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-2.3.0.tgz",
- "integrity": "sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@solana/addresses": "2.3.0",
- "@solana/codecs-core": "2.3.0",
- "@solana/codecs-data-structures": "2.3.0",
- "@solana/codecs-numbers": "2.3.0",
- "@solana/codecs-strings": "2.3.0",
- "@solana/errors": "2.3.0",
- "@solana/functional": "2.3.0",
- "@solana/instructions": "2.3.0",
- "@solana/keys": "2.3.0",
- "@solana/nominal-types": "2.3.0",
- "@solana/rpc-types": "2.3.0",
- "@solana/transaction-messages": "2.3.0"
- },
- "engines": {
- "node": ">=20.18.0"
- },
- "peerDependencies": {
- "typescript": ">=5.3.3"
- }
- },
- "node_modules/@trezor/connect/node_modules/chalk": {
- "version": "5.6.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
- "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "^12.17.0 || ^14.13 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@trezor/connect/node_modules/undici-types": {
- "version": "7.30.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.30.0.tgz",
- "integrity": "sha512-7QjA5O+GhM27do7Id6hQZpnYEd7WzHbs7/XIS9A1k+Gat/ZVF7Jmpzt68zL/205f65FYwDNLSjQemHPS8ReM/A==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/@trezor/crypto-utils": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@trezor/crypto-utils/-/crypto-utils-1.2.0.tgz",
- "integrity": "sha512-9i1NrfW1IE6JO910ut7xrx4u5LxE++GETbpJhWLj4P5xpuGDDSDLEn/MXaYisls2DpE897aOrGPaa1qyt8V6tw==",
- "license": "SEE LICENSE IN LICENSE.md",
- "peer": true,
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/device-authenticity": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@trezor/device-authenticity/-/device-authenticity-1.1.2.tgz",
- "integrity": "sha512-313uSXYR4XKDv3CjtCpgHA+yEe9xxqN7EFl/D68FEn70SPsuWI0+2zUvjPPh6TIOh/EcLv7hCO/QTHUAGd7ZWQ==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
- "dependencies": {
- "@noble/curves": "^2.0.1",
- "@trezor/crypto-utils": "1.2.0",
- "@trezor/protobuf": "1.5.2",
- "@trezor/schema-utils": "1.4.0",
- "@trezor/utils": "9.5.0"
- }
- },
- "node_modules/@trezor/device-authenticity/node_modules/@noble/curves": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-2.4.0.tgz",
- "integrity": "sha512-P4/62zrgfH33CneE3Dn4WhJVA22YUU0eR51wKIan4NVRvwsA0YnPTwWGpNbpuacSujmSFLvyzpyuR30+fbq2Ew==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@noble/hashes": "2.4.0"
- },
- "engines": {
- "node": ">= 20.19.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@trezor/device-authenticity/node_modules/@noble/hashes": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz",
- "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 20.19.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@trezor/device-authenticity/node_modules/@trezor/protobuf": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-1.5.2.tgz",
- "integrity": "sha512-zViaL1jKue8DUTVEDg0C/lMipqNMd/Z3kr29/+MeZOoupjaXIQ2Lqp3WAMe8hvNTKKX8aNQH9JrbapJ6w9FMXw==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
- "dependencies": {
- "@trezor/schema-utils": "1.4.0",
- "long": "5.2.5",
- "protobufjs": "7.4.0"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/device-authenticity/node_modules/protobufjs": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz",
- "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==",
- "hasInstallScript": true,
- "license": "BSD-3-Clause",
- "peer": true,
- "dependencies": {
- "@protobufjs/aspromise": "^1.1.2",
- "@protobufjs/base64": "^1.1.2",
- "@protobufjs/codegen": "^2.0.4",
- "@protobufjs/eventemitter": "^1.1.0",
- "@protobufjs/fetch": "^1.1.0",
- "@protobufjs/float": "^1.0.2",
- "@protobufjs/inquire": "^1.1.0",
- "@protobufjs/path": "^1.1.2",
- "@protobufjs/pool": "^1.1.0",
- "@protobufjs/utf8": "^1.1.0",
- "@types/node": ">=13.7.0",
- "long": "^5.0.0"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/@trezor/device-utils": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@trezor/device-utils/-/device-utils-1.2.0.tgz",
- "integrity": "sha512-Aqp7pIooFTx21zRUtTI6i1AS4d9Lrx7cclvksh2nJQF9WJvbzuCXshEGkLoOsHwhQrCl3IXfbGuMdA12yDenPA==",
- "license": "See LICENSE.md in repo root",
- "peer": true
- },
- "node_modules/@trezor/env-utils": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@trezor/env-utils/-/env-utils-1.5.0.tgz",
- "integrity": "sha512-u1TN7dMQ5Qhpbae08Z4JJmI9fQrbbJ4yj8eIAsuzMQn6vb+Sg9vbntl+IDsZ1G9WeI73uHTLu1wWMmAgiujH8w==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
- "dependencies": {
- "ua-parser-js": "^2.0.4"
- },
- "peerDependencies": {
- "expo-constants": "*",
- "expo-localization": "*",
- "react-native": "*",
- "tslib": "^2.6.2"
- },
- "peerDependenciesMeta": {
- "expo-constants": {
- "optional": true
- },
- "expo-localization": {
- "optional": true
- },
- "react-native": {
- "optional": true
- }
- }
- },
- "node_modules/@trezor/protobuf": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/@trezor/protobuf/-/protobuf-1.5.3.tgz",
- "integrity": "sha512-ZYQtapkT2NaiVrAgb91Zprnk3uhl2Wca0bsnJcWgE7vwzqKegjrSorRnkZLqLTKTbCaT6sgkCYtM2hPl4Hqw5Q==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
- "dependencies": {
- "@trezor/schema-utils": "1.4.0",
- "long": "5.2.5",
- "protobufjs": "7.5.5"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/protocol": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@trezor/protocol/-/protocol-1.3.1.tgz",
- "integrity": "sha512-uNJ83n38+BM+AJKsWza1ocvQ206d6NXJQ8/g+DelPLTj5c37Rj6hFiY5Nb5zgM7DBnq6T8Aa2K8t4TVCzHT1qg==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/schema-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@trezor/schema-utils/-/schema-utils-1.4.0.tgz",
- "integrity": "sha512-K7upSeh7VDrORaIC4KAxYVW93XNlohmUnH5if/5GKYmTdQSRp1nBkO6Jm+Z4hzIthdnz/1aLgnbeN3bDxWLRxA==",
- "license": "See LICENSE.md in repo root",
- "peer": true,
- "dependencies": {
- "@sinclair/typebox": "^0.33.7",
- "ts-mixer": "^6.0.3"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/transport": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/@trezor/transport/-/transport-1.6.3.tgz",
- "integrity": "sha512-GEi9KfiJsBgT/MCGNDIn9RDeXceLaAPjJT/GCayirXaCr3KnlpZCs6LGYkrjqapxiBm73nxM+BctKBKhpUl2cQ==",
- "license": "SEE LICENSE IN LICENSE.md",
- "peer": true,
- "dependencies": {
- "@trezor/protobuf": "1.5.3",
- "@trezor/protocol": "1.3.1",
- "@trezor/type-utils": "1.2.0",
- "@trezor/utils": "9.5.0",
- "cross-fetch": "^4.0.0",
- "usb": "^2.15.0"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/type-utils": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@trezor/type-utils/-/type-utils-1.2.0.tgz",
- "integrity": "sha512-+E2QntxkyQuYfQQyl8RvT01tq2i5Dp/LFUOXuizF+KVOqsZBjBY43j5hewcCO3+MokD7deDiPyekbUEN5/iVlw==",
- "license": "See LICENSE.md in repo root",
- "peer": true
- },
- "node_modules/@trezor/utils": {
- "version": "9.5.0",
- "resolved": "https://registry.npmjs.org/@trezor/utils/-/utils-9.5.0.tgz",
- "integrity": "sha512-kdyMyDbxzvOZmwBNvTjAK+C/kzyOz8T4oUbFvq+KaXn5mBFf1uf8rq5X2HkxgdYRPArtHS3PxLKsfkNCdhCYtQ==",
- "license": "SEE LICENSE IN LICENSE.md",
- "peer": true,
- "dependencies": {
- "bignumber.js": "^9.3.1"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/utils/node_modules/bignumber.js": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
- "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/@trezor/utxo-lib": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/@trezor/utxo-lib/-/utxo-lib-2.5.0.tgz",
- "integrity": "sha512-Fa2cZh0037oX6AHNLfpFIj65UR/OoX0ZJTocFuQASe77/1PjZHysf6BvvGfmzuFToKfrAQ+DM/1Sx+P/vnyNmA==",
- "license": "SEE LICENSE IN LICENSE.md",
- "peer": true,
- "dependencies": {
- "@trezor/utils": "9.5.0",
- "bech32": "^2.0.0",
- "bip66": "^2.0.0",
- "bitcoin-ops": "^1.4.1",
- "blake-hash": "^2.0.0",
- "blakejs": "^1.2.1",
- "bn.js": "^5.2.2",
- "bs58": "^6.0.0",
- "bs58check": "^4.0.0",
- "cashaddrjs": "0.4.4",
- "create-hmac": "^1.1.7",
- "int64-buffer": "^1.1.0",
- "pushdata-bitcoin": "^1.0.1",
- "tiny-secp256k1": "^1.1.7",
- "typeforce": "^1.18.0",
- "varuint-bitcoin": "2.0.0",
- "wif": "^5.0.0"
- },
- "peerDependencies": {
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@trezor/websocket-client": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/@trezor/websocket-client/-/websocket-client-1.3.0.tgz",
- "integrity": "sha512-9KQSaVc3NtmM6rFFj1e+9bM0C5mVKVidbnxlfzuBJu7G2YMRdIdLPcAXhvmRZjs40uzDuBeApK+p547kODz2ug==",
- "license": "SEE LICENSE IN LICENSE.md",
- "peer": true,
- "dependencies": {
- "@trezor/utils": "9.5.0",
- "ws": "^8.18.0"
+ "node": ">=10.0.0"
},
"peerDependencies": {
- "tslib": "^2.6.2"
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
}
},
"node_modules/@ts-morph/common": {
@@ -8806,6 +6271,7 @@
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
"license": "MIT"
},
"node_modules/@types/json5": {
@@ -8828,7 +6294,7 @@
"version": "19.2.14",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
"integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
- "devOptional": true,
+ "dev": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.2.2"
@@ -8838,7 +6304,7 @@
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
- "devOptional": true,
+ "dev": true,
"license": "MIT",
"peerDependencies": {
"@types/react": "^19.2.0"
@@ -8883,20 +6349,6 @@
"integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==",
"license": "MIT"
},
- "node_modules/@types/w3c-web-usb": {
- "version": "1.0.14",
- "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.14.tgz",
- "integrity": "sha512-Qu3Nn6JFuF4+sHKYl+IcX9vYiI40ogleXzFFSxoE1W94rG98o/kXs8uJ0QSfFzuwBCZWlGfUGpPkgwuuX4PchA==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/@types/web": {
- "version": "0.0.197",
- "resolved": "https://registry.npmjs.org/@types/web/-/web-0.0.197.tgz",
- "integrity": "sha512-V4sOroWDADFx9dLodWpKm298NOJ1VJ6zoDVgaP+WBb/utWxqQ6gnMzd9lvVDAr/F3ibiKaxH9i45eS0gQPSTaQ==",
- "license": "Apache-2.0",
- "peer": true
- },
"node_modules/@types/ws": {
"version": "7.4.7",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz",
@@ -10230,74 +7682,6 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
},
- "node_modules/@xrplf/isomorphic": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@xrplf/isomorphic/-/isomorphic-1.0.2.tgz",
- "integrity": "sha512-ncZUdMXr6VlSXtdoiDi0jTH+gBrgGxwVeEidhoegII3PmyErbQsyj6e+j7acmR4LW/lvBkPkzb9QzRfJH0n3rA==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@noble/hashes": "^2.0.1",
- "eventemitter3": "5.0.1",
- "ws": "^8.20.0"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/@xrplf/isomorphic/node_modules/@noble/hashes": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.4.0.tgz",
- "integrity": "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 20.19.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/@xrplf/isomorphic/node_modules/eventemitter3": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
- "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/@xrplf/isomorphic/node_modules/ws": {
- "version": "8.22.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz",
- "integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=10.0.0"
- },
- "peerDependencies": {
- "bufferutil": "^4.0.1",
- "utf-8-validate": ">=5.0.2"
- },
- "peerDependenciesMeta": {
- "bufferutil": {
- "optional": true
- },
- "utf-8-validate": {
- "optional": true
- }
- }
- },
- "node_modules/@xrplf/secret-numbers": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@xrplf/secret-numbers/-/secret-numbers-2.0.0.tgz",
- "integrity": "sha512-z3AOibRTE9E8MbjgzxqMpG1RNaBhQ1jnfhNCa1cGf2reZUJzPMYs4TggQTc7j8+0WyV3cr7y/U8Oz99SXIkN5Q==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@xrplf/isomorphic": "^1.0.1",
- "ripple-keypairs": "^2.0.0"
- }
- },
"node_modules/abitype": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/abitype/-/abitype-1.3.0.tgz",
@@ -10674,25 +8058,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/asn1.js": {
- "version": "4.10.1",
- "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
- "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bn.js": "^4.0.0",
- "inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0"
- }
- },
- "node_modules/asn1.js/node_modules/bn.js": {
- "version": "4.12.5",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz",
- "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==",
- "license": "MIT",
- "peer": true
- },
"node_modules/assertion-error": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
@@ -10788,6 +8153,7 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"possible-typed-array-names": "^1.0.0"
@@ -10923,23 +8289,6 @@
"node": ">=6.0.0"
}
},
- "node_modules/bech32": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
- "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/big-integer": {
- "version": "1.6.36",
- "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz",
- "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==",
- "license": "Unlicense",
- "peer": true,
- "engines": {
- "node": ">=0.6"
- }
- },
"node_modules/big.js": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz",
@@ -10972,52 +8321,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/bindings": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
- "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "file-uri-to-path": "1.0.0"
- }
- },
"node_modules/bip32-path": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/bip32-path/-/bip32-path-0.4.2.tgz",
"integrity": "sha512-ZBMCELjJfcNMkz5bDuJ1WrYvjlhEF5k6mQ8vUr4N7MbVRsXei7ZOg8VhhwMfNiW68NWmLkgkc6WvTickrLGprQ==",
"license": "MIT"
},
- "node_modules/bip66": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/bip66/-/bip66-2.0.0.tgz",
- "integrity": "sha512-kBG+hSpgvZBrkIm9dt5T1Hd/7xGCPEX2npoxAWZfsK1FvjgaxySEh2WizjyIstWXriKo9K9uJ4u0OnsyLDUPXQ==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/bitcoin-ops": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz",
- "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/blake-hash": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/blake-hash/-/blake-hash-2.0.0.tgz",
- "integrity": "sha512-Igj8YowDu1PRkRsxZA7NVkdFNxH5rKv5cpLxQ0CVXSIA77pVYwCPRQJ2sMew/oneUpfuYRyjG6r8SmmmnbZb1w==",
- "hasInstallScript": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "node-addon-api": "^3.0.0",
- "node-gyp-build": "^4.2.2",
- "readable-stream": "^3.6.0"
- },
- "engines": {
- "node": ">= 10"
- }
- },
"node_modules/blakejs": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz",
@@ -11089,129 +8398,6 @@
"integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==",
"license": "MIT"
},
- "node_modules/browserify-aes": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
- "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "buffer-xor": "^1.0.3",
- "cipher-base": "^1.0.0",
- "create-hash": "^1.1.0",
- "evp_bytestokey": "^1.0.3",
- "inherits": "^2.0.1",
- "safe-buffer": "^5.0.1"
- }
- },
- "node_modules/browserify-cipher": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
- "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "browserify-aes": "^1.0.4",
- "browserify-des": "^1.0.0",
- "evp_bytestokey": "^1.0.0"
- }
- },
- "node_modules/browserify-des": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
- "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "cipher-base": "^1.0.1",
- "des.js": "^1.0.0",
- "inherits": "^2.0.1",
- "safe-buffer": "^5.1.2"
- }
- },
- "node_modules/browserify-rsa": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz",
- "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bn.js": "^5.2.1",
- "randombytes": "^2.1.0",
- "safe-buffer": "^5.2.1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/browserify-sign": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.6.tgz",
- "integrity": "sha512-sd+Q65fjlWCYWtZKXiKfrUc8d+4jtp/8f0W2NkwzLtoW4bI6UDnWusLWIurHnmurW0XShIRxpwiOX4EoPtXUAg==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "bn.js": "^5.2.3",
- "browserify-rsa": "^4.1.1",
- "create-hash": "^1.2.0",
- "create-hmac": "^1.1.7",
- "elliptic": "^6.6.1",
- "inherits": "^2.0.4",
- "parse-asn1": "^5.1.9",
- "readable-stream": "^2.3.8",
- "safe-buffer": "^5.2.1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/browserify-sign/node_modules/isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/browserify-sign/node_modules/readable-stream": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
- "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/browserify-sign/node_modules/string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "safe-buffer": "~5.1.0"
- }
- },
- "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "license": "MIT",
- "peer": true
- },
"node_modules/browserslist": {
"version": "4.28.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
@@ -11254,17 +8440,6 @@
"base-x": "^5.0.0"
}
},
- "node_modules/bs58check": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz",
- "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@noble/hashes": "^1.2.0",
- "bs58": "^6.0.0"
- }
- },
"node_modules/buffer": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
@@ -11289,20 +8464,6 @@
"ieee754": "^1.2.1"
}
},
- "node_modules/buffer-equal-constant-time": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
- "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
- "license": "BSD-3-Clause",
- "peer": true
- },
- "node_modules/buffer-xor": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
- "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
- "license": "MIT",
- "peer": true
- },
"node_modules/bufferutil": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz",
@@ -11345,6 +8506,7 @@
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz",
"integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@@ -11436,29 +8598,6 @@
],
"license": "CC-BY-4.0"
},
- "node_modules/cashaddrjs": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/cashaddrjs/-/cashaddrjs-0.4.4.tgz",
- "integrity": "sha512-xZkuWdNOh0uq/mxJIng6vYWfTowZLd9F4GMAlp2DwFHlcCqCm91NtuAc47RuV4L7r4PYcY5p6Cr2OKNb4hnkWA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "big-integer": "1.6.36"
- }
- },
- "node_modules/cbor": {
- "version": "10.0.12",
- "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.12.tgz",
- "integrity": "sha512-exQDevYd7ZQLP4moMQcZkKCVZsXLAtUSflObr3xTh4xzFIv/xBCdvCd6L259kQOUP2kcTC0jvC6PpZIf/WmRXA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "nofilter": "^3.0.2"
- },
- "engines": {
- "node": ">=20"
- }
- },
"node_modules/chai": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/chai/-/chai-6.3.0.tgz",
@@ -11533,21 +8672,6 @@
"node": ">= 6"
}
},
- "node_modules/cipher-base": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz",
- "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "inherits": "^2.0.4",
- "safe-buffer": "^5.2.1",
- "to-buffer": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
"node_modules/class-variance-authority": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
@@ -11770,13 +8894,6 @@
"node": ">=6.6.0"
}
},
- "node_modules/core-util-is": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
- "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
- "license": "MIT",
- "peer": true
- },
"node_modules/cors": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
@@ -11820,84 +8937,6 @@
}
}
},
- "node_modules/create-ecdh": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
- "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bn.js": "^4.1.0",
- "elliptic": "^6.5.3"
- }
- },
- "node_modules/create-ecdh/node_modules/bn.js": {
- "version": "4.12.5",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz",
- "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/create-hash": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
- "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "cipher-base": "^1.0.1",
- "inherits": "^2.0.1",
- "md5.js": "^1.3.4",
- "ripemd160": "^2.0.1",
- "sha.js": "^2.4.0"
- }
- },
- "node_modules/create-hmac": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
- "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "cipher-base": "^1.0.3",
- "create-hash": "^1.1.0",
- "inherits": "^2.0.1",
- "ripemd160": "^2.0.0",
- "safe-buffer": "^5.0.1",
- "sha.js": "^2.4.8"
- }
- },
- "node_modules/cross-fetch": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz",
- "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "node-fetch": "^2.7.0"
- }
- },
- "node_modules/cross-fetch/node_modules/node-fetch": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
- "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -11930,29 +8969,6 @@
"node": "*"
}
},
- "node_modules/crypto-browserify": {
- "version": "3.12.0",
- "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
- "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "browserify-cipher": "^1.0.0",
- "browserify-sign": "^4.0.0",
- "create-ecdh": "^4.0.0",
- "create-hash": "^1.1.0",
- "create-hmac": "^1.1.0",
- "diffie-hellman": "^5.0.0",
- "inherits": "^2.0.1",
- "pbkdf2": "^3.0.3",
- "public-encrypt": "^4.0.0",
- "randombytes": "^2.0.0",
- "randomfill": "^1.0.3"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -12262,6 +9278,7 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0",
@@ -12337,19 +9354,8 @@
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"license": "MIT",
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/des.js": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
- "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0"
+ "engines": {
+ "node": ">= 0.8"
}
},
"node_modules/destr": {
@@ -12364,27 +9370,6 @@
"integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==",
"license": "MIT"
},
- "node_modules/detect-europe-js": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/detect-europe-js/-/detect-europe-js-0.1.2.tgz",
- "integrity": "sha512-lgdERlL3u0aUdHocoouzT10d9I89VVhk0qNRmll7mXdGfJT1/wqZ2ZLA4oJAjeACPY5fT1wsbq2AT+GkuInsow==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/faisalman"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/ua-parser-js"
- },
- {
- "type": "paypal",
- "url": "https://paypal.me/faisalman"
- }
- ],
- "license": "MIT",
- "peer": true
- },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -12417,25 +9402,6 @@
"node": ">=0.3.1"
}
},
- "node_modules/diffie-hellman": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
- "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bn.js": "^4.1.0",
- "miller-rabin": "^4.0.0",
- "randombytes": "^2.0.0"
- }
- },
- "node_modules/diffie-hellman/node_modules/bn.js": {
- "version": "4.12.5",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz",
- "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==",
- "license": "MIT",
- "peer": true
- },
"node_modules/dijkstrajs": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
@@ -12488,16 +9454,6 @@
"node": ">= 0.4"
}
},
- "node_modules/ecdsa-sig-formatter": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
- "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
- "license": "Apache-2.0",
- "peer": true,
- "dependencies": {
- "safe-buffer": "^5.0.1"
- }
- },
"node_modules/eciesjs": {
"version": "0.4.18",
"resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.18.tgz",
@@ -13317,17 +10273,6 @@
"node": ">=18.0.0"
}
},
- "node_modules/evp_bytestokey": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
- "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "md5.js": "^1.3.4",
- "safe-buffer": "^5.1.1"
- }
- },
"node_modules/execa": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz",
@@ -13364,13 +10309,6 @@
"node": ">=12.0.0"
}
},
- "node_modules/exponential-backoff": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz",
- "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
- "license": "Apache-2.0",
- "peer": true
- },
"node_modules/express": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
@@ -13480,6 +10418,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/fast-levenshtein": {
@@ -13535,13 +10474,6 @@
"fast-string-width": "^3.0.2"
}
},
- "node_modules/fastestsmallesttextencoderdecoder": {
- "version": "1.0.22",
- "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz",
- "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==",
- "license": "CC0-1.0",
- "peer": true
- },
"node_modules/fastq": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
@@ -13623,13 +10555,6 @@
"node": ">=16.0.0"
}
},
- "node_modules/file-uri-to-path": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
- "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
- "license": "MIT",
- "peer": true
- },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -13725,6 +10650,7 @@
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
"integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"is-callable": "^1.2.7"
@@ -13919,26 +10845,6 @@
"integrity": "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==",
"license": "MIT"
},
- "node_modules/generate-function": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
- "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "is-property": "^1.0.2"
- }
- },
- "node_modules/generate-object-property": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
- "integrity": "sha512-TuOwZWgJ2VAMEGJvAyPWvpqxSANF0LDpmyHauMjFYzaACvn+QTT/AZomvPCzVBV7yDN3OmwHQ5OvHaeLKre3JQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "is-property": "^1.0.0"
- }
- },
"node_modules/generator-function": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz",
@@ -14198,6 +11104,7 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"es-define-property": "^1.0.0"
@@ -14249,69 +11156,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/hash-base": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz",
- "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "inherits": "^2.0.4",
- "readable-stream": "^2.3.8",
- "safe-buffer": "^5.2.1",
- "to-buffer": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/hash-base/node_modules/isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/hash-base/node_modules/readable-stream": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
- "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "node_modules/hash-base/node_modules/readable-stream/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/hash-base/node_modules/string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "safe-buffer": "~5.1.0"
- }
- },
- "node_modules/hash-base/node_modules/string_decoder/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "license": "MIT",
- "peer": true
- },
"node_modules/hash.js": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
@@ -14531,13 +11375,6 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
- "node_modules/int64-buffer": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-1.1.2.tgz",
- "integrity": "sha512-ZBb2qDtapL5lWiwgXIoNaCRb/OBPrQ6bK6J4p1AcPXzH/JA/eZmoTVCGGCOIQWIsWwOExGsPu5n8+aBG6itMzA==",
- "license": "MIT",
- "peer": true
- },
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -14713,6 +11550,7 @@
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -14908,27 +11746,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-my-ip-valid": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.1.tgz",
- "integrity": "sha512-jxc8cBcOWbNK2i2aTkCZP6i7wkHF1bqKFrwEHuN5Jtg5BSaZHUZQ/JTOJwoV41YvHnOaRyWWh72T/KvfNz9DJg==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/is-my-json-valid": {
- "version": "2.20.6",
- "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.6.tgz",
- "integrity": "sha512-1JQwulVNjx8UqkPE/bqDaxtH4PXCe/2VRh/y3p99heOV87HG4Id5/VfDswd+YiAfHcRTfDlWgISycnHuhZq1aw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "generate-function": "^2.0.0",
- "generate-object-property": "^1.1.0",
- "is-my-ip-valid": "^1.0.0",
- "jsonpointer": "^5.0.0",
- "xtend": "^4.0.0"
- }
- },
"node_modules/is-negative-zero": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
@@ -15004,13 +11821,6 @@
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
- "node_modules/is-property": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
- "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==",
- "license": "MIT",
- "peer": true
- },
"node_modules/is-regex": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
@@ -15084,27 +11894,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-standalone-pwa": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-standalone-pwa/-/is-standalone-pwa-0.1.1.tgz",
- "integrity": "sha512-9Cbovsa52vNQCjdXOzeQq5CnCbAcRk05aU62K20WO372NrTv0NxibLFCK6lQ4/iZEFdEA3p3t2VNOn8AJ53F5g==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/faisalman"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/ua-parser-js"
- },
- {
- "type": "paypal",
- "url": "https://paypal.me/faisalman"
- }
- ],
- "license": "MIT",
- "peer": true
- },
"node_modules/is-stream": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
@@ -15156,6 +11945,7 @@
"version": "1.1.15",
"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
"integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"which-typed-array": "^1.1.16"
@@ -15244,6 +12034,7 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true,
"license": "MIT"
},
"node_modules/isexe": {
@@ -15471,16 +12262,6 @@
"graceful-fs": "^4.1.6"
}
},
- "node_modules/jsonpointer": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
- "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/jsx-ast-utils": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@@ -15497,29 +12278,6 @@
"node": ">=4.0"
}
},
- "node_modules/jwa": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
- "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "buffer-equal-constant-time": "^1.0.1",
- "ecdsa-sig-formatter": "1.0.11",
- "safe-buffer": "^5.0.1"
- }
- },
- "node_modules/jws": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
- "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "jwa": "^2.0.1",
- "safe-buffer": "^5.0.1"
- }
- },
"node_modules/keyv": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -15585,7 +12343,6 @@
"integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==",
"dev": true,
"license": "MPL-2.0",
- "peer": true,
"dependencies": {
"detect-libc": "^2.0.3"
},
@@ -15623,7 +12380,6 @@
"os": [
"android"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15645,7 +12401,6 @@
"os": [
"darwin"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15667,7 +12422,6 @@
"os": [
"darwin"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15689,7 +12443,6 @@
"os": [
"freebsd"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15711,7 +12464,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15733,7 +12485,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15755,7 +12506,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15777,7 +12527,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15799,7 +12548,6 @@
"os": [
"linux"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15821,7 +12569,6 @@
"os": [
"win32"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15843,7 +12590,6 @@
"os": [
"win32"
],
- "peer": true,
"engines": {
"node": ">= 12.0.0"
},
@@ -15965,13 +12711,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/long": {
- "version": "5.2.5",
- "resolved": "https://registry.npmjs.org/long/-/long-5.2.5.tgz",
- "integrity": "sha512-e0r9YBBgNCq1D1o5Dp8FMH0N5hsFtXDBiVa0qoJPHpakvZkmDKPRoGffZJII/XsHvj9An9blm+cRJ01yQqU+Dw==",
- "license": "Apache-2.0",
- "peer": true
- },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -15985,13 +12724,6 @@
"loose-envify": "cli.js"
}
},
- "node_modules/lru_map": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.4.1.tgz",
- "integrity": "sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg==",
- "license": "MIT",
- "peer": true
- },
"node_modules/lru-cache": {
"version": "11.5.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz",
@@ -16041,18 +12773,6 @@
"is-buffer": "~1.1.6"
}
},
- "node_modules/md5.js": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
- "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "hash-base": "^3.0.0",
- "inherits": "^2.0.1",
- "safe-buffer": "^5.1.2"
- }
- },
"node_modules/media-typer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
@@ -16102,27 +12822,6 @@
"node": ">=8.6"
}
},
- "node_modules/miller-rabin": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
- "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bn.js": "^4.0.0",
- "brorand": "^1.0.1"
- },
- "bin": {
- "miller-rabin": "bin/miller-rabin"
- }
- },
- "node_modules/miller-rabin/node_modules/bn.js": {
- "version": "4.12.5",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz",
- "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==",
- "license": "MIT",
- "peer": true
- },
"node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
@@ -16320,13 +13019,6 @@
"thenify-all": "^1.0.0"
}
},
- "node_modules/nan": {
- "version": "2.29.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.29.0.tgz",
- "integrity": "sha512-GlGk3HIvitbvs+LT3g6XUP1kpirKNvmDFwF/bmo6XNWSb/eYEs/O4bfgIEIXCZ+lIOTS5xNwDvSGMw6FJdAhtA==",
- "license": "MIT",
- "peer": true
- },
"node_modules/nanoid": {
"version": "3.3.20",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz",
@@ -16368,160 +13060,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/near-abi": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/near-abi/-/near-abi-0.2.0.tgz",
- "integrity": "sha512-kCwSf/3fraPU2zENK18sh+kKG4uKbEUEQdyWQkmW8ZofmLarObIz2+zAYjA1teDZLeMvEQew3UysnPDXgjneaA==",
- "license": "(MIT AND Apache-2.0)",
- "peer": true,
- "dependencies": {
- "@types/json-schema": "^7.0.11"
- }
- },
- "node_modules/near-api-js": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/near-api-js/-/near-api-js-5.1.1.tgz",
- "integrity": "sha512-h23BGSKxNv8ph+zU6snicstsVK1/CTXsQz4LuGGwoRE24Hj424nSe4+/1tzoiC285Ljf60kPAqRCmsfv9etF2g==",
- "license": "(MIT AND Apache-2.0)",
- "peer": true,
- "dependencies": {
- "@near-js/accounts": "1.4.1",
- "@near-js/crypto": "1.4.2",
- "@near-js/keystores": "0.2.2",
- "@near-js/keystores-browser": "0.2.2",
- "@near-js/keystores-node": "0.1.2",
- "@near-js/providers": "1.0.3",
- "@near-js/signers": "0.2.2",
- "@near-js/transactions": "1.3.3",
- "@near-js/types": "0.3.1",
- "@near-js/utils": "1.1.0",
- "@near-js/wallet-account": "1.3.3",
- "@noble/curves": "1.8.1",
- "borsh": "1.0.0",
- "depd": "2.0.0",
- "http-errors": "1.7.2",
- "near-abi": "0.2.0",
- "node-fetch": "2.6.7"
- }
- },
- "node_modules/near-api-js/node_modules/@noble/curves": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz",
- "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@noble/hashes": "1.7.1"
- },
- "engines": {
- "node": "^14.21.3 || >=16"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/near-api-js/node_modules/@noble/hashes": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz",
- "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "^14.21.3 || >=16"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/near-api-js/node_modules/borsh": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/borsh/-/borsh-1.0.0.tgz",
- "integrity": "sha512-fSVWzzemnyfF89EPwlUNsrS5swF5CrtiN4e+h0/lLf4dz2he4L3ndM20PS9wj7ICSkXJe/TQUHdaPTq15b1mNQ==",
- "license": "Apache-2.0",
- "peer": true
- },
- "node_modules/near-api-js/node_modules/http-errors": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
- "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "depd": "~1.1.2",
- "inherits": "2.0.3",
- "setprototypeof": "1.1.1",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/near-api-js/node_modules/http-errors/node_modules/depd": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
- "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/near-api-js/node_modules/inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
- "license": "ISC",
- "peer": true
- },
- "node_modules/near-api-js/node_modules/node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "whatwg-url": "^5.0.0"
- },
- "engines": {
- "node": "4.x || >=6.0.0"
- },
- "peerDependencies": {
- "encoding": "^0.1.0"
- },
- "peerDependenciesMeta": {
- "encoding": {
- "optional": true
- }
- }
- },
- "node_modules/near-api-js/node_modules/setprototypeof": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
- "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
- "license": "ISC",
- "peer": true
- },
- "node_modules/near-api-js/node_modules/statuses": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
- "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/near-api-js/node_modules/toidentifier": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
- "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=0.6"
- }
- },
"node_modules/negotiator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
@@ -16612,13 +13150,6 @@
"node": "^10 || ^12 || >=14"
}
},
- "node_modules/node-addon-api": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
- "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
- "license": "MIT",
- "peer": true
- },
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
@@ -16701,19 +13232,9 @@
},
"node_modules/node-releases": {
"version": "2.0.44",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz",
- "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==",
- "license": "MIT"
- },
- "node_modules/nofilter": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz",
- "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=12.19"
- }
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.44.tgz",
+ "integrity": "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ==",
+ "license": "MIT"
},
"node_modules/normalize-path": {
"version": "3.0.0",
@@ -17149,23 +13670,6 @@
"node": ">=6"
}
},
- "node_modules/parse-asn1": {
- "version": "5.1.9",
- "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz",
- "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "asn1.js": "^4.10.1",
- "browserify-aes": "^1.2.0",
- "evp_bytestokey": "^1.0.3",
- "pbkdf2": "^3.1.5",
- "safe-buffer": "^5.2.1"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
"node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
@@ -17242,24 +13746,6 @@
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
"license": "MIT"
},
- "node_modules/pbkdf2": {
- "version": "3.1.7",
- "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.7.tgz",
- "integrity": "sha512-nS4mvFgVwUrecPTRdpdseM2fwpdfnX0/HibA8DgBRQtihUAzHQYJFU2l+OlEtiXtpqkrMvCPDwyXMUnASDt6Qw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "create-hash": "^1.2.0",
- "create-hmac": "^1.1.7",
- "ripemd160": "^2.0.3",
- "safe-buffer": "^5.2.1",
- "sha.js": "^2.4.12",
- "to-buffer": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@@ -17357,6 +13843,7 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
"integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -17614,13 +14101,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "license": "MIT",
- "peer": true
- },
"node_modules/process-warning": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.1.0.tgz",
@@ -17678,31 +14158,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/protobufjs": {
- "version": "7.5.5",
- "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz",
- "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==",
- "hasInstallScript": true,
- "license": "BSD-3-Clause",
- "peer": true,
- "dependencies": {
- "@protobufjs/aspromise": "^1.1.2",
- "@protobufjs/base64": "^1.1.2",
- "@protobufjs/codegen": "^2.0.4",
- "@protobufjs/eventemitter": "^1.1.0",
- "@protobufjs/fetch": "^1.1.0",
- "@protobufjs/float": "^1.0.2",
- "@protobufjs/inquire": "^1.1.0",
- "@protobufjs/path": "^1.1.2",
- "@protobufjs/pool": "^1.1.0",
- "@protobufjs/utf8": "^1.1.0",
- "@types/node": ">=13.7.0",
- "long": "^5.0.0"
- },
- "engines": {
- "node": ">=12.0.0"
- }
- },
"node_modules/proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@@ -17731,28 +14186,6 @@
"node": ">=10"
}
},
- "node_modules/public-encrypt": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
- "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bn.js": "^4.1.0",
- "browserify-rsa": "^4.0.0",
- "create-hash": "^1.1.0",
- "parse-asn1": "^5.0.0",
- "randombytes": "^2.0.1",
- "safe-buffer": "^5.1.2"
- }
- },
- "node_modules/public-encrypt/node_modules/bn.js": {
- "version": "4.12.5",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz",
- "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==",
- "license": "MIT",
- "peer": true
- },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -17763,16 +14196,6 @@
"node": ">=6"
}
},
- "node_modules/pushdata-bitcoin": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz",
- "integrity": "sha512-hw7rcYTJRAl4olM8Owe8x0fBuJJ+WGbMhQuLWOXEMN3PxPCKQHRkhfL+XG0+iXUmSHjkMmb3Ba55Mt21cZc9kQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bitcoin-ops": "^1.3.0"
- }
- },
"node_modules/qrcode": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz",
@@ -18083,17 +14506,6 @@
"safe-buffer": "^5.1.0"
}
},
- "node_modules/randomfill": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
- "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "randombytes": "^2.0.5",
- "safe-buffer": "^5.1.0"
- }
- },
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -18247,21 +14659,6 @@
"pify": "^2.3.0"
}
},
- "node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -18494,90 +14891,14 @@
"node": ">=0.10.0"
}
},
- "node_modules/ripemd160": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz",
- "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "hash-base": "^3.1.2",
- "inherits": "^2.0.4"
- },
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/ripple-address-codec": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ripple-address-codec/-/ripple-address-codec-5.0.1.tgz",
- "integrity": "sha512-JQHLKuVJV8lv9Qobmn4aUM2Dpv9WRRLKnNWfM8tN02fAbUtG8mUPsu9q9UYX8P76G4qzytEc5ZKMp/3JggNYmw==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@scure/base": "^2.0.0",
- "@xrplf/isomorphic": "^1.0.2"
- },
- "engines": {
- "node": ">= 18"
- }
- },
- "node_modules/ripple-address-codec/node_modules/@scure/base": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@scure/base/-/base-2.4.0.tgz",
- "integrity": "sha512-thZ1TuJwFwBblOhgsjDKvvGirBxNp+wSvY/DR6tJBJOTDhdAAcHJ8Vbr2eFnqaxeca4+t0i9KBf+uHYGWwZORg==",
- "license": "MIT",
- "peer": true,
- "funding": {
- "url": "https://paulmillr.com/funding/"
- }
- },
- "node_modules/ripple-binary-codec": {
- "version": "2.11.0",
- "resolved": "https://registry.npmjs.org/ripple-binary-codec/-/ripple-binary-codec-2.11.0.tgz",
- "integrity": "sha512-qad61CYAqIi8H7DuPnuDpj40wrXY8wYrc1YbuDcA9G/NZG0Uu8unHNbTC6Itz8SlOSL0P/nF/8HTFW/1caVlTg==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@xrplf/isomorphic": "^1.0.2",
- "bignumber.js": "^10.0.2",
- "ripple-address-codec": "^5.0.1"
- },
- "engines": {
- "node": ">= 18"
- }
- },
- "node_modules/ripple-binary-codec/node_modules/bignumber.js": {
- "version": "10.0.2",
- "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-10.0.2.tgz",
- "integrity": "sha512-E8Wp9O06QA6lneJ4aRUXKYf/1GIomqUEmUMwtIOMtDxf1U52ffJY+y7JBk/8wRafA8qOIqLnXQGqonYXZdBnFQ==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/ripple-keypairs": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ripple-keypairs/-/ripple-keypairs-2.1.0.tgz",
- "integrity": "sha512-B+Pf4A2EOQhU8LavUVz+ilQsS8yLXivmDFrJ0FswmCjL3bMHNvFovfqQVdffsJOZnIVHQDNehy9uiKJBfQSnbw==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@noble/curves": "^1.0.0",
- "@xrplf/isomorphic": "^1.0.1",
- "ripple-address-codec": "^5.0.0"
- },
- "engines": {
- "node": ">= 18"
- }
- },
"node_modules/rolldown": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.13.tgz",
- "integrity": "sha512-/5apOkwWxtACcQtZ5WlrAsKS4JwXVThQPJZ3RqIruRY9UG9M8e0VlXN068xum/JRKA4aIUoJ13ghe/kGCvidiQ==",
+ "version": "1.2.14",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.14.tgz",
+ "integrity": "sha512-eTBTTqMR6uHKLgcUqpJP8ntzDI6V4LYA8negAMBEI7gkgVvOdrx6VsvS2Ym+83KhOPdLCHWJu0w7UQFJZhHKNw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
- "@oxc-project/types": "=0.153.0",
+ "@oxc-project/types": "=0.154.0",
"@rolldown/pluginutils": "^1.0.0"
},
"bin": {
@@ -18587,21 +14908,21 @@
"node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
- "@rolldown/binding-android-arm-eabi": "1.2.13",
- "@rolldown/binding-android-arm64": "1.2.13",
- "@rolldown/binding-darwin-arm64": "1.2.13",
- "@rolldown/binding-darwin-x64": "1.2.13",
- "@rolldown/binding-freebsd-x64": "1.2.13",
- "@rolldown/binding-linux-arm-gnueabihf": "1.2.13",
- "@rolldown/binding-linux-arm64-gnu": "1.2.13",
- "@rolldown/binding-linux-arm64-musl": "1.2.13",
- "@rolldown/binding-linux-ppc64-gnu": "1.2.13",
- "@rolldown/binding-linux-s390x-gnu": "1.2.13",
- "@rolldown/binding-linux-x64-gnu": "1.2.13",
- "@rolldown/binding-linux-x64-musl": "1.2.13",
- "@rolldown/binding-openharmony-arm64": "1.2.13",
- "@rolldown/binding-win32-arm64-msvc": "1.2.13",
- "@rolldown/binding-win32-x64-msvc": "1.2.13"
+ "@rolldown/binding-android-arm-eabi": "1.2.14",
+ "@rolldown/binding-android-arm64": "1.2.14",
+ "@rolldown/binding-darwin-arm64": "1.2.14",
+ "@rolldown/binding-darwin-x64": "1.2.14",
+ "@rolldown/binding-freebsd-x64": "1.2.14",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.2.14",
+ "@rolldown/binding-linux-arm64-gnu": "1.2.14",
+ "@rolldown/binding-linux-arm64-musl": "1.2.14",
+ "@rolldown/binding-linux-ppc64-gnu": "1.2.14",
+ "@rolldown/binding-linux-s390x-gnu": "1.2.14",
+ "@rolldown/binding-linux-x64-gnu": "1.2.14",
+ "@rolldown/binding-linux-x64-musl": "1.2.14",
+ "@rolldown/binding-openharmony-arm64": "1.2.14",
+ "@rolldown/binding-win32-arm64-msvc": "1.2.14",
+ "@rolldown/binding-win32-x64-msvc": "1.2.14"
}
},
"node_modules/router": {
@@ -18906,6 +15227,7 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"define-data-property": "^1.1.4",
@@ -18956,27 +15278,6 @@
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
- "node_modules/sha.js": {
- "version": "2.4.12",
- "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz",
- "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==",
- "license": "(MIT AND BSD-3-Clause)",
- "peer": true,
- "dependencies": {
- "inherits": "^2.0.4",
- "safe-buffer": "^5.2.1",
- "to-buffer": "^1.2.0"
- },
- "bin": {
- "sha.js": "bin.js"
- },
- "engines": {
- "node": ">= 0.10"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/sha1": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz",
@@ -19261,17 +15562,6 @@
"integrity": "sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==",
"license": "MIT"
},
- "node_modules/smart-buffer": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
- "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">= 6.0.0",
- "npm": ">= 3.0.0"
- }
- },
"node_modules/smol-toml": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.0.tgz",
@@ -19312,36 +15602,6 @@
"node": ">=10.0.0"
}
},
- "node_modules/socks": {
- "version": "2.8.10",
- "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.10.tgz",
- "integrity": "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "ip-address": "^10.1.1",
- "smart-buffer": "^4.2.0"
- },
- "engines": {
- "node": ">= 10.0.0",
- "npm": ">= 3.0.0"
- }
- },
- "node_modules/socks-proxy-agent": {
- "version": "8.0.5",
- "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
- "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "agent-base": "^7.1.2",
- "debug": "^4.3.4",
- "socks": "^2.8.3"
- },
- "engines": {
- "node": ">= 14"
- }
- },
"node_modules/sonic-boom": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz",
@@ -19427,17 +15687,6 @@
"node": ">= 0.4"
}
},
- "node_modules/stream-browserify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
- "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "inherits": "~2.0.4",
- "readable-stream": "^3.5.0"
- }
- },
"node_modules/stream-chain": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz",
@@ -19459,16 +15708,6 @@
"integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==",
"license": "MIT"
},
- "node_modules/string_decoder": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
- "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "safe-buffer": "~5.2.0"
- }
- },
"node_modules/string-width": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
@@ -19937,31 +16176,6 @@
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
"license": "MIT"
},
- "node_modules/tiny-secp256k1": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.7.tgz",
- "integrity": "sha512-eb+F6NabSnjbLwNoC+2o5ItbmP1kg7HliWue71JgLegQt6A5mTN8YbvTLCazdlg6e5SV6A+r8OGvZYskdlmhqQ==",
- "hasInstallScript": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bindings": "^1.3.0",
- "bn.js": "^4.11.8",
- "create-hmac": "^1.1.7",
- "elliptic": "^6.4.0",
- "nan": "^2.13.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/tiny-secp256k1/node_modules/bn.js": {
- "version": "4.12.5",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz",
- "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==",
- "license": "MIT",
- "peer": true
- },
"node_modules/tinybench": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.2.1.tgz",
@@ -20048,21 +16262,6 @@
"integrity": "sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==",
"license": "MIT"
},
- "node_modules/to-buffer": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz",
- "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "isarray": "^2.0.5",
- "safe-buffer": "^5.2.1",
- "typed-array-buffer": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -20084,13 +16283,6 @@
"node": ">=0.6"
}
},
- "node_modules/toml": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
- "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==",
- "license": "MIT",
- "peer": true
- },
"node_modules/tough-cookie": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz",
@@ -20261,6 +16453,7 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
"integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"call-bound": "^1.0.3",
@@ -20334,17 +16527,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/typeforce": {
- "version": "1.18.0",
- "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
- "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==",
- "license": "MIT",
- "peer": true
- },
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
@@ -20378,59 +16565,6 @@
"typescript": ">=4.8.4 <6.1.0"
}
},
- "node_modules/ua-is-frozen": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ua-is-frozen/-/ua-is-frozen-0.1.2.tgz",
- "integrity": "sha512-RwKDW2p3iyWn4UbaxpP2+VxwqXh0jpvdxsYpZ5j/MLLiQOfbsV5shpgQiw93+KMYQPcteeMQ289MaAFzs3G9pw==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/faisalman"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/ua-parser-js"
- },
- {
- "type": "paypal",
- "url": "https://paypal.me/faisalman"
- }
- ],
- "license": "MIT",
- "peer": true
- },
- "node_modules/ua-parser-js": {
- "version": "2.0.10",
- "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-2.0.10.tgz",
- "integrity": "sha512-t+3Ktbq0Ies2vaSezfOaWiolH4OigQIO1dk+1xDpOydB1COVPocVYOrEV5rqZ0kFY9XYG1v9LutCyMgYBpABcw==",
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/ua-parser-js"
- },
- {
- "type": "paypal",
- "url": "https://paypal.me/faisalman"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/faisalman"
- }
- ],
- "license": "AGPL-3.0-or-later",
- "peer": true,
- "dependencies": {
- "detect-europe-js": "^0.1.2",
- "is-standalone-pwa": "^0.1.1",
- "ua-is-frozen": "^0.1.2"
- },
- "bin": {
- "ua-parser-js": "script/cli.js"
- },
- "engines": {
- "node": "*"
- }
- },
"node_modules/ufo": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz",
@@ -20449,16 +16583,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/uint8array-tools": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz",
- "integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=14.0.0"
- }
- },
"node_modules/uint8arrays": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz",
@@ -20737,39 +16861,6 @@
"punycode": "^2.1.0"
}
},
- "node_modules/urijs": {
- "version": "1.19.11",
- "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz",
- "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==",
- "license": "MIT",
- "peer": true
- },
- "node_modules/usb": {
- "version": "2.19.1",
- "resolved": "https://registry.npmjs.org/usb/-/usb-2.19.1.tgz",
- "integrity": "sha512-fjVddzu00GFc1Z5fd5+zuZrqylsfuBbmKKygx3rbIS9w5Nh3ddGVWDHkPBQ/BbB3PVEp6kdsZfX9WXhlsRdPDQ==",
- "hasInstallScript": true,
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@types/w3c-web-usb": "^1.0.6",
- "node-addon-api": "^8.0.0",
- "node-gyp-build": "^4.5.0"
- },
- "engines": {
- "node": ">=12.22.0 <13.0 || >=14.17.0"
- }
- },
- "node_modules/usb/node_modules/node-addon-api": {
- "version": "8.9.2",
- "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.9.2.tgz",
- "integrity": "sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "^18 || ^20 || >= 21"
- }
- },
"node_modules/use-callback-ref": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
@@ -20891,16 +16982,6 @@
}
}
},
- "node_modules/varuint-bitcoin": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-2.0.0.tgz",
- "integrity": "sha512-6QZbU/rHO2ZQYpWFDALCDSRsXbAs1VOEmXAxtbtjLtKuMJ/FQ8YbhfxlaiKv5nklci0M6lZtlZyxo9Q+qNnyog==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "uint8array-tools": "^0.0.8"
- }
- },
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -21056,17 +17137,16 @@
}
},
"node_modules/vite": {
- "version": "8.3.3",
- "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.3.tgz",
- "integrity": "sha512-cTAldKPImjg6c+gk48U19POPn3GCBzZwpdsN8ZMEEcbpes+6/wvfqUd0C2y3qYY4wsj8PwgFwrZ/1jBPVttMSg==",
+ "version": "8.3.4",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.3.4.tgz",
+ "integrity": "sha512-IftLE8phJhdNRIGNEV4JCCvfNScoZQVfcXaN8TQropWGJtOHcu+iAB9pHcuGvmEb/kddw0LBe/jS8ztdC6xdiQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"lightningcss": "^1.33.0",
"picomatch": "^4.0.7",
- "postcss": "^8.5.28",
- "rolldown": "~1.2.11",
+ "postcss": "^8.5.29",
+ "rolldown": "~1.2.12",
"tinyglobby": "^0.2.17"
},
"bin": {
@@ -21140,7 +17220,6 @@
"integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=12"
},
@@ -21361,6 +17440,7 @@
"version": "1.1.20",
"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz",
"integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
@@ -21391,16 +17471,6 @@
"node": ">=20.11"
}
},
- "node_modules/wif": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/wif/-/wif-5.0.0.tgz",
- "integrity": "sha512-iFzrC/9ne740qFbNjTZ2FciSRJlHIXoxqk/Y5EnE08QOXu1WjJyCCswwDTYbohAOEnlCtLaAAQBhyaLRFh2hMA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "bs58check": "^4.0.0"
- }
- },
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
@@ -21520,48 +17590,6 @@
"node": ">=0.4.0"
}
},
- "node_modules/xrpl": {
- "version": "4.4.3",
- "resolved": "https://registry.npmjs.org/xrpl/-/xrpl-4.4.3.tgz",
- "integrity": "sha512-vi2OjuNkiaP8nv1j+nqHp8GZwwEjO6Y8+j/OuVMg6M4LwXEwyHdIj33dlg7cyY1Lw5+jb9HqFOQvABhaywVbTQ==",
- "license": "ISC",
- "peer": true,
- "dependencies": {
- "@scure/bip32": "^1.3.1",
- "@scure/bip39": "^1.2.1",
- "@xrplf/isomorphic": "^1.0.1",
- "@xrplf/secret-numbers": "^2.0.0",
- "bignumber.js": "^9.0.0",
- "eventemitter3": "^5.0.1",
- "fast-json-stable-stringify": "^2.1.0",
- "ripple-address-codec": "^5.0.0",
- "ripple-binary-codec": "^2.5.0",
- "ripple-keypairs": "^2.0.0"
- },
- "engines": {
- "node": ">=18.0.0"
- }
- },
- "node_modules/xrpl/node_modules/bignumber.js": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
- "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/xtend": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
- "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
- "license": "MIT",
- "peer": true,
- "engines": {
- "node": ">=0.4"
- }
- },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/package.json b/package.json
index 1839d2c..1517373 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,8 @@
"test": "vitest run",
"sync:bindings": "node scripts/sync-bindings.mjs",
"check:bindings": "node scripts/sync-bindings.mjs --check",
- "e2e:testnet": "vitest run --config vitest.e2e.config.mts"
+ "e2e:testnet": "vitest run --config vitest.e2e.config.mts",
+ "e2e:localnet": "vitest run e2e/localnet"
},
"dependencies": {
"@creit.tech/stellar-wallets-kit": "2.5.0",
@@ -44,6 +45,7 @@
"postcss": "^8.5.14",
"tailwindcss": "^3.4.19",
"typescript": "^5",
+ "vite": "^8.3.4",
"vitest": "^5.0.3"
},
"license": "MIT"
diff --git a/vitest.config.mts b/vitest.config.mts
index e80c8c3..9549bd0 100644
--- a/vitest.config.mts
+++ b/vitest.config.mts
@@ -8,5 +8,10 @@ export default defineConfig({
test: {
environment: "node",
include: ["lib/**/*.test.ts"],
+ typecheck: {
+ enabled: true,
+ include: ["lib/**/*.test-d.ts"],
+ tsconfig: "./tsconfig.json",
+ },
},
});