diff --git a/.treb/addressbook.json b/.treb/addressbook.json index 8431ba3..25329f1 100644 --- a/.treb/addressbook.json +++ b/.treb/addressbook.json @@ -45,19 +45,6 @@ "TransparentUpgradeableProxy:Locking": "0x001Bb66636dCd149A1A2bA8C50E408BdDd80279C", "L2SequencerUptimeFeed": "0x4CD491Dc27C8B0BbD10D516A502856B786939d18" }, - "143": { - "AUSD": "0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a", - "USDC": "0x754704Bc059F8C67012fEd69BC8A327a5aafb603", - "USDT0": "0xe7cd86e13ac4309349f30b3435a9d337750fc82d", - "StableTokenSpokeUSD": "0x866a7e4611C127DCe1a14C6841D2eA962A68dc88", - "StableTokenSpokeGBP": "0xddF082068Caa5B941ED8c603ADf0cecBdBb59f8E", - "StableTokenSpokeImplementation": "0xa8caCd5d58F98Ee303fb54EF101AA4e277777E91", - "MigrationMultisig": "0x58099B74F4ACd642Da77b4B7966b4138ec5Ba458", - "ProtocolFeeRecipient": "0x0Dd57F6f181D0469143fe9380762d8a112e96e4a", - "FeeSetter": "0x58099B74F4ACd642Da77b4B7966b4138ec5Ba458", - "ReserveSafe": "0x87647780180B8f55980C7D3fFeFe08a9B29e9aE1", - "WormholeCoreBridge": "0x194B123c5E96B9b2E49763619985790Dc241CAC0" - }, "11142220": { "MigrationMultisig": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7", "ReserveSafe": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7", @@ -84,6 +71,19 @@ "L2SequencerUptimeFeed": "0x0000000000000000000000000000000000000000", "BiPoolManagerFeeSetter": "0x15b38D560928029a74d1D0a56eE232fb5Ff3A4B1" }, + "143": { + "AUSD": "0x00000000eFE302BEAA2b3e6e1b18d08D69a9012a", + "USDC": "0x754704Bc059F8C67012fEd69BC8A327a5aafb603", + "USDT0": "0xe7cd86e13ac4309349f30b3435a9d337750fc82d", + "StableTokenSpokeUSD": "0x866a7e4611C127DCe1a14C6841D2eA962A68dc88", + "StableTokenSpokeGBP": "0xddF082068Caa5B941ED8c603ADf0cecBdBb59f8E", + "StableTokenSpokeImplementation": "0xa8caCd5d58F98Ee303fb54EF101AA4e277777E91", + "MigrationMultisig": "0x58099B74F4ACd642Da77b4B7966b4138ec5Ba458", + "ProtocolFeeRecipient": "0x0Dd57F6f181D0469143fe9380762d8a112e96e4a", + "FeeSetter": "0x58099B74F4ACd642Da77b4B7966b4138ec5Ba458", + "ReserveSafe": "0x87647780180B8f55980C7D3fFeFe08a9B29e9aE1", + "WormholeCoreBridge": "0x194B123c5E96B9b2E49763619985790Dc241CAC0" + }, "10143": { "USDC": "0x534b2f3a21130d7a60830c2df862319e593943a3", "MigrationMultisig": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7", @@ -93,12 +93,18 @@ "Watchdog": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7", "YieldSplitAddress": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7" }, + "137": { + "WormholeCoreBridge": "0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7" + }, "80002": { "MigrationMultisig": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7", "ReserveSafe": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7", "ProtocolFeeRecipient": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7", "FeeSetter": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7" }, + "8453": { + "WormholeCoreBridge": "0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6" + }, "84532": { "MigrationMultisig": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7", "ReserveSafe": "0x2738F38Fde510743e0c589415E0598C4ceE6eAa7", diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 5562000..dcb0181 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -18,7 +18,7 @@ runtimes: # This is the section where you manage your linters. (https://docs.trunk.io/check/configuration) lint: ignore: - - linters: [gitleaks, trufflehog] + - linters: [gitleaks, trufflehog, checkov] paths: - .treb/*.json # Blockchain contract addresses, not secrets - broadcast/**/*.json # Forge deployment transaction logs diff --git a/script/config/wormhole/NTTConfig.sol b/script/config/wormhole/NTTConfig.sol index 1cc3da1..6f6fa59 100644 --- a/script/config/wormhole/NTTConfig.sol +++ b/script/config/wormhole/NTTConfig.sol @@ -39,6 +39,10 @@ library NTTConfig { uint16 internal constant CELO_WH_CHAIN_ID = 14; uint256 internal constant MONAD_EVM_CHAIN_ID = 143; uint16 internal constant MONAD_WH_CHAIN_ID = 48; + uint256 internal constant POLYGON_EVM_CHAIN_ID = 137; + uint16 internal constant POLYGON_WH_CHAIN_ID = 5; + uint256 internal constant BASE_EVM_CHAIN_ID = 8453; + uint16 internal constant BASE_WH_CHAIN_ID = 30; // ── Rate limit constants ──────────────────────────────────────────── uint256 internal constant USDm_RATE_LIMIT = 500_000e18; @@ -50,13 +54,13 @@ library NTTConfig { // ── Token config getters ───────────────────────────────────────────── /// @notice Returns the full NTT bridge topology for USDm. - /// USDm is burn-mint on BOTH Celo and Monad. + /// USDm is burn-mint on Celo, Monad, and Polygon. function getUSDmConfig() internal pure returns (NTTTokenConfig memory config) { config.tokenName = "USDm"; config.tokenDecimals = 18; config.ownerLabel = "migrationOwner"; - config.chains = new NTTChainConfig[](2); + config.chains = new NTTChainConfig[](3); config.chains[0] = NTTChainConfig({ chainName: "celo", evmChainId: CELO_EVM_CHAIN_ID, @@ -73,10 +77,19 @@ library NTTConfig { isBurning: true, outboundLimit: USDm_RATE_LIMIT }); + config.chains[2] = NTTChainConfig({ + chainName: "polygon", + evmChainId: POLYGON_EVM_CHAIN_ID, + wormholeChainId: POLYGON_WH_CHAIN_ID, + tokenLabel: "USDm", + isBurning: true, + outboundLimit: USDm_RATE_LIMIT + }); - config.inboundLimits = new NTTInboundLimit[](2); + config.inboundLimits = new NTTInboundLimit[](3); config.inboundLimits[0] = NTTInboundLimit({fromChainName: "monad", limit: USDm_RATE_LIMIT}); config.inboundLimits[1] = NTTInboundLimit({fromChainName: "celo", limit: USDm_RATE_LIMIT}); + config.inboundLimits[2] = NTTInboundLimit({fromChainName: "polygon", limit: USDm_RATE_LIMIT}); } /// @notice Returns the full NTT bridge topology for GBPm. @@ -110,13 +123,13 @@ library NTTConfig { } /// @notice Returns the full NTT bridge topology for EURm. - /// EURm is burn-mint on BOTH Celo and Monad. + /// EURm is burn-mint on Celo, Monad, Polygon, and Base. function getEURmConfig() internal pure returns (NTTTokenConfig memory config) { config.tokenName = "EURm"; config.tokenDecimals = 18; config.ownerLabel = "migrationOwner"; - config.chains = new NTTChainConfig[](2); + config.chains = new NTTChainConfig[](4); config.chains[0] = NTTChainConfig({ chainName: "celo", evmChainId: CELO_EVM_CHAIN_ID, @@ -133,10 +146,28 @@ library NTTConfig { isBurning: true, outboundLimit: EURm_RATE_LIMIT }); + config.chains[2] = NTTChainConfig({ + chainName: "polygon", + evmChainId: POLYGON_EVM_CHAIN_ID, + wormholeChainId: POLYGON_WH_CHAIN_ID, + tokenLabel: "EURm", + isBurning: true, + outboundLimit: EURm_RATE_LIMIT + }); + config.chains[3] = NTTChainConfig({ + chainName: "base", + evmChainId: BASE_EVM_CHAIN_ID, + wormholeChainId: BASE_WH_CHAIN_ID, + tokenLabel: "EURm", + isBurning: true, + outboundLimit: EURm_RATE_LIMIT + }); - config.inboundLimits = new NTTInboundLimit[](2); + config.inboundLimits = new NTTInboundLimit[](4); config.inboundLimits[0] = NTTInboundLimit({fromChainName: "monad", limit: EURm_RATE_LIMIT}); config.inboundLimits[1] = NTTInboundLimit({fromChainName: "celo", limit: EURm_RATE_LIMIT}); + config.inboundLimits[2] = NTTInboundLimit({fromChainName: "polygon", limit: EURm_RATE_LIMIT}); + config.inboundLimits[3] = NTTInboundLimit({fromChainName: "base", limit: EURm_RATE_LIMIT}); } /// @notice Returns the full NTT bridge topology for JPYm. diff --git a/script/deploy/dex/DeployMockCollaterals.s.sol b/script/deploy/dex/DeployMockCollaterals.s.sol index fee1369..2523663 100644 --- a/script/deploy/dex/DeployMockCollaterals.s.sol +++ b/script/deploy/dex/DeployMockCollaterals.s.sol @@ -26,15 +26,13 @@ contract DeployMockCollaterals is TrebScript { for (uint256 i = 0; i < mocks.length; i++) { string memory symbol = mocks[i]; + uint256 decimals = config.getTokenDecimals(symbol); + address addy = deployer.create3("MockERC20").setLabel(symbol) - .deploy( - abi.encode( - string.concat("Mento Mock ", symbol), symbol, config.getTokenDecimals(symbol), deployer.account - ) - ); + .deploy(abi.encode(string.concat("Mento Mock ", symbol), symbol, decimals, deployer.account)); MockERC20 coll = MockERC20(deployer.harness(addy)); - coll.mint(deployer.account, 1000000e18); + coll.mint(deployer.account, 1_000_000 * 10 ** decimals); IOwnable(address(coll)).transferOwnership(address(migrationOwner.account)); console.log("Deployed MockERC20 (%s) at %s", symbol, addy); } diff --git a/script/deploy/wormhole/ConfigureNTT.s.sol b/script/deploy/wormhole/ConfigureNTT.s.sol index 87927e6..8dd8779 100644 --- a/script/deploy/wormhole/ConfigureNTT.s.sol +++ b/script/deploy/wormhole/ConfigureNTT.s.sol @@ -93,7 +93,10 @@ contract ConfigureNTT is NTTScriptBase { peerInboundLimits.push(_findInboundLimit(config, peer.chainName)); } - console.log("=== ConfigureNTT: %s on %s (chain %d) ===", tokenName, _myChain.chainName, _myChain.evmChainId); + console.log(""); + console.log("============================================================"); + console.log(" ConfigureNTT: %s on %s (chain %d)", tokenName, _myChain.chainName, _myChain.evmChainId); + console.log("============================================================"); console.log(" NttManager: %s", localNttManager); console.log(" Transceiver: %s", localTransceiver); console.log(" Mode: %s", _myChain.isBurning ? "burning" : "locking"); @@ -123,7 +126,9 @@ contract ConfigureNTT is NTTScriptBase { _setupOwnership(migrationOwner); console.log(""); - console.log("=== ConfigureNTT: %s complete ===", tokenName); + console.log("============================================================"); + console.log(" ConfigureNTT: %s on %s complete", tokenName, myChain.chainName); + console.log("============================================================"); } // ── Setup helpers (idempotent) ────────────────────────────────────── @@ -134,91 +139,127 @@ contract ConfigureNTT is NTTScriptBase { address remoteXceiver = remoteTransceivers[peerIdx]; uint256 inboundLimit = peerInboundLimits[peerIdx]; - console.log(" Peer: %s (wormhole chain %d)", peer.chainName, uint256(peer.wormholeChainId)); + console.log(""); + console.log(" ------------------------------------------------------------"); + console.log(" >> Peer #%d: %s -> %s", peerIdx + 1, myChain.chainName, peer.chainName); + console.log(" ------------------------------------------------------------"); + console.log(" Remote chain: %s (wormhole id %d)", peer.chainName, uint256(peer.wormholeChainId)); console.log(" Remote NttManager: %s", remoteManager); console.log(" Remote Transceiver: %s", remoteXceiver); + console.log(" Inbound limit: %d %s", inboundLimit / 1e18, tokenName); + console.log(""); // NTT Manager peer bytes32 expectedPeerManager = _toBytes32(remoteManager); NttManagerPeer memory existingPeer = INTTManager(localNttManager).getPeer(peer.wormholeChainId); if (existingPeer.peerAddress != expectedPeerManager) { - console.log(" > Setting NTT Manager peer..."); + console.log(" [+] NttManager (%s) -> peer %s (%s)", myChain.chainName, peer.chainName, remoteManager); + console.log(" Setting NTT Manager peer..."); INTTManager(migrationOwner.harness(localNttManager)) .setPeer(peer.wormholeChainId, expectedPeerManager, tokenDecimals, inboundLimit); } else { - console.log(" > NTT Manager peer already set, checking inbound limit..."); + console.log(" [=] NttManager (%s) -> peer %s already set, skipping", myChain.chainName, peer.chainName); uint256 currentInbound = _untrim(INTTManager(localNttManager).getInboundLimitParams(peer.wormholeChainId).limit); if (currentInbound != inboundLimit) { - console.log(" > Updating inbound limit..."); + console.log( + " Updating inbound limit from %d to %d %s...", + currentInbound / 1e18, + inboundLimit / 1e18, + tokenName + ); INTTManager(migrationOwner.harness(localNttManager)).setInboundLimit(inboundLimit, peer.wormholeChainId); } else { - console.log(" > Inbound limit already correct"); + console.log(" Inbound limit already correct (%d %s), skipping", inboundLimit / 1e18, tokenName); } } // Transceiver wormhole peer bytes32 expectedPeerXceiver = _toBytes32(remoteXceiver); if (ITransceiver(localTransceiver).getWormholePeer(peer.wormholeChainId) != expectedPeerXceiver) { - console.log(" > Setting Transceiver wormhole peer..."); + console.log(" [+] Transceiver (%s) -> peer %s (%s)", myChain.chainName, peer.chainName, remoteXceiver); + console.log(" Setting Transceiver wormhole peer..."); ITransceiver(migrationOwner.harness(localTransceiver)) .setWormholePeer(peer.wormholeChainId, expectedPeerXceiver); } else { - console.log(" > Transceiver wormhole peer already set"); + console.log(" [=] Transceiver (%s) -> peer %s already set, skipping", myChain.chainName, peer.chainName); } } function _setupOutboundLimit(Senders.Sender storage migrationOwner) internal { + console.log(""); + console.log(" ------------------------------------------------------------"); + console.log(" >> Outbound rate limit (%s)", myChain.chainName); + console.log(" ------------------------------------------------------------"); uint256 currentOutbound = _untrim(INTTManager(localNttManager).getOutboundLimitParams().limit); if (currentOutbound != myChain.outboundLimit) { - console.log(" > Setting outbound limit to %d...", myChain.outboundLimit / 1e18); + console.log( + " [+] Setting outbound limit: %d -> %d %s", + currentOutbound / 1e18, + myChain.outboundLimit / 1e18, + tokenName + ); INTTManager(migrationOwner.harness(localNttManager)).setOutboundLimit(myChain.outboundLimit); } else { - console.log(" > Outbound limit already correct, skipping"); + console.log(" [=] Outbound limit already %d %s, skipping", myChain.outboundLimit / 1e18, tokenName); } } function _setupBurnMintPermissions(Senders.Sender storage migrationOwner) internal { + console.log(""); + console.log(" ------------------------------------------------------------"); + console.log(" >> Burn/Mint permissions (%s)", myChain.chainName); + console.log(" ------------------------------------------------------------"); address token = lookupProxyOrFail(myChain.tokenLabel); + console.log(" Token: %s (%s)", myChain.tokenLabel, token); + console.log(" NttManager: %s", localNttManager); + console.log(""); if (!IStableTokenSpoke(token).isBurner(localNttManager)) { - console.log(" > Granting NTT Manager burner permission..."); + console.log(" [+] Granting NTT Manager burner permission on %s...", myChain.tokenLabel); IStableTokenSpoke(migrationOwner.harness(token)).setBurner(localNttManager, true); } else { - console.log(" > NTT Manager already has burner permission, skipping"); + console.log(" [=] NTT Manager already has burner permission, skipping"); } if (!IStableTokenSpoke(token).isMinter(localNttManager)) { - console.log(" > Granting NTT Manager minter permission..."); + console.log(" [+] Granting NTT Manager minter permission on %s...", myChain.tokenLabel); IStableTokenSpoke(migrationOwner.harness(token)).setMinter(localNttManager, true); } else { - console.log(" > NTT Manager already has minter permission, skipping"); + console.log(" [=] NTT Manager already has minter permission, skipping"); } } function _setupOwnership(Senders.Sender storage migrationOwner) internal { + console.log(""); + console.log(" ------------------------------------------------------------"); + console.log(" >> Ownership & Pauser (%s)", myChain.chainName); + console.log(" ------------------------------------------------------------"); + console.log(" Target owner/pauser: %s", owner); + console.log(""); + // NTT Manager ownership (cascades to all registered transceivers) if (IOwnable(localNttManager).owner() != owner) { - console.log(" > Transferring NTT Manager ownership to %s...", owner); + console.log(" [+] Transferring NttManager ownership -> %s", owner); IOwnable(migrationOwner.harness(localNttManager)).transferOwnership(owner); } else { - console.log(" > NTT Manager already owned by %s, skipping", owner); + console.log(" [=] NttManager already owned by %s, skipping", owner); } // Pauser capability does NOT cascade — must be set on each contract if (IPausable(localNttManager).pauser() != owner) { - console.log(" > Transferring NTT Manager pauser to %s...", owner); + console.log(" [+] Transferring NttManager pauser -> %s", owner); IPausable(migrationOwner.harness(localNttManager)).transferPauserCapability(owner); } else { - console.log(" > NTT Manager pauser already correct, skipping"); + console.log(" [=] NttManager pauser already correct, skipping"); } if (IPausable(localTransceiver).pauser() != owner) { - console.log(" > Transferring Transceiver pauser to %s...", owner); + console.log(" [+] Transferring Transceiver pauser -> %s", owner); IPausable(migrationOwner.harness(localTransceiver)).transferPauserCapability(owner); } else { - console.log(" > Transceiver pauser already correct, skipping"); + console.log(" [=] Transceiver pauser already correct, skipping"); } } }