# thBonds Implementation

Tharwa Bonds solve a fundamental problem in DeFi: how to offer **predictable, fixed yields** without relying on token emissions or unsustainable farming mechanics. This page explains how our bond system works, from the economic model to the technical implementation.

## **What Problem Do Tharwa Bonds Solve?**

Traditional DeFi yield comes from:

* **Liquidity mining**: Unsustainable token emissions
* **Lending protocols**: Variable rates that can crash during stress
* **Yield farming**: Complex strategies with smart contract risks

**Tharwa Bonds offer something different**: Fixed yields backed by real-world asset performance, structured like traditional bonds but with DeFi composability.

## **The Bond Model Explained**

{% tabs %}
{% tab title="Traditional Bond" %}
**How Traditional Bonds Work:**

* Buy bond for $950
* Receive $1000 at maturity
* $50 profit = yield

**Problems for DeFi:**

* No composability
* No secondary markets
* Complex legal structures
  {% endtab %}

{% tab title="Tharwa Bonds" %}
**How Tharwa Bonds Work:**

* Buy bond for 0.96 thUSD
* Receive 1.00 thUSD at maturity
* 0.04 thUSD profit = yield

**DeFi Advantages:**

* ERC-1155 NFTs (tradeable)
* On-chain metadata
* Instant settlement
* Composable with other protocols
  {% endtab %}
  {% endtabs %}

## **Contract Overview**

| Property     | Value                                                                                                              |
| ------------ | ------------------------------------------------------------------------------------------------------------------ |
| **Contract** | `TharwaBondVaultV1.sol`                                                                                            |
| **Standard** | ERC-1155 with financial metadata                                                                                   |
| **Address**  | `0xAc02FF90bC709A134cD4Ad0b50BaB8be9e0f504e` (Mainnet)                                                             |
| **Audit**    | [PrismSec Report](https://github.com/tharwa-finance/contracts-v0/blob/main/audits/prismsec_tharwa_bonds_audit.pdf) |
| **Security** | 0 Critical, 0 High findings                                                                                        |

***

## **How Tharwa Bonds Work: Technical Architecture**

### **The Token ID System: Why It's Brilliant**

Tharwa Bonds use a unique approach to NFT IDs that makes them both **predictable** and **composable**:

{% hint style="success" %}
**Key Insight**: Each bond's NFT ID equals its maturity timestamp truncated to UTC midnight

**Example**: A 90-day bond purchased on January 1st, 2025 would have token ID `1712102400` (April 1st, 2025 at 00:00:00 UTC)
{% endhint %}

**Why This Matters:**

1. **Predictable IDs**: Anyone can calculate a bond's ID without querying the contract
2. **No Collisions**: Same maturity date = same token ID = fungible bonds
3. **Easy Integration**: External protocols can work with bonds without complex lookups
4. **Metadata Efficiency**: Token ID contains the maturity information

### **Bond Configuration System**

Instead of hardcoding bond parameters, Tharwa uses a flexible configuration system:

```solidity
enum BondDuration {
    NinetyDays,      // 0: 90-day bonds
    OneEightyDays,   // 1: 180-day bonds  
    ThreeSixtyDays   // 2: 360-day bonds
}

struct BondConfig {
    uint256 price;           // Discounted purchase price (e.g., 0.96e18 = 96 cents)
    uint256 cap;             // Maximum total issuance (prevents over-issuance)
    uint256 issued;          // Current amount issued (tracks against cap)
    bool paused;             // Emergency pause for individual bond types
    string uri;              // Metadata URI for NFT marketplaces
}
```

**Real-World Example:**

{% tabs %}
{% tab title="90-Day Bond Config" %}

```solidity
bondConfigs[BondDuration.NinetyDays] = BondConfig({
    price: 0.96e18,        // Buy for 96 cents
    cap: 1_000_000e18,     // Max 1M thUSD issuance
    issued: 0,             // Nothing issued yet
    paused: false,         // Active
    uri: "metadata/90day"  // NFT metadata
});
```

**What this means:**

* Users pay 0.96 thUSD to buy a bond
* They receive 1.00 thUSD at maturity (90 days later)
* Maximum 1M thUSD worth of these bonds can be issued
* 4.17% return over 90 days ≈ 3.94% APY
  {% endtab %}

{% tab title="360-Day Bond Config" %}

```solidity
bondConfigs[BondDuration.ThreeSixtyDays] = BondConfig({
    price: 0.88e18,        // Buy for 88 cents
    cap: 4_000_000e18,     // Max 4M thUSD issuance
    issued: 0,             // Nothing issued yet
    paused: false,         // Active
    uri: "metadata/360day" // NFT metadata
});
```

**What this means:**

* Users pay 0.88 thUSD to buy a bond
* They receive 1.00 thUSD at maturity (360 days later)
* Maximum 4M thUSD worth of these bonds can be issued
* 13.64% return over 360 days ≈ 8.00% APY
  {% endtab %}
  {% endtabs %}

### **User Bond Tracking**

For each bond purchase, the contract stores essential information:

```solidity
struct UserBond {
    uint256 principal;       // How much thUSD the user originally paid
    uint256 maturityAmount;  // How much thUSD they'll receive at maturity
    uint256 purchaseTime;    // When they bought it (for penalty calculations)
}

// Mapping: user address => token ID => bond details
mapping(address => mapping(uint256 => UserBond)) public userBonds;
```

**Why We Track This:**

* **`principal`**: Needed for early exit penalty calculations
* **`maturityAmount`**: The guaranteed payout (always 1:1 with face value)
* **`purchaseTime`**: Determines how much penalty decays over time

**Example User Bond:**

```solidity
userBonds[0x123...][1712102400] = UserBond({
    principal: 960e18,      // Paid 960 thUSD
    maturityAmount: 1000e18, // Will receive 1000 thUSD
    purchaseTime: 1704067200 // Bought on January 1st, 2025
});
```

### **Token ID Calculation: The Technical Deep Dive**

The token ID system is one of Tharwa Bonds' most innovative features. Let's break down exactly how it works and why it's designed this way:

#### **The Algorithm**

```solidity
function _calculateTokenId(BondDuration duration) internal view returns (uint256) {
    uint256 durationSeconds;
    
    if (duration == BondDuration.NinetyDays) {
        durationSeconds = 90 days;
    } else if (duration == BondDuration.OneEightyDays) {
        durationSeconds = 180 days;
    } else if (duration == BondDuration.ThreeSixtyDays) {
        durationSeconds = 360 days;
    }
    
    uint256 maturityTime = block.timestamp + durationSeconds;
    
    // This is the key: truncate to UTC midnight for consistent IDs
    return (maturityTime / 1 days) * 1 days;
}
```

#### **Why Truncate to Midnight?**

{% tabs %}
{% tab title="The Problem" %}
**Without Truncation:**

* Bond bought at 14:30 UTC → Token ID: `1712156200`
* Bond bought at 09:15 UTC → Token ID: `1712137300`
* **Same maturity day, different token IDs**
* **No fungibility between bonds**
* **Complex secondary markets**

**Result**: Fragmented liquidity and poor user experience
{% endtab %}

{% tab title="The Solution" %}
**With Midnight Truncation:**

* Bond bought at 14:30 UTC → Token ID: `1712102400` (midnight)
* Bond bought at 09:15 UTC → Token ID: `1712102400` (midnight)
* **Same maturity day, same token ID**
* **Perfect fungibility**
* **Unified secondary markets**

**Result**: Liquid, efficient bond markets
{% endtab %}
{% endtabs %}

#### **Real-World Example**

**Scenario**: Two users buy 90-day bonds on the same day:

* **User A** buys at 2:30 PM UTC
* **User B** buys at 9:15 AM UTC

**Traditional Approach**: Different token IDs, no fungibility **Tharwa Approach**: Same token ID (`maturity_date_at_midnight`), perfect fungibility

**Impact**: User A can sell to User B seamlessly, or both can trade on secondary markets as the same asset.

```solidity
function _calculateTokenId(BondDuration duration) internal view returns (uint256) {
    uint256 durationSeconds;
    
    if (duration == BondDuration.NinetyDays) {
        durationSeconds = 90 days;
    } else if (duration == BondDuration.OneEightyDays) {
        durationSeconds = 180 days;
    } else if (duration == BondDuration.ThreeSixtyDays) {
        durationSeconds = 360 days;
    }
    
    uint256 maturityTime = block.timestamp + durationSeconds;
    
    // Truncate to UTC midnight for consistent token IDs
    return (maturityTime / 1 days) * 1 days;
}
```

***

## **Bond Economics: How Fixed Yields Work**

### **The Discount Bond Model**

Tharwa Bonds use a **discount bond structure** - the foundation of institutional fixed-income markets:

{% tabs %}
{% tab title="Economic Principle" %}
**How Discount Bonds Work:**

1. **Purchase below par**: Buy bond for less than face value
2. **Hold to maturity**: No coupon payments during term
3. **Redeem at par**: Receive full face value at maturity
4. **Profit = Discount**: Yield comes from the price difference

**Why This Model:**

* **Simple structure**: No complex payment schedules
* **Predictable returns**: Known yield from day one
* **Capital efficient**: No need for coupon reserves
* **Institutional standard**: Familiar to traditional investors
  {% endtab %}

{% tab title="Tharwa Implementation" %}
**Our Bond Structure:**

| Duration | Purchase Price | Face Value | Yield  | APY     |
| -------- | -------------- | ---------- | ------ | ------- |
| 90 days  | 0.96 thUSD     | 1.00 thUSD | 4.17%  | \~3.94% |
| 180 days | 0.93 thUSD     | 1.00 thUSD | 7.53%  | \~5.91% |
| 360 days | 0.88 thUSD     | 1.00 thUSD | 13.64% | \~8.00% |

**Mathematical Foundation:**

```
APY = ((Face Value / Purchase Price) ^ (365/Days)) - 1
```

**Example**: 90-day bond

* Buy for 0.96 thUSD, receive 1.00 thUSD
* Return = (1.00/0.96)^(365/90) - 1 = 3.94% APY
  {% endtab %}
  {% endtabs %}

### **Yield Source & Sustainability**

### **Issuance Caps: Preventing Over-Leverage**

Each bond type has strict issuance caps to prevent over-leverage:

| Duration | Current Cap | Purpose                | Risk Management              |
| -------- | ----------- | ---------------------- | ---------------------------- |
| 90 days  | 1M thUSD    | Short-term liquidity   | Minimal duration risk        |
| 180 days | 2M thUSD    | Medium-term allocation | Balanced risk/reward         |
| 360 days | 4M thUSD    | Long-term commitment   | Higher cap for better yields |

**Why Caps Matter:**

* **Prevents over-issuance** beyond portfolio capacity
* **Maintains yield sustainability** by limiting obligations
* **Protects protocol solvency** during stress scenarios
* **Enables gradual scaling** as the protocol matures

***

## **Core Functions**

### **Bond Purchase**

```solidity
function purchaseBond(
    BondDuration duration,
    uint256 faceAmount,
    address receiver
) external whenNotPaused nonReentrant returns (uint256 tokenId) {
    BondConfig storage config = bondConfigs[duration];
    
    // Validation
    if (faceAmount == 0) revert ZeroAmount();
    if (faceAmount < MINIMUM_FACE_AMOUNT) revert BelowMinimumFaceAmount();
    if (config.issued + faceAmount > config.cap) revert CapExceeded();
    if (config.paused) revert BondPaused();
    
    // Calculate purchase price
    uint256 purchasePrice = faceAmount.mulDiv(config.price, 1e18);
    tokenId = _calculateTokenId(duration);
    
    // Check for maturity collision
    if (exists(tokenId)) revert MaturityCollision();
    
    // Update state
    config.issued += faceAmount;
    userBonds[receiver][tokenId] = UserBond({
        principal: purchasePrice,
        maturityAmount: faceAmount,
        purchaseTime: block.timestamp
    });
    
    // Transfer payment and mint bond
    IERC20(THUSD).safeTransferFrom(msg.sender, address(this), purchasePrice);
    _mint(receiver, tokenId, 1, "");
    
    emit BondIssued(receiver, tokenId, faceAmount, purchasePrice, duration);
}
```

### **Early Exit System: Balancing Liquidity and Commitment**

The early exit system is designed to provide liquidity while protecting the protocol from excessive redemption pressure.

#### **The Penalty Calculation Algorithm**

```solidity
function earlyExit(uint256 tokenId, address receiver) 
    external whenNotPaused nonReentrant returns (uint256 amount) 
{
    // Validation checks
    if (block.timestamp >= tokenId) revert BondMatured();
    if (balanceOf(msg.sender, tokenId) == 0) revert InsufficientBalance();
    
    UserBond memory bond = userBonds[msg.sender][tokenId];
    
    // Core penalty calculation
    uint256 timeElapsed = block.timestamp - bond.purchaseTime;
    uint256 totalTime = tokenId - bond.purchaseTime;
    uint256 penalty = INITIAL_PENALTY.mulDiv(totalTime - timeElapsed, totalTime);
    
    // Apply penalty to principal (not face value)
    amount = bond.principal.mulDiv(10000 - penalty, 10000);
    
    // State cleanup and transfer
    delete userBonds[msg.sender][tokenId];
    _burn(msg.sender, tokenId, 1);
    IERC20(THUSD).safeTransfer(receiver, amount);
    
    emit EarlyExit(msg.sender, tokenId, amount, penalty);
}
```

#### **Understanding the Penalty Formula**

{% tabs %}
{% tab title="The Math" %}
**Penalty Calculation:**

```
timeElapsed = now - purchaseTime
totalTime = maturityTime - purchaseTime  
penalty = INITIAL_PENALTY × (totalTime - timeElapsed) / totalTime
```

**Key Variables:**

* `INITIAL_PENALTY`: 20% (2000 basis points)
* `timeElapsed`: How long you've held the bond
* `totalTime`: Full bond duration
* `penalty`: Decreases linearly to 0% at maturity

**Exit Amount:**

```
exitAmount = principal × (10000 - penalty) / 10000
```

{% endtab %}

{% tab title="Real Example" %}
**360-Day Bond Scenario:**

* **Purchase**: 0.88 thUSD on Day 0
* **Face Value**: 1.00 thUSD at maturity

**Early Exit Timeline:**

* **Day 0**: 20% penalty → Exit for \~0.70 thUSD
* **Day 90**: 15% penalty → Exit for \~0.75 thUSD
* **Day 180**: 10% penalty → Exit for \~0.79 thUSD
* **Day 270**: 5% penalty → Exit for \~0.84 thUSD
* **Day 360**: 0% penalty → Redeem for 1.00 thUSD

**Why This Works:**

* **Early exit possible** but discouraged
* **Penalty decreases** as commitment increases
* **Protocol protected** from excessive redemptions
* **User flexibility** maintained
  {% endtab %}
  {% endtabs %}

#### **Why Penalty on Principal, Not Face Value?**

{% hint style="info" %}
**Critical Design Decision**: Penalties are applied to the **principal** (amount paid), not the **face value** (amount due at maturity).

**Example**: 360-day bond

* **Principal**: 0.88 thUSD (what user paid)
* **Face Value**: 1.00 thUSD (what user gets at maturity)
* **20% penalty**: Applied to 0.88 thUSD, not 1.00 thUSD

**Why This Matters**: Users never lose more than they invested, even with maximum penalty. This protects against catastrophic losses while still discouraging early exits.
{% endhint %}

### **Secondary Market Alternative**

Instead of early exit penalties, users can trade bonds on secondary markets:

{% tabs %}
{% tab title="Early Exit Function" %}
**Direct Protocol Exit:**

* **Immediate**: Get thUSD instantly
* **Penalty**: Time-decaying penalty applied
* **Predictable**: Exact amount calculable
* **Guaranteed**: Protocol always honors exits

**Best for**: Emergency liquidity needs
{% endtab %}

{% tab title="Secondary Market" %}
**NFT Marketplace Trading:**

* **No penalty**: Trade at market price
* **Price discovery**: Market determines value
* **Composable**: Works with any ERC-1155 marketplace
* **Flexible**: Can sell partial positions

**Best for**: Optimizing returns and market timing
{% endtab %}
{% endtabs %}

### **Maturity Redemption**

```solidity
function redeemBond(uint256 tokenId, address receiver) 
    external whenNotPaused nonReentrant returns (uint256 amount) 
{
    if (block.timestamp < tokenId) revert BondNotMatured();
    if (balanceOf(msg.sender, tokenId) == 0) revert InsufficientBalance();
    
    UserBond memory bond = userBonds[msg.sender][tokenId];
    amount = bond.maturityAmount;
    
    // Clean up state
    delete userBonds[msg.sender][tokenId];
    _burn(msg.sender, tokenId, 1);
    
    // Transfer maturity amount (1:1 with face value)
    IERC20(THUSD).safeTransfer(receiver, amount);
    
    emit BondRedeemed(msg.sender, tokenId, amount);
}
```

***

## **Bond Metadata**

### **On-Chain Metadata Structure**

Each bond NFT contains rich metadata for composability:

```json
{
  "name": "Tharwa Bond - 90 Day",
  "description": "Fixed-term bond redeemable for thUSD at maturity",
  "image": "https://metadata.tharwa.finance/bonds/90day.png",
  "attributes": [
    {
      "trait_type": "Duration",
      "value": "90 days"
    },
    {
      "trait_type": "Maturity Date", 
      "value": "2025-12-20T00:00:00Z"
    },
    {
      "trait_type": "Face Amount",
      "value": "1000.00 thUSD"
    },
    {
      "trait_type": "Purchase Price",
      "value": "960.00 thUSD"
    },
    {
      "trait_type": "APY",
      "value": "3.94%"
    },
    {
      "trait_type": "Status",
      "value": "Active"
    }
  ]
}
```

### **Dynamic Metadata Updates**

```solidity
function uri(uint256 tokenId) public view override returns (string memory) {
    // Generate dynamic metadata based on current bond state
    return string(abi.encodePacked(
        "https://metadata.tharwa.finance/bonds/",
        tokenId.toString(),
        ".json"
    ));
}
```

***

## **Integration Examples**

### **Purchase Bond via Contract**

```solidity
contract BondIntegration {
    ITharwaBonds constant bonds = ITharwaBonds(0xAc02FF90bC709A134cD4Ad0b50BaB8be9e0f504e);
    IERC20 constant thUSD = IERC20(0x76972F054aB43829064d31fF5f3AcC5Fabe57FE8);
    
    function buyBond(uint256 faceAmount) external {
        // Approve thUSD spending
        thUSD.approve(address(bonds), type(uint256).max);
        
        // Purchase 90-day bond
        uint256 tokenId = bonds.purchaseBond(
            ITharwaBonds.BondDuration.NinetyDays,
            faceAmount,
            msg.sender
        );
        
        emit BondPurchased(msg.sender, tokenId, faceAmount);
    }
}
```

### **Secondary Market Trading**

```solidity
contract BondMarketplace {
    function listBond(uint256 tokenId, uint256 price) external {
        // Verify ownership
        require(bonds.balanceOf(msg.sender, tokenId) > 0, "Not owner");
        
        // Create listing
        listings[tokenId] = Listing({
            seller: msg.sender,
            price: price,
            active: true
        });
    }
    
    function buyListing(uint256 tokenId) external {
        Listing memory listing = listings[tokenId];
        require(listing.active, "Not active");
        
        // Transfer payment
        thUSD.transferFrom(msg.sender, listing.seller, listing.price);
        
        // Transfer bond NFT
        bonds.safeTransferFrom(listing.seller, msg.sender, tokenId, 1, "");
        
        delete listings[tokenId];
    }
}
```

***

{% hint style="success" %}
**Production Status** thBonds are live on Ethereum mainnet with over $XXX TVL and 0 security incidents since launch.
{% endhint %}

{% hint style="info" %}
**Developer Resources**

* **Source Code**: [TharwaBondVaultV1.sol](https://github.com/tharwa-finance/contracts-v0/blob/main/thBonds/src/TharwaBondVaultV1.sol)
* **Tests**: [Bond Tests](https://github.com/tharwa-finance/contracts-v0/blob/main/thBonds/test/)
* **Audit Report**: [PrismSec Bonds Audit](https://github.com/tharwa-finance/contracts-v0/blob/main/audits/prismsec_tharwa_bonds_audit.pdf)
  {% endhint %}
