Skip to content

Latest commit

 

History

History
215 lines (146 loc) · 9.06 KB

File metadata and controls

215 lines (146 loc) · 9.06 KB

FinHive

Canton-native business banking where role privacy is enforced by the ledger, not by the UI.

License: Apache 2.0 Canton Status Live demo Deck

FinHive is a multi-user business workspace for managing money: invoices, payments, payroll, recurring revenue, treasury. It is built on Canton because role-scoped visibility is enforced cryptographically by the contract, not by application-level access control.

The CEO sees the budget envelope. The bookkeeper sees the line items. The vendor sees only their own invoices. Not because we built a filter, but because Canton's stakeholder model makes any other view impossible.


Contents


Why this matters

Mercury, Brex, Ramp, Bill.com. Every SMB finance tool today is built admin-down: the org admin sees everything, and roles are access-control layers on top. That model leaks salary data through bookkeepers, leaks contractor invoices through the AP queue, and leaks vendor pricing through finance dashboards. You cannot fix it with permissions. The data model is wrong.

Canton inverts the model. signatory, observer and controller are first-class contract primitives. The CEO is never a stakeholder in the line items of an AP clerk's invoice, so the synchronizer never sends that data to the CEO's participant. Privacy is the default. Visibility is the exception you have to opt into.

FinHive ships this as the operating account for teams of 5 to 50 people whose treasury includes stablecoins and whose CEO does not need to see every line item.


Architecture

A single host runs the whole stack. Auth0 and the LLM provider are the only external dependencies.

On the host

Service Port Role
Host Caddy 443 TLS terminator, wildcard *.unitynodes.com on a Cloudflare origin certificate
Next.js 16 (App Router) 3100 Role-switching workspace, server actions, server components
Node AP agent internal Polls invoices, asks an LLM for a verdict, signs proposals on chain
Canton 3.5.1 validator (Splice 0.6.5) 7575 JSON Ledger API v2, Participant, ANS

External

Service Role
Auth0 M2M client_credentials grant, audience https://canton.network.global
LLM provider Any OpenAI-compatible endpoint. Groq Llama 3.3 70B by default; OpenRouter, OpenAI, Anthropic also work

Request flow

  1. Browser hits finhive.unitynodes.com. Host Caddy terminates TLS.
  2. Caddy forwards to the Next.js app on 127.0.0.1:3100.
  3. The web app calls the Canton JSON Ledger API on 127.0.0.1:7575 and Auth0 for M2M tokens.
  4. The AP agent polls the same JSON API, calls the LLM for verdicts, and signs proposals back to the validator.
flowchart LR
  user([User browser])

  subgraph host[Single host]
    direction TB
    caddy["Host Caddy<br/>wildcard TLS"]
    web["Next.js 16 App Router<br/>port 3100"]
    agent["Node AP agent<br/>poller"]
    validator["Canton 3.5.1 validator<br/>Splice 0.6.5<br/>JSON Ledger API v2<br/>port 7575"]
  end

  auth0[("Auth0 M2M")]
  llm[("LLM provider")]

  user --> caddy --> web
  web --> validator
  web --> auth0
  agent --> validator
  agent --> auth0
  agent --> llm
Loading

Not deployed: PQS, Postgres, Keycloak, Daml trigger runner.

See docs/architecture.md for the full breakdown.


Daml templates

Template Signatories Purpose
Company operator Tenant root
Role operator Maps a party to a role: CEO, AP_Clerk, Vendor, HR or Employee
Invoice vendor, operator AP invoice. AP_Clerk is observer. CEO is not a stakeholder
BudgetView apClerk Aggregate view, total only, no line items. CEO is observer
Settlement apClerk Created on ApproveInvoice. Emits FeaturedAppActivityMarker
PaymentPolicy ceo Auto-approval rules: limits, vendor allowlist, frequency caps
AgentSpendingLimit ceo Cryptographic cap on the AI agent's autonomous spend
RecurringPayment customer, vendor, operator AR and subscription primitive

operator is a co-signatory of Invoice and RecurringPayment so it can create FeaturedAppActivityMarker (which requires operator as signatory) in the same transaction. FeaturedAppActivityMarker is emitted on Invoice.ApproveInvoice and RecurringPayment.Charge, the two rewardable choices for Featured App readiness.

Sources in daml/FinHive/.


AI agent

A Node and TypeScript poller in agent/ watches for new Invoice contracts in Pending status via the JSON Ledger API v2. It uses any OpenAI-compatible provider, configured through env (LLM_BASE_URL, LLM_API_KEY, LLM_MODEL). Default is Groq Llama 3.3 70B; OpenRouter, OpenAI and Anthropic-compatible endpoints all work.

For each pending invoice the agent:

  1. Reads the company's PaymentPolicy and AgentSpendingLimit.
  2. Asks the configured LLM for a verdict given the policy, the invoice and the remaining limit.
  3. Falls back to a deterministic rule if the LLM is unavailable.
  4. If the verdict is AUTO_APPROVE and the amount fits the spending limit, exercises ApproveInvoice directly. The ConsumeBudget choice asserts the cap on the ledger.
  5. Otherwise creates a ProposedAction contract that the AP_Clerk sees in their inbox with accept and override buttons.

The agent cannot exceed the cryptographically enforced limit. Even a misbehaving LLM cannot move money beyond what the CEO signed off on.


Quick start

Prerequisites

  • A running Canton 3.5.1 validator (Splice 0.6.5)
  • Daml SDK 3.4.11 (sdk-version: 3.4.11 in daml.yaml)
  • Node.js 20 or later, and pnpm 9
  • Docker Compose 2.26 or later
  • An Auth0 tenant with an M2M application (client_credentials grant, audience https://canton.network.global, scope daml_ledger_api)
  • An OpenAI-compatible LLM API key (default Groq, or OpenRouter, OpenAI, Anthropic-compatible)

Steps

git clone https://github.com/UnityNodes/FinHive.git
cd FinHive

# 1. Install the toolchain (Daml SDK, Java, Node 20, pnpm)
bash scripts/bootstrap-toolchain.sh

# 2. Configure environment
cp .env.example .env
# Edit .env: Auth0 M2M credentials, LLM API key, ledger URL

# 3. Build and test the Daml model
daml build
cd daml-tests && daml test && cd ..

# 4. Upload the DAR to the running validator (writes the package id to .env)
bash scripts/upload-dar.sh

# 5. Allocate the FinHive parties and grant the backend act-as rights
bash scripts/setup-ledger.sh

# 6. (optional) Seed demo data
python3 scripts/seed.py

# 7. Start the web app and agent via Docker Compose
docker compose -f infra/docker-compose.yml up -d

# 8. Route a subdomain through Caddy with TLS
#    Append infra/caddy-finhive.snippet to your Caddyfile, then:
sudo systemctl reload caddy
#    and add a DNS A record for your subdomain to the server

Open the deployed URL, or http://localhost:3100 for local dev. Use the role switcher in the header to move between the Vendor, AP_Clerk, CEO, HR and AR views.

Privacy proof

  1. Vendor creates a $5,000 invoice.
  2. Switch to AP_Clerk. Full line items visible, AI proposal shown.
  3. AP_Clerk approves. Settlement is created and FeaturedAppActivityMarker is emitted on the ledger.
  4. Switch to CEO. The dashboard shows Vendor X paid $5,000 as a BudgetView aggregate. Line items: not visible. This is not a UI filter. The Canton synchronizer never sends Invoice contracts to a party that is not a stakeholder.

Demo

The slide deck walks through the privacy thesis, the role split, the AI assistant and the stack. Use the right and left arrow keys, or click the bottom dots to jump.


Roadmap

  • Phase 0, now. MVP on DevNet. Six Daml templates, multi-role app, AI agent, deployed.
  • Phase 1. TestNet to MainNet, multi-participant privacy, real settlement.
  • Phase 2. Scale and multi-jurisdiction.

License

Apache 2.0. See LICENSE.

Daml templates, frontend, agent and infra config are all open source. The point is composability. If you want to build your own SMB banking product on Canton, fork the templates.


Acknowledgements

Built on the Canton Network and the open-source Splice reference implementation.