Skip to content

ryanb-88/agentbank

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

70 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AgentBank

An autonomous fractional-reserve bank and financial intermediary for the agent economy, built for the Nevermined Autonomous Business Hackathon (March 5–6, 2026).

AgentBank accepts USDC deposits (via Nevermined plans), extends credit lines to agents that need working capital, and earns revenue by proxying upstream services at a markup — buying from seller agents on behalf of borrowers and pocketing the spread.


What It Does

AgentBank implements real banking primitives adapted for the agent economy:

  • Fractional reserve model — 20% reserve ratio, lends out the rest
  • Capital adequacy enforcement — Basel-inspired minimum CAR of 12%
  • Expected Credit Loss (ECL) provisioning — PD × LGD × EAD per loan
  • Double-entry ledger — every transaction produces balanced debits and credits
  • Dynamic interest rate pricing — cost of funds + risk premium + target margin
  • Proxy intermediary layer — buys upstream services with USDC, resells to borrowers at markup via credit plan
  • Collateralized lending — borrowers lock credits as collateral before receiving funds
  • Solvency-gated redemptions — USDC redemptions approved only if bank stays above minimum reserve ratios

The credit peg is fixed: 1 credit = 0.01 USDC.


Tech Stack

Layer Technology
Framework Next.js 14 (App Router)
Language TypeScript (strict mode)
Database Neon (serverless Postgres)
ORM Drizzle ORM
Payments Nevermined SDK (@nevermined-io/payments)
On-chain viem (Base testnet)
AI OpenAI
Validation Zod
Testing Vitest
Styling Tailwind CSS

Getting Started

Prerequisites

  • Node.js 18+
  • A Neon database
  • A Nevermined API key and plan DID
  • A Base testnet wallet with USDC

Installation

npm install

Environment Setup

Copy .env.example to .env.local and fill in your values:

cp .env.example .env.local
Variable Description
NVM_API_KEY Nevermined API key
NVM_ENVIRONMENT testing or production
NVM_PLAN_DID DID of your Nevermined credit plan (backward compat, uses Starter tier)
NVM_PLAN_DID_STARTER DID for Starter tier (100 credits / $1.00 USDC)
NVM_PLAN_DID_GROWTH DID for Growth tier (500 credits / $4.50 USDC)
NVM_PLAN_DID_PRO DID for Pro tier (1000 credits / $8.00 USDC)
NVM_AGENT_DID DID of your Nevermined agent (for observability)
NEON_DATABASE_URL Neon Postgres connection string
OPENAI_API_KEY OpenAI API key (for credit scoring LLM)
USDC_CONTRACT_ADDRESS USDC contract on Base testnet
BANK_WALLET_PRIVATE_KEY Bank's wallet private key (for USDC transfers)
BANK_WALLET_ADDRESS Bank's wallet address

Database Setup

npm run db:generate   # generate migration files
npm run db:migrate    # apply migrations to Neon

Running Locally

npm run dev

Running Tests

npm test              # single run
npm run test:watch    # watch mode

Folder Structure

agentbank/
├── app/                        # Next.js App Router
│   ├── api/                    # API route handlers
│   ├── globals.css
│   ├── layout.tsx
│   └── page.tsx
│
├── db/                         # Database layer
│   ├── schema.ts               # Drizzle table definitions (7 tables)
│   ├── index.ts                # Neon connection + Drizzle instance
│   └── __tests__/
│       └── schema.test.ts
│
├── lib/                        # Core business logic
│   ├── types.ts                # Zod schemas + TypeScript types
│   ├── config.ts               # Risk limits, rate bounds, tier config, chart of accounts
│   ├── ledger.ts               # Double-entry ledger (journal entries, trial balance, balance sheet)
│   ├── rate-engine.ts          # Interest rate and deposit yield calculations
│   ├── risk-engine.ts          # CAR, ECL, LCR, reserve ratio, stress testing
│   ├── banking-engine.ts       # Loan issuance, repayment, default, deposits, withdrawals
│   ├── redemption-engine.ts    # USDC redemption with solvency gates
│   ├── credit-scoring.ts       # Credit scoring with external data acquisition
│   ├── provider-registry.ts    # Data provider registry and ROI tracking
│   ├── proxy-service.ts        # Proxy service layer (buy upstream, sell at markup)
│   ├── nevermined.ts           # Nevermined SDK wrapper (mint, burn, balance, x402)
│   └── __tests__/              # Unit tests for all lib modules
│
├── PRD/                        # Product requirements
│   ├── agent-bank-prd.md       # Full PRD with banking model, risk framework, API contracts
│   └── agent-user-journey.md   # User journey flows
│
├── ImplementationPlans/        # TDD implementation plan
│   └── agentbank-tdd-implementation-plan.md
│
├── scripts/
│   ├── register-plan.mjs       # Register Nevermined credit plan
│   └── validate-env.mjs        # Validate environment variables
│
├── .env.example                # Environment variable template
├── drizzle.config.ts           # Drizzle ORM configuration
├── next.config.js
├── tsconfig.json               # Strict TypeScript config
├── vitest.config.ts
└── CHANGELOG.md                # Full change history with test counts

Database Schema

Seven tables managed by Drizzle ORM:

Table Purpose
agents Agent profiles, credit scores, tiers, blacklist status
loans Active and historical loans with collateral and ECL data
deposits Agent deposits with yield accrual
redemptions USDC redemption records
journal_entries Append-only double-entry ledger
proxy_transactions Proxy service call records
bank_snapshots Periodic balance sheet snapshots

Banking Model Summary

Credit tiers (based on credit score):

Tier Score Rate Max Loan Collateral
A 80–100 15% 500 credits 10%
B 60–79 20% 200 credits 20%
C 40–59 27% 50 credits 30%
Rejected 0–39

Key risk limits (hard constraints, never violated):

  • Reserve ratio ≥ 20%
  • Capital Adequacy Ratio ≥ 12%
  • Liquidity Coverage Ratio ≥ 100%
  • Single borrower ≤ 25% of loan book
  • Loan-to-deposit ratio ≤ 80%

API Endpoints (Planned)

Method Path Auth Description
GET /api/health None Balance sheet, key ratios, bank status
GET /api/rates None Current lending rates and deposit yield
GET /api/stats None Aggregate statistics
GET /api/balance/[agentId] None Agent's loans, deposits, redeemable balance
GET /api/pricing None Service pricing and USDC peg rate
POST /api/deposit x402 Accept a deposit
POST /api/withdraw x402 Withdraw a deposit
POST /api/loan/apply x402 Apply for a loan
POST /api/loan/repay x402 Repay a loan
POST /api/redeem x402 Redeem credits for USDC
POST /api/proxy x402 Proxy a service request

CI/CD

Deployments are fully automated via GitHub Actions (.github/workflows/ci-cd.yml). Direct CLI deploys to production are not permitted.

Pipeline (push to master):

lint + test → deploy (Vercel) → db:push (Neon) → health check

Pipeline (pull request):

lint + test → build verification

Required GitHub Secrets

Secret Description
VERCEL_TOKEN Vercel personal access token
VERCEL_ORG_ID From .vercel/project.jsonorgId
VERCEL_PROJECT_ID From .vercel/project.jsonprojectId
NEON_DATABASE_URL Neon Postgres connection string
VERCEL_DEPLOYMENT_URL Production URL for health checks (e.g. https://agentbank.vercel.app)

Jobs

Job Trigger Purpose
lint PR + push ESLint + tsc --noEmit
test PR + push Vitest unit suite
build PR only Next.js build verification with dummy env vars
deploy push to master Vercel CLI production deploy
migrate after deploy drizzle-kit push schema sync to Neon
health-check after migrate Hits /api/health and /api/.well-known/agent.json

Test Coverage

727 tests passing across all implemented modules (4 skipped — require live DB).

See CHANGELOG.md for a full breakdown by phase and task.


Nevermined Observability

AgentBank integrates with the Nevermined request lifecycle and observability layer to provide:

  • x402 payment validation on all paid API endpoints via payment-signature header
  • Automatic credit settlement after successful request processing
  • Custom event logging to the Nevermined hosted analytics dashboard (per-agent, per-service analytics)

This integration is optional. When the required environment variables are not set, the app degrades gracefully — all endpoints function normally without x402 validation or observability tracking.

Required Environment Variables

Variable Description
NVM_API_KEY Nevermined API key
NVM_ENVIRONMENT testing, sandbox, or production
NVM_PLAN_DID DID of your Nevermined credit plan
NVM_AGENT_DID DID of your Nevermined agent

Credit Costs per Endpoint

Endpoint Credits
POST /api/loan/apply 5
POST /api/loan/repay 1
POST /api/deposit 1
POST /api/withdraw 1
POST /api/redeem 1
POST /api/proxy/[service] Dynamic (from service catalog)
All GET endpoints Free

Dashboard

When observability is enabled, analytics are available on the Nevermined Dashboard. No custom frontend work is required — the hosted dashboard surfaces per-agent, per-service metrics automatically.

Multi-Tier Plan Registration

AgentBank supports three pricing tiers on the Nevermined marketplace:

Tier Credits Price Discount
Starter 100 $1.00 USDC
Growth 500 $4.50 USDC 10%
Pro 1000 $8.00 USDC 20%

To register all tiers:

node scripts/register-plan.mjs

This registers the agent (if needed) and all three plans, outputting the plan DIDs for your .env file.

To register a specific tier:

node scripts/register-plan.mjs --tier=Growth

Set the output DIDs in your environment:

NVM_PLAN_DID_STARTER=did:nvm:...
NVM_PLAN_DID_GROWTH=did:nvm:...
NVM_PLAN_DID_PRO=did:nvm:...

Dynamic Proxy Catalog

AgentBank's proxy service dynamically discovers upstream agents from the Nevermined hackathon marketplace and routes requests to them using x402 authentication. This makes AgentBank a genuine buyer in the agent economy, generating real cross-team transactions.

How It Works

Discovery API → Catalog Manager (TTL cache) → Proxy Service → Upstream Caller (x402) → Real Agent
  1. Discovery: Fetches sellers from https://nevermined.ai/hackathon/register/api/discover
  2. Catalog Manager: Merges dynamic sellers with static fallback catalog
  3. Proxy Service: Routes borrower requests to upstream agents
  4. Upstream Caller: Handles x402 authentication (orderPlan → getX402AccessToken → POST with payment-signature)

Catalog Merging

The catalog merges two sources:

Source Description Fields
Dynamic Discovered from marketplace planId, endpointUrl, creditCost, upstreamCostUsdc, source: 'dynamic'
Static Hardcoded fallback Basic pricing info, source: 'static'

Dynamic entries take precedence when the same agent DID appears in both.

Cache Behavior

  • TTL: 5 minutes (DISCOVERY_CONFIG.refreshIntervalMs)
  • Manual Refresh: GET /api/proxy/catalog?refresh=true
  • Stale-on-Error: If discovery fails, cached catalog is returned

Graceful Degradation

Failure Scenario Behavior
Discovery API 401/500/timeout Returns cached catalog or static fallback
NVM_API_KEY not set Uses static catalog only
Upstream agent returns 402/500 0 credits charged to borrower
orderPlan() or getX402AccessToken() fails Returns upstream_error to borrower

API Endpoint

# Get current catalog (merged dynamic + static)
GET /api/proxy/catalog

# Force cache refresh
GET /api/proxy/catalog?refresh=true

Response includes source and intelligence fields per agent:

{
  "services": [{
    "service": "research",
    "upstream_agents": [{
      "agent": "did:nvm:real-seller",
      "credit_cost": 8,
      "upstream_cost_usdc": 0.05,
      "availability": 1.0,
      "plan_id": "plan-abc",
      "endpoint_url": "https://seller.com/api",
      "source": "dynamic",
      "intelligence": {
        "last_sampled_at": "2026-03-06T14:30:00Z",
        "last_latency_ms": 150,
        "samples_collected": 5
      }
    }]
  }]
}

The intelligence field is null when no market intelligence data exists for that agent+service pair.

Provider Performance Tracking

All upstream agents (dynamic and static) are tracked in the provider registry:

  • queriesMade: Total proxy calls to this agent
  • predictionAccuracy: Success rate (for credit scoring providers)
  • roiScore: Value generated per credit spent

Use selectProviders({ budget }) to rank agents by ROI score.


Treasury Operations

AgentBank is not just a passive proxy — it's an autonomous buyer in the agent economy. The Treasury Operations Engine proactively purchases services from marketplace sellers on a schedule, building counterparty relationships and deploying idle reserves productively.

Why Treasury Operations?

Real banks don't wait for transactions. They:

  1. Establish correspondent relationships via small transactions with counterparties
  2. Make markets by buying services to resell at markup
  3. Perform due diligence by periodically sampling counterparties

AgentBank's treasury engine automates all three strategies.

Four Strategies

Strategy Purpose Budget Allocation
Correspondent Build relationships with new sellers 25%
Market-Making Buy from sellers with positive spread (profit margin) 30%
Due Diligence Re-sample sellers not contacted in 3 minutes 20%
Repeat Customer Buy from proven sellers with successful history 25%

Correspondent Strategy: Targets sellers the bank has never transacted with. Buys 1 request from each, sorted by cost ascending (maximizes breadth per credit). Registers each seller in the provider registry for future credit scoring.

Market-Making Strategy: Targets sellers with positive spread (where creditCost × 0.01 > upstreamCostUsdc). Buys from highest-spread sellers first, building inventory for future proxy requests.

Due Diligence Strategy: Re-samples sellers not contacted in the last 3 minutes. Flags sellers with latency degradation (> 50% increase from historical average).

Repeat Customer Strategy: Prioritizes sellers with proven track record (queriesMade > 0, lastCallFailed = false). Buys from cheapest first to maximize call volume per credit.

Budget Calculation

The treasury budget is calculated from excess reserves:

excessReserves = cashReserves - (totalDeposits × minReserveRatio)
budgetCredits = min(excessReserves × 0.10, 50)
  • Minimum threshold: Budget is 0 if excess reserves < 20 credits
  • Hard cap: Budget never exceeds 50 credits per cycle
  • Conservative: Only 10% of excess is spent per cycle

Scheduler

  • Execution: Vercel cron job triggers GET /api/treasury/cron every minute
  • Bootstrap: Seeds 500 credits ($5 USDC) as initial equity on first run if balance sheet is empty
  • Concurrency guard: No overlapping cycles
  • Error isolation: One failing strategy doesn't abort others

API Endpoints

# Get treasury status
GET /api/treasury

# Trigger a manual cycle
POST /api/treasury

# Vercel cron endpoint (called automatically every minute)
GET /api/treasury/cron

# Get last N cycle results (default: 10)
GET /api/treasury/history
GET /api/treasury/history?limit=5

GET /api/treasury Response:

{
  "status": "active",
  "last_cycle": {
    "cycle_id": "TC-2026030601",
    "started_at": "2026-03-06T10:00:00Z",
    "completed_at": "2026-03-06T10:00:05Z",
    "budget_credits": 10,
    "total_spent_credits": 8,
    "sellers_contacted": 3,
    "success_count": 3,
    "failure_count": 0
  },
  "next_cycle_at": 1709715600000
}

POST /api/treasury Response:

  • 200: Cycle completed successfully
  • 409: Cycle already in progress
  • 422: Treasury operations disabled

Configuration

Treasury behavior is configured in lib/config.ts:

TREASURY_CONFIG = {
  enabled: true,                    // Set to false to disable
  cycleLengthMs: 60_000,            // 1 minute
  maxBudgetPctOfExcessReserves: 0.20,
  maxBudgetCreditsPerCycle: 150,
  minExcessReserveCredits: 10,
  strategyAllocation: {
    correspondent: 0.25,
    marketMaking: 0.30,
    dueDiligence: 0.20,
    repeatCustomer: 0.25,
  },
  dueDiligenceResampleAfterMs: 180_000, // 3 minutes
}

To disable treasury operations, set TREASURY_CONFIG.enabled = false or remove NVM environment variables.

Ledger Integration

Treasury purchases record balanced journal entries:

Account Code Debit Credit
Credit Scoring Data 1300
Cash Reserves 1000
  • Reference type: treasury
  • Reference ID: Cycle ID (e.g., TC-2026030601)
  • Failed purchases: No ledger entry (no charge)

Graceful Degradation

Scenario Behavior
Discovery API unreachable Due diligence runs on known sellers
All upstream agents return errors 0 credits spent, no ledger entries
Budget is 0 (reserves at minimum) No purchases, cycle completes
Treasury disabled via config Scheduler doesn't start
NVM credentials missing Scheduler doesn't start
One strategy throws error Other strategies continue

About

Decentralized banking for AI agents — deposits, loans, redemptions, proxy services for the Nevermined Hackathon in AWS Loft SF

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors