// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/Script.sol"; import {RWATokenRegistry} from "../../../contracts/rwa/RWATokenRegistry.sol"; import {RWATokenFactory} from "../../../contracts/rwa/RWATokenFactory.sol"; import {IRWATokenFactory} from "../../../contracts/rwa/IRWATokenFactory.sol"; import {RWAToken} from "../../../contracts/rwa/RWAToken.sol"; import {UniversalAssetRegistry} from "../../../contracts/registry/UniversalAssetRegistry.sol"; /** * @title DeployRWATokenFactory138 * @notice Deploy RWATokenRegistry + RWATokenFactory and optionally all five Li* M00 indices on Chain 138. * @dev Taxonomy: config/rwa-capital-markets-taxonomy.v1.json. Not for c* eMoney (use DeployCompliantFiatTokens). * * Env: * PRIVATE_KEY, OWNER, ADMIN, COMPLIANCE_ADMIN, INDEX_PUBLISHER * UNIVERSAL_ASSET_REGISTRY (optional; pass address for factory wiring only) * REGISTER_IN_UAR — default 0; use RegisterRWAIndicesInUAR138.s.sol after REGISTRAR_ROLE grant * DEPLOY_LI_INDICES=1 to deploy LiXAU, LiPMG, LiBMG1–3 in one run * RWA_INITIAL_INDEX_VALUE (default 1e6 = 1.0 at 6 decimals) * RWA_INITIAL_SUPPLY (default 0 — mint via policy after index committee attestation) * RWA_METHODOLOGY_HASH (required for DEPLOY_LI_INDICES; default from m00-li-index-methodology-hash.v1.json via cast) * MULTISIG_ADMIN (optional) — grant factory DEPLOYER + registry/UAR REGISTRAR to multisig */ contract DeployRWATokenFactory138 is Script { uint8 constant DECIMALS = 6; uint256 constant DEFAULT_INDEX_VALUE = 1_000_000; function run() external { uint256 pk = vm.envUint("PRIVATE_KEY"); address deployer = vm.addr(pk); address owner = vm.envOr("OWNER", deployer); address compliance = vm.envOr("COMPLIANCE_ADMIN", deployer); address publisher = vm.envOr("INDEX_PUBLISHER", deployer); address uar = vm.envOr("UNIVERSAL_ASSET_REGISTRY", address(0)); // UAR registration reverts if factory lacks REGISTRAR_ROLE — keep off during one-shot deploy. bool registerInUar = vm.envOr("REGISTER_IN_UAR", uint256(0)) != 0; require( !registerInUar || uar != address(0), "REGISTER_IN_UAR requires UNIVERSAL_ASSET_REGISTRY" ); uint256 initialIndexValue = vm.envOr("RWA_INITIAL_INDEX_VALUE", DEFAULT_INDEX_VALUE); uint256 initialSupply = vm.envOr("RWA_INITIAL_SUPPLY", uint256(0)); address multisig = vm.envOr("MULTISIG_ADMIN", address(0)); address governance = vm.envOr("GOVERNANCE_CONTROLLER", address(0)); vm.startBroadcast(pk); // Deployer holds DEFAULT_ADMIN during bootstrap so grants succeed in one broadcast. RWATokenRegistry registry = new RWATokenRegistry(deployer); RWATokenFactory factory = new RWATokenFactory(deployer, address(registry), uar); registry.grantRole(registry.REGISTRAR_ROLE(), address(factory)); if (registerInUar && uar != address(0)) { UniversalAssetRegistry(uar).grantRole( UniversalAssetRegistry(uar).REGISTRAR_ROLE(), address(factory) ); } if (multisig != address(0)) { factory.grantRole(factory.DEPLOYER_ROLE(), multisig); registry.grantRole(registry.REGISTRAR_ROLE(), multisig); } if (governance != address(0)) { factory.grantRole(factory.DEFAULT_ADMIN_ROLE(), governance); registry.grantRole(registry.DEFAULT_ADMIN_ROLE(), governance); } console.log("RWATokenRegistry", address(registry)); console.log("RWATokenFactory", address(factory)); if (vm.envOr("DEPLOY_LI_INDICES", uint256(0)) != 0) { bytes32 methodologyHash = _resolveMethodologyHash(); _deployAllLi( factory, owner, compliance, publisher, initialIndexValue, initialSupply, registerInUar, methodologyHash ); } vm.stopBroadcast(); } function _resolveMethodologyHash() internal view returns (bytes32) { string memory envHash = vm.envOr("RWA_METHODOLOGY_HASH", string("")); if (bytes(envHash).length > 0) { return vm.parseBytes32(envHash); } revert("RWA_METHODOLOGY_HASH required when DEPLOY_LI_INDICES=1"); } function _deployAllLi( RWATokenFactory factory, address owner, address compliance, address publisher, uint256 initialIndexValue, uint256 initialSupply, bool registerInUar, bytes32 methodologyHash ) internal { _deployLi( factory, owner, compliance, publisher, "LiXAU", "XAU Liquidity Index (M00)", "LiXAU", "Precious Metals", "Commodity Index", "Gold", initialIndexValue, initialSupply, registerInUar, methodologyHash ); _deployLi( factory, owner, compliance, publisher, "LiPMG", "Precious Metals Group Index (M00)", "LiPMG", "Precious Metals", "Basket Index", "Precious Metals", initialIndexValue, initialSupply, registerInUar, methodologyHash ); _deployLi( factory, owner, compliance, publisher, "LiBMG1", "Base Metals Group Index 1 (M00)", "LiBMG1", "Industrial Metals", "Basket Index", "Base Metals", initialIndexValue, initialSupply, registerInUar, methodologyHash ); _deployLi( factory, owner, compliance, publisher, "LiBMG2", "Base Metals Group Index 2 (M00)", "LiBMG2", "Industrial Metals", "Basket Index", "Battery Materials", initialIndexValue, initialSupply, registerInUar, methodologyHash ); _deployLi( factory, owner, compliance, publisher, "LiBMG3", "Base Metals Group Index 3 (M00)", "LiBMG3", "Industrial Metals", "Basket Index", "Building Metals", initialIndexValue, initialSupply, registerInUar, methodologyHash ); } function _deployLi( RWATokenFactory factory, address owner, address compliance, address publisher, string memory ticker, string memory name, string memory symbol, string memory assetGroup, string memory instrumentType, string memory underlying, uint256 initialIndexValue, uint256 initialSupply, bool registerInUar, bytes32 methodologyHash ) internal { address token = factory.deployRWAIndex( IRWATokenFactory.RWAProductConfig({ indexTicker: ticker, name: name, symbol: symbol, decimals: DECIMALS, assetClass: "Commodities", assetGroup: assetGroup, instrumentType: instrumentType, underlyingAsset: underlying, gruLayer: "M00", jurisdiction: "International", initialOwner: owner, complianceAdmin: compliance, indexPublisher: publisher, initialIndexValue: initialIndexValue, initialSupply: initialSupply, methodologyDocumentHash: methodologyHash, registerInUniversalAssetRegistry: registerInUar }) ); console.log(ticker, token); } }