Application Services
This document describes the main application services in the wallets package, organized by domain area.
Overview
The application layer contains the business logic and orchestrates domain entities to fulfill specific operations. Application services are organized into:
- Domain-specific services: Simple services focused on a single operation (e.g.,
WalletBalanceUpdater) - Complex application services: Services that orchestrate multiple operations (e.g.,
WalletAddressBalanceSupervisor) - Blockchain-specific services: Services with blockchain-specific logic (UTXO, Tron, Solana)
Wallet Application Services
WalletDepositAddressFinder
Purpose: Finds or creates a deposit address for a specific coin/token on a blockchain.
Key Logic:
- Validates wallet exists and deposits are enabled
- For tokens, validates token is supported and enabled
- Finds highest used address index
- Creates new address if under limit (1000), otherwise reuses oldest
- Publishes domain event for address creation
Dependencies:
HDWalletAddressDerivator- Generates blockchain addressesWalletFinder- Locates walletsWalletTokenFinder- Locates wallet tokensWalletAddressRepository- Persists addressesEventPublisher- Publishes domain events
async run(coinId: CoinId, blockchain: Blockchain): Promise<WalletAddress | undefined>WalletBalanceRetriever
Purpose: Retrieves current balance for a wallet from blockchain.
Key Logic:
- Finds wallet by blockchain
- Queries blockchain adapter for current balance
- Returns balance information
WalletBalanceUpdater
Purpose: Updates wallet balance from blockchain and persists changes.
Key Logic:
- Retrieves current balance from blockchain
- Updates wallet entity
- Persists changes to repository
WalletBalanceScanner
Purpose: Scans entire wallet for balance updates across all addresses.
Key Logic:
- Finds all addresses for wallet
- Updates balance for each address
- Consolidates total wallet balance
WalletWithdrawer
Purpose: Initiates withdrawal transaction from wallet.
Key Logic:
- Validates withdrawal is allowed
- Checks sufficient balance
- Creates withdrawal transaction
- Queues transaction for processing
WalletFinder
Purpose: Locates wallet by blockchain.
async run(blockchain: Blockchain): Promise<Wallet | undefined>WalletTokenFinder
Purpose: Locates specific token within a wallet.
async run(walletId: WalletId, tokenId: TokenId): Promise<WalletToken | undefined>Address Application Services
WalletAddressFundsDetector
Purpose: Detects when funds arrive at a wallet address.
Key Logic:
- Queries blockchain for address transactions
- Identifies new deposits
- Updates address balance
- Triggers sweep if needed
WalletAddressSweeper
Purpose: Sweeps funds from deposit addresses to main wallet.
Key Logic:
- Validates address has sufficient funds
- Calculates optimal sweep amount (considering fees)
- Creates sweep transaction
- Queues transaction for processing
Flow Diagram:
WalletTokenAddressFundsChecker
Purpose: Checks if token address has sufficient native funds for operations.
Key Logic:
- Checks native token balance (for gas/fees)
- Compares against minimum required
- Returns funding status
WalletTokenAddressNativeFundsSender
Purpose: Sends native funds to token addresses for gas/fees.
Key Logic:
- Calculates required native funds
- Creates funding transaction
- Sends from main wallet to token address
WalletAddressBalanceUpdater
Purpose: Updates balance for a specific address.
WalletAddressUnlocker
Purpose: Unlocks a deposit address for reuse.
Key Logic:
- Marks address as available
- Resets usage timestamps
- Persists changes
Transaction Application Services
TransactionSender
Purpose: Sends pending transactions to blockchain.
Key Logic:
- Validates transaction is ready to send
- Signs transaction with wallet keys
- Broadcasts to blockchain
- Updates transaction status
TransactionUpdater
Purpose: Updates transaction status from blockchain.
Key Logic:
- Queries blockchain for transaction status
- Updates local transaction record
- Triggers balance updates if confirmed
TransactionCanceller
Purpose: Cancels pending transactions.
Key Logic:
- Validates transaction can be cancelled
- Updates status to cancelled
- Releases any locked funds
TransactionRetriever
Purpose: Retrieves transaction information.
Blockchain-Specific Application Services
Tron Application Services
TronWalletAddressActivator
Activates Tron addresses by sending initial TRX.
TronWalletAddressDelegator
Delegates Tron energy/bandwidth resources.
TronWalletAddressUnDelegator
Undelegates Tron resources.
UTXO Application Services
UTXOTransactionCPFP
Implements Child-Pays-For-Parent for Bitcoin transactions.
Key Logic:
- Creates child transaction with higher fee
- References parent transaction
- Incentivizes miners to confirm both
Complex Application Services
WalletAddressBalanceSupervisor
Purpose: Orchestrates balance updates and sweep operations for multiple wallet addresses.
Key Logic:
- Finds addresses with oldest
lastUsedAttimestamps - Updates balances for each address (batch processing for UTXO)
- Triggers sweep events for addresses with sufficient balance
- Handles blockchain-specific logic (different limits for UTXO vs account-based)
Dependencies:
WalletAddressBalanceUpdater- Updates individual address balancesUtxoWalletAddressesBalanceUpdater- Batch updates for UTXO addressesWalletAddressRepository- Address persistenceEventPublisher- Publishes sweep events
This is an example of a complex application service that orchestrates multiple simpler services.
Application Service Dependencies
Error Handling
Application services implement consistent error handling patterns:
- Validation Errors: Return undefined or throw domain exceptions
- Infrastructure Errors: Propagate with context
- Business Rule Violations: Return specific error types
Event Publishing
Many application services publish domain events:
WalletAddressCreatedDomainEvent- When new address is createdTransactionCreatedDomainEvent- When transaction is createdBalanceUpdatedDomainEvent- When balance changes
Testing Strategy
Application services are tested with:
- Unit Tests: Mock all dependencies
- Integration Tests: Use in-memory repositories
- Contract Tests: Verify repository interfaces
Performance Considerations
- Address Generation: Cached derivation paths
- Balance Queries: Batched blockchain calls
- Transaction Processing: Queued for async processing
- Event Publishing: Async to avoid blocking
