GnosisDepositProcessorL1

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

import {DefaultDepositProcessorL1, IToken} from "./DefaultDepositProcessorL1.sol";

interface IBridge {
    // Contract: AMB Contract Proxy Foreign
    // Source: https://github.com/omni/tokenbridge-contracts/blob/908a48107919d4ab127f9af07d44d47eac91547e/contracts/upgradeable_contracts/arbitrary_message/MessageDelivery.sol#L22
    // Doc: https://docs.gnosischain.com/bridges/Token%20Bridge/amb-bridge
    /// @dev Requests message relay to the opposite network
    /// @param target Executor address on the other side.
    /// @param data Calldata passed to the executor on the other side.
    /// @param maxGasLimit Gas limit used on the other network for executing a message.
    /// @return Message Id.
    function requireToPassMessage(address target, bytes memory data, uint256 maxGasLimit) external returns (bytes32);

    // Contract: Omnibridge Multi-Token Mediator Proxy
    // Source: https://github.com/omni/omnibridge/blob/c814f686487c50462b132b9691fd77cc2de237d3/contracts/upgradeable_contracts/components/common/TokensRelayer.sol#L54
    // Doc: https://docs.gnosischain.com/bridges/Token%20Bridge/omnibridge
    function relayTokens(address token, address receiver, uint256 amount) external;
}

/// @title GnosisDepositProcessorL1 - Smart contract for sending tokens and data via Gnosis bridge from L1 to L2 and processing data received from L2.
contract GnosisDepositProcessorL1 is DefaultDepositProcessorL1 {
    /// @dev GnosisDepositProcessorL1 constructor.
    /// @param _olas OLAS token address.
    /// @param _l1Dispenser L1 tokenomics dispenser address.
    /// @param _l1TokenRelayer L1 token relayer bridging contract address (OmniBridge).
    /// @param _l1MessageRelayer L1 message relayer bridging contract address (AMB Proxy Foreign).
    constructor(address _olas, address _l1Dispenser, address _l1TokenRelayer, address _l1MessageRelayer)
        DefaultDepositProcessorL1(_olas, _l1Dispenser, _l1TokenRelayer, _l1MessageRelayer)
    {}

    /// @inheritdoc DefaultDepositProcessorL1
    function _sendMessage(address target, uint256 amount, bytes memory, bytes32 batchHash, bytes32 operation)
        internal
        override
        returns (uint256 sequence, uint256 leftovers)
    {
        // Transfer OLAS tokens
        if (operation == STAKE) {
            // Approve tokens for the bridge contract
            IToken(olas).approve(l1TokenRelayer, amount);

            // Transfer tokens
            IBridge(l1TokenRelayer).relayTokens(olas, l2StakingProcessor, amount);
        }

        // Assemble AMB data payload
        bytes memory data = abi.encodeWithSelector(RECEIVE_MESSAGE, abi.encode(target, amount, batchHash, operation));

        // Send message to L2
        // In the current configuration, maxGasPerTx is set to 4000000 on Ethereum and 2000000 on Gnosis Chain.
        // Source: https://docs.gnosischain.com/bridges/Token%20Bridge/amb-bridge#how-to-check-if-amb-is-down-not-relaying-message
        bytes32 iMsg = IBridge(l1MessageRelayer).requireToPassMessage(l2StakingProcessor, data, MESSAGE_GAS_LIMIT);

        sequence = uint256(iMsg);

        // Return msg.value, if provided by mistake
        leftovers = msg.value;
    }
}
"
    },
    "contracts/l1/bridging/DefaultDepositProcessorL1.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

import {IBridgeErrors} from "../../interfaces/IBridgeErrors.sol";

interface IToken {
    /// @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
    /// @param spender Account address that will be able to transfer tokens on behalf of the caller.
    /// @param amount Token amount.
    /// @return True if the function execution is successful.
    function approve(address spender, uint256 amount) external returns (bool);

    /// @dev Gets the amount of tokens owned by a specified account.
    /// @param account Account address.
    /// @return Amount of tokens owned.
    function balanceOf(address account) external view returns (uint256);
}

/// @title DefaultDepositProcessorL1 - Smart contract for sending tokens and data via arbitrary bridge from L1 to L2 and processing data received from L2.
abstract contract DefaultDepositProcessorL1 is IBridgeErrors {
    event MessagePosted(uint256 indexed sequence, address indexed target, uint256 amount, bytes32 indexed batchHash);
    event L2StakerUpdated(address indexed l2StakingProcessor);
    event LeftoversRefunded(address indexed sender, uint256 leftovers, bool success);

    // Stake operation
    bytes32 public constant STAKE = 0x1bcc0f4c3fad314e585165815f94ecca9b96690a26d6417d7876448a9a867a69;
    // receiveMessage selector to be executed on L2
    bytes4 public constant RECEIVE_MESSAGE = bytes4(keccak256(bytes("receiveMessage(bytes)")));
    // Maximum chain Id as per EVM specs
    uint256 public constant MAX_CHAIN_ID = type(uint64).max / 2 - 36;
    // Token transfer gas limit for L2
    // This is safe as the value is practically bigger than observed ones on numerous chains
    uint256 public constant TOKEN_GAS_LIMIT = 300_000;
    // Message transfer gas limit for L2
    uint256 public constant MESSAGE_GAS_LIMIT = 2_000_000;
    // OLAS token address
    address public immutable olas;
    // L1 depository address
    address public immutable l1Depository;
    // L1 token relayer bridging contract address
    address public immutable l1TokenRelayer;
    // L1 message relayer bridging contract address
    address public immutable l1MessageRelayer;
    // L2 staker address, set by the deploying owner
    address public l2StakingProcessor;
    // Contract owner until the time when the l2StakingProcessor is set
    address public owner;
    // Nonce for each message batch
    uint256 public messageBatchNonce;

    // Processed batch hashes
    mapping(bytes32 => bool) public processedHashes;

    /// @dev DefaultDepositProcessorL1 constructor.
    /// @param _olas OLAS token address on L1.
    /// @param _l1Depository L1 depository address.
    /// @param _l1TokenRelayer L1 token relayer bridging contract address.
    /// @param _l1MessageRelayer L1 message relayer bridging contract address.
    constructor(address _olas, address _l1Depository, address _l1TokenRelayer, address _l1MessageRelayer) {
        // Check for zero addresses
        if (_l1Depository == address(0) || _l1TokenRelayer == address(0) || _l1MessageRelayer == address(0)) {
            revert ZeroAddress();
        }

        olas = _olas;
        l1Depository = _l1Depository;
        l1TokenRelayer = _l1TokenRelayer;
        l1MessageRelayer = _l1MessageRelayer;
        owner = msg.sender;
    }

    /// @dev Sends message to the L2 side via a corresponding bridge.
    /// @notice Message is sent to the staker contract to reflect transferred OLAS and staking amounts.
    /// @param target Staking target address.
    /// @param amount Corresponding staking amount.
    /// @param bridgePayload Bridge payload necessary (if required) for a specific bridging relayer.
    /// @param batchHash Unique batch hash for each message transfer.
    /// @param operation Funds operation: stake / unstake.
    /// @return sequence Unique message sequence (if applicable) or the batch hash converted to number.
    /// @return leftovers ETH leftovers from unused msg.value.
    function _sendMessage(
        address target,
        uint256 amount,
        bytes memory bridgePayload,
        bytes32 batchHash,
        bytes32 operation
    ) internal virtual returns (uint256 sequence, uint256 leftovers);

    /// @dev Sends a message to the L2 side via a corresponding bridge.
    /// @param target Staking target addresses.
    /// @param amount Corresponding staking amount.
    /// @param bridgePayload Bridge payload necessary (if required) for a specific bridge relayer.
    /// @param operation Funds operation: stake / unstake.
    /// @param sender Sender account.
    function sendMessage(address target, uint256 amount, bytes memory bridgePayload, bytes32 operation, address sender)
        external
        payable
        virtual
    {
        // Check for the dispenser contract to be the msg.sender
        if (msg.sender != l1Depository) {
            revert ManagerOnly(l1Depository, msg.sender);
        }

        // Check for zero value
        if (operation == STAKE && amount == 0) {
            revert ZeroValue();
        }

        // Get the batch hash
        uint256 batchNonce = messageBatchNonce;
        bytes32 batchHash = keccak256(abi.encode(batchNonce, address(this), block.timestamp, block.chainid));

        // Send the message to L2
        (uint256 sequence, uint256 leftovers) = _sendMessage(target, amount, bridgePayload, batchHash, operation);

        // Send leftover amount back to the sender, if any
        if (leftovers > 0) {
            // If the call fails, ignore to avoid the attack that would prevent this function from executing
            // solhint-disable-next-line avoid-low-level-calls
            (bool success,) = sender.call{value: leftovers}("");

            emit LeftoversRefunded(sender, leftovers, success);
        }

        // Increase the staking batch nonce
        messageBatchNonce = batchNonce + 1;

        emit MessagePosted(sequence, target, amount, batchHash);
    }

    /// @dev Updated the batch hash of a failed message, if applicable.
    /// @param batchHash Unique batch hash for each message transfer.
    function updateHashMaintenance(bytes32 batchHash) external {
        // Check for the dispenser contract to be the msg.sender
        if (msg.sender != l1Depository) {
            revert ManagerOnly(l1Depository, msg.sender);
        }

        // Check that the batch hash has not yet being processed
        // Possible scenario: bridge failed to deliver from L2 to L1, then after some time the bridge somehow
        // re-delivers the same message, and the maintenance function is called by the DAO as well,
        // that is not needed already anymore since the message was processed naturally via a recovered bridge
        if (processedHashes[batchHash]) {
            revert AlreadyDelivered(batchHash);
        }
        processedHashes[batchHash] = true;
    }

    /// @dev Sets L2 staking processor address and zero-s the owner.
    /// @param l2Processor L2 staking processor address.
    function _setL2StakingProcessor(address l2Processor) internal {
        // Check the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(owner, msg.sender);
        }

        // The L2 staker must have a non zero address
        if (l2Processor == address(0)) {
            revert ZeroAddress();
        }
        l2StakingProcessor = l2Processor;

        // Revoke the owner role making the contract ownerless
        owner = address(0);

        emit L2StakerUpdated(l2Processor);
    }

    /// @dev Sets L2 staking processor address.
    /// @param l2Processor L2 staking processor address.
    function setL2StakingProcessor(address l2Processor) external virtual {
        _setL2StakingProcessor(l2Processor);
    }

    /// @dev Gets the maximum number of token decimals able to be transferred across the bridge.
    /// @return Number of supported decimals.
    function getBridgingDecimals() external pure virtual returns (uint256) {
        return 18;
    }
}
"
    },
    "contracts/interfaces/IBridgeErrors.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;

interface IBridgeErrors {
    /// @dev Only `manager` has a privilege, but the `sender` was provided.
    /// @param sender Sender address.
    /// @param manager Required sender address as a manager.
    error ManagerOnly(address sender, address manager);

    /// @dev Only `owner` has a privilege, but the `sender` was provided.
    /// @param sender Sender address.
    /// @param owner Required sender address as an owner.
    error OwnerOnly(address sender, address owner);

    /// @dev Provided zero address.
    error ZeroAddress();

    /// @dev Zero value when it has to be different from zero.
    error ZeroValue();

    /// @dev Provided incorrect data length.
    /// @param expected Expected minimum data length.
    /// @param provided Provided data length.
    error IncorrectDataLength(uint256 expected, uint256 provided);

    /// @dev Received lower value than the expected one.
    /// @param provided Provided value is lower.
    /// @param expected Expected value.
    error LowerThan(uint256 provided, uint256 expected);

    /// @dev Value overflow.
    /// @param provided Overflow value.
    /// @param max Maximum possible value.
    error Overflow(uint256 provided, uint256 max);

    /// @dev Target bridge relayer is incorrect.
    /// @param provided Provided relayer address.
    /// @param expected Expected relayer address.
    error TargetRelayerOnly(address provided, address expected);

    /// @dev Message sender from another chain is incorrect.
    /// @param provided Provided message sender address.
    /// @param expected Expected message sender address.
    error WrongMessageSender(address provided, address expected);

    /// @dev Chain Id originating the call is incorrect.
    /// @param provided Provided chain Id.
    /// @param expected Expected chain Id.
    error WrongChainId(uint256 provided, uint256 expected);

    /// @dev Request with specified params is not found in the queue.
    /// @param target Target address.
    /// @param amount Token amount.
    /// @param batchHash Reference batch hash.
    /// @param operation Funds operation: stake / unstake.
    error RequestNotQueued(address target, uint256 amount, bytes32 batchHash, bytes32 operation);

    /// @dev Insufficient token balance.
    /// @param provided Provided balance.
    /// @param expected Expected available amount.
    error InsufficientBalance(uint256 provided, uint256 expected);

    /// @dev Failure of a transfer.
    /// @param token Address of a token.
    /// @param from Address `from`.
    /// @param to Address `to`.
    /// @param amount Token amount.
    error TransferFailed(address token, address from, address to, uint256 amount);

    /// @dev Delivery hash has been already processed.
    /// @param deliveryHash Delivery hash.
    error AlreadyDelivered(bytes32 deliveryHash);

    /// @dev Wrong amount received / provided.
    /// @param provided Provided amount.
    /// @param expected Expected amount.
    error WrongAmount(uint256 provided, uint256 expected);

    /// @dev Provided token address is incorrect.
    /// @param provided Provided token address.
    /// @param expected Expected token address.
    error WrongTokenAddress(address provided, address expected);

    /// @dev The contract is paused.
    error Paused();

    /// @dev The contract is unpaused.
    error Unpaused();

    // @dev Reentrancy guard.
    error ReentrancyGuard();

    /// @dev Account address is incorrect.
    /// @param account Account address.
    error WrongAccount(address account);

    /// @dev Operation not found.
    /// @param batchHash Batch hash.
    /// @param operation Funds operation type.
    error OperationNotFound(bytes32 batchHash, bytes32 operation);

    /// @dev Redeem request failed.
    /// @param batchHash Batch hash.
    /// @param target Staking target address.
    /// @param amount Staking amount.
    /// @param operation Funds operation: stake / unstake.
    /// @param status Request status.
    error RequestFailed(bytes32 batchHash, address target, uint256 amount, bytes32 operation, uint256 status);
}
"
    }
  },
  "settings": {
    "remappings": [
      "@gnosis.pm/=node_modules/@gnosis.pm/",
      "@layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/",
      "@layerzerolabs/lz-evm-protocol-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/protocol/",
      "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
      "@registries/=lib/autonolas-registries/",
      "@solmate/=lib/solmate/",
      "autonolas-registries/=lib/autonolas-registries/",
      "devtools/=lib/devtools/packages/toolbox-foundry/src/",
      "ds-test/=lib/autonolas-registries/lib/forge-std/lib/ds-test/src/",
      "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
      "forge-std/=lib/autonolas-registries/lib/forge-std/src/",
      "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
      "layerzero-v2/=lib/layerzero-v2/",
      "openzeppelin-contracts/=lib/openzeppelin-contracts/",
      "solmate/=lib/solmate/src/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 1000000
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "prague",
    "viaIR": true
  }
}}

Tags:
Multisig, Upgradeable, Multi-Signature, Factory|addr:0x4a26f79b9dd73a48d57ce4df70295a875afa006c|verified:true|block:23635029|tx:0xb754a5c9f5a888fb4ca2821278211da4c2288d3a8b06ed810309e269517894cb|first_check:1761292502

Submitted on: 2025-10-24 09:55:05

Comments

Log in to comment.

No comments yet.