- 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
87 lines
2.4 KiB
Solidity
87 lines
2.4 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
import "@openzeppelin/contracts/utils/Pausable.sol";
|
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
|
import "../compliance/LegallyCompliantBase.sol";
|
|
|
|
/**
|
|
* @title CompliantMonetaryUnitToken
|
|
* @notice Generic GRU monetary-unit token for non-ISO units such as BTC.
|
|
* @dev Mirrors the compliant fiat token controls while keeping monetary-unit metadata separate
|
|
* from ISO-4217 and commodity classifications.
|
|
*/
|
|
contract CompliantMonetaryUnitToken is ERC20, Pausable, Ownable, LegallyCompliantBase {
|
|
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
|
|
|
uint8 private immutable _decimalsStorage;
|
|
string private _unitCode;
|
|
|
|
constructor(
|
|
string memory name_,
|
|
string memory symbol_,
|
|
uint8 decimals_,
|
|
string memory unitCode_,
|
|
address initialOwner,
|
|
address admin,
|
|
uint256 initialSupply
|
|
)
|
|
ERC20(name_, symbol_)
|
|
Ownable(initialOwner)
|
|
LegallyCompliantBase(admin)
|
|
{
|
|
_decimalsStorage = decimals_;
|
|
_unitCode = unitCode_;
|
|
_grantRole(MINTER_ROLE, initialOwner);
|
|
if (initialSupply > 0) {
|
|
_mint(msg.sender, initialSupply);
|
|
}
|
|
}
|
|
|
|
function decimals() public view override returns (uint8) {
|
|
return _decimalsStorage;
|
|
}
|
|
|
|
function unitCode() external view returns (string memory) {
|
|
return _unitCode;
|
|
}
|
|
|
|
function isMonetaryUnit() external pure returns (bool) {
|
|
return true;
|
|
}
|
|
|
|
function _update(
|
|
address from,
|
|
address to,
|
|
uint256 amount
|
|
) internal override whenNotPaused {
|
|
super._update(from, to, amount);
|
|
if (from != address(0) && to != address(0)) {
|
|
bytes32 legalRefHash = _generateLegalReferenceHash(
|
|
from,
|
|
to,
|
|
amount,
|
|
abi.encodePacked(symbol(), " Transfer")
|
|
);
|
|
emit ValueTransferDeclared(from, to, amount, legalRefHash);
|
|
}
|
|
}
|
|
|
|
function pause() public onlyOwner {
|
|
_pause();
|
|
}
|
|
|
|
function unpause() public onlyOwner {
|
|
_unpause();
|
|
}
|
|
|
|
function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
|
|
_mint(to, amount);
|
|
}
|
|
|
|
function burn(uint256 amount) public {
|
|
_burn(msg.sender, amount);
|
|
}
|
|
}
|