Create an asset-backed financing market

This document maps the complete lifecycle of the collateralized asset-backed financing form the fraction protocol, to the available backend APIs and api-client methods.

  1. First, deploy the asset-backed financing market as an admin
  2. Then the admin can grant the issuer role to create a campaign
  3. Issuers create campaigns that collateralize and fractionalize a pre-deployed asset
  4. Admins validate the sale by changing their state and the investment occurs
  5. The financing is then monitored off-chain to ensure the collateral value does not drop below the financed value
  6. The campaign may enter resolution states, such as a margin call or default
  7. Finally, investors exit their position when the issuer purchases the fraction

Sale states within an asset-backed financing flow


Phase 1: Market Deployment

Before any campaigns can be created, the asset-backed financing market itself must be deployed. This is a one-time setup action per market.

API Client Call:

await apiClient.lending.deploy({
  // Request body containing all market parameters
  chainId: 1,
  adminAddress: "0x...", // Address of the market admin
  lending: {
    minInterest: 0, // Minimum interest rate in basis points (0%)
    maxInterest: 10000, // Maximum interest rate in basis points (100%)
    minDuration: "2592000", // Minimum duration in seconds (30 days)
    maxDuration: "31536000", // Maximum duration in seconds (365 days)
    minimumProportionOverObligation: "1200000000000000000", // 120% (1.2 in 18 decimals)
  },
  discount: {
    burnForDiscount: {
      burnableTokenAddress: "0x...", // Address of the reputation token for discounts
    },
  },
});

API Endpoint: POST /v0/buyback/deploy

After the transaction is mined, you can get the marketAddress by parsing the MarketDeployed event from the transaction receipt.

API Client Call:

const { marketAddress } = await apiClient.fractions.market.getMarketDeployedEvent({
  chainId: 1,
  hash: "0x...", // Transaction hash from deploy
});

API Endpoint: GET /v0/fractions/markets/deployEvent


Phase 2: Grant roles

After the market is deployed, roles must be granted to key participants.

Grant Issuer Role

The issuer needs the FRACTIONS_ISSUER_ROLE to create campaigns.

API Client Call:

await apiClient.fractions.roles.grantRole({
  chainId: "11155111", // supported chain id string from schema
  marketAddress: marketAddress,
  users: ["0x..."], // Issuer/borrower address(es)
  role: "ISSUER",
});

API Endpoint: POST /v0/fractions/roles/grant

Grant Liquidator Role

The liquidator needs appropriate permissions to execute liquidations.

API Client Call:

await apiClient.fractions.roles.grantRole({
  chainId: "11155111",
  marketAddress: marketAddress,
  users: ["0x..."], // Liquidator address(es)
  role: "LIQUIDATOR",
});

API Endpoint: POST /v0/fractions/roles/grant

Grant Investor Role

Investor don't need a role to purchase a fraction in this template. Please reach out if you need an explicit investor role in addition to the compliance rules.


Phase 3: Campaign Initialization

1. Asset Preparation

The issuer (borrower) must approve the platform's wrapper contract to transfer the RWA NFT (or other collateral).

API Client Call:

// For ERC-721 NFTs
await apiClient.fractions.approvals.approveWrapperToSpendErc721({
  wrapperAddress: "0x...", // Address of the wrapper contract
  erc721Address: "0x...", // Address of the NFT contract
});

API Endpoint: POST /v0/fractions/fractions/approveWrapperAsErc721Spender

2. Campaign Creation

The borrower creates the lending campaign, defining all its parameters.

API Client Call:

await apiClient.lending.createSale({
  chainId: 1,
  market: "0x...", // Lending market address from Phase 1 deployment

  // Collateral assets to be wrapped and locked
  wrapped: [
    {
      type: "ERC721",
      address: "0x1234567890abcdef1234567890abcdef12345678", // RWA NFT contract
      tokenIds: ["42"], // Specific NFT token ID(s) used as collateral
    },
  ],

  // Funding token configuration (what investors pay to fund the loan)
  funding: [
    {
      token: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC contract address
      amountPerPacket: "1000000", // 1 USDC (6 decimals) per funding packet
    },
    // Multiple funding tokens can be supported:
    // {
    //   token: "0x6B175474E89094C44Da98b954EedeAC495271d0F", // DAI contract
    //   amountPerPacket: "1000000000000000000", // 1 DAI (18 decimals) per packet
    // },
  ],

  // Fraction token configuration (ERC1155 tokens representing loan positions)
  fractions: {
    name: "RWA Backed Loan Fractions",
    symbol: "RWALOAN",
    amount: "100000", // 100,000 fractions = $100k max loan at $1 per fraction
  },

  // Campaign time boundaries
  timeBoundary: {
    start: "2025-11-01T00:00:00Z", // Purchase window opens
    end: "2025-12-01T00:00:00Z", // Purchase window closes (1 month)
  },

  // Capitalization limits
  cap: {
    soft: "50000", // Soft cap: 50,000 packets ($50k minimum to proceed)
    hard: "100000", // Hard cap: 100,000 packets ($100k maximum)
    softPerAccount: "100", // Min $100 per investor (optional)
    hardPerAccount: "10000", // Max $10k per investor (optional)
  },

  // Buyback (loan repayment) configuration
  buyback: {
    durationSeconds: 15780000, // 6 months (182.5 days) for loan repayment
    interestPercentage: 1000, // 10% annual interest (10% = 1000 basis points)
    liquidationLimitPercentage: 12000, // 120% - liquidation triggers at this ratio
    marginCallLimitPercentage: 14000, // 140% - margin call triggers at this ratio
  },

  // Refund address if campaign fails to reach soft cap
  refundAddress: "0x...", // Address to receive collateral back if not funded

  // Packets per fraction ratio (typically 1:1)
  amountOfPacketsPerFraction: "1", // 1 funding packet = 1 fraction

  // Optional: Discount configuration for burning reputation tokens
  discounts: {
    burnForDiscount: {
      burnableToken: "0x...", // Reputation token address
      burnAmounts: ["100000000000000000", "1000000000000000000"], // 0.1 and 1.0 tokens
      discountPercentages: [5000, 10000], // 50% and 100% fee discounts
    },
  },
});

API Endpoint: POST /v0/buyback/createSale

After the transaction is mined, you can get the campaignId by parsing the FractionsCreated event from the transaction receipt.

API Client Call:

const { campaignId } = await apiClient.fractions.sales.getFractionsCreatedEvent({
  chainId: 1,
  hash: "0x...", // Transaction hash from createSale
});

API Endpoint: GET /v0/fractions/sales/getFractionsCreatedEvent

Phase 4: State Transitions, Validation and Investment

State 1: FRACTIONS_CREATEDAPPROVED_FOR_FUNDING

1. Oracle Price Validation

The platform sets the initial collateral price.

API Client Call:

await apiClient.lending.setCollateralPrice({
  market: "0x...",
  campaignId: "1",
  collateralPriceInFundingPackets: "200000000000", // $200k worth in funding packets
});

API Endpoint: POST /v0/buyback/setCollateralPrice

2. Approve Campaign for Funding

The platform admin approves the campaign, moving it to the funding stage.

API Client Call:

await apiClient.fractions.sales.approveSale({
  marketAddress: "0x...",
  campaignId: "1",
});

API Endpoint: POST /v0/fractions/sales/approve

State 2: APPROVED_FOR_FUNDINGFUNDED

1. Investment Phase

Investors purchase fractions, effectively funding the loan.

API Client Call (for each investor):

await apiClient.lending.purchase({
  chainId: 1,
  market: "0x...",
  campaignId: "1",
  amountToBuy: "5000", // Investor wants to fund $5k worth of fractions
});

API Endpoint: POST /v0/buyback/purchase

2. Complete Funding

After the purchase window ends, an automatic transition (or an admin action) moves the campaign to the FUNDED state.

API Client Call:

await apiClient.fractions.sales.completeSale({
  marketAddress: "0x...",
  campaignId: "1",
});

API Endpoint: POST /v0/fractions/sales/complete

State 3: FUNDEDSTARTED

The borrower receives the loan funds. This is handled by the ReceiveSkeletonFacet.receiveFunds function in the smart contract, which is not directly exposed via an API endpoint in the current implementation. This is typically an automatic step or triggered by the borrower directly on-chain.



Phase 5: Loan Monitoring & Risk Management

This phase is handled by off-chain services that monitor collateral prices via oracles and trigger alerts. There are no direct API calls for this continuous process, but the setCollateralPrice endpoint can be used to update prices.

Phase 6: Loan Resolution Scenarios

Scenario A: Normal Borrower Buyback

The borrower repays the loan plus interest.

API Client Call:

await apiClient.lending.buyback({
  chainId: 1,
  market: "0x...",
  campaignId: "1",
  buybackPacketsAmount: "110000", // Total obligation in packets (principal + interest)
});

API Endpoint: POST /v0/buyback/buyback

Scenario B: Liquidator Intervention

A liquidator can also call the buyback endpoint if the loan is in a liquidatable state. The call is identical to the borrower's buyback.

Phase 7: Investor Exit & Fee Structure

Investors claim their principal and interest after a successful buyback.

API Client Call:

await apiClient.fractions.sales.receiveFundsAfterNonFunded({
  market: "0x...",
  campaignId: "1",
  amountOfFractions: "5000", // Number of fractions the investor owns
  isDiscounted: true, // or false, depending on reputation token usage
  upperGenesisId: "...", // if isDiscounted is true
});

API Endpoint: POST /v0/fractions/sales/receiveFundsAfterNonFunded