- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
251 lines
9.5 KiB
Solidity
251 lines
9.5 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
|
|
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
|
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
|
|
import "./interfaces/IeMoneyToken.sol";
|
|
import "./interfaces/IPolicyManager.sol";
|
|
import "./interfaces/IDebtRegistry.sol";
|
|
import "./interfaces/IComplianceRegistry.sol";
|
|
import "./errors/TokenErrors.sol";
|
|
import "./libraries/ReasonCodes.sol";
|
|
|
|
/**
|
|
* @title eMoneyToken
|
|
* @notice Restricted ERC-20 token with policy-controlled transfers and lien enforcement
|
|
* @dev Implements UUPS upgradeable proxy pattern. All transfers are validated through PolicyManager.
|
|
* Supports two lien enforcement modes: hard freeze (blocks all transfers with liens) and encumbered
|
|
* (allows transfers up to freeBalance = balance - activeLienAmount).
|
|
*/
|
|
contract eMoneyToken is
|
|
Initializable,
|
|
ERC20Upgradeable,
|
|
AccessControlUpgradeable,
|
|
UUPSUpgradeable,
|
|
ReentrancyGuardUpgradeable,
|
|
IeMoneyToken
|
|
{
|
|
bytes32 public constant ISSUER_ROLE = keccak256("ISSUER_ROLE");
|
|
bytes32 public constant ENFORCEMENT_ROLE = keccak256("ENFORCEMENT_ROLE");
|
|
|
|
IPolicyManager public policyManager;
|
|
IDebtRegistry public debtRegistry;
|
|
IComplianceRegistry public complianceRegistry;
|
|
uint8 private _decimals;
|
|
bool private _inForceTransfer;
|
|
bool private _inClawback;
|
|
|
|
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
constructor() {
|
|
_disableInitializers();
|
|
}
|
|
|
|
/**
|
|
* @notice Initializes the token with configuration
|
|
* @dev Called once during proxy deployment. Can only be called once.
|
|
* @param name Token name (e.g., "eMoney Token")
|
|
* @param symbol Token symbol (e.g., "EMT")
|
|
* @param decimals_ Number of decimals (typically 18)
|
|
* @param issuer Address that will receive ISSUER_ROLE and DEFAULT_ADMIN_ROLE
|
|
* @param policyManager_ Address of PolicyManager contract
|
|
* @param debtRegistry_ Address of DebtRegistry contract
|
|
* @param complianceRegistry_ Address of ComplianceRegistry contract
|
|
*/
|
|
function initialize(
|
|
string calldata name,
|
|
string calldata symbol,
|
|
uint8 decimals_,
|
|
address issuer,
|
|
address policyManager_,
|
|
address debtRegistry_,
|
|
address complianceRegistry_
|
|
) external initializer {
|
|
__ERC20_init(name, symbol);
|
|
__AccessControl_init();
|
|
__UUPSUpgradeable_init();
|
|
__ReentrancyGuard_init();
|
|
|
|
_decimals = decimals_;
|
|
policyManager = IPolicyManager(policyManager_);
|
|
debtRegistry = IDebtRegistry(debtRegistry_);
|
|
complianceRegistry = IComplianceRegistry(complianceRegistry_);
|
|
|
|
_grantRole(DEFAULT_ADMIN_ROLE, issuer);
|
|
_grantRole(ISSUER_ROLE, issuer);
|
|
}
|
|
|
|
/**
|
|
* @notice Returns the number of decimals for the token
|
|
* @return Number of decimals (typically 18)
|
|
*/
|
|
function decimals() public view virtual override returns (uint8) {
|
|
return _decimals;
|
|
}
|
|
|
|
/**
|
|
* @notice Returns the free balance available for transfer (balance minus active encumbrances)
|
|
* @dev In encumbered mode, transfers are limited to freeBalance
|
|
* @param account Address to check
|
|
* @return Free balance (balanceOf - activeLienAmount, floored at 0)
|
|
*/
|
|
function freeBalanceOf(address account) external view override returns (uint256) {
|
|
uint256 balance = balanceOf(account);
|
|
uint256 encumbrance = debtRegistry.activeLienAmount(account);
|
|
return balance > encumbrance ? balance - encumbrance : 0;
|
|
}
|
|
|
|
/**
|
|
* @notice Internal hook that enforces transfer restrictions before updating balances
|
|
* @dev Overrides ERC20Upgradeable._update to add policy checks and lien enforcement.
|
|
* Skips checks for mint/burn operations (from/to == address(0)) and privileged operations
|
|
* (clawback, forceTransfer).
|
|
* @param from Sender address (address(0) for mints)
|
|
* @param to Recipient address (address(0) for burns)
|
|
* @param amount Transfer amount
|
|
*/
|
|
function _update(
|
|
address from,
|
|
address to,
|
|
uint256 amount
|
|
) internal virtual override {
|
|
// Skip checks for privileged operations (mint/burn internal transfers)
|
|
if (from == address(0) || to == address(0)) {
|
|
super._update(from, to, amount);
|
|
return;
|
|
}
|
|
|
|
// Skip all checks during clawback (bypasses everything)
|
|
if (_inClawback) {
|
|
super._update(from, to, amount);
|
|
return;
|
|
}
|
|
|
|
// Skip lien checks during forceTransfer (compliance already checked there)
|
|
if (_inForceTransfer) {
|
|
super._update(from, to, amount);
|
|
return;
|
|
}
|
|
|
|
// Check policy manager
|
|
(bool allowed, bytes32 reasonCode) = policyManager.canTransfer(address(this), from, to, amount);
|
|
if (!allowed) {
|
|
revert TransferBlocked(reasonCode, from, to, amount);
|
|
}
|
|
|
|
// Check lien mode enforcement
|
|
uint8 mode = policyManager.lienMode(address(this));
|
|
if (mode == 1) {
|
|
// Hard freeze mode: any active lien blocks all transfers
|
|
if (debtRegistry.hasActiveLien(from)) {
|
|
revert TransferBlocked(ReasonCodes.LIEN_BLOCK, from, to, amount);
|
|
}
|
|
} else if (mode == 2) {
|
|
// Encumbered mode: allow transfers up to freeBalance
|
|
uint256 encumbrance = debtRegistry.activeLienAmount(from);
|
|
uint256 balance = balanceOf(from);
|
|
uint256 freeBalance = balance > encumbrance ? balance - encumbrance : 0;
|
|
if (amount > freeBalance) {
|
|
revert TransferBlocked(ReasonCodes.INSUFF_FREE_BAL, from, to, amount);
|
|
}
|
|
}
|
|
// mode == 0: no lien enforcement
|
|
|
|
super._update(from, to, amount);
|
|
}
|
|
|
|
/**
|
|
* @notice Mints new tokens to an account
|
|
* @dev Requires ISSUER_ROLE. Bypasses all transfer restrictions (mint operation).
|
|
* @param to Recipient address
|
|
* @param amount Amount to mint
|
|
* @param reasonCode Reason code for the mint operation (e.g., ReasonCodes.OK)
|
|
*/
|
|
function mint(address to, uint256 amount, bytes32 reasonCode) external override onlyRole(ISSUER_ROLE) nonReentrant {
|
|
_mint(to, amount);
|
|
emit Minted(to, amount, reasonCode);
|
|
}
|
|
|
|
/**
|
|
* @notice Burns tokens from an account
|
|
* @dev Requires ISSUER_ROLE. Bypasses all transfer restrictions (burn operation).
|
|
* @param from Account to burn from
|
|
* @param amount Amount to burn
|
|
* @param reasonCode Reason code for the burn operation (e.g., ReasonCodes.OK)
|
|
*/
|
|
function burn(address from, uint256 amount, bytes32 reasonCode) external override onlyRole(ISSUER_ROLE) nonReentrant {
|
|
_burn(from, amount);
|
|
emit Burned(from, amount, reasonCode);
|
|
}
|
|
|
|
/**
|
|
* @notice Clawback transfers tokens, bypassing all restrictions
|
|
* @dev Requires ENFORCEMENT_ROLE. Bypasses all checks including liens, compliance, and policy.
|
|
* Used for emergency recovery or enforcement actions.
|
|
* @param from Source address
|
|
* @param to Destination address
|
|
* @param amount Amount to transfer
|
|
* @param reasonCode Reason code for the clawback operation
|
|
*/
|
|
function clawback(
|
|
address from,
|
|
address to,
|
|
uint256 amount,
|
|
bytes32 reasonCode
|
|
) external override onlyRole(ENFORCEMENT_ROLE) nonReentrant {
|
|
// Clawback bypasses all checks including liens and compliance
|
|
_inClawback = true;
|
|
_transfer(from, to, amount);
|
|
_inClawback = false;
|
|
emit Clawback(from, to, amount, reasonCode);
|
|
}
|
|
|
|
/**
|
|
* @notice Force transfer bypasses liens but enforces compliance
|
|
* @dev Requires ENFORCEMENT_ROLE. Bypasses lien enforcement but still checks compliance.
|
|
* Used when liens need to be bypassed but compliance must still be enforced.
|
|
* @param from Source address
|
|
* @param to Destination address
|
|
* @param amount Amount to transfer
|
|
* @param reasonCode Reason code for the force transfer operation
|
|
*/
|
|
function forceTransfer(
|
|
address from,
|
|
address to,
|
|
uint256 amount,
|
|
bytes32 reasonCode
|
|
) external override onlyRole(ENFORCEMENT_ROLE) nonReentrant {
|
|
// ForceTransfer bypasses liens but still enforces compliance
|
|
// Check compliance
|
|
if (!complianceRegistry.isAllowed(from)) {
|
|
revert FromNotCompliant(from);
|
|
}
|
|
if (!complianceRegistry.isAllowed(to)) {
|
|
revert ToNotCompliant(to);
|
|
}
|
|
if (complianceRegistry.isFrozen(from)) {
|
|
revert FromFrozen(from);
|
|
}
|
|
if (complianceRegistry.isFrozen(to)) {
|
|
revert ToFrozen(to);
|
|
}
|
|
|
|
// Set flag to bypass lien checks in _update
|
|
_inForceTransfer = true;
|
|
_transfer(from, to, amount);
|
|
_inForceTransfer = false;
|
|
|
|
emit ForcedTransfer(from, to, amount, reasonCode);
|
|
}
|
|
|
|
/**
|
|
* @notice Authorizes an upgrade to a new implementation
|
|
* @dev Internal function required by UUPSUpgradeable. Only DEFAULT_ADMIN_ROLE can authorize upgrades.
|
|
* @param newImplementation Address of the new implementation contract
|
|
*/
|
|
function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) {}
|
|
}
|
|
|