# 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tharwa.gitbook.io/tharwa/technical-architecture/thbonds-implementation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
