distributor

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": {
    "contracts/distributor.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import "./errors.sol";
import "./interfaces.sol";

/**
 * @title PAI Distributor Contract
 * @author EdgeServo
 * @notice Central coordinator for managing signature verification, vault registration, and token allocation
 * @dev Implements EIP-712 signature standard to ensure operation security and traceability
 *
 * Core Features:
 * - Vault registration verification: verify user identity and vault ownership
 * - Allocation authorization management: authorize token distribution via signatures
 * - Reward distribution coordination: manage third-party token rewards
 * - Replay attack protection: use nonce mechanism to prevent signature reuse
 *
 * Security Features:
 * - EIP-712 typed data signatures
 * - Timestamp expiration verification
 * - Nonce increment mechanism
 * - Multiple identity authentication
 */
contract distributor {
    // ========== EIP-712 Type Hash Definitions ==========

    /// @notice EIP-712 domain separator type hash
    /// @dev Used to construct domain separator, ensuring signatures are valid within specific domain
    bytes32 private constant DOMAIN_TYPEHASH =
        keccak256(
            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
        );

    /// @notice Vault registration message type hash
    /// @dev Defines data structure for vault registration requests
    bytes32 private constant REGISTRATION_TYPEHASH =
        keccak256(
            "VaultRegistration(address vaultAddress,address user,uint256 nonce,uint256 deadline)"
        );

    /// @notice Allocation authorization message type hash
    /// @dev Defines data structure for token allocation authorizations
    bytes32 private constant ALLOCATION_TYPEHASH =
        keccak256(
            "AllocationAuthorization(address userVault,uint256 amount,uint256 nonce,uint256 deadline)"
        );

    // ========== Immutable State Variables ==========

    /// @notice PAI token contract address
    /// @dev Primary token type managed by the system
    address public immutable pai_token;

    /// @notice Vault factory contract address
    /// @dev Used to verify vault legitimacy
    address public immutable vault_factory;

    /// @notice EIP-712 domain separator
    /// @dev Prevents cross-domain signature replay attacks
    bytes32 public immutable DOMAIN_SEPARATOR;

    // ========== Mutable State Variables ==========

    /// @notice Contract owner address
    /// @dev Account with management privileges
    address public owner;

    /// @notice Authorized signer address
    /// @dev Trusted account responsible for issuing allocation and registration authorizations
    address public signer;

    /// @notice Project vault contract address
    /// @dev Central vault storing tokens to be distributed
    address public project_vault;

    // ========== Mapping Storage ==========

    /// @notice User registration operation nonce mapping
    /// @dev user address => current nonce (prevents registration signature replay)
    mapping(address => uint256) public registration_nonces;

    /// @notice Vault allocation operation nonce mapping
    /// @dev vault address => current nonce (prevents allocation signature replay)
    mapping(address => uint256) public allocation_nonces;

    /// @notice Registered vault verification mapping
    /// @dev vault address => whether registered
    mapping(address => bool) public registered_vaults;

    /// @notice User to vault mapping relationship
    /// @dev user address => vault address (one-to-one relationship)
    mapping(address => address) public user_to_vault;

    // ========== Event Definitions ==========

    /**
     * @notice Vault successfully registered event
     * @param vault Registered vault address
     * @param user Vault owner address
     */
    event VaultRegistered(address indexed vault, address indexed user);

    /**
     * @notice Token allocation executed successfully event
     * @param vault Vault receiving allocation
     * @param amount Amount of tokens allocated
     */
    event AllocationExecuted(address indexed vault, uint256 amount);

    /**
     * @notice Project vault address updated event
     * @param new_project_vault Newly set project vault address
     */
    event ProjectVaultUpdated(address indexed new_project_vault);

    // ========== Constructor ==========

    /**
     * @notice Create distributor contract instance
     * @dev Initialize core parameters and construct EIP-712 domain separator
     *
     * @param _token PAI token contract address
     * @param _signer Authorized signer address
     * @param _factory Vault factory contract address
     *
     * Requirements:
     * - All parameters must not be zero address
     *
     * Reverts:
     * - {ZeroAddress} if any parameter is zero address
     */
    constructor(address _token, address _signer, address _factory) {
        // Parameter validation: ensure all addresses are valid
        if (
            _token == address(0) ||
            _signer == address(0) ||
            _factory == address(0)
        ) {
            revert ZeroAddress();
        }

        // Set immutable variables
        owner = msg.sender;
        pai_token = _token;
        signer = _signer;
        vault_factory = _factory;

        // Initialize EIP-712 domain separator
        // Used to construct unique signature domain, preventing cross-contract/cross-chain replay attacks
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                DOMAIN_TYPEHASH,
                keccak256("PAI Allocation System"), // Domain name
                keccak256("1"), // Version number
                block.chainid, // Chain ID
                address(this) // Verifying contract address
            )
        );
    }

    // ========== Management Functions ==========

    /**
     * @notice Set project vault address (one-time operation)
     * @dev Must be completed before system starts running
     *
     * @param _project_vault Project vault contract address
     *
     * Access control:
     * - Can only be called by contract owner
     * - Can only be set once (cannot be changed)
     *
     * State changes:
     * - Set project_vault address
     *
     * Reverts:
     * - {Unauthorized} if caller is not owner
     * - {ZeroAddress} if project vault address is invalid
     * - {AlreadyExists} if already set
     *
     * Emits:
     * - {ProjectVaultUpdated} project vault set successfully
     */
    function set_project_vault(address _project_vault) external {
        // Permission verification: only owner can set
        if (msg.sender != owner) revert Unauthorized();

        // Parameter validation: address must be valid
        if (_project_vault == address(0)) revert ZeroAddress();

        // State verification: prevent duplicate setting
        if (project_vault != address(0)) revert AlreadyExists();

        // Set project vault address
        project_vault = _project_vault;

        // Emit update event
        emit ProjectVaultUpdated(_project_vault);
    }

    // ========== Registration Functions ==========

    /**
     * @notice Complete vault registration through signature verification
     * @dev Multi-step verification process ensures registration security and legitimacy
     *
     * Execution flow:
     * 1. Basic state checks (project vault, signature validity, etc.)
     * 2. Verify vault legitimacy (factory deployment, ownership)
     * 3. Verify EIP-712 signature
     * 4. Update registration state and mapping relationships
     * 5. Notify project vault and complete vault initialization
     *
     * @param vault_address Vault address to register
     * @param deadline Signature expiration timestamp
     * @param signature EIP-712 signature data (65 bytes)
     *
     * Access control:
     * - Anyone can call
     * - But must be vault owner themselves
     * - Requires valid authorization signature
     *
     * Preconditions:
     * - Project vault is set
     * - Vault is not registered
     * - User does not own other vaults
     * - Vault is deployed by factory
     * - Caller is vault owner
     *
     * Security measures:
     * - EIP-712 signature verification
     * - Timestamp expiration check
     * - Nonce mechanism prevents replay
     * - Multiple identity authentication
     *
     * Reverts:
     * - {ZeroAddress} if project vault not set
     * - {SignatureExpired} if signature has expired
     * - {AlreadyExists} if vault registered or user has vault
     * - {Unauthorized} if vault is invalid or caller is not owner
     * - {InvalidSignature} if signature verification fails
     *
     * Emits:
     * - {VaultRegistered} registration successful
     */
    function register_vault_with_signature(
        address vault_address,
        uint256 deadline,
        bytes calldata signature
    ) external {
        address user = msg.sender;

        // ========== Step 1: Basic State Checks ==========

        // Check if project vault is set
        if (project_vault == address(0)) revert ZeroAddress();

        // Check if signature has expired
        if (block.timestamp > deadline) revert SignatureExpired();

        // Check if vault is already registered
        if (registered_vaults[vault_address]) revert AlreadyExists();

        // Check if user already owns another vault
        if (user_to_vault[user] != address(0)) revert AlreadyExists();

        // ========== Step 2: Verify Vault Legitimacy ==========

        // Verify vault is deployed by factory
        if (!i_vault_factory(vault_factory).is_valid_vault(vault_address)) {
            revert Unauthorized();
        }

        // Verify caller is vault owner
        if (i_vault(vault_address).owner() != user) revert Unauthorized();

        // ========== Step 3: Verify EIP-712 Signature ==========

        // Get current user's registration nonce
        uint256 nonce = registration_nonces[user];

        // Construct typed data structure hash
        bytes32 struct_hash = keccak256(
            abi.encode(
                REGISTRATION_TYPEHASH,
                vault_address,
                user,
                nonce,
                deadline
            )
        );

        // Construct EIP-712 signature digest
        bytes32 digest = keccak256(
            abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, struct_hash)
        );

        // Recover signer address from signature
        address recovered = _recover_signer(digest, signature);

        // Verify signer is authorized signer
        if (recovered != signer) revert InvalidSignature();

        // ========== Step 4: Update State ==========

        // Increment user's registration nonce (prevents signature replay)
        unchecked {
            registration_nonces[user] = nonce + 1;
        }

        // Mark vault as registered
        registered_vaults[vault_address] = true;

        // Establish user to vault mapping relationship
        user_to_vault[user] = vault_address;

        // ========== Step 5: Complete Registration Process ==========

        // Notify project vault for corresponding record
        i_project_vault(project_vault).register_vault(vault_address, user);

        // Complete vault initialization process
        i_vault(vault_address).complete_initialization();

        // Emit registration success event
        emit VaultRegistered(vault_address, user);
    }

    // ========== Allocation Functions ==========

    /**
     * @notice Execute PAI token allocation through signature authorization
     * @dev Transfer specified amount of PAI from project vault to user vault
     *
     * Execution flow:
     * 1. Verify vault is registered
     * 2. Check signature has not expired
     * 3. Verify allocation amount is valid
     * 4. Verify EIP-712 signature
     * 5. Update nonce to prevent replay
     * 6. Call project vault to execute transfer
     *
     * @param amount Amount of tokens to allocate (in wei)
     * @param deadline Signature expiration timestamp
     * @param signature EIP-712 signature data (65 bytes)
     * @return success Whether allocation succeeded
     *
     * Access control:
     * - Can only be called by registered vault contract
     * - Requires valid authorization signature
     *
     * Security measures:
     * - EIP-712 signature verification
     * - Timestamp expiration check
     * - Nonce increment prevents replay
     * - Amount validity verification
     *
     * Reverts:
     * - {Unauthorized} if vault not registered
     * - {SignatureExpired} if signature has expired
     * - {ZeroAmount} if allocation amount is zero
     * - {InvalidSignature} if signature verification fails
     * - {TransferFailed} if transfer fails
     *
     * Emits:
     * - {AllocationExecuted} allocation executed successfully
     */
    function execute_allocation(
        uint256 amount,
        uint256 deadline,
        bytes calldata signature
    ) external returns (bool) {
        address user_vault = msg.sender;

        // ========== Step 1: Basic Verification ==========

        // Verify caller is registered vault
        if (!registered_vaults[user_vault]) revert Unauthorized();

        // Check if signature has expired
        if (block.timestamp > deadline) revert SignatureExpired();

        // Verify allocation amount is valid
        if (amount == 0) revert ZeroAmount();

        // ========== Step 2: Verify Signature ==========

        // Get current vault's allocation nonce
        uint256 nonce = allocation_nonces[user_vault];

        // Construct typed data structure hash
        bytes32 struct_hash = keccak256(
            abi.encode(ALLOCATION_TYPEHASH, user_vault, amount, nonce, deadline)
        );

        // Construct EIP-712 signature digest
        bytes32 digest = keccak256(
            abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, struct_hash)
        );

        // Recover and verify signer
        address recovered = _recover_signer(digest, signature);
        if (recovered != signer) revert InvalidSignature();

        // ========== Step 3: Update State ==========

        // Increment vault's allocation nonce (prevents signature replay)
        unchecked {
            allocation_nonces[user_vault] = nonce + 1;
        }

        // ========== Step 4: Execute Allocation ==========

        // Call project vault to execute actual transfer
        bool success = i_project_vault(project_vault).allocate_to_user(
            user_vault,
            amount
        );

        // Verify transfer result
        if (!success) revert TransferFailed();

        // Emit allocation execution event
        emit AllocationExecuted(user_vault, amount);

        return true;
    }

    // ========== Reward Distribution Functions ==========

    /**
     * @notice Distribute third-party token rewards to specified vault
     * @dev Called by project vault, coordinates reward token transfer
     *
     * @param vault_address Vault receiving rewards
     * @param token_address Reward token contract address
     *
     * Access control:
     * - Can only be called by project vault contract
     * - Target vault must be registered
     *
     * Reverts:
     * - {Unauthorized} if caller is not project vault or vault not registered
     */
    function distribute_award(
        address vault_address,
        address token_address
    ) external {
        // Permission verification: only project vault can initiate reward distribution
        if (msg.sender != project_vault) revert Unauthorized();

        // Verify target vault is registered
        if (!registered_vaults[vault_address]) revert Unauthorized();

        // Call vault's award withdrawal function
        i_vault(vault_address).withdraw_award(token_address);
    }

    // ========== Internal Functions ==========

    /**
     * @notice Recover signer address from EIP-712 signature
     * @dev Uses ecrecover precompiled contract for elliptic curve signature recovery
     *
     * @param digest EIP-712 message digest (32 bytes)
     * @param signature Signature data (65 bytes: r + s + v)
     * @return Ethereum address of signer
     *
     * Signature format:
     * - bytes[0:32]: r value (x coordinate of elliptic curve point)
     * - bytes[32:64]: s value (signature proof)
     * - bytes[64]: v value (recovery identifier, 27 or 28)
     *
     * Reverts:
     * - {InvalidAmount} if signature length is not 65 bytes
     * - {InvalidAmount} if v value is not 27 or 28
     */
    function _recover_signer(
        bytes32 digest,
        bytes calldata signature
    ) private pure returns (address) {
        // Verify signature length
        if (signature.length != 65) revert InvalidAmount();

        bytes32 r;
        bytes32 s;
        uint8 v;

        // Use inline assembly for efficient signature parameter extraction
        // Avoids unnecessary memory copies
        assembly {
            // Extract r value (first 32 bytes)
            r := calldataload(signature.offset)
            // Extract s value (next 32 bytes)
            s := calldataload(add(signature.offset, 32))
            // Extract v value (last 1 byte)
            v := byte(0, calldataload(add(signature.offset, 64)))
        }

        // Normalize v value (some signature libraries return 0/1 instead of 27/28)
        if (v < 27) v += 27;

        // Verify v value validity
        if (v != 27 && v != 28) revert InvalidAmount();

        // Use ecrecover to recover signer address
        return ecrecover(digest, v, r, s);
    }

    // ========== Query Functions ==========

    /**
     * @notice Get allocation nonce for specified vault
     * @dev Used by frontend to construct signature messages
     *
     * @param vault Vault address
     * @return Current allocation nonce value
     */
    function get_nonce(address vault) external view returns (uint256) {
        return allocation_nonces[vault];
    }

    /**
     * @notice Get registration nonce for specified user
     * @dev Used by frontend to construct registration signature messages
     *
     * @param user User address
     * @return Current registration nonce value
     */
    function get_registration_nonce(
        address user
    ) external view returns (uint256) {
        return registration_nonces[user];
    }

    /**
     * @notice Query whether user has registered vault
     * @dev Convenience query function
     *
     * @param user User address
     * @return Whether vault is registered
     */
    function has_vault(address user) external view returns (bool) {
        return user_to_vault[user] != address(0);
    }

    /**
     * @notice Get user's vault address
     * @dev Returns zero address if user not registered
     *
     * @param user User address
     * @return User's vault address
     */
    function get_user_vault(address user) external view returns (address) {
        return user_to_vault[user];
    }

    /**
     * @notice Verify if vault is registered
     * @dev Used for external contract verification
     *
     * @param vault Vault address
     * @return Whether registered
     */
    function is_registered(address vault) external view returns (bool) {
        return registered_vaults[vault];
    }
}
"
    },
    "contracts/errors.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

/**
 * @title PAI Token System Custom Error Definitions
 * @author EdgeServo
 * @notice Defines all custom errors used throughout the PAI distribution system
 * @dev Uses Solidity 0.8.4+ custom error feature to save gas costs
 *
 * Advantages:
 * - Gas optimization: significantly reduces deployment and runtime costs compared to require strings
 * - Type safety: compile-time checking, avoids string typos
 * - Code clarity: centralized management, easier to maintain and document
 * - Chain-friendly: error selectors only occupy 4 bytes, more compact than strings
 *
 * Usage examples:
 * ```solidity
 * if (amount == 0) revert ZeroAmount();
 * if (msg.sender != owner) revert Unauthorized();
 * ```
 */

// ========== General Validation Errors ==========

/**
 * @notice Zero address error
 * @dev Triggered when function parameter or return value is zero address (0x0)
 *
 * Trigger scenarios:
 * - Constructor parameter validation fails
 * - Zero address passed when setting critical contract addresses
 * - Query result is zero address but should not be
 *
 * Usage example:
 * ```solidity
 * if (_token == address(0)) revert ZeroAddress();
 * ```
 */
error ZeroAddress();

/**
 * @notice Zero amount error
 * @dev Triggered when token amount, value or count is zero but business logic requires non-zero
 *
 * Trigger scenarios:
 * - Attempt to transfer zero amount of tokens
 * - Allocation authorization amount is zero
 * - Vault balance is zero when attempting withdrawal
 *
 * Usage example:
 * ```solidity
 * if (amount == 0) revert ZeroAmount();
 * if (balance == 0) revert ZeroAmount();
 * ```
 */
error ZeroAmount();

/**
 * @notice Invalid amount error
 * @dev Triggered when amount exceeds valid range, incorrect format or doesn't satisfy business rules
 *
 * Trigger scenarios:
 * - Signature length is not 65 bytes
 * - Signature parameter v value is not 27 or 28
 * - Amount exceeds maximum limit
 * - Amount format doesn't meet requirements
 *
 * Usage example:
 * ```solidity
 * if (signature.length != 65) revert InvalidAmount();
 * if (v != 27 && v != 28) revert InvalidAmount();
 * ```
 */
error InvalidAmount();

/**
 * @notice Unauthorized access error
 * @dev Triggered when caller lacks required permissions or operation is unauthorized
 *
 * Trigger scenarios:
 * - Non-owner attempts to call management functions
 * - Non-EOA attempts to deploy vault
 * - Unregistered vault attempts to execute operations
 * - Reentrancy attack detection
 * - Vault not initialized when calling protected functions
 * - Attempting to operate resources not owned by caller
 *
 * Usage example:
 * ```solidity
 * if (msg.sender != owner) revert Unauthorized();
 * if (!_initialized) revert Unauthorized();
 * if (_locked == _ENTERED) revert Unauthorized();
 * ```
 */
error Unauthorized();

/**
 * @notice Entity already exists error
 * @dev Triggered when attempting to create or register an already existing entity
 *
 * Trigger scenarios:
 * - User already owns a vault, attempts to deploy again
 * - Vault already registered, duplicate registration
 * - Attempting to set configuration that can only be set once
 * - Duplicate vault initialization
 *
 * Usage example:
 * ```solidity
 * if (user_vaults[user] != address(0)) revert AlreadyExists();
 * if (registered_vaults[vault]) revert AlreadyExists();
 * if (distributor != address(0)) revert AlreadyExists();
 * ```
 */
error AlreadyExists();

// ========== Transfer Operation Errors ==========

/**
 * @notice Transfer failed error
 * @dev Triggered when ERC20 token transfer operation returns false or execution fails
 *
 * Trigger scenarios:
 * - transfer() returns false
 * - transferFrom() returns false
 * - Insufficient balance causing transfer failure
 * - Insufficient allowance causing transferFrom failure
 * - Allocation execution failure
 *
 * Usage example:
 * ```solidity
 * bool success = token.transfer(to, amount);
 * if (!success) revert TransferFailed();
 * ```
 *
 * Note:
 * - Some ERC20 tokens revert on failure instead of returning false
 * - Recommend using SafeERC20 library for safer transfer operations
 */
error TransferFailed();

// ========== Signature Verification Errors ==========

/**
 * @notice Invalid signature error
 * @dev Triggered when EIP-712 signature verification fails
 *
 * Trigger scenarios:
 * - Signer is not the authorized signer
 * - Signature data has been tampered with
 * - Signature for wrong data structure
 * - ecrecover recovery fails (returns zero address)
 * - Wrong private key used for signing
 *
 * Usage example:
 * ```solidity
 * address recovered = ecrecover(digest, v, r, s);
 * if (recovered != signer) revert InvalidSignature();
 * if (recovered == address(0)) revert InvalidSignature();
 * ```
 *
 * Security recommendations:
 * - Always verify ecrecover return value is not zero address
 * - Use correct EIP-712 domain separator
 * - Ensure nonce mechanism is correctly implemented
 */
error InvalidSignature();

/**
 * @notice Signature expired error
 * @dev Triggered when signature's validity deadline has passed
 *
 * Trigger scenarios:
 * - Current block timestamp > deadline
 * - Signature created beyond validity period
 * - Network congestion causing transaction confirmation delay
 *
 * Usage example:
 * ```solidity
 * if (block.timestamp > deadline) revert SignatureExpired();
 * ```
 *
 * Considerations:
 * - deadline should have reasonable buffer time
 * - Consider network congestion may cause delays
 * - Expired signatures cannot be reused, must regenerate
 */
error SignatureExpired();
"
    },
    "contracts/interfaces.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

/**
 * @title PAI Token System Interface Definitions
 * @author EdgeServo
 * @notice Defines all contract interaction interfaces in PAI token distribution system
 * @dev Includes ERC20 standard interface and internal system contract interfaces
 *
 * Interface descriptions:
 * - i_erc20: Standard ERC20 token interface (simplified version)
 * - i_vault: User vault contract interface
 * - i_distributor: Distributor contract interface
 * - i_project_vault: Project vault contract interface
 * - i_vault_factory: Vault factory contract interface
 */

// ========== ERC20 Token Interface ==========

/**
 * @title ERC20 Token Interface (Simplified)
 * @notice Defines core ERC20 standard functions needed by PAI system
 * @dev Only includes core functions used by system, not complete ERC20 standard
 */
interface i_erc20 {
    /**
     * @notice Query token balance of specified account
     * @dev Standard ERC20 function
     *
     * @param account Account address to query
     * @return Account's token holdings (in wei)
     *
     * Usage:
     * - Vault queries its own PAI balance
     * - Query reward token balance
     * - Verify sufficient balance before transfer
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @notice Transfer tokens to specified address
     * @dev Standard ERC20 function, transfers from caller's account
     *
     * @param to Recipient address
     * @param amount Transfer amount (in wei)
     * @return Whether transfer succeeded
     *
     * Requirements:
     * - Caller's balance must be >= amount
     * - to address cannot be zero address
     *
     * Usage:
     * - Vault transfers PAI to user
     * - Project vault allocates tokens to user vault
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @notice Transfer tokens from one address to another
     * @dev Standard ERC20 function, requires prior approval
     *
     * @param from Source address (token owner)
     * @param to Recipient address
     * @param amount Transfer amount (in wei)
     * @return Whether transfer succeeded
     *
     * Requirements:
     * - from address balance must be >= amount
     * - Caller must have sufficient allowance
     * - to address cannot be zero address
     *
     * Usage:
     * - Vault withdraws reward tokens (from awarder to accepter)
     * - Requires awarder to pre-call approve() for authorization
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// ========== User Vault Interface ==========

/**
 * @title User Vault Contract Interface
 * @notice Defines externally exposed functions of user vault
 * @dev Used for distributor and project vault to interact with user vaults
 */
interface i_vault {
    /**
     * @notice Get vault owner address
     * @dev Read-only function, returns owner set at vault creation
     *
     * @return Ethereum address of vault owner
     *
     * Usage:
     * - Distributor verifies registrant identity
     * - Frontend displays vault ownership information
     * - Other contracts verify operation permissions
     */
    function owner() external view returns (address);

    /**
     * @notice Complete vault initialization
     * @dev Called by distributor after successful registration, marks vault as usable
     *
     * Access control:
     * - Can only be called by distributor contract
     * - Can only be called once
     *
     * State changes:
     * - Set _initialized flag to true
     * - Vault becomes operational
     *
     * Usage:
     * - Complete final step of vault registration
     * - Activate all vault functions
     */
    function complete_initialization() external;

    /**
     * @notice Withdraw third-party reward tokens
     * @dev Called by distributor, transfers rewards from awarder to accepter
     *
     * @param token_address Reward token contract address
     *
     * Access control:
     * - Can only be called by distributor contract
     * - Vault must be initialized
     *
     * Restrictions:
     * - Cannot withdraw PAI tokens
     * - Awarder must have sufficient balance
     *
     * Usage:
     * - Distribute reward tokens provided by project party
     * - Handle airdrops and other incentive activities
     */
    function withdraw_award(address token_address) external;
}

// ========== Distributor Interface ==========

/**
 * @title Distributor Contract Interface
 * @notice Defines core functions exposed by distributor
 * @dev Used for vaults and project vault to interact with distributor
 */
interface i_distributor {
    /**
     * @notice Get project vault address
     * @dev Read-only function, returns project vault address in system
     *
     * @return Project vault contract address
     *
     * Usage:
     * - Vault queries project vault location
     * - Get award role configuration
     * - Verify system configuration completeness
     */
    function project_vault() external view returns (address);

    /**
     * @notice Execute token allocation operation
     * @dev Verify signature then transfer from project vault to user vault
     *
     * @param amount Amount of tokens to allocate (in wei)
     * @param deadline Signature validity deadline timestamp
     * @param signature EIP-712 signature data (65 bytes)
     * @return Whether allocation succeeded
     *
     * Access control:
     * - Can only be called by registered vault contracts
     * - Requires valid authorization signature
     *
     * Verification flow:
     * 1. Check if vault is registered
     * 2. Verify signature has not expired
     * 3. Verify EIP-712 signature
     * 4. Call project vault to execute transfer
     *
     * Usage:
     * - User vault claims allocation quota
     * - Implement signature-authorized token distribution
     */
    function execute_allocation(
        uint256 amount,
        uint256 deadline,
        bytes calldata signature
    ) external returns (bool);

    /**
     * @notice Distribute reward tokens
     * @dev Coordinate reward token transfer from awarder to accepter
     *
     * @param vault_address Vault receiving rewards
     * @param token_address Reward token contract address
     *
     * Access control:
     * - Can only be called by project vault contract
     * - Target vault must be registered
     *
     * Execution flow:
     * - Verify permissions and vault status
     * - Call vault's withdraw_award() function
     *
     * Usage:
     * - Project vault initiates reward distribution
     * - Handle third-party token rewards
     */
    function distribute_award(
        address vault_address,
        address token_address
    ) external;
}

// ========== Project Vault Interface ==========

/**
 * @title Project Vault Contract Interface
 * @notice Defines core functions exposed by project vault
 * @dev Used for distributor and user vaults to interact with project vault
 */
interface i_project_vault {
    /**
     * @notice Register user vault to system
     * @dev Called by distributor during user registration, establishes vault-user association
     *
     * @param vault_address Vault address to register
     * @param user Vault owner (user address)
     *
     * Access control:
     * - Can only be called by distributor contract
     *
     * State changes:
     * - Record vault and user mapping relationship
     * - May initialize reward configuration, etc.
     *
     * Usage:
     * - Complete vault registration process
     * - Establish user and vault association
     * - Initialize user-related configuration
     */
    function register_vault(address vault_address, address user) external;

    /**
     * @notice Allocate tokens to user vault
     * @dev Transfer specified amount of PAI tokens to user vault
     *
     * @param user_vault User vault address receiving tokens
     * @param amount Allocation amount (in wei)
     * @return Whether allocation succeeded
     *
     * Access control:
     * - Can only be called by distributor contract
     *
     * Preconditions:
     * - Project vault has sufficient balance
     * - User vault is registered
     *
     * Usage:
     * - Execute actual token transfer
     * - Complete final step of allocation authorization
     */
    function allocate_to_user(
        address user_vault,
        uint256 amount
    ) external returns (bool);

    /**
     * @notice Get award role configuration for specified vault
     * @dev Returns reward token awarder and accepter addresses
     *
     * @param vault_address Vault address
     * @return awarder Reward awarder address (token holder)
     * @return accepter Reward accepter address (final beneficiary)
     *
     * Usage:
     * - Vault queries reward configuration
     * - Determine reward token transfer path
     * - Support flexible reward distribution mechanism
     *
     * Note:
     * - Awarder needs to pre-approve vault sufficient allowance
     * - Accepter may be user themselves or other designated address
     */
    function get_award_roles(
        address vault_address
    ) external view returns (address awarder, address accepter);
}

// ========== Vault Factory Interface ==========

/**
 * @title Vault Factory Contract Interface
 * @notice Defines validation functions exposed by vault factory
 * @dev Used for distributor to verify vault legitimacy
 */
interface i_vault_factory {
    /**
     * @notice Verify if address is a valid deployed vault
     * @dev Check if address was deployed by this factory via CREATE2
     *
     * @param vault_address Vault address to verify
     * @return Whether it is a valid vault address
     *
     * Verification logic:
     * - Check deployed_vaults mapping
     * - Confirm vault was deployed by factory
     *
     * Usage:
     * - Distributor verifies vault legitimacy
     * - Prevent registration of unauthorized vaults
     * - Ensure vault code is trustworthy
     *
     * Note:
     * - Only verifies deployment source, not initialization status
     * - Returns true means deployed by factory, but may not be registered
     */
    function is_valid_vault(address vault_address) external view returns (bool);
}
"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200,
      "details": {
        "yul": true,
        "yulDetails": {
          "stackAllocation": true,
          "optimizerSteps": "dhfoDgvulfnTUtnIf"
        }
      }
    },
    "viaIR": false,
    "evmVersion": "paris",
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "abi"
        ]
      }
    }
  }
}}

Tags:
Multisig, Multi-Signature, Factory|addr:0xe3d2c7d5cfc0ff9dd76ba9e1cc60e0a239002e22|verified:true|block:23632516|tx:0x85fe375757020c079ce848fa169977b8e02240db0e65493b8725452b4fe5fde1|first_check:1761241166

Submitted on: 2025-10-23 19:39:29

Comments

Log in to comment.

No comments yet.