Skip to content

Credit V10 governance and pro-rata settlement plan ​

Status: Proposed for approval. No implementation or deployment is authorized by this document.

Goals ​

Credit V10 will address two findings without modifying deployed V9:

  1. replace immediate ownership transfer with a two-step proposal and acceptance flow; and
  2. ensure a borrower who repaid part of their principal before maturity receives the corresponding proportion of their original collateral after maturity.

V9 remains immutable audit history. V10 will be a new contract and isolated service deployment.

Proposed borrower outcome ​

Repayment remains USDC-principal-only and oracle-independent. Under the proposed default policy, repayments remain strictly before maturity.

At maturity:

Principal repaidBorrower collateral entitlementVault collateral entitlement
0%0%100%
50%50%50%
70%70%30%
100%100%0%

The fixed upfront collateral fee remains non-refundable because it paid for the full agreed term when the loan opened.

1. Two-step ownership transfer ​

Contract interface ​

Replace V9's immediate transfer_ownership(new_owner) entry point with:

sway
fn owner() -> Address;
fn pending_owner() -> Address;
fn propose_ownership(new_owner: Address);
fn accept_ownership();
fn cancel_ownership_transfer();

There must be no alternate single-step ownership path.

State transitions ​

  1. The current owner calls propose_ownership(new_owner).
  2. The contract validates that the nominee is nonzero and differs from the current owner.
  3. The nominee is stored as pending_owner; authority does not change.
  4. Only that exact pending address may call accept_ownership().
  5. Acceptance updates owner, clears pending_owner, and immediately removes every owner privilege from the former owner.
  6. Before acceptance, the current owner may replace a pending proposal or call cancel_ownership_transfer().

The existing owner retains responsibility and authority until acceptance. A nominee receives no owner, manager, oracle, strategy, or withdrawal power merely by being proposed.

Events ​

sway
OwnershipTransferProposed { current_owner, pending_owner }
OwnershipTransferCancelled { owner, cancelled_pending_owner }
OwnershipTransferred { previous_owner, new_owner }

Required authorization properties ​

  • Non-owners cannot propose or cancel.
  • Zero/current-owner proposals revert.
  • Current owner, manager, strategies, and unrelated accounts cannot accept unless they are the exact nominee.
  • Acceptance with no pending nominee reverts.
  • A superseded nominee cannot accept.
  • Proposal/cancellation never changes authority.
  • Former owner loses withdrawal, oracle, strategy-permission, manager-proposal, ownership, and cancellation powers after acceptance.
  • The new owner receives owner powers but does not implicitly become manager.

2. Pro-rata maturity settlement ​

Settlement formula ​

When an active loan reaches maturity, permissionless finalization calculates:

text
borrower_claimable = floor(original_collateral × repaid_principal ÷ original_principal)
vault_seized       = original_collateral - borrower_claimable
remaining_default  = original_principal - repaid_principal

All multiplication uses U128; conversion to u64 occurs only after bounded division.

Required invariants:

text
0 <= repaid_principal <= original_principal
0 <= borrower_claimable <= original_collateral
borrower_claimable + vault_seized == original_collateral
repaid_principal + remaining_default == original_principal

Rounding policy proposed for approval ​

Use floor rounding for borrower_claimable. Any indivisible remainder—at most one collateral base unit per loan—goes to the vault.

This is conservative and guarantees the borrower never receives more than their exact pro-rata share. An alternative ceiling policy would favor the borrower by at most one base unit. This choice requires explicit approval before implementation.

Finalization ​

mark_delinquent(loan_id) remains permissionless and available at or after maturity.

For a partially repaid loan it will:

  1. validate active status and the maturity boundary;
  2. calculate remaining USDC default and both collateral portions;
  3. record the loan as terminal/delinquent;
  4. record only vault_seized as collateral_defaulted_to_vault;
  5. remove only vault_seized from borrower-locked collateral accounting;
  6. add vault_seized to vault/defaulted collateral accounting; and
  7. leave borrower_claimable locked in the contract until the borrower claims it.

No oracle read is required.

Borrower claim ​

claim_collateral(loan_id) will support both:

  • fully repaid loans: claim all original collateral at/after maturity; and
  • finalized partially repaid loans: claim original_collateral - collateral_defaulted_to_vault at/after maturity.

The claim remains borrower-only. It transfers the exact unclaimed borrower entitlement and removes that amount from locked-collateral accounting.

The contract must reject:

  • claims before maturity;
  • claims before an unpaid loan is finalized;
  • claims by anyone other than the borrower;
  • a second claim;
  • zero-value claims; and
  • finalization of a terminal loan.

A zero-repayment loan therefore sends all collateral to the vault and exposes no claim action.

Loan and event model ​

The existing immutable originals remain:

  • collateral_amount;
  • principal_amount;
  • upfront fee and opening price data.

The existing mutable fields can continue to express settlement:

  • repaid_amount;
  • collateral_released—actual amount transferred to the borrower;
  • collateral_defaulted_to_vault—the finalized vault share;
  • terminal status.

Add or revise events so indexers do not need to infer state from ambiguous logs:

sway
LoanMaturitySettled {
  loan_id,
  original_principal,
  repaid_amount,
  defaulted_usdc,
  borrower_collateral_claimable,
  collateral_defaulted_to_vault
}

LoanCollateralClaimed {
  loan_id,
  borrower,
  collateral_asset_id,
  collateral_amount
}

Contract reads remain authoritative.

3. Explicit policy gate: post-maturity repayment ​

The recommended V10 scope does not reopen repayment after maturity. It changes collateral allocation based on payments already made before the agreed deadline.

Allowing post-maturity cure is a separate economic design requiring decisions about:

  • grace-period duration;
  • who may finalize during that period;
  • late fees or unchanged economics;
  • races between repayment and finalization;
  • capital and reporting treatment; and
  • whether the vault may already have deployed its entitlement.

Default proposal: repayment closes at maturity, permissionless finalization opens at maturity, and pre-maturity repayment determines the pro-rata collateral share.

This policy also requires explicit approval.

4. Accounting changes ​

For each collateral asset independently:

text
borrower_collateral_owed
  = active collateral
  + fully repaid but unclaimed collateral
  + finalized partial-loan borrower entitlements not yet claimed

At partial maturity finalization:

  • locked/owed decreases only by the vault portion;
  • defaulted collateral increases by the vault portion;
  • borrower entitlement remains unavailable for owner withdrawal and strategy deployment.

At borrower claim:

  • locked/owed decreases by the transferred borrower portion;
  • claimed collateral increases by that same amount;
  • onchain collateral decreases by that same amount.

V10 tests must enforce conservation across FUEL and stFUEL separately:

text
original collateral
  = borrower claimed
  + borrower still owed
  + vault defaulted

Strategy exposure remains deployed capital, not borrower liability. Neither owner nor manager may withdraw or deploy borrower-claimable collateral.

5. Versioning and migration ​

Immutable V9 ​

Create contracts/fuel-credit-v10 by copying the reviewed V9 source, then make only approved V10 changes. Preserve all V1–V9 source, bytecode, deployment manifests, and journals.

Existing V9 loans cannot be migrated in place: their collateral is held by V9 and their settlement rules are enforced by V9 bytecode. Those loans retain the V9 all-or-nothing maturity terms.

Testnet cutover ​

  1. Inventory every V9 loan, pool balance, borrower liability, strategy exposure, realized yield/loss, owner, manager, and oracle.
  2. Stop new V9 originations in the frontend before activating V10.
  3. Settle or maintain monitoring for every existing V9 loan under V9 rules.
  4. Return/write down and reconcile V9 strategy exposure as authorized.
  5. Withdraw only V9 capital that is owner-withdrawable after borrower liabilities.
  6. Deploy and independently fund V10; never treat a D1 copy as migration.
  7. Keep the V9 indexer/read path available for legacy loan history and actions.
  8. Route new quotes/originations to V10 only after deployment verification and smoke tests.

Mainnet remains untouched unless separately and explicitly authorized.

6. Implementation workstreams ​

Contract ​

  • Add pending-owner storage, methods, getters, and events.
  • Remove the immediate transfer method from the V10 ABI.
  • Add checked pro-rata helper math using U128.
  • Update maturity finalization and borrower claim rules.
  • Preserve oracle-independent repayment, finalization, and claims.
  • Update pool/liability counters conservatively and atomically.

Deployment tooling ​

  • Add isolated V10 build, deploy, fund, smoke, and readiness scripts.
  • Validate owner, pending owner, manager, oracle, asset IDs, chain ID, and initial strategy state.
  • Create a V10 manifest and append-only deployment journal.
  • Require a fresh V10 contract ID; reject V9 IDs in V10 activation scripts.

Indexer and data ​

  • Deploy isolated V10 D1 and Worker configuration.
  • Decode ownership proposal/cancellation/acceptance and maturity-settlement events.
  • Store borrower claimable and vault-seized collateral separately.
  • Reconcile event projections against authoritative get_loan, pool_stats, and capital-accounting reads.
  • Keep V9 and V10 projections version-scoped; do not merge loan IDs without contract identity.

Frontend ​

  • Add V10 ABI and deployment configuration.
  • Disable V9 origination while preserving V9 position management.
  • Show, before borrowing, that partial pre-maturity repayment earns the same pro-rata collateral share at maturity.
  • For active loans, display repaid percentage and estimated collateral entitlement.
  • For finalized partial loans, display claimable collateral separately from vault-seized collateral.
  • Allow the borrower to claim their nonzero pro-rata share.
  • Replace immediate owner transfer controls with proposal, pending nominee, cancel, and nominee acceptance controls.

Reporting and documentation ​

  • Report defaulted USDC, borrower-claimable collateral, claimed collateral, and vault-seized collateral separately.
  • Update architecture, controls, risks, borrowing, interest, managed-vault, UX, deployments, and release documentation.
  • State clearly that V9 loans retain old terms and V10 loans use pro-rata settlement.

7. Test plan ​

Sway unit tests ​

Ownership:

  • initial owner and zero pending owner;
  • zero/current-owner proposal rejection;
  • unauthorized proposal/cancellation;
  • exact nominee acceptance;
  • unauthorized, stale, and superseded nominee rejection;
  • proposal replacement and cancellation;
  • pending state clears on acceptance;
  • former/new owner privilege boundaries;
  • owner/manager independence.

Pro-rata math:

  • zero repayment;
  • one base unit repaid;
  • exact 50% and 70%;
  • principal minus one base unit;
  • full repayment;
  • indivisible ratios and one-base-unit dust bound;
  • maximal safe u64 operands through U128 intermediates;
  • invalid repaid > principal, zero principal, overflow, and underflow;
  • conservation for every vector.

Fuel Core E2E tests ​

For both FUEL and stFUEL:

  • open → no repayment → maturity finalization → all collateral to vault;
  • open → 50% repayment → finalization → 50% borrower claim and 50% vault share;
  • open → 70% repayment → exact floor share and bounded dust;
  • open → principal minus one → near-full proportional claim;
  • open → full repayment → full maturity claim;
  • multiple partial repayments equal one aggregate repayment;
  • exact-maturity repayment/finalization boundary has no overlap or gap;
  • stale oracle does not block repayment, finalization, or claim;
  • attacker cannot repay for borrower under current borrower-only policy, claim, double-finalize, or double-claim;
  • owner/manager cannot withdraw or deploy borrower-claimable balances;
  • failed calls leave loan, pool, liability, balance, and strategy state unchanged;
  • aggregate accounting and events reconcile exactly across mixed loans.

Ownership E2E:

  • proposal does not grant nominee authority;
  • only nominee accepts;
  • former owner loses every owner-only method after acceptance;
  • new owner controls owner methods but not manager methods;
  • malicious proposal/acceptance/cancellation sequences cannot seize authority.

Application and service tests ​

  • ABI/config point only new originations to V10.
  • V9 legacy and V10 current positions render together with correct contract-scoped actions.
  • Claimable/vault shares use integer math identical to the contract.
  • Indexer replay is idempotent and reconciles after missed events.
  • CSV, statistics, telemetry, and reports contain no secret or identifying additions.
  • Browser QA covers desktop/mobile borrowing, partial repayment, maturity state, claim, and admin ownership handoff.

Testnet smoke and soak ​

  • Deploy isolated V10 and verify configuration by RPC.
  • Complete FUEL and stFUEL 0%, 50%, 70%, and 100% repayment lifecycles.
  • Complete owner A → B and B → A two-step transfers.
  • Re-run manager and strategy adversarial controls.
  • Run a mixed-term soak across 6/9/12-month loans with simulated local maturity first, then bounded live testnet smoke where practical.
  • Reconcile direct RPC, indexer, frontend, and reporting values.

8. Release gates ​

V10 may replace V9 for new testnet originations only after:

  • both policy decisions below are approved;
  • contract unit and E2E suites pass;
  • independent security review covers ownership and settlement math;
  • testnet lifecycle and accounting smoke passes for both collateral assets;
  • V9 legacy-loan handling is visible and operational;
  • V10 indexer reconciliation passes;
  • frontend/admin browser QA passes; and
  • deployment manifest, journal, ABI, docs, and production configuration agree.

Mainnet deployment, funding, governance assignment, and activation each remain separate approvals.

Approval requested ​

Please approve or revise these two decisions before implementation:

  1. Rounding: floor borrower collateral entitlement, assigning at most one base unit of remainder to the vault; or ceiling it in the borrower's favor.
  2. Maturity: keep repayment strictly before maturity and use pre-maturity repayments for the pro-rata split; or design a separate post-maturity grace/cure period.

After approval, implementation should proceed as isolated Credit V10, followed by complete testing and a new testnet deployment. No V9 contract will be altered.

Open-source infrastructure on Fuel.