Introduction
Payment settlement is evolving rapidly. From traditional ACH to blockchain-based settlement, understanding the differences is crucial for building modern financial systems.
Key Statistics:
- Traditional ACH: 1-3 days settlement
- FedNow: Instant settlement (<30 seconds)
- Blockchain: 1-15 minutes finality
- Real-time payments growing 40% annually
Settlement Comparison
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Payment Settlement Methods โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โ
โ Traditional โ
โ โโโ ACH: 1-3 business days ($0.01-0.05 per transaction) โ
โ โโโ Wire: Same day ($15-30 per transaction) โ
โ โโโ Check: 2-7 days โ
โ โโโ Card: 1-2 days (with fees) โ
โ โ
โ Modern Real-time โ
โ โโโ FedNow: Instant (<$0.05 per transaction) โ
โ โโโ RTP: Instant (24/7) โ
โ โโโ Push to Card: Seconds โ
โ โ
โ Blockchain โ
โ โโโ Bitcoin: ~10 min (Layer 1) โ
โ โโโ Ethereum: ~15 min (Layer 1) โ
โ โโโ USDC: ~seconds (anchor) โ
โ โโโ DeFi: Variable, often minutes โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Traditional Banking
ACH Processing
#!/usr/bin/env python3
"""ACH payment processing."""
import csv
from datetime import datetime, timedelta
class ACHProcessor:
"""Process ACH payments."""
def __init__(self, bank_client):
self.bank = bank_client
def create_ach_entry(self, amount, receiver_account,
receiver_routing, entry_class='PPD'):
"""Create ACH entry."""
entry = {
'record_type_code': '6', # PPD
'transaction_code': '22' if amount > 0 else '32', # Credit/Debit
'receiver_routing_number': receiver_routing,
'receiver_account_number': receiver_account,
'amount': int(amount * 100), # In cents
'individual_id': generate_individual_id(),
'individual_name': '', # To be filled
'discretionary_data': '',
'addenda_record_indicator': '0'
}
return entry
def create_ach_file(self, entries, batch_header):
"""Create ACH file ( NACHA format)."""
file_header = {
'record_type_code': '1',
'priority_code': '01',
'immediate_destination': bank_routing_number,
'immediate_origin': company_identification,
'file_creation_date': datetime.now().strftime('%y%m%d'),
'file_creation_time': datetime.now().strftime('%H%M'),
'file_id_modifier': 'A',
'record_size': '094',
'blocking_factor': '10',
'format_code': '1',
'immediate_destination_name': 'FEDERAL RESERVE BANK',
'immediate_origin_name': 'COMPANY NAME'
}
# Calculate entry hash
entry_hash = sum(
int(e['receiver_routing_number'][:8])
for e in entries
) % 10**10
batch_control = {
'record_type_code': '8',
'service_class_code': batch_header['service_class_code'],
'entry_addenda_count': len(entries),
'entry_hash': str(entry_hash).zfill(10),
'total_debit': sum(e['amount'] for e in entries if e['amount'] > 0),
'total_credit': sum(e['amount'] for e in entries if e['amount'] < 0),
'company_identification': company_identification,
'message_authentication_code': '',
'originating_dfi_id': company_routing[:8],
'batch_number': 1
}
return ACHFile(file_header, batch_header, entries, batch_control)
FedNow Implementation
#!/usr/bin env python3
"""FedNow instant payment integration."""
class FedNowProcessor:
"""Process FedNow instant payments."""
def __init__(self, config):
self.api_url = config['fednow_api_url']
self.client = create_client(config)
def create_payment(self, sender, receiver, amount, reference):
"""Create FedNow payment."""
request = {
'messageType': 'Payment',
'messageMetaData': {
'creationDateTime': datetime.utcnow().isoformat(),
'endToEndIdentification': reference
},
'creditTransferTransactionInformation': {
'amount': {
'amount': str(amount),
'currency': 'USD'
},
'creditorAccount': {
'accountNumber': receiver['account_number'],
'accountType': receiver.get('account_type', 'Checking'),
'routingNumber': receiver['routing_number']
},
'creditorName': receiver['name'],
'remittanceInformation': {
'unstructured': f'Payment ref: {reference}'
}
},
'debtorAccount': {
'accountNumber': sender['account_number'],
'accountType': sender.get('account_type', 'Checking'),
'routingNumber': sender['routing_number']
},
'debtorName': sender['name']
}
response = self.client.post('/payments', request)
return PaymentResponse(
payment_id=response['paymentId'],
status=response['transactionStatus'],
status_reason=response.get('statusReason'),
settlement_time=response.get('settlementDateTime')
)
def get_payment_status(self, payment_id):
"""Get payment status."""
response = self.client.get(f'/payments/{payment_id}')
return PaymentStatus(
payment_id=payment_id,
status=response['transactionStatus'],
status_reason=response.get('statusReason'),
completion_date_time=response.get('completionDateTime')
)
Blockchain Settlement
On-Chain Settlement
#!/usr/bin/env python3
"""Blockchain payment settlement."""
import eth_abi
from web3 import Web3
class BlockchainSettler:
"""Settle payments on blockchain."""
def __init__(self, rpc_url, private_key):
self.w3 = Web3(Web3.HTTPProvider(rpc_url))
self.account = self.w3.eth.account.from_key(private_key)
def settle_usdc(self, to_address, amount):
"""Settle USDC payment."""
# USDC contract on Ethereum
usdc_address = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
# Encode transfer function
data = eth_abi.encode(
['address', 'uint256'],
[to_address, amount * 10**6] # USDC has 6 decimals
)
# Build transaction
tx = {
'from': self.account.address,
'to': usdc_address,
'value': 0,
'data': data,
'gas': 65000,
'gasPrice': self.w3.eth.gas_price,
'nonce': self.w3.eth.get_transaction_count(self.account.address),
'chainId': 1
}
# Sign and send
signed_tx = self.account.sign_transaction(tx)
tx_hash = self.w3.eth.send_raw_transaction(signed_tx.rawTransaction)
# Wait for confirmation
receipt = self.w3.eth.wait_for_transaction_receipt(tx_hash)
return {
'tx_hash': tx_hash.hex(),
'block_number': receipt['blockNumber'],
'status': 'confirmed' if receipt['status'] == 1 else 'failed',
'gas_used': receipt['gasUsed']
}
def verify_settlement(self, tx_hash, expected_amount):
"""Verify blockchain settlement."""
receipt = self.w3.eth.get_transaction_receipt(tx_hash)
if receipt['status'] != 1:
return {'verified': False, 'reason': 'Transaction failed'}
# Check block confirmations
current_block = self.w3.eth.block_number
confirmations = current_block - receipt['blockNumber']
if confirmations < 12:
return {
'verified': False,
'reason': f'Only {confirmations} confirmations'
}
return {
'verified': True,
'confirmations': confirmations,
'block_number': receipt['blockNumber']
}
Hybrid Approaches
#!/usr/bin/env python3
"""Hybrid settlement system."""
class HybridSettlementEngine:
"""Route payments to optimal settlement method."""
def __init__(self, config):
self.ach = ACHProcessor(config['ach'])
self.fednow = FedNowProcessor(config['fednow'])
self.blockchain = BlockchainSettler(config['blockchain'])
def select_settlement_method(self, payment):
"""Select optimal settlement method."""
# Decision logic
if payment.amount < 10000 and payment.currency == 'USD':
# Use FedNow for instant
if self.fednow.is_available():
return 'fednow'
if payment.amount < 100000 and payment.is_business_day:
# Use ACH for cost efficiency
return 'ach'
if payment.currency != 'USD':
# Use blockchain for cross-border
return 'blockchain'
return 'ach'
def settle_payment(self, payment):
"""Execute payment with selected method."""
method = self.select_settlement_method(payment)
if method == 'fednow':
return self.fednow.create_payment(
payment.sender,
payment.receiver,
payment.amount,
payment.reference
)
elif method == 'ach':
return self.ach.create_batch_payment(payment)
elif method == 'blockchain':
return self.blockchain.settle_usdc(
payment.receiver_address,
payment.amount
)
raise ValueError(f"Unknown settlement method: {method}")
Comparison
| Method | Speed | Cost | Reach | Finality |
|---|---|---|---|---|
| ACH | 1-3 days | $0.01-0.05 | US only | 1-3 days |
| FedNow | <30 sec | <$0.05 | US only | <30 sec |
| RTP | <30 sec | $0.04-0.10 | US only | <30 sec |
| Wire | Same day | $15-30 | Global | Same day |
| Bitcoin | ~10 min | $1-10 | Global | ~10 min |
| Ethereum | ~15 min | $1-50 | Global | ~15 min |
| USDC | ~seconds | $0.01 | Global | ~seconds |
Comments