DACAuthority

Description:

Decentralized Finance (DeFi) protocol contract providing Swap, Liquidity, Factory functionality.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/DACAuthority.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

import {IDACAuthority} from "./IDACAuthority.sol";
import {DACAccessManaged} from "./DACAccessManaged.sol";

// ================================================================
// │                           ERRORS                             │
// ================================================================

/**
 * @dev Thrown when the admin is not a valid admin account (e.g., `address(0)`).
 * @param adminAccount The invalid admin account.
 */
error DACAuthority__InvalidAdmin(address adminAccount);
/**
 * @dev Thrown when the Chronicles Agent is not a valid Chronicles Agent account (e.g., `address(0)`).
 * @param chroniclesAgentAccount The invalid Chronicles Agent account.
 */
error DACAuthority__InvalidChroniclesAgent(address chroniclesAgentAccount);
/**
 * @dev Thrown when the Liquidity Manager Agent is not a valid Liquidity Manager Agent account (e.g., `address(0)`).
 * @param liquidityAgentAccount The invalid Liquidity Manager Agent account.
 */
error DACAuthority__InvalidLiquidityAgent(address liquidityAgentAccount);
/**
 * @dev Thrown when the Treasurer Agent is not a valid Treasurer Agent account (e.g., `address(0)`).
 * @param treasurerAgentAccount The invalid Treasurer Agent account.
 */
error DACAuthority__InvalidTreasurerAgent(address treasurerAgentAccount);
/**
 * @dev Thrown when the treasury is not a valid treasury contract (e.g., `address(0)`).
 * @param treasury The invalid treasury account.
 */
error DACAuthority__InvalidTreasury(address treasury);
/**
 * @dev Thrown when trying to whitelist an invalid swapper account.
 * @param swapper The invalid swapper account.
 */
error DACAuthority__InvalidSwapper(address swapper);
/**
 * @dev Thrown when trying to whitelist a swapper that's already whitelisted.
 * @param swapper The swapper account already whitelisted.
 */
error DACAuthority__SwapperAlreadyWhitelisted(address swapper);
/**
 * @dev Thrown when trying to disable a swapper that's not whitelisted.
 * @param swapper The swapper account not whitelisted.
 */
error DACAuthority__SwapperNotWhitelisted(address swapper);

/**
 * @title DACAuthority
 * @dev Manages roles and permissions for the DAC (Decentralized AI Chronicles) ecosystem.
 * This contract serves as the central authority to manage access control across various
 * components of the DAC ecosystem. It allows for role management
 * and validation of permissions required by other contracts in the ecosystem.
 */
contract DACAuthority is IDACAuthority, DACAccessManaged {
    // ================================================================
    // │                           CONSTANTS                          │
    // ================================================================

    // Time period for which a swapper is timelocked
    uint256 public constant SWAPPER_TIMELOCK = 7 days;

    // ================================================================
    // │                      State variables                         │
    // ================================================================

    address private s_admin;
    address private s_chroniclesAgent;
    address private s_liquidityAgent;
    address private s_treasurerAgent;
    address private s_treasury;

    // Mapping from swapper address to activation timestamp
    mapping(address => uint256) private s_swappers;

    // Array to keep track of all swappers for enumeration
    address[] private s_swapperList;

    // ================================================================
    // │                        Constructor                           │
    // ================================================================

    constructor(
        address initialAdmin,
        address initialChroniclesAgent,
        address initialLiquidityAgent,
        address initialTreasurerAgent
    ) DACAccessManaged(IDACAuthority(address(this))) {
        if (initialAdmin == address(0)) {
            revert DACAuthority__InvalidAdmin(address(0));
        }
        if (initialChroniclesAgent == address(0)) {
            revert DACAuthority__InvalidChroniclesAgent(address(0));
        }
        if (initialLiquidityAgent == address(0)) {
            revert DACAuthority__InvalidLiquidityAgent(address(0));
        }
        if (initialTreasurerAgent == address(0)) {
            revert DACAuthority__InvalidTreasurerAgent(address(0));
        }
        _setAdmin(initialAdmin);
        _setChroniclesAgent(initialChroniclesAgent);
        _setLiquidityAgent(initialLiquidityAgent);
        _setTreasurerAgent(initialTreasurerAgent);
    }

    // ================================================================
    // │                         Functions                            │
    // ================================================================

    /**
     * @dev Set the new DAC Admin.
     * Can only be called by the current admin.
     */
    function setAdmin(address newAdmin) external onlyAdmin {
        if (newAdmin == address(0)) {
            revert DACAuthority__InvalidAdmin(address(0));
        }
        _setAdmin(newAdmin);
    }

    /**
     * @dev Set the new DAC Chronicles Agent.
     * Can only be called by the current admin.
     */
    function setChroniclesAgent(address newChroniclesAgent) external onlyAdmin {
        if (newChroniclesAgent == address(0)) {
            revert DACAuthority__InvalidChroniclesAgent(address(0));
        }
        _setChroniclesAgent(newChroniclesAgent);
    }

    /**
     * @dev Set the new Liquidity Manager Agent.
     * Can only be called by the current admin.
     */
    function setLiquidityAgent(address newLiquidityAgent) external onlyAdmin {
        if (newLiquidityAgent == address(0)) {
            revert DACAuthority__InvalidLiquidityAgent(address(0));
        }
        _setLiquidityAgent(newLiquidityAgent);
    }

    /**
     * @dev Set the new Treasurer Agent.
     * Can only be called by the current admin.
     */
    function setTreasurerAgent(address newTreasurerAgent) external onlyAdmin {
        if (newTreasurerAgent == address(0)) {
            revert DACAuthority__InvalidTreasurerAgent(address(0));
        }
        _setTreasurerAgent(newTreasurerAgent);
    }

    /**
     * @dev Set the new DAC Treasury.
     * Can only be called by the current admin.
     */
    function setTreasury(address newTreasury) external onlyAdmin {
        if (newTreasury == address(0)) {
            revert DACAuthority__InvalidTreasury(address(0));
        }
        _setTreasury(newTreasury);
    }

    /**
     * @inheritdoc IDACAuthority
     */
    function admin() external view override returns (address) {
        return s_admin;
    }

    /**
     * @inheritdoc IDACAuthority
     */
    function chroniclesAgent() external view override returns (address) {
        return s_chroniclesAgent;
    }

    /**
     * @inheritdoc IDACAuthority
     */
    function liquidityManagerAgent() external view override returns (address) {
        return s_liquidityAgent;
    }

    /**
     * @inheritdoc IDACAuthority
     */
    function treasurerAgent() external view override returns (address) {
        return s_treasurerAgent;
    }

    /**
     * @inheritdoc IDACAuthority
     */
    function treasury() external view override returns (address) {
        return s_treasury;
    }

    /**
     * @inheritdoc IDACAuthority
     */
    function isSwapper(address account) external view override returns (bool) {
        uint256 activationTime = s_swappers[account];
        return activationTime != 0 && block.timestamp >= activationTime;
    }

    /**
     * @inheritdoc IDACAuthority
     */
    function getSwappers() external view override returns (address[] memory) {
        return s_swapperList;
    }

    /**
     * @inheritdoc IDACAuthority
     */
    function getSwapperActivationTime(address account) external view override returns (uint256) {
        return s_swappers[account];
    }

    /**
     * @dev Whitelists a new swapper with a 7-day activation timelock.
     * Can only be called by the admin.
     * @param swapper The address to be whitelisted as a swapper.
     */
    function whitelistSwapper(address swapper) external onlyAdmin {
        if (swapper == address(0)) {
            revert DACAuthority__InvalidSwapper(swapper);
        }
        if (s_swappers[swapper] != 0) {
            revert DACAuthority__SwapperAlreadyWhitelisted(swapper);
        }
        uint256 activationTime = block.timestamp + SWAPPER_TIMELOCK;
        s_swappers[swapper] = activationTime;
        s_swapperList.push(swapper);
        emit SwapperWhitelisted(swapper, activationTime);
    }

    /**
     * @dev Disables a swapper immediately.
     * Can only be called by the admin.
     * @param swapper The address of the swapper to disable.
     */
    function disableSwapper(address swapper) external onlyAdmin {
        if (s_swappers[swapper] == 0) {
            revert DACAuthority__SwapperNotWhitelisted(swapper);
        }
        delete s_swappers[swapper];
        // Remove from swapperList
        for (uint256 i = 0; i < s_swapperList.length; i++) {
            if (s_swapperList[i] == swapper) {
                s_swapperList[i] = s_swapperList[s_swapperList.length - 1];
                s_swapperList.pop();
                break;
            }
        }
        emit SwapperDisabled(swapper);
    }

    /**
     * @dev Set the new DAChronicle Admin.
     * Private function without access restriction.
     */
    function _setAdmin(address newAdmin) private {
        address oldAdmin = s_admin;
        s_admin = newAdmin;
        emit AdminSet(oldAdmin, newAdmin);
    }

    /**
     * @dev Set the new DAC Chronicles Agent.
     * Private function without access restriction.
     */
    function _setChroniclesAgent(address newChroniclesAgent) private {
        address oldChroniclesAgent = s_chroniclesAgent;
        s_chroniclesAgent = newChroniclesAgent;
        emit ChroniclesAgentSet(oldChroniclesAgent, newChroniclesAgent);
    }

    /**
     * @dev Set the new DAC Liquidity Manager Agent.
     * Private function without access restriction.
     */
    function _setLiquidityAgent(address newLiquidityAgent) private {
        address oldLiquidityAgent = s_liquidityAgent;
        s_liquidityAgent = newLiquidityAgent;
        emit LiquidityAgentSet(oldLiquidityAgent, newLiquidityAgent);
    }

    /**
     * @dev Set the new DAC Treasurer Agent.
     * Private function without access restriction.
     */
    function _setTreasurerAgent(address newTreasurerAgent) private {
        address oldTreasurerAgent = s_treasurerAgent;
        s_treasurerAgent = newTreasurerAgent;
        emit TreasurerAgentSet(oldTreasurerAgent, newTreasurerAgent);
    }

    /**
     * @dev Set the new DAC Treasury.
     * Private function without access restriction.
     */
    function _setTreasury(address newTreasury) private {
        address oldTreasury = s_treasury;
        s_treasury = newTreasury;
        emit TreasurySet(oldTreasury, newTreasury);
    }
}
"
    },
    "src/IDACAuthority.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

/**
 * @title IDACAuthority
 * @dev Interface for the DACAuthority contract, which defines events and functions
 * that other contracts in the DAC (Decentralized AI Chronicles) ecosystem can interact with.
 */
interface IDACAuthority {
    // ================================================================
    // │                           Events                             │
    // ================================================================

    /**
     * @dev Emitted when the admin account is updated.
     * @param previousAdmin The address of the previous admin.
     * @param newAdmin The address of the new admin.
     */
    event AdminSet(address indexed previousAdmin, address indexed newAdmin);

    /**
     * @dev Emitted when the chronicles agent account is updated.
     * @param previousChroniclesAgent The address of the previous chronicles agent.
     * @param newChroniclesAgent The address of the new chronicles agent.
     */
    event ChroniclesAgentSet(address indexed previousChroniclesAgent, address indexed newChroniclesAgent);

    /**
     * @dev Emitted when the liquidity manager agent account is updated.
     * @param previousLiquidityAgent The address of the previous liquidity manager agent.
     * @param liquidityAgent The address of the new liquidity manager agent.
     */
    event LiquidityAgentSet(address indexed previousLiquidityAgent, address indexed liquidityAgent);

    /**
     * @dev Emitted when the treasurer agent account is updated.
     * @param previousTreasurerAgent The address of the previous treasurer agent.
     * @param treasurerAgent The address of the new treasurer agent.
     */
    event TreasurerAgentSet(address indexed previousTreasurerAgent, address indexed treasurerAgent);

    /**
     * @dev Emitted when the treasury contract is updated.
     * @param previousTreasury The address of the previous treasury contract.
     * @param newTreasury The address of the new treasury contract.
     */
    event TreasurySet(address indexed previousTreasury, address indexed newTreasury);

    /**
     * @dev Emitted when a new swapper is proposed to be whitelisted.
     * @param swapper The address of the swapper proposed to be whitelisted.
     * @param activationTime The timestamp when the swapper becomes active.
     */
    event SwapperWhitelisted(address indexed swapper, uint256 activationTime);

    /**
     * @dev Emitted when a swapper is disabled.
     * @param swapper The address of the swapper that has been disabled.
     */
    event SwapperDisabled(address indexed swapper);

    // ================================================================
    // │                         Functions                            │
    // ================================================================

    /**
     * @notice Returns the address of the admin account.
     * @return The current admin address.
     */
    function admin() external view returns (address);

    /**
     * @notice Returns the address of the chronicles agent account.
     * @return The current chronicles agent address.
     */
    function chroniclesAgent() external view returns (address);

    /**
     * @notice Returns the address of the liquidity manager agent account.
     * @return The current liquidity manager agent address.
     */
    function liquidityManagerAgent() external view returns (address);

    /**
     * @notice Returns the address of the treasurer agent account.
     * @return The current treasurer agent address.
     */
    function treasurerAgent() external view returns (address);

    /**
     * @notice Returns the address of the treasury contract.
     * @return The current treasury contract address.
     */
    function treasury() external view returns (address);

    /**
     * @notice Checks if an address is an active swapper.
     * @param account The address to check.
     * @return True if the address is an active swapper, false otherwise.
     */
    function isSwapper(address account) external view returns (bool);

    /**
     * @notice Returns a list of all whitelisted swappers.
     * @return An array of swapper addresses.
     */
    function getSwappers() external view returns (address[] memory);

    /**
     * @notice Returns the activation timestamp of a swapper.
     * @param account The swapper address.
     * @return The timestamp when the swapper becomes active.
     */
    function getSwapperActivationTime(address account) external view returns (uint256);
}
"
    },
    "src/DACAccessManaged.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.24;

import {IDACAuthority} from "./IDACAuthority.sol";

// ================================================================
// │                           ERRORS                             │
// ================================================================

/**
 * @dev Thrown when the authority is not a authority contract (e.g., `address(0)`).
 * @param authority The invalid authority contract.
 */
error DACAuthority__InvalidAuthority(address authority);
/**
 * @dev Thrown when the caller is not authorized to perform an admin operation.
 * @param account The address of the unauthorized caller.
 */
error DACAccessManaged__AdminUnauthorizedAccount(address account);
/**
 * @dev Thrown when the caller is not authorized to perform a chronicles agent operation.
 * @param account The address of the unauthorized caller.
 */
error DACAccessManaged__ChroniclesAgentUnauthorizedAccount(address account);
/**
 * @dev Thrown when the caller is not authorized to perform a liquidity manager agent operation.
 * @param account The address of the unauthorized caller.
 */
error DACAccessManaged__LiquidityAgentUnauthorizedAccount(address account);
/**
 * @dev Thrown when the caller is not authorized to perform a treasurer agent operation.
 * @param account The address of the unauthorized caller.
 */
error DACAccessManaged__TreasurerAgentUnauthorizedAccount(address account);
/**
 * @dev Thrown when the caller is not authorized to perform a treasury operation.
 * @param treasury The address of the unauthorized caller.
 */
error DACAccessManaged__TreasuryUnauthorizedAccount(address treasury);
/**
 * @dev Thrown when the provided address is not authorized to perform a swapper operation.
 * @param account The address of the unauthorized swapper.
 */
error DACAccessManaged__SwapperUnauthorizedAccount(address account);
/**
 * @dev Thrown when a new authority is not yet proposed.
 */
error DACAuthority__NewAuthorityNotProposed();
/**
 * @dev Thrown when trying to activate an authority before the timelock has passed.
 * @param authority The authority address.
 * @param activationTime The required activation time.
 */
error DACAuthority__AuthorityTimelockNotPassed(address authority, uint256 activationTime);

/**
 * @title DACAccessManaged
 * @dev Abstract contract that provides access control mechanisms for contracts
 * in the DAC (Decentralized AI Chronicles) ecosystem. This contract acts as a
 * base for managing access permissions for different roles such as admin, chronicles agent,
 * liquidity manager agent, treasurer agent, treasury, and swapper.
 */
abstract contract DACAccessManaged {
    // ================================================================
    // │                           CONSTANTS                          │
    // ================================================================

    // Time period for which a new authority is timelocked
    uint256 public constant AUTHORITY_TIMELOCK = 7 days;

    // ================================================================
    // │                      State variables                         │
    // ================================================================

    /**
     * @dev The DACAuthority contract that manages roles and permissions for the DAC ecosystem.
     */
    IDACAuthority private s_authority;

    // Proposed authority change
    IDACAuthority private s_proposedAuthority;
    uint256 private s_authorityChangeExecutionTime;

    // ================================================================
    // │                           Events                             │
    // ================================================================

    /**
     * @dev Emitted when a proposed authority change is executed.
     * @param previousAuthority The address of the previous DACAuthority contract.
     * @param newAuthority The address of the new DACAuthority contract.
     */
    event AuthorityChangeExecuted(address indexed previousAuthority, address indexed newAuthority);

    /**
     * @dev Emitted when a new authority change is proposed.
     * @param proposedAuthority The address of the proposed new authority.
     * @param executionTime The timestamp when the authority change can be executed.
     */
    event AuthorityChangeProposed(address indexed proposedAuthority, uint256 executionTime);

    // ================================================================
    // │                         Modifiers                            │
    // ================================================================

    /**
     * @dev Modifier to restrict access to admin operations.
     * Reverts if the caller is not authorized.
     */
    modifier onlyAdmin() {
        if (s_authority.admin() != msg.sender) {
            revert DACAccessManaged__AdminUnauthorizedAccount(msg.sender);
        }
        _;
    }

    /**
     * @dev Modifier to restrict access to chronicles agent operations.
     * Reverts if the caller is not authorized.
     */
    modifier onlyChroniclesAgent() {
        if (s_authority.chroniclesAgent() != msg.sender) {
            revert DACAccessManaged__ChroniclesAgentUnauthorizedAccount(msg.sender);
        }
        _;
    }

    /**
     * @dev Modifier to restrict access to Liquidity Manager Agent operations.
     * Reverts if the caller is not authorized.
     */
    modifier onlyLiquidityAgent() {
        if (s_authority.liquidityManagerAgent() != msg.sender) {
            revert DACAccessManaged__LiquidityAgentUnauthorizedAccount(msg.sender);
        }
        _;
    }

    /**
     * @dev Modifier to restrict access to Treasurer Agent operations.
     * Reverts if the caller is not authorized.
     */
    modifier onlyTreasurerAgent() {
        if (s_authority.treasurerAgent() != msg.sender) {
            revert DACAccessManaged__TreasurerAgentUnauthorizedAccount(msg.sender);
        }
        _;
    }

    /**
     * @dev Modifier to restrict access to treasury operations.
     * Reverts if the caller is not authorized.
     */
    modifier onlyTreasury() {
        if (s_authority.treasury() != msg.sender) {
            revert DACAccessManaged__TreasuryUnauthorizedAccount(msg.sender);
        }
        _;
    }

    /**
     * @dev Modifier to restrict access to swapper operations.
     * @param swapper The address of the swapper to check.
     * Reverts if the caller is not an active swapper.
     */
    modifier onlySwapper(address swapper) {
        if (!s_authority.isSwapper(swapper)) {
            revert DACAccessManaged__SwapperUnauthorizedAccount(swapper);
        }
        _;
    }

    // ================================================================
    // │                        Constructor                           │
    // ================================================================

    /**
     * @notice Initializes the contract with the specified DACAuthority instance.
     * @param authority The address of the DACAuthority contract.
     */
    constructor(IDACAuthority authority) {
        if (address(authority) == address(0)) {
            revert DACAuthority__InvalidAuthority(address(0));
        }
        s_authority = authority;
        emit AuthorityChangeExecuted(address(0), address(authority));
    }

    // ================================================================
    // │                         Functions                            │
    // ================================================================

    /**
     * @notice Returns the address of the current DACAuthority contract.
     * @return The current DACAuthority contract.
     */
    function getAuthority() public view returns (IDACAuthority) {
        return s_authority;
    }

    /**
     * @notice Proposes a new DACAuthority contract with a 7-day timelock.
     * @dev Can only be called by the admin.
     * Emits an {AuthorityChangeProposed} event.
     * @param newAuthority The address of the new DACAuthority contract.
     */
    function proposeAuthorityChange(IDACAuthority newAuthority) external onlyAdmin {
        if (address(newAuthority) == address(0)) {
            revert DACAuthority__InvalidAuthority(address(0));
        }
        s_proposedAuthority = newAuthority;
        s_authorityChangeExecutionTime = block.timestamp + AUTHORITY_TIMELOCK;
        emit AuthorityChangeProposed(address(newAuthority), s_authorityChangeExecutionTime);
    }

    /**
     * @notice Executes the previously proposed authority change after the timelock.
     * @dev Can only be called by the admin.
     * Emits an {AuthorityChangeExecuted} event.
     */
    function executeAuthorityChange() external onlyAdmin {
        if (address(s_proposedAuthority) == address(0)) {
            revert DACAuthority__NewAuthorityNotProposed();
        }
        if (block.timestamp < s_authorityChangeExecutionTime) {
            revert DACAuthority__AuthorityTimelockNotPassed(
                address(s_proposedAuthority), s_authorityChangeExecutionTime
            );
        }
        address oldAuthority = address(s_authority);
        s_authority = s_proposedAuthority;
        s_proposedAuthority = IDACAuthority(address(0));
        s_authorityChangeExecutionTime = 0;
        emit AuthorityChangeExecuted(address(oldAuthority), address(s_authority));
    }

    /**
     * @notice Returns the address of the proposed new authority.
     * @return The proposed authority address.
     */
    function getProposedAuthority() external view returns (address) {
        return address(s_proposedAuthority);
    }

    /**
     * @notice Returns the timestamp when the authority change can be executed.
     * @return The execution timestamp.
     */
    function getAuthorityChangeExecutionTime() external view returns (uint256) {
        return s_authorityChangeExecutionTime;
    }
}
"
    }
  },
  "settings": {
    "remappings": [
      "@openzeppelin/=lib/openzeppelin-contracts/",
      "@uniswap/=lib/v2-periphery/",
      "@uniswapcore/=lib/v2-core/",
      "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
      "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
      "forge-std/=lib/forge-std/src/",
      "foundry-devops/=lib/foundry-devops/",
      "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
      "openzeppelin-contracts/=lib/openzeppelin-contracts/",
      "v2-core/=lib/v2-core/contracts/",
      "v2-periphery/=lib/v2-periphery/contracts/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "none",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "prague",
    "viaIR": false
  }
}}

Tags:
DeFi, Swap, Liquidity, Factory|addr:0x975f1dac2fc1f24a86284c9c95059f78382bbacb|verified:true|block:23733983|tx:0xfabdd8404299aa16f1ee97f3fec78b04addfcd1b4e6da84d06c0a9b000334168|first_check:1762360102

Submitted on: 2025-11-05 17:28:23

Comments

Log in to comment.

No comments yet.