Files
smom-dbis-138/contracts/iso4217w/ISO4217WToken.sol
defiQUG 76aa419320 feat: bridges, PMM, flash workflow, token-aggregation, and deployment docs
- CCIP/trustless bridge contracts, GRU tokens, DEX/PMM tests, reserve vault.
- Token-aggregation service routes, planner, chain config, relay env templates.
- Config snapshots and multi-chain deployment markdown updates.
- gitignore services/btc-intake/dist/ (tsc output); do not track dist.

Run forge build && forge test before deploy (large solc graph).

Made-with: Cursor
2026-04-07 23:40:52 -07:00

247 lines
8.4 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "../vendor/openzeppelin/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../vendor/openzeppelin/ReentrancyGuardUpgradeable.sol";
import "./interfaces/IISO4217WToken.sol";
import "./libraries/ISO4217WCompliance.sol";
/**
* @title ISO4217WToken
* @notice ISO-4217 W token (e.g., USDW, EURW, GBPW) - M1 eMoney token
* @dev Represents 1:1 redeemable digital claim on fiat currency
*
* COMPLIANCE:
* - Classification: M1 eMoney
* - Legal Tender: NO
* - Synthetic / Reserve Unit: NO
* - Commodity-Backed: NO
* - Money Multiplier: m = 1.0 (hard-fixed, no fractional reserve)
* - Backing: 1:1 with fiat currency in segregated custodial accounts
* - GRU Isolation: Direct/indirect GRU conversion prohibited
*/
contract ISO4217WToken is
IISO4217WToken,
Initializable,
ERC20Upgradeable,
AccessControlUpgradeable,
UUPSUpgradeable,
ReentrancyGuardUpgradeable
{
using ISO4217WCompliance for *;
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
bytes32 public constant RESERVE_UPDATE_ROLE = keccak256("RESERVE_UPDATE_ROLE");
string private _currencyCode; // ISO-4217 code (e.g., "USD")
uint8 private _decimals; // Token decimals (typically 2 for fiat)
uint256 private _verifiedReserve; // Verified reserve balance in base currency units
address private _custodian;
address private _mintController;
address private _burnController;
address private _complianceGuard;
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initialize the ISO-4217 W token
* @param name Token name (e.g., "USDW Token")
* @param symbol Token symbol (e.g., "USDW")
* @param currencyCode_ ISO-4217 currency code (e.g., "USD")
* @param decimals_ Token decimals (typically 2 for fiat)
* @param custodian_ Custodian address
* @param mintController_ Mint controller address
* @param burnController_ Burn controller address
* @param complianceGuard_ Compliance guard address
* @param admin Admin address
*/
function initialize(
string memory name,
string memory symbol,
string memory currencyCode_,
uint8 decimals_,
address custodian_,
address mintController_,
address burnController_,
address complianceGuard_,
address admin
) external initializer {
__ERC20_init(name, symbol);
__AccessControl_init();
__UUPSUpgradeable_init();
__ReentrancyGuard_init();
// Validate ISO-4217 format
require(
ISO4217WCompliance.isValidISO4217Format(currencyCode_),
"ISO4217WToken: invalid ISO-4217 format"
);
// Validate token symbol matches <CCC>W pattern
require(
ISO4217WCompliance.validateTokenSymbol(currencyCode_, symbol),
"ISO4217WToken: token symbol must be <CCC>W"
);
// Validate GRU isolation
require(
!ISO4217WCompliance.violatesGRUIsolation(currencyCode_),
"ISO4217WToken: GRU isolation violation"
);
require(custodian_ != address(0), "ISO4217WToken: zero custodian");
require(mintController_ != address(0), "ISO4217WToken: zero mint controller");
require(burnController_ != address(0), "ISO4217WToken: zero burn controller");
require(complianceGuard_ != address(0), "ISO4217WToken: zero compliance guard");
_currencyCode = currencyCode_;
_decimals = decimals_;
_custodian = custodian_;
_mintController = mintController_;
_burnController = burnController_;
_complianceGuard = complianceGuard_;
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(MINTER_ROLE, mintController_);
_grantRole(BURNER_ROLE, burnController_);
}
/**
* @notice Get the ISO-4217 currency code this token represents
* @return currencyCode 3-letter ISO-4217 code
*/
function currencyCode() external view override returns (string memory) {
return _currencyCode;
}
/**
* @notice Override totalSupply to resolve multiple inheritance conflict
* @return Total supply of tokens
*/
function totalSupply() public view override(ERC20Upgradeable, IISO4217WToken) returns (uint256) {
return super.totalSupply();
}
/**
* @notice Get verified reserve balance
* @return reserveBalance Reserve balance in base currency units
*/
function verifiedReserve() external view override returns (uint256) {
return _verifiedReserve;
}
/**
* @notice Check if reserves are sufficient
* @dev Reserve MUST be >= supply (enforcing 1:1 backing)
* @return isSufficient True if verifiedReserve >= totalSupply
*/
function isReserveSufficient() external view override returns (bool) {
return ISO4217WCompliance.isReserveSufficient(_verifiedReserve, totalSupply());
}
/**
* @notice Get custodian address
*/
function custodian() external view override returns (address) {
return _custodian;
}
/**
* @notice Get mint controller address
*/
function mintController() external view override returns (address) {
return _mintController;
}
/**
* @notice Get burn controller address
*/
function burnController() external view override returns (address) {
return _burnController;
}
/**
* @notice Get compliance guard address
*/
function complianceGuard() external view override returns (address) {
return _complianceGuard;
}
/**
* @notice Update verified reserve (oracle/attestation)
* @dev Can only be called by authorized reserve update role
* @param newReserve New reserve balance
*/
function updateVerifiedReserve(uint256 newReserve) external onlyRole(RESERVE_UPDATE_ROLE) {
uint256 currentSupply = totalSupply();
// Enforce money multiplier = 1.0
// Reserve MUST be >= supply (1:1 backing or better)
if (newReserve < currentSupply) {
emit ReserveInsufficient(newReserve, currentSupply);
// Do not revert - allow flagging for monitoring
}
_verifiedReserve = newReserve;
emit ReserveUpdated(newReserve, block.timestamp);
}
/**
* @notice Mint tokens (only by mint controller)
* @param to Recipient address
* @param amount Amount to mint
*/
function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) nonReentrant {
require(to != address(0), "ISO4217WToken: zero address");
require(amount > 0, "ISO4217WToken: zero amount");
uint256 currentSupply = totalSupply();
uint256 newSupply = currentSupply + amount;
// Enforce money multiplier = 1.0
// Reserve MUST be >= new supply (1:1 backing)
require(
_verifiedReserve >= newSupply,
"ISO4217WToken: reserve insufficient - money multiplier violation"
);
_mint(to, amount);
emit Minted(to, amount, _currencyCode);
}
/**
* @notice Burn tokens (only by burn controller)
* @param from Source address
* @param amount Amount to burn
*/
function burn(address from, uint256 amount) external onlyRole(BURNER_ROLE) nonReentrant {
require(amount > 0, "ISO4217WToken: zero amount");
_burn(from, amount);
emit Burned(from, amount, _currencyCode);
}
/**
* @notice Override decimals (typically 2 for fiat currencies)
*/
function decimals() public view virtual override returns (uint8) {
return _decimals;
}
/**
* @notice Authorize upgrade (UUPS)
* @dev Only non-monetary components may be upgraded
*/
function _authorizeUpgrade(address newImplementation) internal override onlyRole(DEFAULT_ADMIN_ROLE) {
// In production, add checks to ensure monetary logic is immutable
// Only allow upgrades to non-monetary components
}
}