Fakturindocs

System design

The design decisions behind Fakturin, the alternatives considered, and how the system would scale beyond the demo.

Design goals

  1. One invoice, one financing. Double financing must be impossible, not merely detectable.
  2. Only the issuer can borrow. Knowing an invoice number must not be enough.
  3. No trusted operator for money. Funds move only by contract rules; no admin can take them.
  4. Plain for non-crypto users. Few signatures, exact approvals, every step explained.
  5. Swap simulations for real providers without touching contracts.

Key decisions

Data model

classDiagram
class Invoice {
  address seller
  address vault
  bytes32 buyerNpwpHash
  uint256 nominal
  uint64 issuedAt
  uint64 dueDate
  uint64 requestedAt
  Status status
  uint8 rejectCode
}
class FakturRegistry {
  mapping invoiceId → Invoice
  mapping invoiceId → fakturNumber
  mapping vault → invoiceId
  mapping seller → sellerDefaulted
  mapping seller → sellerOutstanding
  mapping buyerNpwpHash → buyerOutstanding
  quote(nominal, dueDate) Quote
}
class FakturVault {
  immutable invoiceId, seller, nominal
  immutable target, advance, holdback, fee
  immutable fundingDeadline, dueDate, gracePeriod
  State state
}
FakturRegistry "1" --> "*" Invoice
Invoice "1" --> "0..1" FakturVault

Onchain: IDs, hashes, amounts, dates, status. Offchain (tax office, issuer): names, NPWPs, documents.

Scaling beyond the demo

ConcernDemoAt scale
Reading listsEvent scan from the deploy block in the browserAn indexer (The Graph, Ponder) or a small API cache
Keeper scanclosable() loops over every vaultKeep a queue of open vaults, or index deadlines offchain and pass exact addresses in the report
Vault deploymentFull contract per invoiceERC-1167 minimal proxies to cut deployment gas
VerificationRelayer or CRE simulationCRE on the Chainlink DON with a real PJAP
Identity issuingServer route with one keyLicensed KYC/KYB provider as ACE issuer, credential expiry and revocation
TokenMockIDRXIDRX or another rupiah stablecoin once on Arbitrum
KeysOne relayer key for verifier, keeper and issuerSeparate keys or no keys: CRE for verifier and keeper, the provider for identity

Consistency and failure

  • At-most-once verification. fulfillVerification only acts on Pending invoices, so a duplicate report (relayer and CRE both answering) is rejected with NotPending.
  • Missed events. The CRE listener starts at the current block; an invoice submitted while it was down stays Pending and can be replayed with --evm-tx-hash. In relayer mode the app re-posts the request.
  • Keeper races. Every close re-checks state and deadlines; a vault closed by someone else just emits VaultCloseFailed and the loop continues.
  • Chain reorgs. Arbitrum confirms in seconds; the app waits for receipts before moving on.

On this page