Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 155 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@

Djed is a formally verified crypto-backed autonomous stablecoin protocol. To learn more, visit the [Djed Alliance's Website](http://www.djed.one).

## Protocol Variants

This repository contains three variants of the Djed stablecoin protocol:

### 1. **Djed** (Standard)
The original implementation with:
- Single oracle price feed
- Reserve ratio constraints (min/max)
- Linear treasury fee decay
- `sellBothCoins()` function for atomic operations

### 2. **Djed Shu**
Enhanced version with:
- Dual-oracle pricing (24-hour min/max)
- Reserve ratio constraints (min/max)
- Linear treasury fee decay
- Protection against flash-crash attacks
- `sellBothCoins()` function

### 3. **Djed Tefnut** (New)
Simplified variant based on Djed Shu with:
- ✅ Dual-oracle pricing (24-hour min/max)
- ❌ No reserve ratio constraints (maximum flexibility)
- ❌ No `sellBothCoins()` function (simplified)
- ❌ Fixed treasury fee (no linear decay)
- **Use cases**: Experimental deployments, testing, volatile markets
- **Trade-off**: Higher risk, requires active monitoring

## Setting Up

Install [Foundry](https://github.com/foundry-rs/foundry/blob/master/README.md). Then:
Expand All @@ -20,6 +48,32 @@ forge test
forge coverage
```

### Run Specific Test Suites

Test individual protocol variants:

```bash
# Test standard Djed
forge test --match-contract DjedTest -vv

# Test Djed Shu
forge test --match-contract DjedShuTest -vv

# Test Djed Tefnut
forge test --match-contract DjedTefnutTest -vv
```

### Tefnut Test Coverage

The Tefnut implementation includes 17 comprehensive tests covering:
- ✅ No reserve ratio constraints on all operations
- ✅ Removal of `sellBothCoins()` function
- ✅ Fixed treasury fee (no decay mechanism)
- ✅ Dual-oracle pricing (min/max from 24h window)
- ✅ Core mint/redeem flows for SC and RC
- ✅ Fee distribution (treasury, protocol, UI)
- ✅ Multi-user transaction scenarios

## Linting

Pre-configured `solhint` and `prettier-plugin-solidity`. Can be run by
Expand All @@ -31,18 +85,117 @@ npm run prettier

## Deployments

The `scripts/env/` folder contain sample .env files for different networks. To deploy an instance of djed contract, create an .env file with and run:
The `scripts/env/` folder contain sample .env files for different networks.

### Deploy Djed (Standard)

To deploy an instance of the standard Djed contract:

```shell
forge script ./scripts/deployDjedContract.s.sol:DeployDjed -vvvv --broadcast --rpc-url <NETWORK_RPC_ENDPOINT> --sig "run(uint8)" -- <SupportedNetworks_ID> --verify
```

### Deploy Djed Shu

To deploy the Shu variant with dual-oracle pricing:

```shell
forge script ./scripts/deployDjedShuContract.sol:DeployDjedShu -vvvv --broadcast --rpc-url <NETWORK_RPC_ENDPOINT> --sig "run(uint8)" -- <SupportedNetworks_ID> --verify
```

### Deploy Djed Tefnut

To deploy the simplified Tefnut variant:

```shell
forge script ./scripts/deployDjedTefnutContract.s.sol:DeployDjedTefnutContract --broadcast --rpc-url <NETWORK_RPC_ENDPOINT> --verify
```

**Note**: Update the network in the deployment script before running. Tefnut uses the same oracle infrastructure as Shu.

Refer `foundry.toml` for NETWORK_RPC_ENDPOINT and `scripts/DeploymentParameters.sol` for SupportedNetworks_ID. Update `scripts/DeploymentParameters.sol` file with each Oracle deployments.

### Deploy Oracles

To deploy chainlink oracle, run:

```shell
forge script ./scripts/deployChainlinkOracle.s.sol:DeployChainlinkOracle -vvvv --broadcast --rpc-url <NETWORK_RPC_ENDPOINT> --sig "run()" --verify
```

We can also deploy Inverting Chainlink Oracle (if chainlink oracle returns price feed from ETH/USD, the corresponding inverting oracle would return price feed from USD/ETH), replace DeployChainlinkOracle with DeployInvertingChainlinkOracle in the above script.
We can also deploy Inverting Chainlink Oracle (if chainlink oracle returns price feed from ETH/USD, the corresponding inverting oracle would return price feed from USD/ETH), replace DeployChainlinkOracle with DeployInvertingChainlinkOracle in the above script.

## Protocol Comparison

| Feature | Djed | Djed Shu | Djed Tefnut |
|---------|------|----------|-------------|
| **Oracle Type** | Single price | Dual (24h min/max) | Dual (24h min/max) |
| **Reserve Ratio Min** | ✅ Enforced | ✅ Enforced | ❌ No constraint |
| **Reserve Ratio Max** | ✅ Enforced | ✅ Enforced | ❌ No constraint |
| **Treasury Fee** | 📉 Linear decay | 📉 Linear decay | 📊 Fixed |
| **sellBothCoins()** | ✅ Available | ✅ Available | ❌ Removed |
| **Flash-crash Protection** | ❌ No | ✅ Yes | ✅ Yes |
| **Complexity** | Medium | High | Low |
| **Security** | Medium | High | Medium |
| **Flexibility** | Medium | Low | High |
| **Gas Cost** | Medium | High | Low |
| **Best For** | General use | Production | Testing/Experimental |

## Contract Architecture

```
src/
├── Djed.sol # Standard implementation
├── DjedShu.sol # Time-weighted oracle variant
├── DjedTefnut.sol # Simplified variant (NEW)
├── Coin.sol # ERC20 for SC and RC
├── IOracle.sol # Standard oracle interface
├── IOracleShu.sol # Dual-oracle interface
├── ShuOracleConverter.sol # Wraps oracle with 24h tracking
├── ChainlinkOracle.sol # Chainlink integration
├── ChainlinkInvertingOracle.sol # Inverted Chainlink feed
├── API3Oracle.sol # API3 integration
├── API3InvertingOracle.sol # Inverted API3 feed
├── HebeSwapOracle.sol # DEX-based pricing
├── HebeSwapInvertingOracle.sol # Inverted DEX pricing
└── mock/
├── MockOracle.sol # Testing oracle
└── MockShuOracle.sol # Testing dual oracle (UPDATED)
```

## Key Differences: Djed Tefnut

Tefnut is designed for maximum flexibility by removing safety constraints:

**Removed:**
- `reserveRatioMin` and `reserveRatioMax` - No overcollateralization requirements
- `sellBothCoins()` - Simplified selling mechanism
- `treasuryRevenue` and `treasuryRevenueTarget` - No fee decay tracking
- `isRatioAboveMin()` and `isRatioBelowMax()` - No ratio validation

**Preserved:**
- Dual-oracle pricing from DjedShu for flash-crash protection
- All core mint/redeem functionality
- Fee distribution (treasury, protocol, UI)
- Transaction limits and threshold supply checks
- Reentrancy protection

**Use Cases:**
- Experimental deployments on new chains
- Testing different economic parameters
- Markets with high volatility
- Scenarios where ratio constraints are too restrictive

**⚠️ Warning:** Tefnut has no overcollateralization guarantees. It can operate with reserve < liabilities. Suitable for testing and experimental use only.

## Contributing

Contributions are welcome! Please ensure:
1. All tests pass: `forge test`
2. Code is formatted: `npm run prettier`
3. No linting errors: `npm run solhint`
4. New features include comprehensive tests

## License

See [LICENSE.md](LICENSE.md) for details.
17 changes: 17 additions & 0 deletions foundry.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"lib/contracts": {
"rev": "72073d0e2cabf7966b493fc77291e4891c5402d7"
},
"lib/forge-std": {
"rev": "f73c73d2018eb6a111f35e4dae7b4f27401e9421"
},
"lib/hebeswap-contract": {
"rev": "fb606bdcf5ddaee985039605bcd847918a66c3a7"
},
"lib/openzeppelin-contracts": {
"rev": "0457042d93d9dfd760dbaa06a4d2f1216fdbe297"
},
"lib/solmate": {
"rev": "3998897acb502fa7b480f505138a6ae1842e8d10"
}
}
3 changes: 3 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@ libs = ['node_modules', 'lib']
remappings = [
'@chainlink/contracts/=node_modules/@chainlink/contracts'
]
via_ir = true
optimizer = true
optimizer_runs = 200

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
123 changes: 114 additions & 9 deletions scripts/DeploymentParameters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ contract DeploymentParameters {

enum SupportedVersion {
DJED,
DJED_SHU
DJED_SHU,
DJED_TEFNUT
}

mapping(SupportedNetworks enumValue => string humanReadableName)
Expand All @@ -34,6 +35,18 @@ contract DeploymentParameters {
address constant HEBESWAP_ORACLE_INVERTED_ADDRESS_MAINNET = 0x2fd961e20896e121EC7D499cC4F38462e286994A;
address constant HEBESWAP_SHU_ORACLE_INVERTED_ADDRESS_MORDOR = 0x8Bd4A5F6a4727Aa4AC05f8784aACAbE2617e860A;

// DEPLOYMENT REQUIRED: Before using Tefnut on mainnet, deploy ShuOracleConverter
// Step 1: Run deployment script to wrap the existing HebeSwap oracle:
// forge script scripts/deployOracleConverter.s.sol:DeployOracleConverter \
// --rpc-url https://etc.rivet.link \
// --broadcast \
// --verify
//
// Step 2: Update this constant with the deployed ShuOracleConverter address
// Step 3: The converter will wrap HEBESWAP_ORACLE_INVERTED_ADDRESS_MAINNET (0x2fd961e20896e121EC7D499cC4F38462e286994A)
// and provide IOracleShu interface (readMaxPrice, readMinPrice, updateOracleValues)
address constant HEBESWAP_SHU_ORACLE_INVERTED_ADDRESS_MAINNET = address(0); // TODO: Deploy ShuOracleConverter first

address oracleAddress;
address treasuryAddress;

Expand All @@ -44,6 +57,9 @@ contract DeploymentParameters {
networks[SupportedNetworks.ETHEREUM_CLASSIC_MAINNET] = "Ethereum Classic Mainnet";
}

// Get configuration for Djed or DjedShu variants
// NOTE: For DJED_TEFNUT, use getTefnutConfigFromNetwork() instead.
// This function will revert if DJED_TEFNUT is passed to prevent oracle misrouting.
function getConfigFromNetwork(
SupportedNetworks network,
SupportedVersion version
Expand All @@ -54,6 +70,12 @@ contract DeploymentParameters {
uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256, uint256
)
{
// DJED_TEFNUT has its own configuration function with different parameters
require(
version != SupportedVersion.DJED_TEFNUT,
"Use getTefnutConfigFromNetwork() for DJED_TEFNUT deployment"
);

if (network == SupportedNetworks.ETHEREUM_SEPOLIA) {
oracleAddress = CHAINLINK_SEPOLIA_INVERTED_ORACLE_ADDRESS;
treasuryAddress = 0x0f5342B55ABCC0cC78bdB4868375bCA62B6c16eA;
Expand All @@ -67,12 +89,12 @@ contract DeploymentParameters {
RESERVE_COIN_MINIMUM_PRICE=1e18;
RESERVE_COIN_INITIAL_PRICE=1e20;
TX_LIMIT=1e10;


}

if (network == SupportedNetworks.ETHEREUM_CLASSIC_MORDOR) {
oracleAddress = version == SupportedVersion.DJED_SHU ? HEBESWAP_SHU_ORACLE_INVERTED_ADDRESS_MORDOR : HEBESWAP_ORACLE_INVERTED_ADDRESS_MORDOR;
else if (network == SupportedNetworks.ETHEREUM_CLASSIC_MORDOR) {
// Use SHU oracle for DJED_SHU, regular oracle for DJED
oracleAddress = (version == SupportedVersion.DJED_SHU)
? HEBESWAP_SHU_ORACLE_INVERTED_ADDRESS_MORDOR
: HEBESWAP_ORACLE_INVERTED_ADDRESS_MORDOR;
treasuryAddress = 0xBC80a858F6F9116aA2dc549325d7791432b6c6C4;
SCALING_FACTOR=1e24;
INITIAL_TREASURY_FEE=25e20;
Expand All @@ -85,9 +107,17 @@ contract DeploymentParameters {
RESERVE_COIN_INITIAL_PRICE=1e18;
TX_LIMIT=1e10;
}

if (network == SupportedNetworks.ETHEREUM_CLASSIC_MAINNET) {
oracleAddress = HEBESWAP_ORACLE_INVERTED_ADDRESS_MAINNET;
else if (network == SupportedNetworks.ETHEREUM_CLASSIC_MAINNET) {
// Use SHU oracle for DJED_SHU if deployed, regular oracle for DJED
if (version == SupportedVersion.DJED_SHU) {
require(
HEBESWAP_SHU_ORACLE_INVERTED_ADDRESS_MAINNET != address(0),
"Deploy ShuOracleConverter on mainnet before using DJED_SHU"
);
oracleAddress = HEBESWAP_SHU_ORACLE_INVERTED_ADDRESS_MAINNET;
} else {
oracleAddress = HEBESWAP_ORACLE_INVERTED_ADDRESS_MAINNET;
}
treasuryAddress = 0xBC80a858F6F9116aA2dc549325d7791432b6c6C4;
SCALING_FACTOR=1e24;
INITIAL_TREASURY_FEE=25e20;
Expand All @@ -100,6 +130,12 @@ contract DeploymentParameters {
RESERVE_COIN_INITIAL_PRICE=1e18;
TX_LIMIT=1e10;
}
else {
revert(string(abi.encodePacked(
"Unsupported network: ",
networks[network]
)));
}

return (
oracleAddress,
Expand All @@ -116,4 +152,73 @@ contract DeploymentParameters {
TX_LIMIT
);
}

// Tefnut version - simplified parameters (no reserve ratios, no treasury revenue target)
// NOTE: Mainnet deployment will revert until ShuOracleConverter is deployed.
// This is an intentional safeguard because DjedTefnut requires IOracleShu interface,
// but the mainnet HebeSwap oracle only implements IOracle. The require() check ensures
// no one accidentally deploys with address(0), which would cause runtime failures.
function getTefnutConfigFromNetwork(
SupportedNetworks network
)
internal
returns (
address, address,
uint256, uint256, uint256, uint256, uint256, uint256, uint256
)
{
if (network == SupportedNetworks.ETHEREUM_SEPOLIA) {
oracleAddress = CHAINLINK_SEPOLIA_INVERTED_ORACLE_ADDRESS;
treasuryAddress = 0x0f5342B55ABCC0cC78bdB4868375bCA62B6c16eA;
SCALING_FACTOR=1e24;
INITIAL_TREASURY_FEE=25e20; // Used as fixed treasury fee for Tefnut
FEE=15e21;
THREASHOLD_SUPPLY_SC=5e11;
RESERVE_COIN_MINIMUM_PRICE=1e18;
RESERVE_COIN_INITIAL_PRICE=1e20;
TX_LIMIT=1e10;
} else if (network == SupportedNetworks.ETHEREUM_CLASSIC_MORDOR) {
oracleAddress = HEBESWAP_SHU_ORACLE_INVERTED_ADDRESS_MORDOR;
treasuryAddress = 0xBC80a858F6F9116aA2dc549325d7791432b6c6C4;
SCALING_FACTOR=1e24;
INITIAL_TREASURY_FEE=25e20; // Used as fixed treasury fee for Tefnut
FEE=12500e18;
THREASHOLD_SUPPLY_SC=10e6;
RESERVE_COIN_MINIMUM_PRICE=1e15;
RESERVE_COIN_INITIAL_PRICE=1e18;
TX_LIMIT=1e10;
} else if (network == SupportedNetworks.ETHEREUM_CLASSIC_MAINNET) {
// Mainnet requires ShuOracleConverter deployment first
require(
HEBESWAP_SHU_ORACLE_INVERTED_ADDRESS_MAINNET != address(0),
"Deploy ShuOracleConverter on mainnet before using Tefnut. Run: forge script scripts/deployOracleConverter.s.sol"
);
oracleAddress = HEBESWAP_SHU_ORACLE_INVERTED_ADDRESS_MAINNET;
treasuryAddress = 0xBC80a858F6F9116aA2dc549325d7791432b6c6C4;
SCALING_FACTOR=1e24;
INITIAL_TREASURY_FEE=25e20; // Used as fixed treasury fee for Tefnut
FEE=12500e18;
THREASHOLD_SUPPLY_SC=10e6;
RESERVE_COIN_MINIMUM_PRICE=1e15;
RESERVE_COIN_INITIAL_PRICE=1e18;
TX_LIMIT=1e10;
} else {
revert(string(abi.encodePacked(
"Tefnut not supported on network: ",
networks[network]
)));
}

return (
oracleAddress,
treasuryAddress,
SCALING_FACTOR,
INITIAL_TREASURY_FEE, // Fixed treasury fee (no decay)
FEE,
THREASHOLD_SUPPLY_SC,
RESERVE_COIN_MINIMUM_PRICE,
RESERVE_COIN_INITIAL_PRICE,
TX_LIMIT
);
}
}
Loading