Skip to main content

Architecture

This section explains how the protocol works under the hood: the components, the tokens that flow between them, and the lifecycle of a mortgage from creation to resolution.

Protocol Overview

Buttonwood V1 is a decentralized convertible credit protocol for tokenized equities. It enables collateralized lending with a unique conversion mechanism that aligns incentives between borrowers and lenders.

The protocol is chain-agnostic and deploys to any EVM chain carrying supported collateral and a price feed. Support for Robinhood Chain and its tokenized equities is forthcoming.

Core Concept

Traditional DeFi lending forces borrowers to choose: either hold an appreciating asset or access liquidity. Buttonwood eliminates this trade-off with convertible credit — mortgages that can automatically convert if the collateral appreciates, letting borrowers capture upside while guaranteeing lender returns.

Three User Flows

1. Buy Now Pay Later (BNPL)

Users purchase equity tokens with a stablecoin down payment and finance the remainder through origination pools. A Mortgage NFT is minted representing the position, with the purchased equity tokens locked as collateral.

2. Coin Compounding

Users deposit equity tokens they already hold to borrow more on credit (~2x leverage). The position is automatically enrolled in the Conversion Queue, so if the equity appreciates the debt is forgiven in exchange for a portion of the collateral.

3. Lending

Lenders deposit stablecoins into pools that fund borrower mortgages. They earn yield through Consol tokens and can participate via direct pool deposits, automated rollover vaults, or fulfillment vaults.

Architecture Diagram

┌─────────────┐     ┌──────────┐     ┌──────────────────┐
│ Borrower │────►│ Router │────►│ Origination Pools│
│ (BNPL / │ │ │ │ (Lender Capital)│
│ Compound) │ └────┬─────┘ └────────┬─────────┘
└─────────────┘ │ │
▼ ▼
┌─────────────┐ ┌────────────────┐
│ LoanManager │ │ Consol Token │
│ (Mortgage │ │ (Yield-bearing │
│ NFTs) │ │ rebasing) │
└──────┬──────┘ └────────┬────────┘
│ │
▼ ▼
┌─────────────┐ ┌────────────────┐
│ SubConsol │ │ USDX │
│ (Escrow) │ │ (Multi-token │
│ │ │ stablecoin) │
└──────┬──────┘ └────────────────┘


┌──────────────┐
│ Conversion │
│ Queue │
└──────────────┘

Price Oracles

The protocol uses Pyth Network pull-oracles for:

  • Collateral pricingPythPriceOracle reads real-time collateral/USD prices, validates freshness (max 60 seconds old) and confidence thresholds
  • Interest ratesPythInterestRateOracle reads 3-year and 5-year US Treasury rates, multiplies by 2, and adds 100 bps. An additional 100 bps is added for mortgages without a payment plan. Reverts if the price age exceeds 60 seconds or confidence exceeds 100 bps. A StaticInterestRateOracle serves as a fallback.

Order Fulfillment

When a borrower submits a BNPL or Compounding order:

  1. Borrower calls generalManager.requestMortgageCreation(creationRequest) (via the Router)
  2. A Mortgage NFT is minted with the requested MortgageId
  3. A PurchaseOrder is enqueued in the OrderPool with the collateral amount and purchase price
  4. An authorized fulfiller monitors the OrderPool and calls orderPool.processOrders(indices, hintPrevIds)
  5. For each order, the fulfiller swaps collateral for the USDX purchase amount
  6. The OriginationPool flash-deploys USDX and receives Consol as repayment (via IOriginationPoolDeployCallback)
  7. Collateral is deposited into SubConsol, and the mortgage is created in LoanManager
  8. If a ConversionQueue was specified, the mortgage is automatically enqueued

BNPL specifics: The borrower provides USDX for half the collateral purchase; the other half is borrowed from the OriginationPool. Pool fees are added on top.

Compounding specifics: The borrower provides half the collateral directly (not USDX). The other half is purchased with USDX borrowed from the OriginationPool. Pool fees are factored into the borrowed amount.

Orders have a 5-minute expiration window. Expired orders are deleted and NFTs burned, freeing the MortgageId for reuse. The fulfiller collects a gas fee for each processed order.

Key Design Decisions

  • Simple interest — Loans use simple (not compound) interest: totalDebt = principal * (1 + APR * years)
  • Fixed 36-period terms — All mortgages have a maximum of 36 monthly periods (30 days each)
  • Multi-stablecoin support — Users can pay in USDT0 or USDC; the Router auto-wraps to USDX
  • NFT-based positions — Each mortgage is an ERC-721 token, making positions transferable
  • Rebasing yield — Consol is a rebasing ERC20 that automatically accrues yield for lenders
  • Non-upgradeable core — OriginationPool, LoanManager, and token contracts are immutable to minimize smart contract risk. Only GeneralManager and OriginationPoolScheduler are UUPS-upgradeable.
  • Permissionless queue processing — Anyone can call processWithdrawalRequests() on the queues and collect gas fees as incentive
  • Flash-deploy origination — OriginationPools flash-lend USDX and receive Consol repayment in a single transaction via callbacks

Token System

Buttonwood's protocol uses several interconnected tokens, each serving a specific role in the lending and borrowing lifecycle.

Equity Tokens (Collateral)

Collateral is a tokenized equity — an on-chain token tracking shares in a listed company. Buttonwood extends convertible credit only against equity tokens whose underlying company exceeds $1 trillion of off-chain market capitalization. When a mortgage is created, the equity token is purchased (BNPL) or deposited (Compounding) and locked in the SubConsol escrow contract.

  • Used as collateral for all mortgage positions
  • Priced via the deployment's oracle price feed
  • Locked in SubConsol until the mortgage is redeemed, converted, or foreclosed

Which equity tokens are accepted is configured per deployment and governed on-chain — the protocol itself is asset-agnostic and enforces no fixed list.

USDX (Protocol Stablecoin)

USDX is the protocol's internal unit of account — a multi-token vault that wraps multiple USD stablecoins into a single fungible token.

Supported Underlying Tokens

The accepted stablecoins are configured per deployment and depend on what circulates on the host chain. They have included:

TokenDescription
USDCCircle's USD Coin
USDT0Omnichain USDT

How It Works

USDX extends the MultiTokenVault contract. Users deposit any supported stablecoin and receive USDX at a 1:1 ratio. The Router handles wrapping/unwrapping automatically so users can interact with the protocol using whichever stablecoin they prefer.

Key properties:

  • 1:1 backing by underlying stablecoins
  • Wrap and unwrap at any time
  • All protocol-internal accounting is denominated in USDX

Consol (Yield Token)

Consol is a rebasing ERC20 token that represents lender yield. It extends MultiTokenVault and RebasingERC20.

How Yield Accrues

Consol is backed by:

  1. USDX deposited by lenders and earned from borrower payments
  2. Forfeited assets from foreclosed positions (via ForfeitedAssetsPool)

As the backing pool grows from borrower interest payments and forfeited assets, the rebasing mechanism automatically increases each holder's balance proportionally. Lenders earn yield simply by holding Consol tokens.

Earning Consol

Lenders earn Consol through:

  • Origination Pool deposits — stablecoins are converted to Consol upon deposit
  • Rollover Vault staking — the vault accumulates Consol from rolled-over pool positions
  • Fulfillment Vault staking — earns Consol from order fulfillment fees

SubConsol (Escrow)

SubConsol is the escrow contract that holds collateral for active mortgages. It is not a token users interact with directly — it's an internal protocol component.

Responsibilities

  • Holds locked equity-token collateral for each Mortgage NFT
  • Releases collateral upon redemption (full payoff) or conversion
  • Transfers collateral to the ForfeitedAssetsPool upon foreclosure
  • Tracks per-mortgage collateral balances

Token Flow Diagram

User deposits stablecoin


┌──────────────┐
│ Supported │── wrap ──► USDX ──── mint ────► Consol
│ stablecoins │ │ │
└──────────────┘ │ │
▼ ▼
Borrower debt Lender yield
denominated (rebasing)
in USDX


Equity tokens purchased
on the chain's venue


Locked in SubConsol (escrow)

Share Tokens

In addition to the core tokens, the protocol issues share tokens for vault participation:

TokenVaultWhat it represents
Pool TokensOrigination PoolShare of a specific lending pool epoch
RLVRollover VaultShare of the automated rollover strategy
FLVFulfillment VaultShare of the order fulfillment liquidity

These are standard ERC20 tokens that can be transferred. Redeeming them burns the share tokens and returns the proportional underlying assets.

Mortgage Lifecycle

Every borrowing position in Buttonwood is represented by a Mortgage NFT (ERC-721). This document describes the full lifecycle of a mortgage from creation to resolution.

1. Creation

BNPL Path

  1. User submits a purchase order with a stablecoin down payment
  2. The Router wraps stablecoins to USDX and submits the order to the MortgageQueue
  3. A fulfillment service purchases the equity token on the chain's trading venue
  4. On-chain settlement mints the Mortgage NFT via LoanManager
  5. Purchased equity tokens are locked in SubConsol

Compounding Path

  1. User deposits equity tokens and requests more on credit
  2. The protocol executes a flash-loan-equivalent: deposit is used as down payment, borrowed amount finances more equity tokens
  3. All equity tokens (deposit + borrowed) are locked in SubConsol
  4. Position is automatically enrolled in the ConversionQueue

Order Fulfillment Window

  • Orders are queued on-chain with a 5-minute expiration
  • Fulfillment takes approximately 60 seconds
  • If not filled before expiration, all funds are refunded
  • Users cannot cancel during the fill window

2. Active Period

Once created, the mortgage enters its active period:

  • Term: Up to 36 monthly periods (30 days each)
  • Interest: Simple interest — totalDebt = principal * (1 + APR * years)
  • Payment schedule: Monthly payments of totalDebt / 36 in USDX (if payment plan is enabled)

Making Payments

Payments are processed through the LoanManager:

  1. User pays in any supported stablecoin via the Router
  2. Router wraps to USDX and forwards the payment
  3. LoanManager records the payment against the mortgage
  4. Payment flows to lenders through the Consol system

Late Payments

  • Grace period: 3 days after the due date
  • Penalty: A percentage of the monthly payment amount accrues as a penalty
  • Penalty payment: Must be paid in addition to the regular monthly payment

3. Resolution

A mortgage can resolve in one of three ways:

Redemption (Full Payoff)

All payments made ──► Mortgage marked "Redeemable"


User calls redeem()


SubConsol releases collateral
Mortgage NFT burned
User receives collateral
  1. All 36 monthly payments are completed (or bullet payment at maturity)
  2. Mortgage status changes to Redeemable
  3. User calls redeem() on the /manage page
  4. SubConsol releases all locked equity tokens back to the user
  5. The Mortgage NFT is burned

Conversion (Auto-conversion)

Token price hits trigger ─► ConversionQueue processes position


Debt portion of collateral
sent to lenders/protocol


Remaining collateral
returned to borrower


Mortgage resolved
  1. The equity token's price reaches the Conversion Trigger Price
  2. The ConversionQueue automatically processes the position
  3. A portion of collateral sufficient to cover remaining debt is taken
  4. The remaining collateral is returned to the borrower
  5. Any outstanding payment obligations are adjusted

Foreclosure (Default)

Missed 2+ payments ──► Position eligible for foreclosure


Keeper/protocol calls foreclose()


All collateral seized
Sent to ForfeitedAssetsPool
Mortgage NFT marked "Foreclosed"
  1. Borrower misses more than 2 payments
  2. Position becomes eligible for foreclosure
  3. A keeper or the protocol calls the foreclosure function
  4. All locked equity tokens are seized from SubConsol
  5. Collateral is sent to the ForfeitedAssetsPool
  6. The Mortgage NFT is marked as foreclosed (not burned — it remains as a record)

Mortgage States

StateDescription
PendingOrder submitted, awaiting fulfillment
ActiveMortgage is live, payments being made
At RiskPayments missed, approaching foreclosure threshold
RedeemableFully paid off, ready for collateral redemption
RedeemedCollateral returned, NFT burned
ForeclosedCollateral seized due to payment default

Conversion Mechanism

The conversion mechanism is the core innovation of Buttonwood's convertible credit system. It allows mortgages to automatically resolve when collateral appreciates — borrowers capture upside while lenders receive guaranteed returns.

How Conversion Works

Trigger Price Calculation

Each convertible mortgage has a Conversion Trigger Price — the collateral price at which auto-conversion activates:

triggerPrice = (1 + conversionPremium%) * amountBorrowed * 2 / collateralAmount

The conversion premium is a protocol-configured percentage that ensures lenders receive a return above the principal.

Example

ParameterValue
Equity tokens deposited100 tokens
Token price at deposit$25
Amount borrowed$1,250 (50 tokens equivalent)
Total collateral locked~200 tokens
Conversion premium50%
Trigger price$37.50

If the equity token reaches $37.50:

  • The debt portion of collateral (valued at the remaining debt) is transferred to the protocol/lenders
  • The borrower keeps the remaining collateral (~64 tokens after accounting for interest)
  • At $37.50 per token, the borrower's ~64 tokens are worth ~$2,400 — nearly the same as their original $2,500 but with zero remaining debt

ConversionQueue Contract

The ConversionQueue is a double-queue — it inherits from both LenderQueue (FIFO withdrawal queue) and MortgageQueue (price-sorted linked list). It manages two sides:

  1. Lender side: Lenders deposit Consol and wait to receive collateral with a premium
  2. Borrower side: Borrowers submit mortgage positions and wait to be converted when prices trigger

Enrollment

  • Coin Compounding positions are automatically enrolled — a conversionQueue address is required when requesting a compounding mortgage
  • BNPL positions can optionally enable conversion via the UI toggle, or the borrower can later call generalManager.enqueueMortgage(tokenId, conversionQueue, hintPrevId)
  • The borrower must be the owner of the mortgage
  • A valid hintPrevId must be provided to reduce gas costs (the hint should be as close as possible to the proper sorted index)
  • Both GeneralManager and ConversionQueue must not be paused

Processing

When the oracle reports a collateral price at or above a position's trigger price:

  1. A permissionless actor calls conversionQueue.processWithdrawalRequests(numberOfRequests)
  2. The ConversionQueue matches lender withdrawal requests (FIFO) against eligible mortgage positions
  3. For each matched conversion:
    • Portions of qualified mortgages are liquidated at market prices
    • Lump-sum interest payments are rewarded to the withdrawing lenders
    • SubConsol burns collateral tokens and releases underlying collateral
    • Remaining collateral is returned to the borrower
    • LoanManager updates the mortgage status via the Conversion Role
  4. The processor collects gas fees for each processed request

Queue Ordering

The borrower side uses a sorted linked-list (via MortgageQueue) maintaining positions ordered by trigger price, lowest to highest. When the collateral reaches a certain price, all positions with trigger prices at or below that level are eligible for conversion. The processor works through them sequentially, matching against the FIFO lender queue.

Conversion Premium

The conversion premium is a key parameter that balances borrower and lender incentives:

  • Higher premium = higher trigger price = less likely to convert, but more profit for lenders if it does
  • Lower premium = lower trigger price = more likely to convert, but smaller lender premium

The premium is set at the protocol level and applies to all new mortgages.

Collateral After Conversion

The amount of collateral a borrower keeps after conversion depends on:

  1. Total collateral locked (deposit + borrowed amount)
  2. Interest accrued over the loan term
  3. Remaining debt at the time of conversion
collateralKept = totalCollateral - (remainingDebt / triggerPrice)

Since conversion can happen at any point during the loan term, earlier conversions (before much interest accrues) result in more collateral returned to the borrower.

Integration with Other Components

PythPriceOracle

│ price update

QueueProcessor (off-chain keeper)

│ identifies eligible positions

ConversionQueue

├──► SubConsol ──► release collateral

├──► UsdxQueue ──► lender payments

└──► LoanManager ──► update mortgage status

The conversion mechanism relies on:

  • PythPriceOracle for accurate, low-latency price feeds
  • QueueProcessor (off-chain keeper) for monitoring and triggering conversions
  • SubConsol for collateral custody and release
  • LoanManager for mortgage state management
  • UsdxQueue for routing converted collateral to lenders