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:
- replace immediate ownership transfer with a two-step proposal and acceptance flow; and
- 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 repaid | Borrower collateral entitlement | Vault 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:
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
- The current owner calls
propose_ownership(new_owner). - The contract validates that the nominee is nonzero and differs from the current owner.
- The nominee is stored as
pending_owner; authority does not change. - Only that exact pending address may call
accept_ownership(). - Acceptance updates
owner, clearspending_owner, and immediately removes every owner privilege from the former owner. - 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
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:
borrower_claimable = floor(original_collateral × repaid_principal ÷ original_principal)
vault_seized = original_collateral - borrower_claimable
remaining_default = original_principal - repaid_principalAll multiplication uses U128; conversion to u64 occurs only after bounded division.
Required invariants:
0 <= repaid_principal <= original_principal
0 <= borrower_claimable <= original_collateral
borrower_claimable + vault_seized == original_collateral
repaid_principal + remaining_default == original_principalRounding 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:
- validate active status and the maturity boundary;
- calculate remaining USDC default and both collateral portions;
- record the loan as terminal/delinquent;
- record only
vault_seizedascollateral_defaulted_to_vault; - remove only
vault_seizedfrom borrower-locked collateral accounting; - add
vault_seizedto vault/defaulted collateral accounting; and - leave
borrower_claimablelocked 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_vaultat/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:
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:
borrower_collateral_owed
= active collateral
+ fully repaid but unclaimed collateral
+ finalized partial-loan borrower entitlements not yet claimedAt 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:
original collateral
= borrower claimed
+ borrower still owed
+ vault defaultedStrategy 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
- Inventory every V9 loan, pool balance, borrower liability, strategy exposure, realized yield/loss, owner, manager, and oracle.
- Stop new V9 originations in the frontend before activating V10.
- Settle or maintain monitoring for every existing V9 loan under V9 rules.
- Return/write down and reconcile V9 strategy exposure as authorized.
- Withdraw only V9 capital that is owner-withdrawable after borrower liabilities.
- Deploy and independently fund V10; never treat a D1 copy as migration.
- Keep the V9 indexer/read path available for legacy loan history and actions.
- 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
u64operands throughU128intermediates; - 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:
- Rounding: floor borrower collateral entitlement, assigning at most one base unit of remainder to the vault; or ceiling it in the borrower's favor.
- 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.