> For the complete documentation index, see [llms.txt](https://tharwa.gitbook.io/tharwa/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tharwa.gitbook.io/tharwa/technical-architecture/sthusd-implementation.md).

# sthUSD Implementation

sthUSD transforms idle thUSD into a yield-generating asset while maintaining the liquidity and stability users expect from stablecoins. This page explains how sthUSD works under the hood, from its ERC-4626 foundation to the custom mechanisms that make it secure and efficient.

## **What Problem Does sthUSD Solve?**

Traditional stablecoins force users to choose between **yield** and **liquidity**. You can either:

* Hold USDC (liquid but no yield)
* Lock tokens in vaults (yield but no liquidity)

sthUSD eliminates this trade-off by providing **both yield and liquidity** through an intelligent vault design.

## **Contract Overview**

| Property     | Value                                                                                                               |
| ------------ | ------------------------------------------------------------------------------------------------------------------- |
| **Contract** | `sthUSD.sol`                                                                                                        |
| **Standard** | ERC-4626 Vault with Tharwa extensions                                                                               |
| **Address**  | `0xf7Af0A8079F12F19533B0DF69ce7ee6718b0C46f` (Mainnet)                                                              |
| **Audit**    | [PrismSec Report](https://github.com/tharwa-finance/contracts-v0/blob/main/audits/prismsec_tharwa_sthUSD_audit.pdf) |
| **Security** | 0 Critical, 0 High findings                                                                                         |

***

## **How sthUSD Works: Core Concepts**

### **The Share-Based Model**

sthUSD uses the **ERC-4626 vault standard**, which represents ownership through shares rather than direct token amounts. Here's why this matters:

{% tabs %}
{% tab title="Traditional Staking" %}
**Problem**: Direct 1:1 token staking

* 100 tokens in = 100 tokens out
* Yield added by minting new tokens
* Creates inflation and dilution

**Example**: Stake 1000 USDC, earn 50 USDC in new tokens
{% endtab %}

{% tab title="sthUSD Shares" %}
**Solution**: Share-based ownership

* Deposit thUSD, receive sthUSD shares
* Share value increases as yield is added
* No token inflation or dilution

**Example**: Stake 1000 thUSD for 1000 shares. Later, 1000 shares = 1050 thUSD
{% endtab %}
{% endtabs %}

### **Asset Definitions**

sthUSD manages one primary asset with sophisticated accounting:

#### **`asset()` - thUSD (The Underlying Token)**

This represents the ERC-20 token that users deposit to earn yield. In sthUSD's case, this is always thUSD (`0x76972F054aB43829064d31fF5f3AcC5Fabe57FE8`).

**Key Point**: Users deposit thUSD and receive sthUSD shares. The value of these shares grows as the vault earns yield from Tharwa's RWA portfolio.

#### **`shares` - sthUSD (The Vault Token)**

These represent proportional ownership in the vault. Unlike many DeFi protocols where shares are minted/burned arbitrarily, sthUSD shares have **real economic meaning**:

```solidity
shareValue = totalAssets() / totalSupply()
```

As `totalAssets()` grows through yield, each share becomes worth more thUSD.

### **State Variables Explained**

sthUSD tracks several key variables to maintain security and prevent manipulation:

```solidity
contract sthUSD is ERC4626, AccessControl, Pausable, ERC20Permit {
    // === CORE ACCOUNTING ===
    uint256 private _pooledAssets;      // Total thUSD we've accounted for
    uint256 private _yieldAmount;       // How much yield is currently vesting
    uint256 private _vestingEnd;        // When the current yield finishes vesting
    uint256 private _vestingPeriod;     // How long yield takes to vest (30 days)
    
    // === COOLDOWN SYSTEM ===
    uint256 private _cooldownPeriod;    // How long users must wait to withdraw
    ThUSDSilo private _silo;           // Where assets sit during cooldown
    
    // === FEE SYSTEM ===
    uint256 private _entryFeeBps;       // Fee charged on deposits (basis points)
    uint256 private _exitFeeBps;        // Fee charged on withdrawals (basis points)
    address private _feeRecipient;      // Where fees are sent
}
```

**Why These Variables Matter:**

* **`_pooledAssets`**: Prevents "donation attacks" where someone sends tokens directly to manipulate share price
* **`_yieldAmount` & `_vestingEnd`**: Ensures new depositors can't immediately claim yield that was earned before they arrived
* **`_cooldownPeriod` & `_silo`**: Provides flexibility between instant liquidity and enhanced security
* **Fee variables**: Allow protocol sustainability without hardcoded rates

***

## **Accounting Model: How Value Accrues**

### **The Core Challenge: Preventing Manipulation**

The biggest challenge in yield-bearing tokens is preventing "donation attacks" where malicious actors manipulate share prices. Here's how sthUSD solves this:

{% tabs %}
{% tab title="The Attack" %}
**Scenario**: Malicious actor exploits naive accounting

1. **Attacker deposits** 1 wei to get shares
2. **Attacker donates** 1000 thUSD directly to contract
3. **Share price skyrockets** artificially
4. **New depositors** get almost no shares for their deposits
5. **Attacker withdraws** at inflated price

**Result**: New users get rugged, attacker profits
{% endtab %}

{% tab title="sthUSD Protection" %}
**Solution**: Separate tracking of accounted vs actual assets

1. **`_pooledAssets`** tracks only legitimate deposits/yields
2. **Direct donations** don't affect `totalAssets()`
3. **Share price** based on accounted assets only
4. **Attack becomes impossible**

**Result**: Users protected, fair share pricing maintained
{% endtab %}
{% endtabs %}

### **Total Assets Calculation**

The heart of sthUSD's security is its `totalAssets()` function:

```solidity
function totalAssets() public view override returns (uint256) {
    return _pooledAssets - _unvestedAmount();
}
```

**Breaking this down:**

* **`_pooledAssets`**: Only includes legitimate deposits and properly added yield
* **`_unvestedAmount()`**: Excludes yield that hasn't finished vesting yet
* **Result**: Share price reflects only "earned" and "available" assets

### **Yield Vesting: Preventing Yield Theft**

When Tharwa adds yield to sthUSD, it doesn't become immediately available. Instead, it vests linearly over 30 days:

```solidity
function _unvestedAmount() internal view returns (uint256) {
    if (block.timestamp >= _vestingEnd) return 0;
    
    uint256 timeRemaining = _vestingEnd - block.timestamp;
    return _yieldAmount.mulDiv(timeRemaining, _vestingPeriod);
}
```

**Why Vesting Matters:**

{% hint style="info" %}
**Without Vesting**: Someone could deposit right before yield is added, immediately claim a large portion, then withdraw

**With Vesting**: Yield is distributed fairly over time to users who were actually staked when it was earned
{% endhint %}

**Example:**

* **Day 0**: 1000 thUSD yield added, starts 30-day vest
* **Day 15**: 50% of yield (500 thUSD) is vested and included in `totalAssets()`
* **Day 30**: 100% of yield (1000 thUSD) is fully vested

### **Asset Flow Tracking**

```solidity
// Deposit flow
function _deposit(address caller, address receiver, uint256 assets, uint256 shares) 
    internal override 
{
    // Calculate and deduct entry fee
    uint256 fee = assets.mulDiv(_entryFeeBps, 10_000);
    uint256 netAssets = assets - fee;
    
    // Update pooled assets
    _pooledAssets += netAssets;
    
    // Transfer fee to recipient
    if (fee > 0) {
        IERC20(asset()).safeTransferFrom(caller, _feeRecipient, fee);
    }
    
    // Continue with standard ERC4626 deposit
    super._deposit(caller, receiver, netAssets, shares);
}
```

### **Yield Vesting Mechanism**

```solidity
function addYield(uint256 amount) external onlyRole(YIELD_MANAGER_ROLE) {
    if (totalSupply() == 0) revert NoShares();
    if (_unvestedAmount() != 0) revert VestingActive();
    
    // Transfer yield into the vault
    IERC20(asset()).safeTransferFrom(msg.sender, address(this), amount);
    
    // Update accounting
    _pooledAssets += amount;
    _yieldAmount = amount;
    _vestingEnd = block.timestamp + _vestingPeriod;
    
    emit YieldAdded(amount, _vestingEnd);
}
```

***

## **Cooldown System**

### **Cooldown States**

The cooldown system provides flexibility for different withdrawal preferences:

| Cooldown Period | Behavior                         | Use Case                               |
| --------------- | -------------------------------- | -------------------------------------- |
| `0` (OFF)       | Standard ERC4626 withdraw/redeem | DeFi integrations, instant liquidity   |
| `3 days`        | Staged cooldown via silo         | Reduced exit fees, planned withdrawals |
| `7 days`        | Extended cooldown via silo       | Maximum security, institutional use    |

### **Cooldown Implementation**

```solidity
function cooldownAssets(uint256 assets) external whenNotPaused nonReentrant {
    if (_cooldownPeriod == 0) revert CooldownIsOff();
    
    address owner = msg.sender;
    uint256 shares = previewWithdraw(assets);
    
    // Calculate exit fee
    uint256 fee = assets.mulDiv(_exitFeeBps, 10_000);
    uint256 netAssets = assets - fee;
    
    // Update accounting
    _pooledAssets -= assets;
    
    // Transfer to silo for cooldown
    IERC20(asset()).safeTransfer(address(_silo), netAssets);
    _silo.deposit(owner, netAssets, block.timestamp + _cooldownPeriod);
    
    // Burn shares and handle fee
    _burn(owner, shares);
    if (fee > 0) {
        IERC20(asset()).safeTransfer(_feeRecipient, fee);
    }
    
    emit CooldownInitiated(owner, assets, netAssets, block.timestamp + _cooldownPeriod);
}
```

### **Silo Contract**

The `ThUSDSilo` contract manages assets during cooldown:

```solidity
contract ThUSDSilo {
    struct CooldownInfo {
        uint256 amount;
        uint256 cooldownEnd;
    }
    
    mapping(address => CooldownInfo) public cooldowns;
    
    function deposit(address user, uint256 amount, uint256 cooldownEnd) external onlyVault {
        cooldowns[user].amount += amount;
        cooldowns[user].cooldownEnd = cooldownEnd; // Latest cooldown resets timer
    }
    
    function withdraw(address user, address receiver) external onlyVault returns (uint256) {
        CooldownInfo storage info = cooldowns[user];
        require(block.timestamp >= info.cooldownEnd, "Cooldown active");
        
        uint256 amount = info.amount;
        delete cooldowns[user];
        
        IERC20(thUSD).safeTransfer(receiver, amount);
        return amount;
    }
}
```

***

## **Fee Structure**

### **Fee Configuration**

```solidity
function setFees(
    uint256 entryFeeBps,
    uint256 exitFeeBps,
    address feeRecipient
) external onlyRole(FEE_MANAGER_ROLE) {
    if (entryFeeBps > 1000 || exitFeeBps > 1000) revert FeeTooHigh(); // Max 10%
    if (feeRecipient == address(0)) revert RecipientZero();
    
    _entryFeeBps = entryFeeBps;
    _exitFeeBps = exitFeeBps;
    _feeRecipient = feeRecipient;
    
    emit FeesUpdated(entryFeeBps, exitFeeBps, feeRecipient);
}
```

### **Current Fee Parameters**

| Fee Type  | Current Rate | Maximum        | Applied When             |
| --------- | ------------ | -------------- | ------------------------ |
| Entry Fee | 0 bps (0%)   | 1000 bps (10%) | Deposit/Mint             |
| Exit Fee  | 0 bps (0%)   | 1000 bps (10%) | Withdraw/Redeem/Cooldown |

***

## **Access Control & Security**

### **Role-Based Permissions**

```solidity
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
bytes32 public constant YIELD_MANAGER_ROLE = keccak256("YIELD_MANAGER_ROLE");
bytes32 public constant FEE_MANAGER_ROLE = keccak256("FEE_MANAGER_ROLE");
```

| Role                 | Permissions                  | Purpose             |
| -------------------- | ---------------------------- | ------------------- |
| `DEFAULT_ADMIN_ROLE` | All administrative functions | Protocol governance |
| `PAUSER_ROLE`        | Pause/unpause contract       | Emergency response  |
| `YIELD_MANAGER_ROLE` | Add yield to vault           | Treasury operations |
| `FEE_MANAGER_ROLE`   | Configure fee parameters     | Fee optimization    |

### **Security Features**

1. **Pausable**: Emergency pause for all user-facing functions
2. **Blacklist**: Compliance-focused address restrictions
3. **Reentrancy Protection**: All external functions protected
4. **Safe Math**: OpenZeppelin's Math library for overflow protection

```solidity
function pause() external onlyRole(PAUSER_ROLE) {
    _pause();
}

function setBlacklisted(address account, bool blacklisted) 
    external onlyRole(DEFAULT_ADMIN_ROLE) 
{
    _blacklisted[account] = blacklisted;
    emit BlacklistUpdated(account, blacklisted);
}
```

***

## **Gas Optimization**

### **Efficient Storage Layout**

```solidity
// Packed struct to minimize storage slots
struct VaultState {
    uint128 pooledAssets;    // Sufficient for 3.4e38 tokens
    uint128 yieldAmount;     // Sufficient for yield amounts
    uint64 vestingEnd;       // Timestamp fits in uint64
    uint64 vestingPeriod;    // Duration fits in uint64
    uint32 cooldownPeriod;   // Duration fits in uint32
    uint16 entryFeeBps;      // Max 65535 bps (655.35%)
    uint16 exitFeeBps;       // Max 65535 bps (655.35%)
}
```

### **Gas-Efficient Operations**

| Operation | Gas Cost | Optimization             |
| --------- | -------- | ------------------------ |
| Deposit   | \~50,000 | Minimal external calls   |
| Withdraw  | \~45,000 | Direct asset transfer    |
| Cooldown  | \~60,000 | Single silo interaction  |
| Add Yield | \~40,000 | Simple accounting update |

***

## **Testing & Validation**

### **Comprehensive Test Suite**

```solidity
contract sthUSDTest is Test {
    function testDepositWithdraw() public {
        // Standard ERC4626 functionality
    }
    
    function testYieldVesting() public {
        // Yield vesting mechanics
    }
    
    function testCooldownSystem() public {
        // Cooldown and silo interactions
    }
    
    function testDonationAttackResistance() public {
        // Security against share price manipulation
    }
    
    function testFeeCalculations() public {
        // Entry and exit fee mechanics
    }
}
```

### **Invariant Testing**

Key invariants maintained throughout all operations:

1. `totalAssets() >= totalSupply() * minSharePrice`
2. `_pooledAssets >= totalAssets() + unvestedAmount()`
3. `sum(balanceOf(users)) == totalSupply()`
4. `cooldownAssets + vaultAssets == totalPooledAssets`

***

## **Integration Examples**

### **Basic Integration**

```solidity
interface ISThUSD {
    function deposit(uint256 assets, address receiver) external returns (uint256 shares);
    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
    function totalAssets() external view returns (uint256);
    function previewDeposit(uint256 assets) external view returns (uint256 shares);
}

contract TharwaIntegration {
    IsthUSD constant sthUSD = IsthUSD(0xf7Af0A8079F12F19533B0DF69ce7ee6718b0C46f);
    IERC20 constant thUSD = IERC20(0x76972F054aB43829064d31fF5f3AcC5Fabe57FE8);
    
    function stake(uint256 amount) external {
        thUSD.transferFrom(msg.sender, address(this), amount);
        thUSD.approve(address(sthUSD), amount);
        
        uint256 shares = sthUSD.deposit(amount, msg.sender);
        emit Staked(msg.sender, amount, shares);
    }
}
```

### **Advanced Integration with Cooldown**

```solidity
contract AdvancedIntegration {
    function initiateWithdrawal(uint256 assets) external {
        if (sthUSD.cooldownPeriod() > 0) {
            // Use cooldown system
            sthUSD.cooldownAssets(assets);
        } else {
            // Direct withdrawal
            sthUSD.withdraw(assets, msg.sender, msg.sender);
        }
    }
    
    function completeWithdrawal() external {
        sthUSD.unstake(msg.sender);
    }
}
```

***

{% hint style="success" %}
**Production Ready** sthUSD is fully audited, tested, and operational on Ethereum mainnet with zero critical findings from PrismSec.
{% endhint %}

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

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