synapsecns/sanguine

View on GitHub
packages/contracts-rfq/script/ConfigureFastBridge.s.sol

Summary

Maintainability
Test Coverage
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {FastBridge} from "../contracts/FastBridge.sol";

import {SynapseScript, stdJson} from "@synapsecns/solidity-devops/src/SynapseScript.sol";

// solhint-disable no-empty-blocks
contract ConfigureFastBridge is SynapseScript {
    using stdJson for string;

    string public constant NAME = "FastBridge";

    FastBridge public fastBridge;
    string public config;

    /// @notice We include an empty "test" function so that this contract does not appear in the coverage report.
    function testConfigureFastBridge() external {}

    function run() external broadcastWithHooks {
        configureFB(ENVIRONMENT_PROD);
    }

    function runTestnet() external broadcastWithHooks {
        configureFB("testnet");
    }

    function configureFB(string memory environment) internal {
        loadConfig(environment);
        syncRole("governor", fastBridge.GOVERNOR_ROLE());
        setChainGasAmount();
        setProtocolFeeRate();
        syncRole("guard", fastBridge.GUARD_ROLE());
        syncRole("relayer", fastBridge.RELAYER_ROLE());
        syncRole("refunder", fastBridge.REFUNDER_ROLE());
    }

    function loadConfig(string memory environment) internal {
        config = readGlobalDeployConfig({contractName: NAME, environment: environment, revertIfNotFound: true});
        fastBridge = FastBridge(getDeploymentAddress({contractName: NAME, revertIfNotFound: true}));
    }

    function setChainGasAmount() internal {
        printLog("Setting chain gas amount");
        uint256 chainGasAmount = config.readUint(".chainGasAmount");
        string memory action = string.concat("set to ", vm.toString(chainGasAmount));
        if (fastBridge.chainGasAmount() != chainGasAmount) {
            fastBridge.setChainGasAmount(chainGasAmount);
            printSuccessWithIndent(string.concat("Chain gas amount ", action));
        } else {
            printSkipWithIndent(string.concat("already ", action));
        }
    }

    function setProtocolFeeRate() internal {
        printLog("Setting protocol fee rate");
        uint256 protocolFeeRate = config.readUint(".protocolFeeRate");
        string memory action = string.concat("set to ", vm.toString(protocolFeeRate));
        if (fastBridge.protocolFeeRate() != protocolFeeRate) {
            fastBridge.setProtocolFeeRate(protocolFeeRate);
            printSuccessWithIndent(string.concat("Protocol fee rate ", action));
        } else {
            printSkipWithIndent(string.concat("already ", action));
        }
    }

    function syncRole(string memory roleName, bytes32 role) internal {
        string memory roleNamePlural = string.concat(roleName, "s");
        printLog(string.concat("Syncing ", roleNamePlural));
        address[] memory members = config.readAddressArray(string.concat(".accounts.", roleNamePlural));
        address[] memory existingMembers = getMembers(role);
        // Remove members that are not in the config
        uint256 removed = 0;
        for (uint256 i = 0; i < existingMembers.length; i++) {
            if (!contains(members, existingMembers[i])) {
                fastBridge.revokeRole(role, existingMembers[i]);
                printSuccessWithIndent(string.concat("Removed ", roleName, " ", vm.toString(existingMembers[i])));
                ++removed;
            }
        }
        // Add members that are in the config but not in the contract
        uint256 added = 0;
        for (uint256 i = 0; i < members.length; i++) {
            if (!contains(existingMembers, members[i])) {
                fastBridge.grantRole(role, members[i]);
                printSuccessWithIndent(string.concat("Added ", roleName, " ", vm.toString(members[i])));
                ++added;
            }
        }
        if (added + removed == 0) {
            printSkipWithIndent(string.concat(roleNamePlural, " are up to date"));
        } else {
            printLog(
                string.concat("Added ", vm.toString(added), " and removed ", vm.toString(removed), " ", roleNamePlural)
            );
        }
    }

    function getMembers(bytes32 role) internal view returns (address[] memory members) {
        uint256 count = fastBridge.getRoleMemberCount(role);
        members = new address[](count);
        for (uint256 i = 0; i < count; i++) {
            members[i] = fastBridge.getRoleMember(role, i);
        }
    }

    function contains(address[] memory array, address value) internal pure returns (bool) {
        for (uint256 i = 0; i < array.length; i++) {
            if (array[i] == value) return true;
        }
        return false;
    }
}