Skip to content
FBP-03Spec version v0.1-draftnormativedraft

FBP-03 · StableFlow

FlowBond Protocol

FBP-03 defines a closed-loop credit: a unit that exists inside one economy, is spent inside that economy, and leaves it only by being burned. It is the primitive that lets an application meter access, reward participation and let an agent spend on a person’s behalf — without creating a financial instrument.

Rationale (non-normative). A closed-loop credit that can be exchanged for cash is a stored-value instrument, and in most jurisdictions that is a regulated activity with licensing, safeguarding and reporting obligations attached. More importantly, the moment redemption exists, the credit acquires a market price, and every design decision in the economy becomes a financial decision.

Making redemption unavailable by policy would leave it one product decision away. Making it a constitutional invariant means a consumer cannot introduce it without leaving the protocol — which is exactly the intent. A conformant implementation MUST NOT provide a configuration flag whose effect is redemption, and MUST NOT accept a consumer agreement that purports to grant one.

An economy instance is a namespace with its own supply, its own rules and its own stream.

Economy instance
{
"v": 1,
"id": "ec_01J92…",
"stream": "s_bb70…",
"unit": { "name_commitment": "0x3d2…", "decimals": 0 },
"policy": {
"mint_authorities": ["fbid:z6Mk…X"],
"mint_authority_threshold": 1,
"expiry_events": null,
"transferable_between_holders": false,
"max_supply": null
},
"redeemable": false,
"created": "e_01J92…"
}
  • Each consumer operates its own economy instance. Credits MUST NOT be fungible across instances, and an implementation MUST NOT provide a conversion path between them.
  • decimals SHOULD be 0. Credits are countable things; fractional credits invite pricing behaviour that belongs to money.
  • redeemable MUST be false. The field exists so the invariant is legible in the data, not so it can be changed: an economy instance with redeemable: true MUST be rejected at creation, and an event attempting to set it MUST be rejected.
  • transferable_between_holders MAY be true, permitting peer transfer within the instance. Even when true, §3.2 constraints apply.
  • max_supply: null means unbounded issuance by the authorities. Where a cap exists, a mint that would exceed it MUST be rejected.
OperationEventWho MAY perform it
Mintfbp03.credit.mintedA mint_authority of the instance, at or above mint_authority_threshold
Burnfbp03.credit.burnedThe holder, or an authority where the instance policy permits expiry
Transferfbp03.credit.transferredThe holder, only within the instance, only if transferable_between_holders
Spendfbp03.credit.spentThe holder or a gated agent; burns the credit against a named consumption

Normative rules:

  • Mint. MUST name its authority and MUST commit to a reason. Minting MUST NOT be possible by any party outside mint_authorities. Mint events MUST be included in the public supply aggregate.
  • Burn. MUST be irreversible. A burned credit MUST NOT be re-minted as the same credit; new issuance is a new mint, visible in the supply aggregate.
  • Transfer. MUST NOT cross instance boundaries. An implementation MUST reject a transfer whose destination is outside the instance, and MUST NOT expose an API surface that could express one.
  • Spend. MUST reference what was consumed, by commitment. A spend with no counterpart consumption is a burn and MUST be recorded as one.
  • No operation MAY create a negative balance. A spend exceeding balance MUST be rejected before signing, and a node that observes one after merge MUST mark the stream in conflict and refuse further spends until an explicit resolution event.

Where policy.expiry_events is set, credits expire after that much ledger progress from mint.

  • Expiry MUST be a burn event, attributed to the instance policy, not a silent disappearance.
  • The holder MUST be notified before expiry through the links on their FBID, where any exist.
  • Expiry MUST NOT be applied retroactively to credits minted before the policy was set.
  • The instance MUST publish a running supply commitment updated by every mint and burn.
  • Any observer MUST be able to verify outstanding = minted − burned from public data and proofs alone, with no privileged access.
  • Individual balances MUST be private. A balance MUST NOT be inferable from public state by an observer who is not the holder or an explicitly granted party.
  • An implementation MUST publish the supply aggregate at least once per some bounded interval of ledger progress, and MUST make historical aggregates verifiable, so that supply cannot be inflated and quietly corrected.
  • A balance is a projection of the holder’s credit stream, not a stored number. The authoritative answer to “how many credits” is always the ordered event set.
  • A holder MUST be an FBID. Bearer balances — a credit held by whoever holds a token — MUST NOT exist, because they reintroduce transferability out of band.
  • A holder MUST be able to export their own balance history at any time, in full, in a machine-readable form.

The interface through which a Plane 3 agent is permitted to spend. It is normative here and elaborated at Agent Interface.

Spend gate authorisation
{
"id": "sg_01J93…",
"principal": "fbid:z6Mk…P",
"agent": "fbid:z6Mk…AG",
"economy": "ec_01J92…",
"limit": { "per_action": 25, "per_window": 200, "window_events": 1440 },
"scope": ["purpose:research-tools", "purpose:media-generation"],
"expires": { "lamport": 9600 },
"step_up_above": 50,
"revocable": true
}

Normative rules:

  • An agent MUST NOT spend without a live gate authorisation naming that agent, that economy, and a purpose within scope.
  • A gate MUST carry a per-action limit, a windowed limit, and an expiry. An authorisation missing any of the three MUST be rejected.
  • A gate MUST be revocable by the principal alone, with immediate effect and without the agent’s cooperation.
  • step_up_above names the amount beyond which fresh human authorisation is REQUIRED for a single action. It MUST NOT be disabled by the agent.
  • Every gated spend MUST be attributed on the ledger to both the agent and the principal. An unattributable agent spend MUST be rejected.
  • The gate MUST fail closed. If gate state cannot be evaluated — offline, merge conflict, expired — the spend MUST NOT proceed.
  • An agent MUST NOT hold a gate that outlives the task it was granted for, and implementations SHOULD scope gates per task rather than per session.
An agent spend: the gate is evaluated before anything is signed, and fails closed.
MUST be provableMUST NOT be revealed
Supply reconciles: outstanding = minted − burnedIndividual balances
A holder had sufficient balance for a spendThe balance, or the amount, to non-parties
A spend was within its gate’s limitsThe gate’s limits, to non-parties
A credit belongs to this instance and no otherThe holder’s identity, to non-parties
A mint was authorised by a valid authorityWhich authority, where the authority set permits it
  • Balances MUST be private by default. An implementation that publishes balances is not conformant, even if identifiers are pseudonymous — pseudonymous balance histories de-anonymise readily.
  • Where a consumer needs analytics, it MUST be served by aggregate proofs, not by per-holder data.
  • No code path, flag, admin action or contract term produces cash redemption.
  • No conversion path exists between two economy instances.
  • Transfers to a destination outside the instance are unrepresentable in the API.
  • Public supply reconciles from public data alone, with no privileged access.
  • Individual balances are not derivable from public state.
  • An agent with an expired, revoked or unevaluable gate cannot spend.
  • Every agent spend names both agent and principal on the ledger.
  • Expiry, where enabled, appears as an attributed burn and is preceded by notice.