Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m20s
CI/CD Pipeline / Security Scanning (push) Successful in 2m48s
CI/CD Pipeline / Lint and Format (push) Failing after 47s
CI/CD Pipeline / Terraform Validation (push) Failing after 28s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 30s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 44s
Validation / validate-genesis (push) Successful in 37s
Validation / validate-terraform (push) Failing after 42s
Validation / validate-kubernetes (push) Failing after 12s
Validation / validate-smart-contracts (push) Failing after 16m44s
Validation / validate-security (push) Failing after 20s
Validation / validate-documentation (push) Failing after 19s
Verify Deployment / Verify Deployment (push) Failing after 1m21s
Use dedicated cusdc_v2/cusdt_v2 SVG paths so GRU token alignment validation passes.
141 lines
5.0 KiB
Solidity
141 lines
5.0 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
import "@openzeppelin/contracts/access/AccessControl.sol";
|
|
import "./interfaces/IDebtRegistry.sol";
|
|
import "./errors/RegistryErrors.sol";
|
|
|
|
/**
|
|
* @title DebtRegistry
|
|
* @notice Manages liens (encumbrances) on accounts for debt/liability enforcement
|
|
* @dev Supports multiple liens per account with aggregation. Uses hard expiry policy - expiry is informational and requires explicit release.
|
|
* Liens are used by eMoneyToken to enforce transfer restrictions (hard freeze or encumbered modes).
|
|
*/
|
|
contract DebtRegistry is IDebtRegistry, AccessControl {
|
|
bytes32 public constant DEBT_AUTHORITY_ROLE = keccak256("DEBT_AUTHORITY_ROLE");
|
|
|
|
uint256 private _nextLienId;
|
|
mapping(uint256 => Lien) private _liens;
|
|
mapping(address => uint256) private _activeEncumbrance;
|
|
mapping(address => uint256) private _activeLienCount;
|
|
|
|
/**
|
|
* @notice Initializes the DebtRegistry with an admin address
|
|
* @param admin Address that will receive DEFAULT_ADMIN_ROLE
|
|
*/
|
|
constructor(address admin) {
|
|
_grantRole(DEFAULT_ADMIN_ROLE, admin);
|
|
}
|
|
|
|
/**
|
|
* @notice Returns the total active encumbrance (sum of all active lien amounts) for a debtor
|
|
* @param debtor Address to check
|
|
* @return Total amount encumbered across all active liens
|
|
*/
|
|
function activeLienAmount(address debtor) external view override returns (uint256) {
|
|
return _activeEncumbrance[debtor];
|
|
}
|
|
|
|
/**
|
|
* @notice Returns whether a debtor has any active liens
|
|
* @param debtor Address to check
|
|
* @return true if debtor has at least one active lien, false otherwise
|
|
*/
|
|
function hasActiveLien(address debtor) external view override returns (bool) {
|
|
return _activeLienCount[debtor] > 0;
|
|
}
|
|
|
|
/**
|
|
* @notice Returns the number of active liens for a debtor
|
|
* @param debtor Address to check
|
|
* @return Count of active liens
|
|
*/
|
|
function activeLienCount(address debtor) external view override returns (uint256) {
|
|
return _activeLienCount[debtor];
|
|
}
|
|
|
|
/**
|
|
* @notice Returns full lien information for a given lien ID
|
|
* @param lienId The lien identifier
|
|
* @return Lien struct containing all lien details
|
|
*/
|
|
function getLien(uint256 lienId) external view override returns (Lien memory) {
|
|
return _liens[lienId];
|
|
}
|
|
|
|
/**
|
|
* @notice Places a new lien on a debtor account
|
|
* @dev Requires DEBT_AUTHORITY_ROLE. Increments active encumbrance and lien count.
|
|
* @param debtor Address to place lien on
|
|
* @param amount Amount to encumber
|
|
* @param expiry Expiry timestamp (0 = no expiry). Note: expiry is informational; explicit release required.
|
|
* @param priority Priority level (0-255)
|
|
* @param reasonCode Reason code for the lien (e.g., ReasonCodes.LIEN_BLOCK)
|
|
* @return lienId The assigned lien identifier
|
|
*/
|
|
function placeLien(
|
|
address debtor,
|
|
uint256 amount,
|
|
uint64 expiry,
|
|
uint8 priority,
|
|
bytes32 reasonCode
|
|
) external override onlyRole(DEBT_AUTHORITY_ROLE) returns (uint256 lienId) {
|
|
if (debtor == address(0)) revert DebtZeroDebtor();
|
|
if (amount == 0) revert DebtZeroAmount();
|
|
|
|
lienId = _nextLienId++;
|
|
_liens[lienId] = Lien({
|
|
debtor: debtor,
|
|
amount: amount,
|
|
expiry: expiry,
|
|
priority: priority,
|
|
authority: msg.sender,
|
|
reasonCode: reasonCode,
|
|
active: true
|
|
});
|
|
|
|
_activeEncumbrance[debtor] += amount;
|
|
_activeLienCount[debtor]++;
|
|
|
|
emit LienPlaced(lienId, debtor, amount, expiry, priority, msg.sender, reasonCode);
|
|
}
|
|
|
|
/**
|
|
* @notice Reduces the amount of an active lien
|
|
* @dev Requires DEBT_AUTHORITY_ROLE. Updates active encumbrance accordingly.
|
|
* @param lienId The lien identifier
|
|
* @param reduceBy Amount to reduce the lien by (must not exceed current lien amount)
|
|
*/
|
|
function reduceLien(uint256 lienId, uint256 reduceBy) external override onlyRole(DEBT_AUTHORITY_ROLE) {
|
|
Lien storage lien = _liens[lienId];
|
|
if (!lien.active) revert DebtLienNotActive(lienId);
|
|
|
|
uint256 oldAmount = lien.amount;
|
|
if (reduceBy > oldAmount) revert DebtReduceByExceedsAmount(lienId, reduceBy, oldAmount);
|
|
|
|
uint256 newAmount = oldAmount - reduceBy;
|
|
lien.amount = newAmount;
|
|
|
|
_activeEncumbrance[lien.debtor] -= reduceBy;
|
|
|
|
emit LienReduced(lienId, reduceBy, newAmount);
|
|
}
|
|
|
|
/**
|
|
* @notice Releases an active lien, removing it from active tracking
|
|
* @dev Requires DEBT_AUTHORITY_ROLE. Decrements active encumbrance and lien count.
|
|
* @param lienId The lien identifier to release
|
|
*/
|
|
function releaseLien(uint256 lienId) external override onlyRole(DEBT_AUTHORITY_ROLE) {
|
|
Lien storage lien = _liens[lienId];
|
|
if (!lien.active) revert DebtLienNotActive(lienId);
|
|
|
|
lien.active = false;
|
|
_activeEncumbrance[lien.debtor] -= lien.amount;
|
|
_activeLienCount[lien.debtor]--;
|
|
|
|
emit LienReleased(lienId);
|
|
}
|
|
}
|
|
|