Get the code
dfns/dfns-solutions: bank-custody
Overview
The reference implementation models a retail financial platform (using a bank as the working example, but the same pattern fits any fintech or institution):- Customers see their fiat accounts (EUR checking, savings) and crypto wallets in one dashboard
- The platform operator holds a DFNS service account. Customers never interact with DFNS directly
- Transfers below a threshold execute immediately; larger transfers require operator approval
- Family delegation lets customers share wallet access with relatives, with per-person transfer limits
Prerequisites
- Python 3.10+
- Node.js 18+
- A DFNS account with a service account
- An Auth0 tenant
Configuration
1
Clone and install
2
Set up Auth0
Create an Auth0 application (Regular Web Application) and an API:To enable operator access (compliance, treasury, ops), create a role called
Authorize your application to access the API (Application → APIs tab → toggle on). On the API settings, enable RBAC and Allow Offline Access.Create a Post-Login Action to include user info in the access token:
employee in Auth0 → User Management → Roles and assign it to the relevant users.3
Configure environment variables
Frontend variables:
4
Start the backend
5
Start the frontend
Demo walkthrough
The demo follows a family using a financial platform called SecureFinance: two parents (Alice and Bob) and their kid (Charlie). An operator compliance officer (Claire) oversees transfers.Part 1: Platform setup
- Create an Auth0 user for the compliance officer (e.g.
compliance@securefinance.com) - Assign the
employeerole to this user in Auth0 → User Management → Roles - Set
APPROVAL_THRESHOLD=0.05inbackend/.envso you can test the approval flow with small amounts
Part 2: Create the family
Create three Auth0 users. They register automatically in the app on first login:Part 3: Alice sets up wallets
Log in as Alice:- Create wallets: click ”+ New crypto account” twice: “Alice’s Wallet” and “Charlie’s Wallet” (both Ethereum Sepolia)
- Fund both wallets using a Sepolia faucet
- Share access via the Family page:
- Share “Alice’s Wallet” with Bob → View + Transfer
- Share “Charlie’s Wallet” with Bob → View + Transfer
- Share “Charlie’s Wallet” with Charlie → View + Transfer, approval threshold:
0.01ETH
Part 4: Bob sets up his wallet
Log in as Bob:- Create a wallet: “Bob’s Wallet” (Ethereum Sepolia)
- Verify he can see Alice’s and Charlie’s wallets (marked “Shared”)
- Share “Bob’s Wallet” with Alice → View + Transfer
Part 5: Charlie sends funds
Log in as Charlie:- See “Charlie’s Wallet” in the dashboard (marked “Shared”)
- Send 0.001 ETH: goes through immediately (under his 0.01 ETH limit)
- Send 0.02 ETH: queued for operator approval (over his personal limit)
Part 6: Operator reviews
Log in as the compliance officer:- Go to the Admin section → Pending approvals
- See Charlie’s pending transfer
- Approve or Reject the transfer
- Approved transfers execute on-chain via DFNS
How It Works
Authentication Flow
The frontend uses Auth0 for authentication. On login, Auth0 issues a JWT access token containing custom claims (email, name, roles). The backend verifies this token against Auth0’s JWKS endpoint and auto-creates a local user record on first login.Wallet Operations
All wallet operations go through the backend’s DFNS service account:
The backend converts ETH amounts to wei before sending to DFNS.
Approval Logic
Transfers are checked against two thresholds:- Global threshold (
APPROVAL_THRESHOLDenv var): applies to wallet owners - Per-delegation limit (
transfer_limiton delegations): applies to delegated users, overrides the global threshold
pending. A bank employee can then approve (which broadcasts via DFNS) or reject it.
Family Delegation
Wallet owners can grant two levels of access to family members:
Delegations are stored in SQLite and enforced in the backend. The wallet owner can revoke access at any time.
API Reference
Customer endpoints (require Auth0 JWT)
Employee endpoints (require Auth0 JWT + employee role)
Design Decisions
DFNS is the source of truth for wallet balances, addresses, and transaction status. SQLite stores what DFNS doesn’t know: user-wallet ownership, friendly names, delegations, and the approval queue. Service account pattern: the backend holds a single DFNS service account key. Customers never interact with DFNS directly. This is the “platform-as-custodian” model where the operator (bank, fintech, or institution) has full control over wallet operations. App-level approvals: transfer approval is handled in the application layer (SQLite queue + employee dashboard), not via DFNS policies. This keeps the architecture simple and lets you define custom rules (per-user limits, role-based access). A future blueprint could explore DFNS policies for on-chain governance where operators are registered as DFNS users. Mobile-ready API: pure REST, JWT Bearer auth, JSON responses. No server-side sessions or cookies required on the API side.Adapting for Production
Different networks: change thenetwork parameter when creating wallets (e.g., Ethereum, Polygon, Arbitrum). The DFNS SDK handles chain-specific details.
Real fiat integration: replace the demo fiat accounts with a real banking or account-info API (e.g., Plaid, Open Banking) to show actual account balances.
Multi-level approvals: extend the approval logic to support multiple approvers, approval chains, or time-delayed execution for high-value transfers.
DFNS policies: for stricter governance, DFNS policies can enforce signing rules (e.g., approval quorums, velocity limits) independent of the application layer. This requires operators to be registered as DFNS users rather than using a single service account.