Skip to content

Comments

feat: Implement Private Deposit Functionality#4

Open
toruguera wants to merge 4 commits intomainfrom
feat/deposit-integration-provider
Open

feat: Implement Private Deposit Functionality#4
toruguera wants to merge 4 commits intomainfrom
feat/deposit-integration-provider

Conversation

@toruguera
Copy link
Contributor

Implement Private Deposit Functionality

This PR implements the private deposit flow, allowing users to deposit public funds into private channels by creating UTXOs with configurable privacy levels. The implementation follows the same patterns as the receive flow and aligns with the sandbox reference implementation.

Overview

Users can now deposit funds from their public Stellar account into a private channel by specifying:

  • Deposit amount
  • Entropy level (privacy level) that determines the number of UTXOs created
  • Deposit method (currently only DIRECT is supported)

The system will:

  • Reserve UTXOs based on the selected entropy level (1, 5, 10, or 20 UTXOs)
  • Calculate fees based on entropy level
  • Randomly partition the deposit amount across the UTXOs
  • Generate DEPOSIT and CREATE operations
  • Submit the operation bundle to the privacy provider

Features

  • Deposit Form: Input screen for specifying deposit parameters

    • Displays channel and provider information
    • Method selection (DIRECT / 3RD-PARTY RAMP - ramp disabled for now)
    • Amount input with validation against available public balance
    • Entropy level selection (LOW, MEDIUM, HIGH, V_HIGH)
    • Real-time balance checking
    • Provider connection validation
  • Deposit Review: Confirmation screen showing transaction details

    • Total amount including fees
    • Transaction details (direction, method, entropy level)
    • UTXO count and operation breakdown
    • Account and channel information
    • Warning message for user verification
    • Execute transaction button
  • Home Integration: Deposit button in private view navigates to the deposit flow

Technical Changes

Backend

  • Handler: src/background/handlers/private/deposit.ts

    • Validates wallet, channel, provider, and session
    • Calculates fees based on entropy level
    • Reserves UTXOs using UtxoBasedStellarAccount (count based on entropy level)
    • Partitions amount randomly using partitionAmountRandom utility
    • Creates MoonlightOperation.deposit operation with conditions
    • Creates MoonlightOperation.create operations for each UTXO
    • Converts operations to MLXDR format
    • Submits bundle to privacy provider via PrivacyProviderClient
    • Handles authentication errors and session cleanup
  • Types: src/background/handlers/private/deposit.types.ts

    • DepositRequest: network, channelId, providerId, accountId, method, amount, entropyLevel
    • DepositResponse: ok, id, hash, error
    • DepositMethod: "DIRECT" | "3RD-PARTY RAMP"
    • EntropyLevel: "LOW" | "MEDIUM" | "HIGH" | "V_HIGH"
  • Message system: Added MessageType.Deposit to message routing

Frontend

  • API service: src/popup/api/deposit.ts

    • Wrapper for calling the deposit background handler
  • Pages:

    • src/popup/pages/deposit-page.tsx: Main deposit form page
      • Loads private channels and available balance
      • Validates provider session
      • Manages form state (method, amount, entropy level)
      • Navigates to review page on submit
    • src/popup/pages/deposit-review-page.tsx: Review and confirmation page
      • Displays transaction summary
      • Calculates fees and total amount
      • Executes deposit transaction
      • Handles errors and navigation
  • Templates:

    • src/popup/templates/deposit-form-template.tsx: Reusable form component
      • Method selection buttons
      • Amount input with balance display
      • Entropy level dropdown
      • Provider status indicator
    • src/popup/templates/deposit-review-template.tsx: Review component
      • Transaction details display
      • Expandable operations section
      • Warning messages
      • Action buttons
  • State management: Added deposit routes and state handling

    • Routes: deposit, deposit-review
    • Actions: goDeposit, goDepositReview, setDepositFormData, clearDepositFormData
    • Form data persistence between pages
  • Navigation: Integrated deposit button in HomeTemplate private view

Implementation Details

  • Entropy levels: Configurable privacy levels that determine UTXO count

    • LOW: 1 UTXO, 0.05 XLM fee
    • MEDIUM: 5 UTXOs, 0.25 XLM fee
    • HIGH: 10 UTXOs, 0.5 XLM fee
    • V_HIGH: 20 UTXOs, 0.75 XLM fee
  • Amount partitioning: Uses cryptographically secure random distribution via partitionAmountRandom

  • Fee calculation: Fees are based on entropy level and added to the total amount

  • UTXO reservation: Automatically derives and reserves enough UTXOs for the selected entropy level

  • Operation structure: Creates one DEPOSIT operation with conditions from multiple CREATE operations

  • Expiration handling: Calculates transaction expiration using RPC ledger sequence

  • Error handling: Comprehensive error codes (LOCKED, NOT_FOUND, SESSION_NOT_FOUND, INVALID_SESSION, AUTH_FAILED, DEPOSIT_FAILED)

  • Session management: Automatically clears provider session on authentication errors

  • Type safety: Full TypeScript typing throughout

  • Consistency: Follows same patterns as receive flow for maintainability

Files Changed

New Files:

  • src/background/handlers/private/deposit.ts
  • src/background/handlers/private/deposit.types.ts
  • src/popup/api/deposit.ts
  • src/popup/pages/deposit-page.tsx
  • src/popup/pages/deposit-review-page.tsx
  • src/popup/templates/deposit-form-template.tsx
  • src/popup/templates/deposit-review-template.tsx

Modified Files:

  • src/background/messages.ts - Added Deposit message type
  • src/background/handler.ts - Registered deposit handler
  • src/popup/hooks/state.tsx - Added deposit routes and state
  • src/popup/app.tsx - Added deposit route handling
  • src/popup/pages/home-page.tsx - Connected deposit button
  • src/popup/templates/home-template.tsx - Added deposit action prop

Testing Notes

  • Verify deposit flow with valid channel and provider connection
  • Test amount validation (minimum amount, balance checking)
  • Test entropy level selection and UTXO count
  • Verify fee calculation for each entropy level
  • Confirm UTXO reservation and operation generation
  • Test bundle submission to privacy provider
  • Verify error handling for locked wallet, missing channel/provider, expired sessions
  • Test navigation flow from home to deposit to review
  • Verify form data persistence between pages

Future Enhancements

  • Implement 3RD-PARTY RAMP deposit method
  • Add support for custom fee calculation
  • Add transaction history tracking
  • Implement deposit status polling
  • Add support for batch deposits
  • Improve fee estimation accuracy
  • Add deposit confirmation notifications

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a new “private deposit” flow (UI + background handler) to move funds from a public Stellar account into a private channel by creating multiple UTXOs based on a chosen entropy (privacy) level.

Changes:

  • Added a background DEPOSIT message + handler that reserves UTXOs, partitions amounts, builds Moonlight operations, and submits a bundle to the privacy provider.
  • Added popup deposit + deposit review pages/templates and wired navigation from the private Home view.
  • Added utilities and client improvements (random partition helper; privacy provider client auth/bundle submission updates).

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/popup/templates/home-template.tsx Adds private-view action buttons and hooks “Ramp” button into deposit start.
src/popup/pages/home-page.tsx Wires onStartDeposit to popup state navigation.
src/popup/hooks/state.tsx Adds deposit/deposit-review routes and persists deposit form data.
src/popup/app.tsx Routes deposit pages.
src/popup/api/deposit.ts Adds popup API wrapper to call background deposit handler.
src/popup/pages/deposit-page.tsx Implements deposit form page (loads channel/provider/session and public balance).
src/popup/pages/deposit-review-page.tsx Implements deposit review + execution page.
src/popup/templates/deposit-form-template.tsx Deposit form UI (method, amount, entropy).
src/popup/templates/deposit-review-template.tsx Review/confirm UI showing details and operations breakdown.
src/background/messages.ts Adds MessageType.Deposit and payload/response typing.
src/background/handler.ts Registers the deposit handler.
src/background/handlers/private/deposit.types.ts Introduces DepositRequest/Response, method + entropy enums.
src/background/handlers/private/deposit.ts Implements backend private deposit flow (UTXO reservation, op creation, provider submission).
src/background/utils/random-partition.ts Adds cryptographically-secure random amount partitioning utility.
src/background/services/privacy-provider-client.ts Improves auth token validation, normalizes postAuth response, adds bundle submission with auth error mapping.
src/background/handlers/private/connect-privacy-provider.ts Adds token validation and logs when saving provider sessions.
deno.lock Updates dependency lockfile (includes @types/node and various bumps).
deno.json Minor formatting changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +48 to +62
useMemo(() => {
if (!formData) return;
getPrivateChannels({ network })
.then((res) => {
if (res.ok) {
setPrivateChannels({
channels: res.channels,
selectedChannelId: res.selectedChannelId,
});
}
})
.catch((err) => {
console.error("Failed to load private channels", err);
});
}, [network, formData]);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Side effects (fetching private channels + setState) are being executed inside useMemo. useMemo is not guaranteed to run exactly once per dependency change and should be pure; this can cause repeated network calls during render. Move this logic to useEffect and keep useMemo only for derived values.

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +78
// Calculate estimated fee (simplified - in production this should come from the backend)
const estimatedFee = useMemo(() => {
// Rough estimate: 0.00001 XLM per UTXO
return (utxoCount * 0.00001).toFixed(7);
}, [utxoCount]);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fee shown to the user is calculated as utxoCount * 0.00001, but the backend deposit handler uses a fixed fee schedule per entropy level (e.g., 0.05/0.25/0.5/0.75 XLM). This will display an incorrect total on the review screen and can mislead users about the amount debited. Use the same fee table as the backend or fetch an exact quote from the backend and display that here.

Copilot uses AI. Check for mistakes.
const entropyLevels: EntropyLevel[] = ["LOW", "MEDIUM", "HIGH", "V_HIGH"];

return (
<SubpageShell title="Ramp" onBack={props.onBack}>
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The subpage title is set to "Ramp", but this component is used for the deposit flow. Update the title (and any related copy) to "Deposit"/"Deposit Funds" so navigation and headings match the actual action.

Suggested change
<SubpageShell title="Ramp" onBack={props.onBack}>
<SubpageShell title="Deposit Funds" onBack={props.onBack}>

Copilot uses AI. Check for mistakes.
Comment on lines +662 to +681
{
icon: IconCoinFilled,
label: "Ramp",
key: "ramp",
onClick: () => {
if (!canStartDeposit) return;
if (
!selectedPrivateChannel
?.id ||
!selectedPrivateChannel
?.selectedProviderId
) {
return;
}
props.onStartDeposit?.(
selectedPrivateChannel.id,
selectedPrivateChannel
.selectedProviderId!,
);
},
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This action is labeled "Ramp" but triggers onStartDeposit(...). Rename the label/key to reflect the actual behavior (e.g., "Deposit"), otherwise users and future maintainers will assume it opens an on-ramp flow rather than the deposit flow.

Copilot uses AI. Check for mistakes.
Comment on lines +112 to +119
const {
network,
channelId,
providerId,
accountId,
amount,
entropyLevel,
} = message as DepositRequest & { type: MessageType.Deposit };
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DepositRequest includes a method, but the handler ignores it entirely. Since the UI can select "3RD-PARTY RAMP" (even if disabled today) and the API type allows it, the handler should validate method and explicitly reject unsupported values (e.g., return an error code like UNSUPPORTED_METHOD) instead of silently treating everything as DIRECT.

Copilot uses AI. Check for mistakes.
Comment on lines +237 to +246
// Convert human-readable amount and fee to BigInt
const parsedAmount = Number.parseFloat(amount);
if (!Number.isFinite(parsedAmount) || parsedAmount <= 0) {
throw new Error("Invalid deposit amount");
}

const feeAmount = getFeeForEntropyLevel(entropyLevel);
const totalAmount = fromDecimals(parsedAmount + feeAmount, 7);

const amountBigInt = fromDecimals(parsedAmount, 7);
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fee/amount arithmetic is done in JS number space (parseFloat, feeAmount number, then parsedAmount + feeAmount). Using floating point for monetary amounts can introduce rounding errors at 7-decimal precision. Prefer doing all calculations in integer space (e.g., convert amount and fee to base units as bigint and add) to guarantee exact stroop values.

Suggested change
// Convert human-readable amount and fee to BigInt
const parsedAmount = Number.parseFloat(amount);
if (!Number.isFinite(parsedAmount) || parsedAmount <= 0) {
throw new Error("Invalid deposit amount");
}
const feeAmount = getFeeForEntropyLevel(entropyLevel);
const totalAmount = fromDecimals(parsedAmount + feeAmount, 7);
const amountBigInt = fromDecimals(parsedAmount, 7);
// Convert human-readable amount and fee to BigInt, and do all math in integer space.
const amountBigInt = fromDecimals(amount, 7);
if (amountBigInt <= 0n) {
throw new Error("Invalid deposit amount");
}
const feeAmount = getFeeForEntropyLevel(entropyLevel);
const feeBigInt = fromDecimals(feeAmount.toFixed(7), 7);
const totalAmount = amountBigInt + feeBigInt;

Copilot uses AI. Check for mistakes.
Comment on lines +363 to +364
console.log("operationsMLXDR", operationsMLXDR);

Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console.log("operationsMLXDR", operationsMLXDR) logs the full operation payloads. These XDRs can contain sensitive transaction details and will also spam logs in production. Remove this log or gate it behind the existing DEV flag / a debug logger that can be disabled.

Suggested change
console.log("operationsMLXDR", operationsMLXDR);

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@fazzatti
Copy link
Contributor

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link

Copilot AI commented Feb 20, 2026

@fazzatti I've opened a new pull request, #8, to work on those changes. Once the pull request is ready, I'll request review from you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants