A decentralized protocol for tokenizing Indonesian Rupiah (IDR) bonds with yield distribution mechanisms built on blockchain technology using Foundry framework.
- Overview
- System Architecture
- Core Contracts
- Smart Contract Details
- Deployment
- Testing
- Development
- Security Features
The IDRC Protocol is a sophisticated DeFi system that allows users to:
- Subscribe to tokenized bonds using IDRX (Indonesian Rupiah stablecoin)
- Receive IDRC tokens representing their bond positions
- Automatically earn proportional rewards from bond coupons/maturity
- Redeem their positions back to IDRX
- Upgradeable Architecture: All core contracts use UUPS proxy pattern for upgradeability
- Role-Based Access Control: Granular permissions for admin operations
- Automatic Yield Distribution: Proportional reward distribution to all token holders
- 1:1 Pegging: IDRC tokens maintain 1:1 parity with IDRX collateral
- Reentrancy Protection: Guards against reentrancy attacks
- Pausable Operations: Emergency pause functionality for subscriptions/redemptions
┌─────────────────────────────────────────────────────────────────┐
│ IDRC Protocol │
└─────────────────────────────────────────────────────────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ │ │ │ │
│ IDRX Token │◄────────┤ Hub │────────►│ IDRC │
│ (ERC20) │ │ (Proxy) │ │ (Proxy) │
│ │ │ │ │ │
└──────────────┘ └──────┬───────┘ └──────┬───────┘
│ │
│ │
│ │
┌──────▼────────────────────────▼───┐
│ │
│ RewardDistributor (Proxy) │
│ │
└───────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ User Flow │
└─────────────────────────────────────────────────────────────────┘
User Hub IDRC Reward
│ │ │ │
│──subscribe()────►│ │ │
│ (send IDRX) │ │ │
│ │──mintByHub()────►│ │
│ │──update()─────►│
│ │ │
│◄─────receive IDRC tokens────────────┘ │
│ │
│ Admin │
│ │ │
│ │──injectReward()────────────────►│
│ │ (bond coupon) │
│ │
│──claimReward()──────────────────────────────────────►│
│◄─────receive IDRX rewards────────────────────────────┘
│
│──redeem()───────►│
│ (burn IDRC) │──burnByHub()────►│ Burn Token
│◄──receive IDRX───┘
Purpose: Central contract managing subscriptions, redemptions, and asset custody
Key Functions:
requestSubscription(address tokenIn, uint256 amount): Deposit IDRX and receive IDRC tokensrequestRedemption(address tokenOut, uint256 shares): Burn IDRC and receive IDRX backdepositAsset(address tokenIn, uint256 amount): Admin deposits assets (yield from bonds)withdrawAsset(address tokenOut, uint256 amount): Admin withdraws assets
Roles:
ADMIN_ROLE: Can deposit/withdraw assets for yield management
Storage Pattern: Uses ERC-7201 namespaced storage (HubStorage library)
Purpose: Upgradeable ERC20 token representing user's bond position
Key Functions:
mintByHub(address to, uint256 amount): Hub-only mintingburnByHub(address from, uint256 amount): Hub-only burningtvl(): Returns total value locked (total supply)
Special Features:
- Hooks into RewardDistributor on every transfer/mint/burn via
_update()override - IDRCv2 adds
decimals()override (returns 2) andinitializeV2()for upgrades
Purpose: Manages proportional yield distribution to IDRC holders
Key Functions:
injectReward(uint256 amount): Admin injects bond yield (coupons/maturity)earned(address account): View pending rewards for an accountclaimReward(): Users claim their accumulated rewardsupdateReward(address account): Called by IDRC to update reward accounting
Roles:
ADMIN_MANAGER_ROLE: Can inject rewards
Reward Mechanism:
rewardPerToken = (rewardAmount * 1e6) / totalSupply
userReward = userBalance * (rewardPerToken - lastUserRewardPerToken) / 1e6
Purpose: Mock stablecoin representing Indonesian Rupiah (for testnet)
Features:
- Standard ERC20 with configurable decimals
- Public
mint()andburn()for testing purposes
The contracts have circular dependencies requiring deterministic address prediction:
1. IDRX (simple ERC20, no proxy)
2. IDRC Implementation
3. Hub Implementation
4. RewardDistributor Implementation
5. RewardDistributor Proxy (needs Hub + IDRC proxy addresses)
6. IDRC Proxy (needs Hub + Reward proxy addresses)
7. Hub Proxy (needs IDRX + IDRC proxy addresses)All upgradeable contracts (Hub, IDRC, RewardDistributor) use UUPS pattern:
// Only owner can upgrade
function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}Example upgrade flow:
// Deploy new implementation
IDRCv2 newImpl = new IDRCv2();
// Upgrade via owner
idrcProxy.upgradeToAndCall(address(newImpl), "");
// Optionally call reinitializer
idrcProxy.initializeV2(hubAddress, rewardAddress);Hub: Uses ERC-7201 namespaced storage to avoid collisions
library HubStorage {
struct MainStorage {
IIDRC idrc;
IRewardDistributor rewardDistributor;
address asset;
mapping(uint256 => uint256) prices;
uint256 currentPriceId;
}
bytes32 private constant MAIN_STORAGE_LOCATION =
0x410db8097748b2adc18a3d9c7c820c57f308a38a62322863dc75caf59c7b4000;
}IDRC & RewardDistributor: Use standard state variables with OpenZeppelin upgradeable base contracts
-
Injection: Admin deposits yield into RewardDistributor
rewardPerTokenStored += (rewardAmount * 1e6) / totalSupply
-
Balance Changes: IDRC calls
updateReward()before any transfer/mint/burnfunction _update(address from, address to, uint256 amount) internal override { if (from != address(0)) rewardDistributor.updateReward(from); if (to != address(0)) rewardDistributor.updateReward(to); super._update(from, to, amount); }
-
Reward Calculation:
pending = balance * (rewardPerTokenStored - userRewardPerTokenPaid[user]) / 1e6 totalEarned = rewards[user] + pending
-
Claiming: User receives their accumulated rewards in IDRX
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup
# Install dependencies
forge installCreate .env file:
PRIVATE_KEY=your_private_key_here
ADMIN_MANAGER=0x... # Address with admin privileges
RPC_URL=https://... # Base Sepolia or other network
ETHERSCAN_API_KEY=your_api_key # For verification# Deploy all contracts
forge script script/Deploy.s.sol --rpc-url base-sepolia --broadcast --verify
# Fill transaction data (if needed)
forge script script/FillTransact.s.sol --rpc-url base-sepolia --broadcastforge script script/Upgrades.s.sol --rpc-url base-sepolia --broadcast --verify# Run full test suite
forge test
# Run with verbosity
forge test -vvv
# Run specific test file
forge test --match-path test/Hub.t.sol
# Run specific test
forge test --match-test testRequestSubscriptionSuccess
# Generate gas report
forge test --gas-report
# Generate coverage
forge coveragetest/
├── IDRC.t.sol # Unit tests for IDRC token
├── Hub.t.sol # Unit tests for Hub contract
├── RewardDistributor.t.sol # Unit tests for reward system
├── Integration.t.sol # End-to-end integration tests
├── Deploy.t.sol # Deployment script tests
├── Upgrades.t.sol # Upgrade process tests
└── FillTransact.t.sol # Transaction filling tests
- ✅ Initialization and setup
- ✅ Subscription and redemption flows
- ✅ Minting and burning mechanisms
- ✅ Reward injection and distribution
- ✅ Reward claiming
- ✅ Access control (roles)
- ✅ Upgrade functionality
- ✅ Edge cases (zero amounts, insufficient balance, etc.)
- ✅ Multi-user scenarios
- ✅ Reentrancy protection
contract/
├── src/
│ ├── Hub.sol # Main hub contract
│ ├── IDRC.sol # IDRC token v1
│ ├── IDRCv2.sol # IDRC token v2 (upgraded)
│ ├── IDRX.sol # Mock stablecoin
│ ├── RewardDistributor.sol # Yield distribution
│ ├── interfaces/
│ │ ├── IHub.sol
│ │ ├── IIDRC.sol
│ │ └── IRewardDistributor.sol
│ └── libraries/
│ └── HubStorage.sol # Namespaced storage
├── script/
│ ├── Deploy.s.sol # Deployment script
│ ├── Upgrades.s.sol # Upgrade script
│ └── FillTransact.s.sol # Transaction filler
├── test/ # Comprehensive test suite
├── lib/ # Dependencies (OpenZeppelin)
├── foundry.toml # Foundry configuration
└── remappings.txt # Import remappings
# Compile contracts
forge build
# Clean build artifacts
forge clean
# Format code
forge fmt# Start local node
anvil
# Deploy to local
forge script script/Deploy.s.sol --rpc-url http://localhost:8545 --broadcast- Hub:
ADMIN_ROLEfor asset management - RewardDistributor:
ADMIN_MANAGER_ROLEfor reward injection - IDRC: Only Hub can mint/burn
- Upgradeability: Only owner can upgrade contracts
- Reentrancy Guards: All state-changing functions in Hub and RewardDistributor
- Pausable: Hub can be paused in emergencies
- Input Validation: Zero amount checks, zero address checks
- Safe Math: Solidity 0.8.30+ with overflow protection
- SafeERC20: Used for token transfers in RewardDistributor
- IDRX is a mock token with public mint/burn (not for production)
- Admin roles are powerful and should be controlled by multisig or governance
- Contract upgradeability requires trust in owner
UNLICENSED - Private/Proprietary Code
- Solidity Version: ^0.8.30
- Framework: Foundry
- Proxy Pattern: UUPS (ERC-1967)
- Storage Pattern: ERC-7201 (namespaced storage)
- Dependencies:
- OpenZeppelin Contracts v5.x
- OpenZeppelin Contracts Upgradeable v5.x
- Forge-std (testing)
Proxy Contracts (User-Facing)
| Contract | Address | Explorer |
|---|---|---|
| Hub Proxy | 0xf2CCA756D7dE98d54ed00697EA8Cf50D71ea0Dd1 |
View on BaseScan |
| IDRC Proxy | 0xD3723bD07766d4993FBc936bEA1895227B556ea3 |
View on BaseScan |
| RewardDistributor Proxy | 0xA77C8059B011Ad0DB426623d1c1B985E53fdb7db |
View on BaseScan |
Implementation Contracts
| Contract | Address | Explorer |
|---|---|---|
| Hub Implementation | 0x4CAa4eC854306F961A2e476B62c4e6dacb8C23eF |
View on BaseScan |
| IDRC Implementation (v1) | 0x770d11A0583290f6B5BE500EE70720E3a3c01ea1 |
View on BaseScan |
| IDRC Implementation (v2) | 0x1BdF47D9736DDA87269D71d256F791FC418e31F6 |
View on BaseScan |
| RewardDistributor Implementation | 0xd3D46E3bf01c947794Ce8aF52a30Fd6559a83a72 |
View on BaseScan |
Supporting Contracts
| Contract | Address | Explorer |
|---|---|---|
| IDRX Token (Mock Stablecoin) | 0x3E4c9e0a4F7F735401971dace92d18418da9c937 |
View on BaseScan |
- Network: Base Sepolia Testnet
- Chain ID: 84532
- RPC URL: https://sepolia.base.org
- Block Explorer: https://sepolia.basescan.org
✅ For mainnet deployment, new addresses will be generated. The current addresses are for Base Sepolia testnet only.
🔄 Upgradeability: Implementation contracts can be upgraded by the owner through the proxy pattern. The IDRCv2 implementation is an example of an upgraded version.
For questions or issues, please contact the development team.