WIP: Chain138 deployment scripts, flash receivers, HYBX OMNL recovery

This commit is contained in:
defiQUG
2026-06-02 06:09:44 -07:00
parent e1560a880b
commit f04a7cb7c8
35 changed files with 2279 additions and 83 deletions

View File

@@ -0,0 +1,74 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console} from "forge-std/Script.sol";
import {CWNavOracle} from "../contracts/cw-settlement/CWNavOracle.sol";
import {CWRedemptionQueue} from "../contracts/cw-settlement/CWRedemptionQueue.sol";
import {CWStabilityFund} from "../contracts/cw-settlement/CWStabilityFund.sol";
import {CWBuybackExecutor} from "../contracts/cw-settlement/CWBuybackExecutor.sol";
import {CWProtocolTreasury} from "../contracts/cw-settlement/CWProtocolTreasury.sol";
import {CWReserveVerifier} from "../contracts/bridge/integration/CWReserveVerifier.sol";
interface ICWMultiTokenBridgeL1Admin {
function setReserveVerifier(address newVerifier) external;
}
/**
* @title DeployCWReserveSettlementStack
* @notice Deploy NAV oracle, redemption queue, stability fund, buyback, treasury, and reserve verifier on Chain 138.
*
* Env:
* PRIVATE_KEY, RPC_URL_138
* CW_L1_BRIDGE (default 0x152ed3e9912161b76bdfd368d0c84b7c31c10de7)
* CW_RESERVE_SYSTEM (default 0x607e97cD626f209facfE48c1464815DDE15B5093)
* CW_CANONICAL_USDT / CW_CANONICAL_USDC
* CW_ATTACH_VERIFIER_TO_L1=1
*/
contract DeployCWReserveSettlementStack is Script {
function run() external {
uint256 privateKey = vm.envUint("PRIVATE_KEY");
address admin = vm.addr(privateKey);
address l1Bridge = vm.envOr("CW_L1_BRIDGE", address(0x152eD3e9912161b76BDFd368D0C84B7C31C10dE7));
address reserveSystem = vm.envOr("CW_RESERVE_SYSTEM", address(0x607e97cD626f209facfE48c1464815DDE15B5093));
address canonicalUSDT = vm.envOr("CW_CANONICAL_USDT", address(0x93E66202A11B1772E55407B32B44e5Cd8eda7f22));
address canonicalUSDC = vm.envOr("CW_CANONICAL_USDC", address(0xf22258f57794CC8E06237084b353Ab30fFfa640b));
bool attachVerifier = vm.envOr("CW_ATTACH_VERIFIER_TO_L1", uint256(0)) == 1;
bool skipVerifierDeploy = vm.envOr("CW_SKIP_RESERVE_VERIFIER", uint256(1)) == 1;
vm.startBroadcast(privateKey);
address verifierAddr;
if (skipVerifierDeploy) {
verifierAddr = address(0);
} else {
CWReserveVerifier verifier = new CWReserveVerifier(admin, l1Bridge, address(0), reserveSystem);
verifierAddr = address(verifier);
if (attachVerifier) {
ICWMultiTokenBridgeL1Admin(l1Bridge).setReserveVerifier(verifierAddr);
}
verifier.configureToken(canonicalUSDT, address(0), false, false, false);
verifier.configureToken(canonicalUSDC, address(0), false, false, false);
}
CWNavOracle navOracle = new CWNavOracle(admin, l1Bridge, reserveSystem);
CWRedemptionQueue redemptionQueue = new CWRedemptionQueue(admin);
CWStabilityFund stabilityFund = new CWStabilityFund(admin);
CWProtocolTreasury treasury = new CWProtocolTreasury(admin, address(0));
CWBuybackExecutor buyback = new CWBuybackExecutor(admin, verifierAddr, address(treasury));
treasury.setBuybackExecutor(address(buyback));
navOracle.configureToken(canonicalUSDT, address(0));
navOracle.configureToken(canonicalUSDC, address(0));
vm.stopBroadcast();
console.log("CWReserveVerifier:", verifierAddr);
console.log("CWNavOracle:", address(navOracle));
console.log("CWRedemptionQueue:", address(redemptionQueue));
console.log("CWStabilityFund:", address(stabilityFund));
console.log("CWProtocolTreasury:", address(treasury));
console.log("CWBuybackExecutor:", address(buyback));
}
}

View File

@@ -0,0 +1,129 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Script, console} from "forge-std/Script.sol";
import "../../../contracts/bridge/trustless/EnhancedSwapRouterV2.sol";
import "../../../contracts/bridge/trustless/RouteTypesV2.sol";
/// @notice Enable UniV3, Balancer, and Curve routes on live EnhancedSwapRouterV2 (Chain 138).
/// Adapters must already be set via initial deploy; this script only enables providers + routes.
contract ConfigureEnhancedSwapRouterV2MultiVenue is Script {
address constant DEFAULT_ROUTER_V2 = 0xa421706768aEB7fafA2D912C5E10824eF3437ad4;
address constant CHAIN138_WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address constant CHAIN138_USDT = 0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1;
address constant CHAIN138_USDC = 0x71D6687F38b93CCad569Fa6352c876eea967201b;
address constant CHAIN138_cUSDT = 0x93E66202A11B1772E55407B32B44e5Cd8eda7f22;
address constant CHAIN138_cUSDC = 0xf22258f57794CC8E06237084b353Ab30fFfa640b;
address constant CHAIN138_DODO_PROVIDER = 0x3f729632E9553EBacCdE2e9b4c8F2B285b014F2e;
address constant CHAIN138_POOL_CUSDTCUSDC = 0x9e89bAe009adf128782E19e8341996c596ac40dC;
address constant CHAIN138_POOL_CUSDTUSDT = 0x866Cb44b59303d8dc5f4F9E3E7A8e8b0bf238d66;
address constant CHAIN138_POOL_CUSDCUSDC = 0xc39B7D0F40838cbFb54649d327f49a6DAC964062;
address constant CHAIN138_POOL_WETH_USDT = 0xe227F6C0520c0c6E8786fE56Fa76c4914F861533;
address constant CHAIN138_POOL_WETH_USDC = 0xb53A0508940b1Ff90F1AAD4f6cb50a7012Fe5593;
address constant UNISWAP_V3_ROUTER = 0xde9cD8ee2811E6E64a41D5F68Be315d33995975E;
address constant UNISWAP_QUOTER = 0x6abbB1CEb2468e748a03A00CD6aA9BFE893AFa1f;
address constant BALANCER_VAULT = 0x96423d7C1727698D8a25EbFB88131e9422d1a3C3;
bytes32 constant BALANCER_WETH_USDT_POOL_ID =
0x877cd220759e8c94b82f55450c85d382ae06856c426b56d93092a420facbc324;
bytes32 constant BALANCER_WETH_USDC_POOL_ID =
0xd8dfb18a6baf9b29d8c2dbd74639db87ac558af120df5261dab8e2a5de69013b;
address constant CURVE_3POOL = 0xE440Ec15805BE4C7BabCD17A63B8C8A08a492e0f;
function run() external {
require(block.chainid == 138, "ConfigureEnhancedSwapRouterV2MultiVenue: Chain 138 only");
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address routerAddress = vm.envOr("ENHANCED_SWAP_ROUTER_V2_ADDRESS", DEFAULT_ROUTER_V2);
EnhancedSwapRouterV2 router = EnhancedSwapRouterV2(payable(routerAddress));
uint24 wethUsdtFee = uint24(vm.envOr("UNISWAP_V3_WETH_USDT_FEE", uint256(3000)));
uint24 wethUsdcFee = uint24(vm.envOr("UNISWAP_V3_WETH_USDC_FEE", uint256(500)));
vm.startBroadcast(deployerPrivateKey);
_setDodoPair(router, CHAIN138_cUSDT, CHAIN138_cUSDC, CHAIN138_DODO_PROVIDER, CHAIN138_POOL_CUSDTCUSDC);
_setDodoPair(router, CHAIN138_cUSDT, CHAIN138_USDT, CHAIN138_DODO_PROVIDER, CHAIN138_POOL_CUSDTUSDT);
_setDodoPair(router, CHAIN138_cUSDC, CHAIN138_USDC, CHAIN138_DODO_PROVIDER, CHAIN138_POOL_CUSDCUSDC);
_setDodoPair(router, CHAIN138_WETH, CHAIN138_USDT, CHAIN138_DODO_PROVIDER, CHAIN138_POOL_WETH_USDT);
_setDodoPair(router, CHAIN138_WETH, CHAIN138_USDC, CHAIN138_DODO_PROVIDER, CHAIN138_POOL_WETH_USDC);
_setUniswapPair(router, CHAIN138_WETH, CHAIN138_USDT, UNISWAP_V3_ROUTER, UNISWAP_QUOTER, wethUsdtFee);
_setUniswapPair(router, CHAIN138_WETH, CHAIN138_USDC, UNISWAP_V3_ROUTER, UNISWAP_QUOTER, wethUsdcFee);
_setBalancerPair(router, CHAIN138_WETH, CHAIN138_USDT, BALANCER_VAULT, BALANCER_WETH_USDT_POOL_ID);
_setBalancerPair(router, CHAIN138_WETH, CHAIN138_USDC, BALANCER_VAULT, BALANCER_WETH_USDC_POOL_ID);
_setCurvePair(router, CHAIN138_USDT, CHAIN138_USDC, CURVE_3POOL, 0, 1, false);
router.setProviderEnabled(RouteTypesV2.Provider.Dodo, true);
router.setProviderEnabled(RouteTypesV2.Provider.UniswapV3, true);
router.setProviderEnabled(RouteTypesV2.Provider.Balancer, true);
router.setProviderEnabled(RouteTypesV2.Provider.Curve, true);
router.setProviderEnabled(RouteTypesV2.Provider.OneInch, false);
router.setProviderEnabled(RouteTypesV2.Provider.Partner, false);
router.setProviderEnabled(RouteTypesV2.Provider.DodoV3, false);
RouteTypesV2.Provider[] memory providers = new RouteTypesV2.Provider[](4);
providers[0] = RouteTypesV2.Provider.Dodo;
providers[1] = RouteTypesV2.Provider.UniswapV3;
providers[2] = RouteTypesV2.Provider.Balancer;
providers[3] = RouteTypesV2.Provider.Curve;
router.setRoutingConfig(0, providers);
router.setRoutingConfig(1, providers);
router.setRoutingConfig(2, providers);
vm.stopBroadcast();
console.log("EnhancedSwapRouterV2 multi-venue configured:", routerAddress);
}
function _setDodoPair(EnhancedSwapRouterV2 router, address tokenA, address tokenB, address target, address pool)
internal
{
bytes memory providerData = abi.encode(pool);
router.setProviderRoute(tokenA, tokenB, RouteTypesV2.Provider.Dodo, target, providerData, true);
router.setProviderRoute(tokenB, tokenA, RouteTypesV2.Provider.Dodo, target, providerData, true);
}
function _setUniswapPair(
EnhancedSwapRouterV2 router,
address tokenA,
address tokenB,
address target,
address quoter,
uint24 fee
) internal {
bytes memory providerData = abi.encode(bytes(""), fee, quoter, false);
router.setProviderRoute(tokenA, tokenB, RouteTypesV2.Provider.UniswapV3, target, providerData, true);
router.setProviderRoute(tokenB, tokenA, RouteTypesV2.Provider.UniswapV3, target, providerData, true);
}
function _setBalancerPair(
EnhancedSwapRouterV2 router,
address tokenA,
address tokenB,
address target,
bytes32 poolId
) internal {
bytes memory providerData = abi.encode(poolId);
router.setProviderRoute(tokenA, tokenB, RouteTypesV2.Provider.Balancer, target, providerData, true);
router.setProviderRoute(tokenB, tokenA, RouteTypesV2.Provider.Balancer, target, providerData, true);
}
function _setCurvePair(
EnhancedSwapRouterV2 router,
address tokenA,
address tokenB,
address target,
int128 i,
int128 j,
bool useUnderlying
) internal {
bytes memory providerData = abi.encode(i, j, useUnderlying);
router.setProviderRoute(tokenA, tokenB, RouteTypesV2.Provider.Curve, target, providerData, true);
router.setProviderRoute(tokenB, tokenA, RouteTypesV2.Provider.Curve, target, providerData, true);
}
}

View File

@@ -0,0 +1,34 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console} from "forge-std/Script.sol";
import {AaveUniV2CwStableRebalanceFlashReceiver} from "../../contracts/flash/AaveUniV2CwStableRebalanceFlashReceiver.sol";
/**
* @title DeployAaveUniV2CwStableRebalanceFlashReceiver
* @notice Deploy the UniV2 rebalance + remove Aave flash receiver.
*
* Env:
* PRIVATE_KEY
* AAVE_POOL_ADDRESS optional; default Aave V3 mainnet Pool
* UNIV2_FLASH_REBALANCE_OWNER optional; default deployer
*/
contract DeployAaveUniV2CwStableRebalanceFlashReceiver is Script {
address internal constant DEFAULT_AAVE_POOL_MAINNET = 0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2;
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address pool = vm.envOr("AAVE_POOL_ADDRESS", DEFAULT_AAVE_POOL_MAINNET);
address deployer = vm.addr(pk);
address owner = vm.envOr("UNIV2_FLASH_REBALANCE_OWNER", deployer);
vm.startBroadcast(pk);
AaveUniV2CwStableRebalanceFlashReceiver receiver =
new AaveUniV2CwStableRebalanceFlashReceiver(pool, owner);
vm.stopBroadcast();
console.log("AaveUniV2CwStableRebalanceFlashReceiver", address(receiver));
console.log("owner", owner);
console.log("aavePool", pool);
}
}

View File

@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Script.sol";
import "../../../contracts/bridge/adapters/evm/ZedxionAdapter.sol";
/**
* @notice Deploy ZedxionAdapter on Chain 138.
* Env: PRIVATE_KEY, ADMIN (optional), ZEDXION_TRANSPORT (optional — call setZedxionTransport after)
*/
contract DeployZedxionAdapter is Script {
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address admin = vm.envOr("ADMIN", vm.addr(pk));
vm.startBroadcast(pk);
ZedxionAdapter adapter = new ZedxionAdapter(admin);
vm.stopBroadcast();
console2.log("ZedxionAdapter", address(adapter));
address transport = vm.envOr("ZEDXION_TRANSPORT", address(0));
if (transport != address(0)) {
vm.startBroadcast(pk);
adapter.setZedxionTransport(transport);
vm.stopBroadcast();
console2.log("ZedxionTransport wired", transport);
}
}
}

View File

@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Script.sol";
import "../../../contracts/bridge/ZedxionCustomBridge.sol";
/**
* @notice Deploy ZedxionCustomBridge on Chain 138 and/or ZEDXION (83872).
* @dev For CREATE2 same-address deploy, use DeployDeterministicCore pattern with salt keccak256("ZedxionCustomBridge").
* Env: PRIVATE_KEY, ADMIN (defaults msg.sender)
*/
contract DeployZedxionCustomBridge is Script {
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address admin = vm.envOr("ADMIN", vm.addr(pk));
vm.startBroadcast(pk);
ZedxionCustomBridge bridge = new ZedxionCustomBridge(admin);
vm.stopBroadcast();
console2.log("ZedxionCustomBridge", address(bridge));
console2.log("Admin", admin);
}
}

View File

@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Script.sol";
import {UniversalAssetRegistry} from "../../../contracts/registry/UniversalAssetRegistry.sol";
/**
* @title GrantUarRegistrarRWA138
* @notice Grant REGISTRAR_ROLE on UAR to broadcaster (for RegisterRWAIndicesInUAR138).
* @dev Broadcaster must hold DEFAULT_ADMIN_ROLE on UAR.
*/
contract GrantUarRegistrarRWA138 is Script {
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address grantee = vm.envOr("UAR_REGISTRAR_GRANTEE", vm.addr(pk));
address uarAddr = vm.envAddress("UNIVERSAL_ASSET_REGISTRY");
UniversalAssetRegistry uar = UniversalAssetRegistry(uarAddr);
bytes32 role = uar.REGISTRAR_ROLE();
vm.startBroadcast(pk);
uar.grantRole(role, grantee);
vm.stopBroadcast();
console.log("REGISTRAR_ROLE granted to", grantee, "on UAR", uarAddr);
}
}

View File

@@ -0,0 +1,147 @@
// 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";
/**
* @title RedeployLiIndexPublisher138
* @notice Operator recovery when Gnosis Safe co-signer keys are unavailable:
* deactivate Li* in registry, redeploy with deployer as INDEX_PUBLISHER, publish index level.
*
* Env: LI_TICKER (LiXAU|LiPMG|LiBMG1|LiBMG2|LiBMG3), PRIVATE_KEY, RWA_TOKEN_REGISTRY, RWA_TOKEN_FACTORY
* REBASE_INDEX_VALUE (optional), OWNER, COMPLIANCE_ADMIN, INDEX_PUBLISHER, RWA_METHODOLOGY_HASH
*/
contract RedeployLiIndexPublisher138 is Script {
struct LiProduct {
string indexTicker;
string name;
string symbol;
string assetGroup;
string instrumentType;
string underlyingAsset;
uint256 defaultIndexValue;
}
function run() external {
string memory ticker = vm.envString("LI_TICKER");
LiProduct memory p = _product(ticker);
uint256 pk = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(pk);
address registryAddr = vm.envAddress("RWA_TOKEN_REGISTRY");
address factoryAddr = vm.envAddress("RWA_TOKEN_FACTORY");
address owner = vm.envOr("OWNER", vm.envOr("OMNL_COMPLIANCE_MULTISIG", deployer));
address compliance = vm.envOr("COMPLIANCE_ADMIN", vm.envOr("OMNL_GNOSIS_SAFE_ADMIN", deployer));
address publisher = vm.envOr("INDEX_PUBLISHER", deployer);
uint256 rebaseValue = vm.envOr("REBASE_INDEX_VALUE", p.defaultIndexValue);
bytes32 methodologyHash = vm.parseBytes32(
vm.envOr("RWA_METHODOLOGY_HASH", string("0x6b6e599d0ba31d048b49302e263a12f0c59502f67a35100ad5c65b503b1d4b82"))
);
RWATokenRegistry registry = RWATokenRegistry(registryAddr);
RWATokenFactory factory = RWATokenFactory(factoryAddr);
vm.startBroadcast(pk);
if (registry.isRegistered(p.indexTicker)) {
registry.deactivateIndex(p.indexTicker);
console.log("Deactivated", p.indexTicker, "in registry");
}
address token = factory.deployRWAIndex(
IRWATokenFactory.RWAProductConfig({
indexTicker: p.indexTicker,
name: p.name,
symbol: p.symbol,
decimals: 6,
assetClass: "Commodities",
assetGroup: p.assetGroup,
instrumentType: p.instrumentType,
underlyingAsset: p.underlyingAsset,
gruLayer: "M00",
jurisdiction: "International",
initialOwner: owner,
complianceAdmin: compliance,
indexPublisher: publisher,
initialIndexValue: p.defaultIndexValue,
initialSupply: 0,
methodologyDocumentHash: methodologyHash,
registerInUniversalAssetRegistry: false
})
);
if (rebaseValue != p.defaultIndexValue) {
RWAToken(token).updateIndexValue(rebaseValue);
}
vm.stopBroadcast();
console.log("Li* redeployed", p.indexTicker, token);
console.log("indexValue", RWAToken(token).indexValue());
console.log("indexPublisher", publisher);
}
function _product(string memory ticker) internal pure returns (LiProduct memory p) {
bytes32 h = keccak256(bytes(ticker));
if (h == keccak256("LiXAU")) {
return LiProduct({
indexTicker: "LiXAU",
name: "XAU Liquidity Index (M00)",
symbol: "LiXAU",
assetGroup: "Precious Metals",
instrumentType: "Commodity Index",
underlyingAsset: "Gold",
defaultIndexValue: 1_000_000
});
}
if (h == keccak256("LiPMG")) {
return LiProduct({
indexTicker: "LiPMG",
name: "Precious Metals Group Index (M00)",
symbol: "LiPMG",
assetGroup: "Precious Metals",
instrumentType: "Basket Index",
underlyingAsset: "Precious Metals",
defaultIndexValue: 1_000_000
});
}
if (h == keccak256("LiBMG1")) {
return LiProduct({
indexTicker: "LiBMG1",
name: "Base Metals Group Index 1 (M00)",
symbol: "LiBMG1",
assetGroup: "Industrial Metals",
instrumentType: "Basket Index",
underlyingAsset: "Base Metals",
defaultIndexValue: 1_000_000
});
}
if (h == keccak256("LiBMG2")) {
return LiProduct({
indexTicker: "LiBMG2",
name: "Base Metals Group Index 2 (M00)",
symbol: "LiBMG2",
assetGroup: "Industrial Metals",
instrumentType: "Basket Index",
underlyingAsset: "Battery Metals",
defaultIndexValue: 1_000_000
});
}
if (h == keccak256("LiBMG3")) {
return LiProduct({
indexTicker: "LiBMG3",
name: "Base Metals Group Index 3 (M00)",
symbol: "LiBMG3",
assetGroup: "Industrial Metals",
instrumentType: "Basket Index",
underlyingAsset: "Building Metals",
defaultIndexValue: 1_000_000
});
}
revert("RedeployLiIndexPublisher138: unsupported LI_TICKER");
}
}

View File

@@ -0,0 +1,71 @@
// 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";
/**
* @title RedeployLiXauPublisher138
* @notice Operator recovery when Gnosis Safe co-signer keys are unavailable:
* deactivate LiXAU in registry, redeploy with deployer as INDEX_PUBLISHER, publish rebase level.
*
* Env: PRIVATE_KEY, RWA_TOKEN_REGISTRY, RWA_TOKEN_FACTORY, REBASE_INDEX_VALUE (default 1885856)
* OWNER (default OMNL multisig), COMPLIANCE_ADMIN (default Gnosis Safe admin)
* INDEX_PUBLISHER (default deployer), RWA_METHODOLOGY_HASH
*/
contract RedeployLiXauPublisher138 is Script {
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(pk);
address registryAddr = vm.envAddress("RWA_TOKEN_REGISTRY");
address factoryAddr = vm.envAddress("RWA_TOKEN_FACTORY");
address owner = vm.envOr("OWNER", vm.envOr("OMNL_COMPLIANCE_MULTISIG", deployer));
address compliance = vm.envOr("COMPLIANCE_ADMIN", vm.envOr("OMNL_GNOSIS_SAFE_ADMIN", deployer));
address publisher = vm.envOr("INDEX_PUBLISHER", deployer);
uint256 rebaseValue = vm.envOr("REBASE_INDEX_VALUE", uint256(1_885_856));
bytes32 methodologyHash = vm.parseBytes32(vm.envOr("RWA_METHODOLOGY_HASH", string("0x6b6e599d0ba31d048b49302e263a12f0c59502f67a35100ad5c65b503b1d4b82")));
RWATokenRegistry registry = RWATokenRegistry(registryAddr);
RWATokenFactory factory = RWATokenFactory(factoryAddr);
vm.startBroadcast(pk);
if (registry.isRegistered("LiXAU")) {
registry.deactivateIndex("LiXAU");
console.log("Deactivated LiXAU in registry");
}
address token = factory.deployRWAIndex(
IRWATokenFactory.RWAProductConfig({
indexTicker: "LiXAU",
name: "XAU Liquidity Index (M00)",
symbol: "LiXAU",
decimals: 6,
assetClass: "Commodities",
assetGroup: "Precious Metals",
instrumentType: "Commodity Index",
underlyingAsset: "Gold",
gruLayer: "M00",
jurisdiction: "International",
initialOwner: owner,
complianceAdmin: compliance,
indexPublisher: publisher,
initialIndexValue: 1_000_000,
initialSupply: 0,
methodologyDocumentHash: methodologyHash,
registerInUniversalAssetRegistry: false
})
);
RWAToken(token).updateIndexValue(rebaseValue);
vm.stopBroadcast();
console.log("LiXAU redeployed", token);
console.log("indexValue", RWAToken(token).indexValue());
console.log("indexPublisher", publisher);
}
}

View File

@@ -0,0 +1,125 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console} from "forge-std/Script.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {
AaveUniV2CwStableRebalanceFlashReceiver
} from "../../contracts/flash/AaveUniV2CwStableRebalanceFlashReceiver.sol";
/**
* @title RunMainnetUniV2CwusdcUsdcFlashRebalanceRemove
* @notice Simulate or broadcast flash rebalance + LP remove on mainnet cWUSDC/USDC UniV2.
*
* Prerequisite: run plan-mainnet-cwusdc-usdc-univ2-flash-rebalance-remove.py and transfer LP
* to the receiver (or set UNIV2_FLASH_PULL_LP=1 with prior LP approval to receiver).
*
* Env:
* PRIVATE_KEY
* ETHEREUM_MAINNET_RPC
* UNIV2_FLASH_REBALANCE_RECEIVER_MAINNET
* UNIV2_FLASH_REBALANCE_PLAN_JSON optional path to planner JSON
*/
contract RunMainnetUniV2CwusdcUsdcFlashRebalanceRemove is Script {
address internal constant DEFAULT_PAIR = 0xC28706F899266b36BC43cc072b3a921BDf2C48D9;
address internal constant DEFAULT_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
address internal constant DEFAULT_CW = 0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a;
address internal constant DEFAULT_USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address receiver = vm.envAddress("UNIV2_FLASH_REBALANCE_RECEIVER_MAINNET");
string memory planPath = vm.envOr(
"UNIV2_FLASH_REBALANCE_PLAN_JSON",
string("reports/status/mainnet-cwusdc-usdc-univ2-flash-rebalance-plan-latest.json")
);
(
address pair,
address router,
address cw,
address usdc,
address lpHolder,
address recipient,
uint256 lpAmount,
uint256 flashStableIn,
uint256 minCwRebalance,
uint256 minCwRemove,
uint256 minStableRemove,
uint256 cwToSell,
uint256 minStableRepay
) = _loadPlan(planPath);
pair = pair == address(0) ? DEFAULT_PAIR : pair;
router = router == address(0) ? DEFAULT_ROUTER : router;
cw = cw == address(0) ? DEFAULT_CW : cw;
usdc = usdc == address(0) ? DEFAULT_USDC : usdc;
console.log("receiver", receiver);
console.log("pair", pair);
console.log("lpHolder", lpHolder);
console.log("lpAmount", lpAmount);
console.log("flashStableIn", flashStableIn);
console.log("receiverLpBefore", IERC20(pair).balanceOf(receiver));
vm.startBroadcast(pk);
if (vm.envOr("UNIV2_FLASH_PULL_LP", uint256(0)) == 1) {
AaveUniV2CwStableRebalanceFlashReceiver(receiver).pullLpFrom(pair, lpHolder, lpAmount);
}
AaveUniV2CwStableRebalanceFlashReceiver.RebalanceRemoveParams memory p =
AaveUniV2CwStableRebalanceFlashReceiver.RebalanceRemoveParams({
router: router,
pair: pair,
cwToken: cw,
stableToken: usdc,
lpAmount: lpAmount,
rebalanceStableIn: flashStableIn,
minCwFromRebalance: minCwRebalance,
minStableFromRemove: minStableRemove,
minCwFromRemove: minCwRemove,
cwToSellForRepay: cwToSell,
minStableFromRepaySwap: minStableRepay,
recipient: recipient
});
AaveUniV2CwStableRebalanceFlashReceiver(receiver).runRebalanceRemove(usdc, flashStableIn, p);
vm.stopBroadcast();
console.log("recipientStableAfter", IERC20(usdc).balanceOf(recipient));
console.log("recipientCwAfter", IERC20(cw).balanceOf(recipient));
}
function _loadPlan(string memory path)
internal
view
returns (
address pair,
address router,
address cw,
address usdc,
address lpHolder,
address recipient,
uint256 lpAmount,
uint256 flashStableIn,
uint256 minCwRebalance,
uint256 minCwRemove,
uint256 minStableRemove,
uint256 cwToSell,
uint256 minStableRepay
)
{
string memory json = vm.readFile(path);
pair = vm.parseJsonAddress(json, ".pair");
router = vm.parseJsonAddress(json, ".router");
cw = vm.parseJsonAddress(json, ".cwToken");
usdc = vm.parseJsonAddress(json, ".stableToken");
lpHolder = vm.parseJsonAddress(json, ".lpHolder");
recipient = vm.parseJsonAddress(json, ".recipient");
lpAmount = vm.parseJsonUint(json, ".lpAmountRaw");
flashStableIn = vm.parseJsonUint(json, ".flashLoan.stableBorrowRaw");
minCwRebalance = vm.parseJsonUint(json, ".rebalanceSwap.minCwOutRaw");
minCwRemove = vm.parseJsonUint(json, ".removeLiquidity.minCwOutRaw");
minStableRemove = vm.parseJsonUint(json, ".removeLiquidity.minStableOutRaw");
cwToSell = vm.parseJsonUint(json, ".repaySwap.cwToSellRaw");
minStableRepay = vm.parseJsonUint(json, ".repaySwap.minStableOutRaw");
}
}

View File

@@ -0,0 +1,101 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console} from "forge-std/Script.sol";
import {AaveQuotePushFlashReceiver} from "../../contracts/flash/AaveQuotePushFlashReceiver.sol";
import {QuotePushTreasuryManager} from "../../contracts/flash/QuotePushTreasuryManager.sol";
interface IDODOPMMPoolQuoteManagedUsdt {
function querySellQuote(address trader, uint256 payQuoteAmount) external view returns (uint256 receiveBaseAmount, uint256 mtFee);
}
/// @notice USDT rail mirror of RunManagedMainnetAaveCwusdcUsdcQuotePushCycle.
contract RunManagedMainnetAaveCwusdtUsdtQuotePushCycle is Script {
address internal constant DEFAULT_POOL = 0x79156F6B7bf71a1B72D78189B540A89A6C13F6FC;
address internal constant DEFAULT_CWUSDT = 0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE;
address internal constant DEFAULT_USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
uint256 internal constant DEFENDED_SAFE_CAP_RAW = 2_964_298;
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address receiver = vm.envAddress("AAVE_QUOTE_PUSH_RECEIVER_MAINNET");
address managerAddr = vm.envAddress("QUOTE_PUSH_TREASURY_MANAGER_MAINNET");
address pool = vm.envOr("POOL_CWUSDT_USDT_MAINNET", DEFAULT_POOL);
address integration = vm.envAddress("DODO_PMM_INTEGRATION_MAINNET");
address baseToken = vm.envOr("CWUSDT_MAINNET", DEFAULT_CWUSDT);
address usdt = vm.envOr("USDT_MAINNET", DEFAULT_USDT);
address unwinder = vm.envAddress("QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET");
uint256 amount = vm.envUint("FLASH_QUOTE_AMOUNT_RAW");
uint256 localCap = vm.envOr("MAX_FLASH_QUOTE_AMOUNT_RAW", DEFENDED_SAFE_CAP_RAW);
bool harvest = vm.envOr("QUOTE_PUSH_TREASURY_HARVEST", uint256(1)) == 1;
uint256 gasHoldbackTargetRaw = vm.envOr("QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW", uint256(0));
require(pool == DEFAULT_POOL, "defended pool only");
require(localCap <= DEFENDED_SAFE_CAP_RAW, "local cap exceeds defended safe cap");
require(amount <= localCap, "flash amount exceeds cap");
QuotePushTreasuryManager manager = QuotePushTreasuryManager(managerAddr);
AaveQuotePushFlashReceiver.QuotePushParams memory p =
_loadQuotePushParams(receiver, pool, integration, baseToken, unwinder, amount);
vm.startBroadcast(pk);
(uint256 harvested, uint256 gasAmount, uint256 recycleAmount) =
manager.runManagedCycle(usdt, amount, p, harvest, gasHoldbackTargetRaw);
vm.stopBroadcast();
console.log("managedCycleHarvestedRaw", harvested);
console.log("managedCycleGasDistributionRaw", gasAmount);
console.log("managedCycleRecycleDistributionRaw", recycleAmount);
}
function _loadQuotePushParams(
address receiver,
address pool,
address integration,
address baseToken,
address unwinder,
uint256 amount
) internal view returns (AaveQuotePushFlashReceiver.QuotePushParams memory p) {
uint256 minPmmNum = vm.envOr("MIN_OUT_PMM_NUM", uint256(985));
uint256 minPmmDen = vm.envOr("MIN_OUT_PMM_DEN", uint256(1000));
uint256 minOutPmm = vm.envOr("MIN_OUT_PMM", uint256(0));
if (minOutPmm == 0) {
(uint256 baseOut,) = IDODOPMMPoolQuoteManagedUsdt(pool).querySellQuote(receiver, amount);
minOutPmm = (baseOut * minPmmNum) / minPmmDen;
}
uint256 premiumBps = vm.envOr("AAVE_FLASH_PREMIUM_BPS", uint256(5));
uint256 buf = vm.envOr("MIN_OUT_UNWIND_BUFFER_RAW", uint256(5000));
uint256 premium = (amount * premiumBps) / 10000;
uint256 minOutUnwind = vm.envOr("MIN_OUT_UNWIND", amount + premium + buf);
uint256 unwindMode = vm.envOr("UNWIND_MODE", uint256(1));
bytes memory unwindData;
if (unwindMode == 1) {
address dodoPool = vm.envOr("UNWIND_DODO_POOL", pool);
unwindData = abi.encode(dodoPool);
} else {
revert("USDT rail: UNWIND_MODE=1 (DODO) required for now");
}
p = AaveQuotePushFlashReceiver.QuotePushParams({
integration: integration,
pmmPool: pool,
baseToken: baseToken,
externalUnwinder: unwinder,
minOutPmm: minOutPmm,
minOutUnwind: minOutUnwind,
unwindData: unwindData,
atomicBridge: AaveQuotePushFlashReceiver.AtomicBridgeParams({
coordinator: address(0),
sourceChain: 0,
destinationChain: 0,
destinationAsset: address(0),
bridgeAmount: 0,
minDestinationAmount: 0,
destinationRecipient: address(0),
destinationDeadline: 0,
routeId: bytes32(0),
settlementMode: bytes32(0),
submitCommitment: false
})
});
}
}

View File

@@ -0,0 +1,90 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console} from "forge-std/Script.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
interface IDODOPMMIntegrationSeed {
function isRegisteredPool(address pool) external view returns (bool);
function addLiquidity(address pool, uint256 baseAmount, uint256 quoteAmount)
external
returns (uint256 baseShare, uint256 quoteShare, uint256 lpShare);
}
interface IDODOPMMPoolSeed {
function _BASE_TOKEN_() external view returns (address);
function _QUOTE_TOKEN_() external view returns (address);
function getVaultReserve() external view returns (uint256 baseReserve, uint256 quoteReserve);
}
/// @notice Permanently seed defended mainnet cWUSDC/USDC or cWUSDT/USDT DODO pools via addLiquidity.
/// @dev Uses deployer inventory — not flash (flash must repay same block). Pair with Aave borrow + vault deposit off-chain.
contract SeedMainnetCwStablePoolPermanent is Script {
using SafeERC20 for IERC20;
address internal constant DEFAULT_INTEGRATION = 0xa9F284eD010f4F7d7F8F201742b49b9f58e29b84;
address internal constant POOL_CWUSDC_USDC = 0x69776fc607e9edA8042e320e7e43f54d06c68f0E;
/// @dev Registered on DODOPMMIntegration.pools(cWUSDT, USDT); 0x99d012… is an unregistered duplicate.
address internal constant POOL_CWUSDT_USDT = 0x79156F6B7bf71a1B72D78189B540A89A6C13F6FC;
address internal constant CWUSDC = 0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a;
address internal constant CWUSDT = 0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE;
address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(pk);
string memory rail = vm.envOr("CW_STABLE_RAIL", string("USDC"));
uint256 baseAmount = vm.envUint("SEED_BASE_AMOUNT_RAW");
uint256 quoteAmount = vm.envUint("SEED_QUOTE_AMOUNT_RAW");
address integration = vm.envOr("DODO_PMM_INTEGRATION_MAINNET", DEFAULT_INTEGRATION);
(address pool, address baseToken, address quoteToken) = _resolveRail(rail);
IDODOPMMPoolSeed poolView = IDODOPMMPoolSeed(pool);
require(poolView._BASE_TOKEN_() == baseToken, "base mismatch");
require(poolView._QUOTE_TOKEN_() == quoteToken, "quote mismatch");
require(IDODOPMMIntegrationSeed(integration).isRegisteredPool(pool), "pool not registered on integration");
(uint256 baseBefore, uint256 quoteBefore) = poolView.getVaultReserve();
console.log("deployer", deployer);
console.log("rail", rail);
console.log("pool", pool);
console.log("baseAmount", baseAmount);
console.log("quoteAmount", quoteAmount);
console.log("baseReserveBefore", baseBefore);
console.log("quoteReserveBefore", quoteBefore);
vm.startBroadcast(pk);
IERC20(baseToken).forceApprove(integration, baseAmount);
IERC20(quoteToken).forceApprove(integration, quoteAmount);
(uint256 baseShare, uint256 quoteShare, uint256 lpShare) =
IDODOPMMIntegrationSeed(integration).addLiquidity(pool, baseAmount, quoteAmount);
IERC20(baseToken).forceApprove(integration, 0);
IERC20(quoteToken).forceApprove(integration, 0);
vm.stopBroadcast();
(uint256 baseAfter, uint256 quoteAfter) = poolView.getVaultReserve();
console.log("baseShare", baseShare);
console.log("quoteShare", quoteShare);
console.log("lpShare", lpShare);
console.log("baseReserveAfter", baseAfter);
console.log("quoteReserveAfter", quoteAfter);
}
function _resolveRail(string memory rail)
internal
pure
returns (address pool, address baseToken, address quoteToken)
{
bytes32 key = keccak256(bytes(rail));
if (key == keccak256(bytes("USDC"))) {
return (POOL_CWUSDC_USDC, CWUSDC, USDC);
}
if (key == keccak256(bytes("USDT"))) {
return (POOL_CWUSDT_USDT, CWUSDT, USDT);
}
revert("CW_STABLE_RAIL must be USDC or USDT");
}
}

View File

@@ -0,0 +1,48 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console2} from "forge-std/Script.sol";
import {ReserveCommitmentStore} from "../../contracts/hybx-omnl/ReserveCommitmentStore.sol";
/// @notice Deploy reserve store with deployer bootstrap, enable notary gate, migrate commitment, hand DEFAULT_ADMIN to vault Safe.
contract RecoverOMNLReserveVaultSafe is Script {
bytes32 private constant DEFAULT_ADMIN_ROLE = 0x00;
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(pk);
address vaultSafe = vm.envAddress("OMNL_VAULT_SAFE");
address legacyStore = vm.envAddress("OMNL_RESERVE_STORE_138");
address notary = vm.envAddress("OMNL_NOTARY_REGISTRY");
bytes32 lineId = vm.envBytes32("OMNL_HEALTH_LINE_ID");
bytes32 jurId = keccak256(bytes(vm.envOr("OMNL_JURISDICTION_ID", string("ID"))));
bytes32 matrixId = keccak256(bytes(vm.envOr("OMNL_MATRIX_CONTROL_ID", string("ID-OMNL-001"))));
uint256 attTh = vm.envOr("OMNL_RESERVE_ATTESTATION_THRESHOLD", uint256(3));
ReserveCommitmentStore legacy = ReserveCommitmentStore(legacyStore);
ReserveCommitmentStore.Commitment memory c = legacy.getCommitment(lineId);
address mirror = legacy.mirrorReceiver();
vm.startBroadcast(pk);
ReserveCommitmentStore storeV3 = new ReserveCommitmentStore(deployer);
storeV3.configureNotaryGate(notary, true, jurId, matrixId);
storeV3.setAttestationThreshold(attTh);
if (mirror != address(0)) {
storeV3.setMirrorReceiver(mirror);
}
if (c.R != 0) {
storeV3.commitReserve(lineId, c.R, c.validUntil, c.evidenceHash, c.merkleRoot);
}
storeV3.grantRole(DEFAULT_ADMIN_ROLE, vaultSafe);
storeV3.revokeRole(DEFAULT_ADMIN_ROLE, deployer);
vm.stopBroadcast();
console2.log("ReserveCommitmentStoreV3", address(storeV3));
console2.log("vaultSafe", vaultSafe);
console2.log("requireNotarizedEvidence", storeV3.requireNotarizedEvidence());
console2.log("legacyStore", legacyStore);
}
}

View File

@@ -103,13 +103,14 @@ contract DeployM00DiamondHub138 is Script {
}
function _accessSelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](6);
s = new bytes4[](7);
s[0] = AccessFacet.grantRoles.selector;
s[1] = AccessFacet.revokeRoles.selector;
s[2] = AccessFacet.ROLE_UPGRADE_BIT.selector;
s[3] = AccessFacet.ROLE_GOVERNANCE_BIT.selector;
s[4] = AccessFacet.ROLE_INDEX_BIT.selector;
s[5] = AccessFacet.ROLE_MONETARY_BIT.selector;
s[2] = AccessFacet.hasRoles.selector;
s[3] = AccessFacet.ROLE_UPGRADE_BIT.selector;
s[4] = AccessFacet.ROLE_GOVERNANCE_BIT.selector;
s[5] = AccessFacet.ROLE_INDEX_BIT.selector;
s[6] = AccessFacet.ROLE_MONETARY_BIT.selector;
}
function _bridgeSelectors() internal pure returns (bytes4[] memory s) {
@@ -137,15 +138,19 @@ contract DeployM00DiamondHub138 is Script {
}
function _rwaDocSelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](2);
s = new bytes4[](4);
s[0] = RWADocumentFacet.anchorDocument.selector;
s[1] = RWADocumentFacet.setPrimaryContentHash.selector;
s[2] = RWADocumentFacet.documentCount.selector;
s[3] = RWADocumentFacet.getDocument.selector;
}
function _rwaStdSelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](3);
s = new bytes4[](5);
s[0] = RWAStandardsRegistryFacet.enableStandard.selector;
s[1] = RWAStandardsRegistryFacet.disableStandard.selector;
s[2] = RWAStandardsRegistryFacet.bindAssetStandardFacet.selector;
s[3] = RWAStandardsRegistryFacet.isStandardEnabled.selector;
s[4] = RWAStandardsRegistryFacet.assetStandardFacet.selector;
}
}

View File

@@ -0,0 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Script.sol";
import {IndexFacet} from "@gru/facets/IndexFacet.sol";
import {IERC173} from "@gru/interfaces/IERC173.sol";
/// @notice Seed unit weights (1e18) for each Li* index on the M00 diamond hub.
contract SeedM00LiIndexWeights138 is Script {
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address diamond = vm.envAddress("M00_DIAMOND_HUB");
uint256 chainId = 138;
string[5] memory tickers = ["LiXAU", "LiPMG", "LiBMG1", "LiBMG2", "LiBMG3"];
vm.startBroadcast(pk);
for (uint256 i = 0; i < tickers.length; i++) {
bytes32 indexId = keccak256(abi.encode(tickers[i], chainId));
bytes32[] memory keys = new bytes32[](1);
keys[0] = keccak256(abi.encode(tickers[i]));
uint256[] memory weights = new uint256[](1);
weights[0] = 1e18;
IndexFacet(diamond).setWeights(indexId, keys, weights, 1, keccak256("M00_LI_v1"));
}
address newOwner = vm.envOr("M00_DIAMOND_OWNER", vm.envOr("GOVERNANCE_CONTROLLER", address(0)));
if (newOwner != address(0)) {
IERC173(diamond).transferOwnership(newOwner);
}
vm.stopBroadcast();
}
}

View File

@@ -0,0 +1,133 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Script.sol";
import {IDiamondCut} from "@gru/interfaces/IDiamondCut.sol";
import {IndexFacet} from "@gru/facets/IndexFacet.sol";
import {MonetaryFacet} from "@gru/facets/MonetaryFacet.sol";
import {GovernanceFacet} from "@gru/facets/GovernanceFacet.sol";
import {AccessFacet} from "@gru/facets/AccessFacet.sol";
import {IAccess} from "@gru/interfaces/IAccess.sol";
import {IGovernance} from "@gru/interfaces/IGovernance.sol";
import {RWAInstrumentFacet} from "../../contracts/rwa/diamond/facets/RWAInstrumentFacet.sol";
import {RWADocumentFacet} from "../../contracts/rwa/diamond/facets/RWADocumentFacet.sol";
import {RWAStandardsRegistryFacet} from "../../contracts/rwa/diamond/facets/RWAStandardsRegistryFacet.sol";
/**
* @title UpgradeM00DiamondHubComplete138
* @notice Add GRC Index/Monetary/Governance facets, RWA read selectors, AccessFacet.hasRoles; grant GRC roles.
*/
contract UpgradeM00DiamondHubComplete138 is Script {
uint256 internal constant ROLE_ALL_GRC = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3);
function run() external {
uint256 pk = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(pk);
address diamond = vm.envAddress("M00_DIAMOND_HUB");
address governance = vm.envOr("GOVERNANCE_CONTROLLER", deployer);
address accessFacet = vm.envAddress("M00_ACCESS_FACET");
address rwaInst = vm.envAddress("M00_RWA_INSTRUMENT_FACET");
address rwaDoc = vm.envAddress("M00_RWA_DOCUMENT_FACET");
address rwaStd = vm.envAddress("M00_RWA_STANDARDS_FACET");
vm.startBroadcast(pk);
IndexFacet index = new IndexFacet();
MonetaryFacet monetary = new MonetaryFacet();
GovernanceFacet govFacet = new GovernanceFacet();
IDiamondCut.FacetCut[] memory cut = new IDiamondCut.FacetCut[](7);
cut[0] = _add(address(index), _indexSelectors());
cut[1] = _add(address(monetary), _monetarySelectors());
cut[2] = _add(address(govFacet), _governanceSelectors());
cut[3] = _add(accessFacet, _accessExtraSelectors());
cut[4] = _add(rwaInst, _rwaInstViewSelectors());
cut[5] = _add(rwaDoc, _rwaDocViewSelectors());
cut[6] = _add(rwaStd, _rwaStdViewSelectors());
IDiamondCut(diamond).diamondCut(cut, address(0), "");
IAccess(diamond).grantRoles(governance, ROLE_ALL_GRC);
if (governance != deployer) {
IAccess(diamond).grantRoles(deployer, ROLE_ALL_GRC);
}
IGovernance(diamond).setGovernanceParams(86_400, 5_000);
console.log("M00Diamond", diamond);
console.log("IndexFacet", address(index));
console.log("MonetaryFacet", address(monetary));
console.log("GovernanceFacet", address(govFacet));
vm.stopBroadcast();
}
function _add(address facet, bytes4[] memory sels)
internal
pure
returns (IDiamondCut.FacetCut memory)
{
return IDiamondCut.FacetCut({
facetAddress: facet,
action: IDiamondCut.FacetCutAction.Add,
functionSelectors: sels
});
}
function _indexSelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](8);
s[0] = IndexFacet.setWeights.selector;
s[1] = IndexFacet.getIndex.selector;
s[2] = IndexFacet.recalcLiCRI.selector;
s[3] = IndexFacet.recalcLiCRIWeighted.selector;
s[4] = IndexFacet.setDashboardComposite.selector;
s[5] = IndexFacet.getLiCRI.selector;
s[6] = IndexFacet.setIndexValue.selector;
s[7] = IndexFacet.getIndexValue.selector;
}
function _monetarySelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](6);
s[0] = MonetaryFacet.mintM1.selector;
s[1] = MonetaryFacet.burnM1.selector;
s[2] = MonetaryFacet.issueM0.selector;
s[3] = MonetaryFacet.redeemM0.selector;
s[4] = MonetaryFacet.setScalarS.selector;
s[5] = MonetaryFacet.getLayers.selector;
}
function _governanceSelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](9);
s[0] = GovernanceFacet.proposeCut.selector;
s[1] = GovernanceFacet.queueCut.selector;
s[2] = GovernanceFacet.executeCut.selector;
s[3] = GovernanceFacet.emergencyBrake.selector;
s[4] = GovernanceFacet.timelock.selector;
s[5] = GovernanceFacet.quorumBps.selector;
s[6] = GovernanceFacet.eta.selector;
s[7] = GovernanceFacet.proposer.selector;
s[8] = GovernanceFacet.setGovernanceParams.selector;
}
function _accessExtraSelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](1);
s[0] = AccessFacet.hasRoles.selector;
}
function _rwaInstViewSelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](2);
s[0] = RWAInstrumentFacet.getIssuanceMode.selector;
s[1] = RWAInstrumentFacet.getTokenPointer.selector;
}
function _rwaDocViewSelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](2);
s[0] = RWADocumentFacet.documentCount.selector;
s[1] = RWADocumentFacet.getDocument.selector;
}
function _rwaStdViewSelectors() internal pure returns (bytes4[] memory s) {
s = new bytes4[](2);
s[0] = RWAStandardsRegistryFacet.isStandardEnabled.selector;
s[1] = RWAStandardsRegistryFacet.assetStandardFacet.selector;
}
}

View File

@@ -0,0 +1,168 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console} from "forge-std/Script.sol";
import {Aggregator} from "../../contracts/oracle/Aggregator.sol";
interface IOraclePriceFeedWire {
function aggregators(address asset) external view returns (address);
function setAggregator(address asset, address aggregator, uint256 multiplier) external;
function updatePriceFeed(address asset) external;
function setUpdateInterval(uint256 interval) external;
function updateInterval() external view returns (uint256);
}
interface IPriceFeedKeeperWire {
function isTracked(address asset) external view returns (bool);
function trackAsset(address asset) external;
function maxUpdatesPerCall() external view returns (uint256);
function setMaxUpdatesPerCall(uint256 max) external;
}
interface IDODOPMMIntegrationWire {
function setReserveSystem(address reserveSystem_) external;
function reserveSystem() external view returns (address);
}
interface IReserveSystemWire {
function updatePriceFeed(address asset, uint256 price, uint256 timestamp) external;
}
interface IAggregatorWire {
function addTransmitter(address transmitter) external;
function updateAnswer(uint256 answer) external;
function isTransmitter(address transmitter) external view returns (bool);
function latestRoundData()
external
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound);
}
/// @notice Wire canonical Chain 138 assets to Chainlink-mirrored repo aggregators + keeper + reserve.
contract WireChain138OraclePegs138 is Script {
uint256 internal constant MULT = 1e10;
address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address internal constant WETH10 = 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F;
address internal constant LINK = 0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03;
address internal constant CUSDT = 0x93E66202A11B1772E55407B32B44e5Cd8eda7f22;
address internal constant CUSDC = 0xf22258f57794CC8E06237084b353Ab30fFfa640b;
address internal constant CEURC = 0x8085961F9cF02b4d800A3c6d386D31da4B34266a;
address internal constant CEURT = 0xdf4b71c61E5912712C1Bdd451416B9aC26949d72;
address internal constant CGBPC = 0x003960f16D9d34F2e98d62723B6721Fb92074aD2;
address internal constant CGBPT = 0x350f54e4D23795f86A9c03988c7135357CCaD97c;
address internal constant CAUDC = 0xD51482e567c03899eecE3CAe8a058161FD56069D;
address internal constant CJPYC = 0xEe269e1226a334182aace90056EE4ee5Cc8A6770;
address internal constant CCHFC = 0x873990849DDa5117d7C644f0aF24370797C03885;
address internal constant CCADC = 0x54dBd40cF05e15906A2C21f600937e96787f5679;
address internal constant CXAUC = 0x290E52a8819A4fbD0714E517225429aA2B70EC6b;
address internal constant CXAUT = 0x94e408E26c6FD8F4ee00b54dF19082FDA07dC96E;
address internal constant CBTC = 0xe94260c555aC1d9D3CC9E1632883452ebDf0082E;
function run() external {
require(block.chainid == 138, "ChainID 138 only");
uint256 pk = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(pk);
address opf = vm.envAddress("ORACLE_PRICE_FEED");
address keeperAddr = vm.envAddress("PRICE_FEED_KEEPER_ADDRESS");
address rs = vm.envAddress("RESERVE_SYSTEM");
address ethAgg = vm.envAddress("AGGREGATOR_ADDRESS");
address dodo = vm.envAddress("CHAIN_138_DODO_PMM_INTEGRATION");
uint256 ethSeed8 = vm.envOr("FEED_ETH_USD_8", uint256(0));
IOraclePriceFeedWire op = IOraclePriceFeedWire(opf);
IPriceFeedKeeperWire keeper = IPriceFeedKeeperWire(keeperAddr);
console.log("=== Wire Chain 138 oracle pegs ===");
console.log("Deployer:", deployer);
vm.startBroadcast(pk);
if (op.updateInterval() != 86400) {
try op.setUpdateInterval(86400) {} catch {}
}
if (ethSeed8 > 0) {
IAggregatorWire eth = IAggregatorWire(ethAgg);
if (!eth.isTransmitter(deployer)) {
try eth.addTransmitter(deployer) {} catch {}
}
try eth.updateAnswer(ethSeed8) {} catch {}
}
if (keeper.maxUpdatesPerCall() < 20) {
keeper.setMaxUpdatesPerCall(20);
}
address usdAgg = _deployMirror("USD/USD Chainlink mirror", vm.envUint("FEED_USD_USD_8"));
address linkAgg = _deployMirror("LINK/USD Chainlink mirror", vm.envUint("FEED_LINK_USD_8"));
address btcAgg = _deployMirror("BTC/USD Chainlink mirror", vm.envUint("FEED_BTC_USD_8"));
address xauAgg = _deployMirror("XAU/USD Chainlink mirror", vm.envUint("FEED_XAU_USD_8"));
address eurAgg = _deployMirror("EUR/USD Chainlink mirror", vm.envUint("FEED_EUR_USD_8"));
address gbpAgg = _deployMirror("GBP/USD Chainlink mirror", vm.envUint("FEED_GBP_USD_8"));
address audAgg = _deployMirror("AUD/USD Chainlink mirror", vm.envUint("FEED_AUD_USD_8"));
address jpyAgg = _deployMirror("JPY/USD Chainlink mirror", vm.envUint("FEED_JPY_USD_8"));
address chfAgg = _deployMirror("CHF/USD Chainlink mirror", vm.envUint("FEED_CHF_USD_8"));
address cadAgg = _deployMirror("CAD/USD Chainlink mirror", vm.envUint("FEED_CAD_USD_8"));
_wire(op, keeper, rs, WETH9, ethAgg);
_wire(op, keeper, rs, WETH10, ethAgg);
_wire(op, keeper, rs, LINK, linkAgg);
_wire(op, keeper, rs, CUSDT, usdAgg);
_wire(op, keeper, rs, CUSDC, usdAgg);
_wire(op, keeper, rs, CEURC, eurAgg);
_wire(op, keeper, rs, CEURT, eurAgg);
_wire(op, keeper, rs, CGBPC, gbpAgg);
_wire(op, keeper, rs, CGBPT, gbpAgg);
_wire(op, keeper, rs, CAUDC, audAgg);
_wire(op, keeper, rs, CJPYC, jpyAgg);
_wire(op, keeper, rs, CCHFC, chfAgg);
_wire(op, keeper, rs, CCADC, cadAgg);
_wire(op, keeper, rs, CXAUC, xauAgg);
_wire(op, keeper, rs, CXAUT, xauAgg);
_wire(op, keeper, rs, CBTC, btcAgg);
IDODOPMMIntegrationWire dodoInt = IDODOPMMIntegrationWire(dodo);
if (dodoInt.reserveSystem() != rs) {
dodoInt.setReserveSystem(rs);
console.log("DODO reserveSystem wired:", rs);
}
vm.stopBroadcast();
console.log("=== Done ===");
}
function _deployMirror(string memory description, uint256 price8) internal returns (address) {
require(price8 > 0, "missing seed price");
Aggregator agg = new Aggregator(description, msg.sender, 3600, 50);
agg.addTransmitter(msg.sender);
agg.updateAnswer(price8);
console.log("Deployed feed:", description);
console.log(" aggregator:", address(agg));
return address(agg);
}
function _wire(
IOraclePriceFeedWire op,
IPriceFeedKeeperWire keeper,
address rs,
address token,
address agg
) internal {
require(agg != address(0), "zero aggregator");
if (op.aggregators(token) == address(0)) {
op.setAggregator(token, agg, MULT);
}
if (!keeper.isTracked(token)) {
keeper.trackAsset(token);
}
try op.updatePriceFeed(token) {} catch {
(, int256 ans,, uint256 updatedAt,) = IAggregatorWire(agg).latestRoundData();
require(ans > 0, "bad agg price");
IReserveSystemWire(rs).updatePriceFeed(token, uint256(ans) * MULT, updatedAt);
}
}
}