Skip to main content
Issue tokenized corporate bonds on Ethereum where investors subscribe with stablecoins, receive ERC-20 bond tokens, collect periodic coupon payments, and redeem principal at maturity. All transactions signed through DFNS managed wallets.

Get the code

dfns/dfns-solutions: bond-issuance

Overview

The system models a bond issuance with two actors:
  • Issuer: deploys the bond contract, manages the lifecycle (close issuance, fund coupons, return principal)
  • Investor: subscribes with stablecoins, claims bond tokens, collects coupons, redeems at maturity
The bond lifecycle works as follows:
  1. The Issuer deploys a stablecoin (EURC) and the Bond contract
  2. Investors subscribe by depositing EURC into escrow
  3. The Issuer closes the issuance. The interest accrual clock starts
  4. Investors claim ERC-20 bond tokens proportional to their investment
  5. Each coupon period, the Issuer funds and Investors claim their pro-rata share
  6. At maturity, the Issuer deposits principal and Investors redeem bonds for EURC
The contract also includes default protection: if the Issuer fails to fund a coupon within a 5-day grace period, anyone can trigger a default flag that halts further operations.

Prerequisites

Project Structure

Configuration

1

Clone and install

2

Set up environment variables

Copy the example environment file and fill in your values:
.env
3

Compile contracts

4

Run tests

The test suite runs against a local Hardhat network (no DFNS credentials needed):
16 tests cover the full lifecycle: subscription, over/under-subscription, coupon claims, redemption, grace periods, default triggering, and interest math.

Deploy

Step 1: Deploy the stablecoin

The script prompts for a name and symbol (defaults to “Euro Coin” / “EURC”) and deploys from the Issuer wallet. Save the contract address.

Step 2: Mint stablecoin to the investor

Enter the stablecoin address, the investor’s wallet address, and the amount to mint.

Step 3: Deploy the bond

The script prompts for bond parameters: Save the bond contract address.

End-to-End Bond Lifecycle

Step 1: Investor subscribes

This approves the Bond contract to spend the investor’s EURC, then calls subscribe(). The stablecoin is held in escrow.

Step 2: Issuer closes issuance

This locks the subscription total, starts the interest accrual clock, and calculates the coupon amount per period.

Step 3: Issuer withdraws proceeds

The issuer receives the raised stablecoin.

Step 4: Investor claims bond tokens

The investor receives ERC-20 bond tokens. The number of tokens is calculated as:
Where decimals is 6 (matching the stablecoin).

Step 5: Coupon payments (each period)

Issuer deposits the coupon:
The required amount is calculated automatically: (totalPrincipal * APR * frequency) / (365 days * 10000). Investor claims:
The CLI auto-detects all due, funded, unclaimed coupons and claims them in sequence. Each investor’s share is proportional to their bond holdings:

Step 6: Redemption at maturity

Issuer returns principal:
Investor redeems:
Bond tokens are burned and the original investment amount is returned in EURC.

Web UI

The browser UI covers the full bond lifecycle. It shows two dashboards side by side, Issuer (blue) and Investor (green), with numbered steps to follow in order.
Open http://localhost:3000. The UI calls a lightweight Express server that signs and broadcasts transactions via the DFNS API. Bond status auto-refreshes every 5 seconds. Each step in the UI maps to a contract function call:
  1. Deploy StableCoin: deploy the EURC contract
  2. Mint EURC: fund both wallets
  3. Deploy Bond: configure face value, APR, coupon frequency, and duration
  4. Subscribe: investor deposits EURC into escrow
  5. Close Issuance: lock subscriptions, start interest clock
  6. Withdraw Proceeds: issuer collects raised EURC
  7. Claim Bond Tokens: investor mints ERC-20 bond tokens
  8. Deposit Coupon: issuer funds the next coupon period
  9. Claim Coupon: investor collects pro-rata interest (auto-detects coupon index)
  10. Return Principal: issuer deposits EURC for redemption
  11. Redeem: investor burns bonds, gets principal back

End-to-End Script

Run the full lifecycle non-interactively:
This deploys both contracts, mints stablecoins, subscribes, closes issuance, claims bonds, deposits and claims a coupon, all in a single run. Useful for verifying the setup end to end.

Smart Contract Reference

Bond.sol

An ERC-20 token representing a corporate bond with full lifecycle management: Bond lifecycle: OpenIssuance ClosedCouponsMaturity / Redemption Default path: Coupon DueGrace Period (5 days)Default

BondMath.sol

Library for interest calculations:
APR is in basis points (400 = 4%). The contract treats a year as exactly 365 days.

StableCoin.sol

ERC-20 stablecoin used as the settlement currency:

How DFNS Is Used

All on-chain transactions are signed and broadcast through the DFNS API. No private keys are stored locally. The scripts use viem to encode deployment data and function calldata, then broadcast via DFNS. A viem PublicClient reads on-chain state (balances, bond status, coupon dates) without requiring signing.

Adapting for Production

Different networks: Replace the RPC URL in .env with one for your target network (Ethereum mainnet, Polygon, Arbitrum). Update the chain import in scripts/dfns.ts. Real stablecoins: Replace the demo StableCoin contract with USDC or EURC addresses. The Bond contract accepts any ERC-20 with 6 decimals as the settlement currency. Multiple investors. The system supports any number of investors. Each uses a separate DFNS wallet. Add more wallet IDs to .env or build a backend that maps users to DFNS wallets (see the accept cryptocurrencies blueprint for this pattern). Secondary trading: Bond tokens are standard ERC-20 and can be traded on any DEX. For institutional use, consider an RFQ model (UniswapX or CowSwap) where professional market makers provide quotes based on yield-to-maturity. Approval policies: DFNS policies can enforce approval quorums or velocity limits on sensitive operations (closing issuance, large coupon deposits). This adds governance without changing the smart contracts.
Last modified on July 7, 2026