rwaUSD: Overcollateralizing
Overcollateralizing Assets to Get rwaUSD
The user can get rwaUSD by overcollateralizing their LUMIA.
This option is implemented through the Lumia rwaUSD CDP Protocol.
Lumia rwaUSD CDP is a decentralized lending protocol, extending the 3A Lending Protocol.
It is customized for Lumia to enable LUMIA token holders to use their tokens as collateral for borrowing the rwaUSD stablecoin.
Later on, we plan to whitelist and support different types of tokenized RWAs as collateral, with different collateralization ratios.
It works fairly simply: The user deposits whitelisted assets as collateral into a smart contract called vault, allowing them to mint and withdraw RWAs. In order to avoid liquidation, vaults must maintain a required Health Factor (HF) determined by our data-driven risk model.
The protocol is implemented as a set of smart contracts.
Smart Contracts
The smart contracts implementing the protocol are:
API3MarketPriceFeed (0x58504c4eE9f9e9cf7b17988817fddFa9934E76d4) — Adapter; gets the latest WLUMIA price from the market, with a 24h price update threshold.
AuctionManager (0xCAE7cf522D37b05AF6038E6c98441A2F50154EA5) — Manages the auction where the liquidated user funds are sold to cover the user's debt.
LastResortLiquidation (0x5D8153141ec1a4837437981dc5Da26436E88985D) — Manages collateral and bad debt distribution. Initiates the liquidation process when the user's collateral goes under the min threshold to the amount of minted rwaUSD; this leads to selling the user's collateralized assets in an auction to cover the debt.
LiquidationRouter (0x7Ea6031dD3AF19D61772E2Ec2E2177dD958d8F78) — Handles liquidation and redistribution of collaterals and debts in the system.
Mintable Token Owner (0x482EaBBA837170DaaE5De9AB288c5003EEC93C1a) — Implements the owner of the rwaUSD mintable token contract.
OwnerProxy (0xAF8164dEe8743B1D1Ec8130E15EE9Da70a79482d) — Allows the main owner to add fine-grained permissions to other operators (addresses).
SmartVaultProxy (0xdb6ee8d804Df3d93Ae92c02aB2fB377b5d9bA2B0) — Enables the execution of whitelisted methods authorized by the proxy owner across all smart vaults.
Smart Vault Deployer (0x25873c3d82dE1eD069B02feDA958eE9D3A5E69B4) — Deploys new instances of the Vault contract.
TokenToPriceFeed (0x489d04f2AF0a423d4031Aa14a7De3677AEC5dfA0) — Gets the latest market price for a specified token. Controls price feed configurations.
rwaUSD mintable token (0xDf6b509693B431BD289CBC442F4B78ddaCb2A1E0) — Burns/mints rwaUSD for the user.
VaultBorrowRate (0x64b8ddcFEd7b752A8BD18a2c1af22f9383C6bB33) — Calculates the borrow rate for a specified Vault.
VaultExtraSettings (0x00e0117427F547cEc271558b60D1973DC6F51f81) — Manages extra settings for a Vault instance: maximum redeemable percentage, debt treshold, redemption fee kickback.
VaultFactory (0xF2C2691Ea8937f5Dbf07E6FF69F40d80AFD8789C) — Manages the creation, configuration, and operations of Vaults with collateral and borrowing functionality.
VaultFactoryZapper (0x8A4C3Bc98dB9A2c8a1DaEF7695ee57262446883C) — Facilitates the creation of Vaults and manages their operations.
VaultFactoryHelperV2 (0x38ccdf424Bf32E6756C5b607c898A83A885B6915) — Provides various functions to retrieve information about vaults in a vault factory.
WLUMIA token (0xE891B5EE2F52E312038710b761EC165792AD25B1) — Burns/mints the wrapped LUMIA token for the user.
Workflow
To better understand the interaction of smart contracts and the flow, rely on the unit tests showing the whole flow.
Also, the following diagrams refer to the unit test and outlines, in broader details, the workflow and interaction:


Contract Methods Requiring Owner Privileges
The following methods require owner privileges across the Lumia rwaUSD CDP Protocol.
AuctionManager
Owner can configure core auction parameters.
Configuration Methods:
setVaultFactory(address _vaultFactory)
: Updates the vault factory addresssetAuctionDuration(uint256 _auctionDuration)
: Sets the duration for auctionssetLowestHF(uint256 _lowestHF)
: Sets the lowest acceptable health factor
LastResortLiquidation
Manages collateral and bad debt distribution.
Access Control:
addAllowed(address _allowed)
: Adds an address to the allowed operators listremoveAllowed(address _allowed)
: Removes an address from the allowed operators list
Collateral Management
withdrawCollateral(address _collateral, uint256 _amount, address _to)
: Withdraws collateral to specified addressdistributeBadDebt(address _vault, uint256 _amount)
: Distributes bad debt to a specific vault
TokenToPriceFeed
Controls price feed configurations.
Price Feed Management
setTokenPriceFeed(address _token, address _priceFeed, uint256 _mcr, uint256 _mlr, uint256 _borrowRate, uint256 _decimals)
:Sets or updates price feed parameters for a token
Controls Minimal Collateral Ratio (MCR)
Sets Minimal Liquidation Ratio (MLR)
Defines borrowing rates
transferOwnership(address newOwner)
: Transfers ownership of the contract
VaultFactory
Core configuration of the vault system.
System Parameters
setMaxTokensPerVault(uint256 _maxTokensPerVault)
: Maximum tokens allowed per vaultsetPriceFeed(address _priceFeed)
: Updates the price feed contract addresssetRedemptionRate(uint256 _redemptionRate)
: Sets the redemption fee ratesetBorrowRate(address _borrowRate)
: Sets the contract address for calculating borrow ratessetRedemptionHealthFactorLimit(uint256 _redemptionHealthFactorLimit)
: Sets minimum health factor for redemptionssetBorrowFeeRecipient(address _borrowFeeRecipient)
: Sets address receiving borrowing feessetRedemptionFeeRecipient(address _redemptionFeeRecipient)
: Sets address receiving redemption feessetDebtCeiling(uint256 _debtCeiling)
: Sets maximum total debt allowed in the systemsetMaxDebtPerWindow(uint256 _maxDebtPerWindow)
: Sets maximum debt that can be taken in a time windowsetDebtWindowSize(uint256 _debtWindowSize)
: Sets the size of the time window for debt limitssetCollateralCapacity(address _collateral, uint256 _capacity)
: Sets maximum amount of a specific collateral typesetLiquidationRouter(address _liquidationRouter)
: Updates the liquidation router addresssetVaultDeployer(address _vaultDeployer)
: Sets the contract responsible for deploying new vaults
VaultExtraSettings
Controls additional vault parameters.
Vault Parameters
setMaxRedeemablePercentage(uint256 _debtTreshold, uint256 _maxRedeemablePercentage)
: Sets maximum redeemable percentage and debt thresholdsetRedemptionKickback(uint256 _redemptionKickback)
: Sets redemption fee kickback rate
SmartVaultProxy
Manages permissions for smart vault operations.
Permission Management
addPermission(address targetAddress, bytes4 targetSignature)
: Whitelists method callsremovePermission(address targetAddress, bytes4 targetSignature)
: Removes whitelisted methodssetRewardFee(uint16 _newRewardFee)
: Sets reward fee percentagesetRewardCollector(address newRewardCollector)
: Updates reward collector addresstransferOwnership(address newOwner)
: Transfers ownership of the contract
OwnerProxy
Manages fine-grained permissions.
Permission Control
addPermission(address caller, address targetAddress, bytes4 targetSignature)
: Grants specific call permissionsremovePermission(uint256 permissionHash)
: Revokes specific permissionsexecuteOwner(address target, string memory func, bytes memory data)
: Executes privileged calls
MintableTokenOwner
Controls token minting privileges.
Token Management
transferTokenOwnership(address _newOwner)
: Transfers token ownershipaddMinter(address _newMinter)
: Adds new minting privilegesrevokeMinter(address _minter)
: Revokes minting privileges
FeeRecipientManager
Manages fee distribution.
Fee Management
claimRewards(address[] tokenFrom, address[] tokenTo, bool[] stable, uint256 amountOutMin)
: Claims and swaps rewardsforceWithdraw(address[] tokenFrom, address to)
: Emergency withdrawal of tokenssetfeeReceiver(address _feeReceiver)
: Updates fee receiver addresssetRouter(address _router)
: Updates the router contract address used for swaps
StabilityPool
Configuration
setVaultFactory(address _vaultFactory)
: Updates the vault factory addresssetA3AToken(address _a3aToken)
: Sets the A3A token address
veA3AStaking
Slashing Configuration
setSlashingDuration(uint256 _round, uint256 _duration)
: Sets duration for a slashing roundsetSlashingRate(uint256 _round, uint256 _rate)
: Sets rate for a slashing roundsetSlashingReturnForStabilityPool(uint256 _slashingReturnForStabilityPool)
: Sets percentage of slashed tokens returned to stability poolsetStabilityPool(address _stabilityPool)
: Sets the stability pool addresssetVaultFactory(address _vaultFactory)
: Updates the vault factory addresssetFactory(address _factory)
: Sets the factory contract addresssetStable(address _stable)
: Sets the stable token addresssetA3aToken(address _a3aToken)
: Sets the A3A token address
LiquidationRouter
Configuration
setVaultFactory(address _vaultFactory)
: Updates the vault factory addresssetStabilityPool(address _stabilityPool)
: Sets the stability pool addresssetAuctionManager(address _auctionManager)
: Sets the auction manager addresssetLastResortLiquidation(address _lastResortLiquidation)
: Sets the last resort liquidation address
Critical Considerations
Ownership Transfer
Most contracts inherit from OpenZeppelin's
Ownable
Use
transferOwnership()
carefully as it transfers all privilegesConsider using multi-sig wallets for ownership
Every contract that inherits from Ownable includes a
transferOwnership(address newOwner)
methodThis method should be used with extreme caution as it transfers complete control of the contract
Understanding OwnerProxy
The OwnerProxy contract provides a way to delegate specific contract method permissions to different addresses. This allows for fine-grained access control beyond simple ownership.
How to Grant Permissions
Adding Permissions (Owner only)
function addPermission( address caller, // The address being granted permission address targetAddress, // The contract address containing the method bytes4 targetSignature // The method signature to allow )
Example:
// To allow an address to call setMaxTokensPerVault on VaultFactory: const methodSignature = 'setMaxTokensPerVault(uint256)'; const encodedSignature = ethers.utils.id(methodSignature).slice(0, 10); // Get first 4 bytes await ownerProxy.addPermission( operatorAddress, vaultFactoryAddress, encodedSignature );
Revoking Permissions (Owner only)
function removePermission(uint256 permissionHash)
Executing Methods
For Whitelisted Operators
function execute( address target, // Contract address string memory func, // Function name with signature bytes memory data // Encoded parameters )
Example:
// To call setMaxTokensPerVault(5): const data = ethers.utils.defaultAbiCoder.encode(['uint256'], [5]); await ownerProxy.execute( vaultFactoryAddress, 'setMaxTokensPerVault(uint256)', data );
For Owner Only
function executeOwner( address target, string memory func, bytes memory data )
Only the owner can call this method
No permission check is performed
Can execute any method on any contract
Permission Management
Permissions are stored as hashes combining caller, target, and method signature
Each permission must be explicitly granted
Permissions can be revoked individually
Owner can execute any method without needing explicit permission
Best Practices
When Granting Permissions
Verify the target contract address carefully
Double-check method signatures
Test permissions with small operations first
When Executing Methods
Verify encoded parameters before execution
Use helper functions to encode data correctly
Keep track of granted permissions
Security Considerations
Maintain a list of all granted permissions
Regularly audit active permissions
Remove unused permissions promptly
Consider using timelock for sensitive operations
More Information
For more information, see the source code and more documented specific params in the GitHub repo.
Last updated
Was this helpful?