CFHelpersStatev0

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}
"
    },
    "@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
"
    },
    "contracts/CFHelpersStatev0.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import "@openzeppelin/contracts/access/Ownable.sol";

interface ICFHelpersVaultFactory {
    function createVault(bytes32 clientId) external returns (address);
}
contract CFHelpersStatev0 {
    // Error codes
    error UnauthorizedUser();
    error UserExists();
    error AddressExists();
    error KeyExists();
    error InvalidInvite();
    error InviteReplay();
    error InviteExpired();
    error InviteExists();
    error InvalidPreimage();
    error InactiveUser();
    error InvalidUser();
    error InvalidPosition();
    error MinAdmins();
    error PolicyReplay();
    error UnauthorizedCaller();
    error InvalidPolicy();
    error InvalidHelper();
    error InvalidPolicyType();
    error InvalidClient();
    // Structs
    struct User {
        address addr;
        string position;
        bool isAdmin;
        bool active;
    }

    struct Policy {
        bool active;
        string title;
        string policyType;
        address[] signers;
        uint256 threshold;
        Transaction transactionDetails;
        Transfer transferDetails;
        bool isTransaction;
    }

    struct Transaction {
        address wrapper;
        string func;
    }

    struct Transfer {
        uint256 maxAmount;
        address token;
        address[] recipients;
    }

    struct Invite {
        bool activated;
        string userId;
        bool isAdmin;
        string userPosition;
        uint256 expireHeight;
    }

    // Mappings
    mapping(string => address) public helperContracts;
    mapping(address => bool) public isCofundAdmin;
    mapping(string => bool) public isSupportedType;
    mapping(bytes32 => mapping(bytes32 => Invite)) public invites;
    mapping(bytes32 => mapping(string => Policy)) public policies;
    mapping(bytes32 => mapping(string => User)) public users;
    mapping(address => mapping(bytes32 => string)) public usersByAddress;
    mapping(bytes32 => uint256) public activeAdmins;
    mapping(bytes32 => mapping(address => mapping(string => bool))) private clientContractAuthBool;
    mapping(bytes32 => address) public clientVaults;

    // Events
    event UserInviteAdded(bytes32 indexed clientId, bytes32 inviteHash, string userId, string position);
    event UserInviteCompleted(bytes32 indexed clientId, bytes32 inviteHash, address userAddress);
    event UserRemoved(bytes32 indexed clientId, string userId, string removedUserId);
    event UserRotated(bytes32 indexed clientId, string userId, bytes newKey);
    event PolicyActivated(bytes32 indexed clientId, string policyId);
    event PolicyDeactivated(bytes32 indexed clientId, string policyId);
    event DebugSetClientContractAuthBool(bytes32 clientId, address contractAddr, string authId, bool value);
    event NewClientCreated(bytes32 indexed clientId, bytes32 inviteHash, string adminId);

    constructor(address initialAdmin) {
        // Initialize helper contracts
        isCofundAdmin[initialAdmin] = true;
        helperContracts["signatures"] = address(0);
        isSupportedType["Contractor_Stipend"] = true;
        isSupportedType["Crypto_Onramp"] = true;
        isSupportedType["Business_Invoice"] = true;
        isSupportedType["Operational_Expense"] = true;
        isSupportedType["Treasury_Management"] = true;

        // Manually create initial admin user (userId = "0")
        bytes32 clientId = 0x16cbd0716887fd9259f39d403e19eb3436e3bdf3c17a37035cf0f8f0d7851e0b;
        users[clientId]["0"] = User({
            addr: initialAdmin,
            position: "admin",
            isAdmin: true,
            active: true
        });

        usersByAddress[initialAdmin][clientId] = "0";
        activeAdmins[clientId] = 1;
    }

    function setHelperContract(string memory contractType, address contractAddress) external {
        // Check that caller is a Cofund Admin
        if (!isCofundAdmin[msg.sender]) revert UnauthorizedCaller();
        // Update helper contracts mapping
        helperContracts[contractType] = contractAddress;
    }

    function setSupportedType(string memory policyType) external {
        // Check that caller is a Cofund Admin
        if (!isCofundAdmin[msg.sender]) revert UnauthorizedCaller();
        // Update supported type
        isSupportedType[policyType] = true;
    }

    function setClientContractAuthBool(bytes32 clientId, address contractAddr, string memory authId, bool value) external {
        // Replay protection: only allow setting if not already set
        if (clientContractAuthBool[clientId][contractAddr][authId]) revert KeyExists();
        emit DebugSetClientContractAuthBool(clientId, contractAddr, authId, value);
        clientContractAuthBool[clientId][contractAddr][authId] = value;
    }

    function getClientContractAuthBool(bytes32 clientId, address contractAddr, string memory authId) external view returns (bool) {
        return clientContractAuthBool[clientId][contractAddr][authId];
    }

    // User Functions
    function addUserInvite(
        bytes32 clientId,
        bytes32 inviteHash,
        string memory callerId,
        string memory newUserId,
        bool isAdmin,
        string memory newUserPosition
    ) external returns (bool) {
        // Checks that caller is the active "users" contract
        if (msg.sender != helperContracts["users"]) revert UnauthorizedCaller();
        // Fetch calling user
        User storage caller = users[clientId][callerId];
        // Check that caller is active
        if (!caller.active) revert InactiveUser();
        // Check that caller address matches tx.origin
        if (caller.addr != tx.origin) revert UnauthorizedUser();
        // Check that invite does not exist
        if (invites[clientId][inviteHash].expireHeight != 0) revert InviteExists();
        // Check that new user does not exist
        if (users[clientId][newUserId].addr != address(0)) revert UserExists();

        // Add invite, expires in 1 day (7160 blocks)
        invites[clientId][inviteHash] = Invite({
            activated: false,
            userId: newUserId,
            isAdmin: isAdmin,
            userPosition: newUserPosition,
            expireHeight: block.number + 7160
        });

        // Emit event
        emit UserInviteAdded(clientId, inviteHash, newUserId, newUserPosition);
        return true;
    }
    function completeUserInvite(
        bytes32 clientId,
        bytes32 inviteHash,
        uint256 invitePreimageId
    ) external returns (bool) {
        Invite storage invite = invites[clientId][inviteHash];
        if (invite.expireHeight == 0) revert InvalidInvite();
        if (invite.activated) revert InviteReplay();
        if (block.number > invite.expireHeight) revert InviteExpired();

        // Verify preimage hash
        bytes32 computedHash = keccak256(abi.encodePacked(
            keccak256(abi.encodePacked(invitePreimageId)),
            keccak256(abi.encodePacked(clientId))
        ));
        if (computedHash != inviteHash) revert InvalidPreimage();

        // Add new user
        users[clientId][invite.userId] = User({
            addr: tx.origin,
            position: invite.userPosition,
            isAdmin: invite.isAdmin,
            active: true
        });

        usersByAddress[tx.origin][clientId] = invite.userId;
        
        if (invite.isAdmin) {
            activeAdmins[clientId]++;
        }

        invite.activated = true;

        emit UserInviteCompleted(clientId, inviteHash, tx.origin);
        return true;
    }
    function removeUser(
        bytes32 clientId,
        string memory userId,
        string memory removedUserId,
        uint256 adminSignedDataOptLength
    ) external returns (bool) {
        // Check that caller is the active "users" contract
        if (msg.sender != helperContracts["users"]) revert UnauthorizedCaller();
        // Fetch calling user
        User storage removedUser = users[clientId][removedUserId];
        // Update user to inactive
        users[clientId][removedUserId] = User({
            addr: removedUser.addr,
            isAdmin: removedUser.isAdmin,
            position: removedUser.position,
            active: false
        });
        // Emit event
        emit UserRemoved(clientId, userId, removedUserId);
        return true;
    }
    
    // Policy Functions 
    // Activate Policy
    function activatePolicy(
        bytes32 clientId,
        string memory callerId,
        string memory policyId,
        string memory policyType,
        string memory title,
        address[] memory signers,
        uint256 threshold,
        Transaction memory transactionDetails,
        Transfer memory transferDetails,
        bool isTransaction
    ) external returns (bool) {
        // Check that caller is the active "policies" contract
        if (msg.sender != helperContracts["policies"]) revert UnauthorizedCaller();
        // Fetch User
        User storage caller = users[clientId][callerId];
        // Check that user is active
        if (!caller.active) revert InactiveUser();
        // Check that policy does not exist
        if (policies[clientId][policyId].active) revert InvalidPolicy();
        // Check that policy type is supported
        if (!isSupportedType[policyType]) revert InvalidPolicyType();
        // Update policy
        policies[clientId][policyId] = Policy({
            active: true,
            title: title,
            policyType: policyType,
            signers: signers,
            threshold: threshold,
            transactionDetails: transactionDetails,
            transferDetails: transferDetails,
            isTransaction: isTransaction
        });

        emit PolicyActivated(clientId, policyId);
        return true;
    }
    // Deactivate Policy
    function deactivatePolicy(
        bytes32 clientId,
        string memory callerId,
        string memory policyId
    ) external returns (bool) {
        if (msg.sender != helperContracts["policies"]) revert UnauthorizedCaller();
        
        User storage caller = users[clientId][callerId];
        if (!caller.active) revert InactiveUser();
        
        Policy storage policy = policies[clientId][policyId];
        if (!policy.active) revert InvalidPolicy();
        
        policy.active = false;
        
        emit PolicyDeactivated(clientId, policyId);
        return true;
    }
    // Activate new client
    function newClient(
        bytes32 clientId,
        bytes32 inviteHash,
        string memory adminId
    ) external returns (bool) {
        // Check that caller is a Cofund Admin
        if (!isCofundAdmin[msg.sender]) revert UnauthorizedCaller();

        // Check that invite doesn't exist
        if (invites[clientId][inviteHash].expireHeight != 0) revert InviteExists();

        // Create new invite for first admin
        invites[clientId][inviteHash] = Invite({
            activated: false,
            userId: adminId,
            isAdmin: true,
            userPosition: "admin",
            expireHeight: block.number + 7160  // 1 day in blocks
        });

        // Create new vault for client
        address vaultFactory = helperContracts["vaults"];
        if (vaultFactory == address(0)) revert InvalidHelper();

        address vault = ICFHelpersVaultFactory(vaultFactory).createVault(clientId);
        clientVaults[clientId] = vault;

        emit NewClientCreated(clientId, inviteHash, adminId);
        return true;
    }

    // View Functions
    function getUser(bytes32 clientId, string memory userId) external view returns (User memory) {
        return users[clientId][userId];
    }

    function getPolicy(bytes32 clientId, string memory policyId) external view returns (Policy memory) {
        return policies[clientId][policyId];
    }

    function getActiveAdmins(bytes32 clientId) external view returns (uint256) {
        return activeAdmins[clientId];
    }

    function getInvite(bytes32 clientId, bytes32 inviteHash) external view returns (Invite memory) {
        return invites[clientId][inviteHash];
    }

    function getUserIdByAddress(address userAddress, bytes32 clientId) external view returns (string memory) {
        return usersByAddress[userAddress][clientId];
    }
}"
    }
  },
  "settings": {
    "viaIR": true,
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "evmVersion": "paris",
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    }
  }
}}

Tags:
Multisig, Multi-Signature, Factory|addr:0x42f3dce932aab36eccf6458e1f0f46ea88973566|verified:true|block:23418686|tx:0x62236ba99e941b3d9b5caffa01f59f296d725feace852c0e895bca600fbff45b|first_check:1758549728

Submitted on: 2025-09-22 16:02:09

Comments

Log in to comment.

No comments yet.