MultiSigManager

Description:

Smart contract deployed on Ethereum with Factory features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/MultiSigManager.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "./interface/IBarkHooks.sol";

contract MultiSigManager {

    address public admin1;
    address public admin2;
    address public admin3;
    address public robot;

    IBarkHooks public barkHooks;

    mapping(bytes32 => mapping(address => bool)) public approvals;

    bytes32 public currentPendingAction;

    event AdminChanged(address oldAdmin, address newAdmin, uint256 adminIndex);
    event RobotChanged(address oldRobot, address newRobot);
    event ActionApproved(bytes32 actionId, address indexed admin);


    modifier onlyAdmins() {
        require(
            msg.sender == admin1 || msg.sender == admin2 || msg.sender == admin3,
            "Not an admin"
        );
        _;
    }

    modifier onlyAdminOrRobot() {
        require(
            msg.sender == admin1 || msg.sender == admin2 || msg.sender == admin3 || msg.sender == robot,
            "Not an admin or robot"
        );
        _;
    }

    constructor(address _admin1, address _admin2, address _admin3, address _robot, address _barkHooks) {
        barkHooks = IBarkHooks(_barkHooks);
        admin1 = _admin1;
        admin2 = _admin2;
        admin3 = _admin3;
        robot = _robot;
    }

    function _clearPreviousPendingAction(bytes32 actionId) internal{
        if (actionId != currentPendingAction && currentPendingAction != bytes32(0)) {
            approvals[currentPendingAction][admin1] = false;
            approvals[currentPendingAction][admin2] = false;
            approvals[currentPendingAction][admin3] = false;
            currentPendingAction = bytes32(0);
        }
        currentPendingAction = actionId;
    }

    function _resetPendingAction(bytes32 actionId) internal{
        approvals[actionId][admin1] = false;
        approvals[actionId][admin2] = false;
        approvals[actionId][admin3] = false;
        currentPendingAction = bytes32(0);
    }

    function changeAdmin(address newAdmin, uint256 adminIndex) external onlyAdmins {
        require(adminIndex >= 1 && adminIndex <= 3, "Invalid admin index");
        require(newAdmin != admin1 && newAdmin != admin2 && newAdmin != admin3, "Invalid newAdmin");

        bytes32 actionId = keccak256(abi.encodePacked("changeAdmin", newAdmin, adminIndex));

        _clearPreviousPendingAction(actionId);

        approvals[actionId][msg.sender] = true;
        emit ActionApproved(actionId, msg.sender);

        if (_getApprovalCount(actionId) == 3) {

            address[3] memory admins = [admin1, admin2, admin3];
            address oldAdmin = admins[adminIndex - 1];

            if (adminIndex == 1) admin1 = newAdmin;
            else if (adminIndex == 2) admin2 = newAdmin;
            else if (adminIndex == 3) admin3 = newAdmin;

            _resetPendingAction(actionId);

            emit AdminChanged(oldAdmin, newAdmin, adminIndex);
        }
    }

    function changeRobot(address newRobot) external onlyAdmins {
        require(robot != newRobot, "Invalid newRobot");

        bytes32 actionId = keccak256(abi.encodePacked("changeRobot", newRobot));

        _clearPreviousPendingAction(actionId);

        approvals[actionId][msg.sender] = true;
        emit ActionApproved(actionId, msg.sender);

        if (_getApprovalCount(actionId) == 2) {
            address oldRobot = robot;
            robot = newRobot;

            _resetPendingAction(actionId);

            emit RobotChanged(oldRobot, newRobot);
        }
    }


    function _getApprovalCount(bytes32 actionId) internal view returns (uint256 count) {
        if (approvals[actionId][admin1]) count++;
        if (approvals[actionId][admin2]) count++;
        if (approvals[actionId][admin3]) count++;
        return count;
    }

    function setClose() external onlyAdminOrRobot {
        barkHooks.setClose();
    }

    function setFeeCalculator(address newCalculator) external onlyAdmins {

        bytes32 actionId = keccak256(abi.encodePacked("setFeeCalculator", newCalculator));

        _clearPreviousPendingAction(actionId);

        approvals[actionId][msg.sender] = true;
        emit ActionApproved(actionId, msg.sender);

        if (_getApprovalCount(actionId) == 2) {
            barkHooks.setFeeCalculator(newCalculator);

            _resetPendingAction(actionId);
        }
    }

    function setCurveDisable(bool disable) external onlyAdmins {
        bytes32 actionId = keccak256(abi.encodePacked("setCurveDisable", disable));

        _clearPreviousPendingAction(actionId);

        approvals[actionId][msg.sender] = true;
        emit ActionApproved(actionId, msg.sender);

        if (_getApprovalCount(actionId) == 2) {
            barkHooks.setCurveDisable(disable);

            _resetPendingAction(actionId);
        }
    }

    function setDonateDisable(bool disable) external onlyAdmins {
        bytes32 actionId = keccak256(abi.encodePacked("setDonateDisable", disable));

        _clearPreviousPendingAction(actionId);

        approvals[actionId][msg.sender] = true;
        emit ActionApproved(actionId, msg.sender);

        if (_getApprovalCount(actionId) == 2) {
            barkHooks.setDonateDisable(disable);

            _resetPendingAction(actionId);
        }
    }

    function setTreasury(address newTreasury) external onlyAdmins {
        bytes32 actionId = keccak256(abi.encodePacked("setTreasury", newTreasury));

        _clearPreviousPendingAction(actionId);

        approvals[actionId][msg.sender] = true;
        emit ActionApproved(actionId, msg.sender);

        if (_getApprovalCount(actionId) == 2) {
            barkHooks.setTreasury(newTreasury);

            _resetPendingAction(actionId);
        }
    }

    // transfer masterChef owner
    function transferOwnership(address newOwner) external onlyAdmins {

        bytes32 actionId = keccak256(abi.encodePacked("transferOwnership", newOwner));

        _clearPreviousPendingAction(actionId);

        approvals[actionId][msg.sender] = true;
        emit ActionApproved(actionId, msg.sender);

        if (_getApprovalCount(actionId) == 2) {
            barkHooks.transferOwnership(newOwner);

            _resetPendingAction(actionId);
        }

    }
}
"
    },
    "src/interface/IBarkHooks.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface IBarkHooks {
    function setClose() external;
    function setFeeCalculator(address newCalculator) external;
    function setCurveDisable(bool disable) external;
    function setDonateDisable(bool disbale) external;
    function setTreasury(address newTreasury) external;

    function transferOwnership(address newOwner) external;
}
"
    }
  },
  "settings": {
    "remappings": [
      "@ensdomains/=lib/v4-core/node_modules/@ensdomains/",
      "@openzeppelin/=lib/v4-core/lib/openzeppelin-contracts/",
      "@uniswap/v4-core/=lib/v4-periphery/lib/v4-core/",
      "ds-test/=lib/solmate/lib/ds-test/src/",
      "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
      "forge-gas-snapshot/=lib/v4-periphery/lib/permit2/lib/forge-gas-snapshot/src/",
      "forge-std/=lib/forge-std/src/",
      "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
      "hardhat/=lib/v4-core/node_modules/hardhat/",
      "openzeppelin-contracts/=lib/openzeppelin-contracts/",
      "permit2/=lib/v4-periphery/lib/permit2/",
      "solmate/=lib/solmate/src/",
      "v4-core/=lib/v4-core/src/",
      "v4-periphery/=lib/v4-periphery/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "cancun",
    "viaIR": false
  }
}}

Tags:
Factory|addr:0xad6b7eec4e50a9f28e647f371ef4c56535134bee|verified:true|block:23566909|tx:0x51f1b7116296ac0c7fb4e2d8d9283ff0a825910c46e3ebeff276a3e3df9341ea|first_check:1760347616

Submitted on: 2025-10-13 11:26:56

Comments

Log in to comment.

No comments yet.