// File: @openzeppelin/contracts/proxy/Clones.sol



// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/Clones.sol)

pragma solidity ^0.8.0;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create(0, 0x09, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
            // of the `implementation` address with the bytecode before the address.
            mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
            // Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
            mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
            instance := create2(0, 0x09, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(add(ptr, 0x38), deployer)
            mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
            mstore(add(ptr, 0x14), implementation)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
            mstore(add(ptr, 0x58), salt)
            mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
            predicted := keccak256(add(ptr, 0x43), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt
    ) internal view returns (address predicted) {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

// File: contracts/interface/IORChallengeSpv.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {PublicInputParseLib} from "../library/ChallengeSpvLib.sol";

interface IORChallengeSpv {
    function setSpvVerifierAddr(address sourceTxVerifier, address destTxVerifier) external;

    function getSpvVerifierAddr() external view returns (address, address);

    function verifySourceTx(bytes calldata zkProof) external returns (bool);

    function verifyDestTx(bytes calldata zkProof) external returns (bool);

    function parseSourceTxProof(
        bytes calldata zkProof
    ) external pure returns (PublicInputParseLib.PublicInputDataSource memory);

    function parseDestTxProof(
        bytes calldata zkProof
    ) external pure returns (PublicInputParseLib.PublicInputDataDest memory);
}

// File: contracts/interface/IORMakerDeposit.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {IORChallengeSpv} from "./IORChallengeSpv.sol";
import {BridgeLib} from "../library/BridgeLib.sol";
import {RuleLib} from "../library/RuleLib.sol";

interface IORMakerDeposit {
    struct ChallengeStatement {
        uint256 sourceTxFrom; // From of the source tx. Uint to support other networks
        uint64 sourceTxTime; // Timestamp of the source tx
        address freezeToken; // Freeze token on L1
        uint64 challengeUserRatio; // Manager's _challengeUserRatio
        uint256 freezeAmount0; // Owner's freeze amount
        uint256 freezeAmount1; // Challenger's freeze amount
        uint64 challengeTime; // Time of challenge
        uint64 abortTime; // Time of abort caused by checkChallenge
        uint64 sourceTxBlockNum;
        uint64 sourceTxIndex;
        uint128 challengerVerifyTransactionFee; // Transaction fee of challenger verify
    }

    struct ChallengeResult {
        address winner; //Challenger Address
        uint64 verifiedTime0; // Time of verifyChallengeSource. Greater than 0 means verification passed
        uint64 verifiedTime1; // Time of verifyChallengeDest. Greater than 0 means verification passed
        uint64 lastChallengeBlockNum; // Last challenge block number
        bytes32 verifiedDataHash0; // Data's hash of verifyChallengeSource
    }
    struct ChallengeInfo {
        mapping(address => ChallengeStatement) statement;
        ChallengeResult result;
    }

    struct ChallengeNode {
        uint256 prev;
        uint64 challengeCreateTime;
        bool challengeFinished;
    }

    struct WithdrawRequestList {
        uint256 requestAmount;
        uint64 requestTimestamp;
        address requestToken;
    }

    struct verifiedDataInfo {
        uint256 minChallengeSecond;
        uint256 maxChallengeSecond;
        uint256 nonce;
        uint256 destChainId;
        uint256 from;
        uint256 destToken;
        uint256 destAmount;
        uint256 responseMakersHash;
        uint256 responseTime;
    }

    event WithdrawRequested(uint256 requestAmount, uint64 requestTimestamp, address requestToken);

    event ColumnArrayUpdated(
        address indexed impl,
        bytes32 columnArrayHash,
        address[] dealers,
        address[] ebcs,
        uint64[] chainIds
    );
    event SpvUpdated(address indexed impl, uint64 chainId, address spv);
    event ResponseMakersUpdated(address indexed impl, uint256[] responseMakers);
    event RulesRootUpdated(address indexed impl, address ebc, RuleLib.RootWithVersion rootWithVersion);
    event ChallengeInfoUpdated(bytes32 indexed challengeId, ChallengeStatement statement, ChallengeResult result);

    function initialize(address owner_) external;

    function owner() external view returns (address);

    function mdcFactory() external view returns (address);

    function columnArrayHash() external view returns (bytes32);

    function updateColumnArray(
        uint64 enableTime,
        address[] calldata dealers,
        address[] calldata ebcs,
        uint64[] calldata chainIds
    ) external;

    function spv(uint64 chainId) external view returns (address);

    function updateSpvs(uint64 enableTime, address[] calldata spvs, uint64[] calldata chainIds) external;

    function responseMakersHash() external view returns (bytes32);

    function updateResponseMakers(uint64 enableTime, bytes[] calldata responseMakerSignatures) external;

    function freezeAssets(address token) external view returns (uint256);

    function deposit(address token, uint256 amount) external payable;

    function getWithdrawRequestList(address targetToken) external view returns (WithdrawRequestList memory);

    function withdrawRequest(address requestToken, uint256 requestAmount) external;

    function withdraw(address token) external;

    function rulesRoot(address ebc) external view returns (RuleLib.RootWithVersion memory);

    function updateRulesRoot(
        uint64 enableTime,
        address ebc,
        RuleLib.Rule[] calldata rules,
        RuleLib.RootWithVersion calldata rootWithVersion,
        uint64[] calldata sourceChainIds,
        uint256[] calldata pledgeAmounts
    ) external payable;

    function updateRulesRootERC20(
        uint64 enableTime,
        address ebc,
        RuleLib.Rule[] calldata rules,
        RuleLib.RootWithVersion calldata rootWithVersion,
        uint64[] calldata sourceChainIds,
        uint256[] calldata pledgeAmounts,
        address token
    ) external;

    function canChallengeContinue(uint256 challengeIdentNum) external view returns (bool);

    function challenge(
        uint64 sourceTxTime,
        uint64 sourceChainId,
        uint64 sourceTxBlockNum,
        uint64 sourceTxIndex,
        bytes32 sourceTxHash,
        bytes32 ruleKeyHash,
        address freezeToken,
        uint256 freezeAmount1,
        uint256 parentNodeNumOfTargetNode
    ) external payable;

    function checkChallenge(uint64 sourceChainId, bytes32 sourceTxHash, address[] calldata challengers) external;

    function verifyChallengeSource(
        address challenger,
        address spvAddress,
        uint64 sourceChainId,
        bytes calldata proof,
        bytes calldata rawDatas,
        bytes calldata rlpRuleBytes
    ) external;

    function verifyChallengeDest(
        address challenger,
        address spvAddress,
        uint64 sourceChainId,
        bytes32 sourceTxHash,
        bytes calldata proof,
        verifiedDataInfo calldata verifiedSourceTxData,
        bytes calldata rawDatas
    ) external;
}

// File: contracts/interface/IORManager.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {BridgeLib} from "../library/BridgeLib.sol";
import {IORSpvData} from "../interface/IORSpvData.sol";

interface IORManager {
    event ChainInfoUpdated(uint64 indexed id, BridgeLib.ChainInfo chainInfo);
    event ChainTokenUpdated(uint64 indexed id, BridgeLib.TokenInfo tokenInfo);
    event EbcsUpdated(address[] ebcs, bool[] statuses);
    event SubmitterFeeUpdated(address submitter);
    event ProtocolFeeUpdated(uint64 protocolFee);
    event MinChallengeRatioUpdated(uint64 minChallengeRatio);
    event ChallengeUserRatioUpdated(uint64 challengeUserRatio);
    event FeeChallengeSecondUpdated(uint64 feeChallengeSecond);
    event FeeTakeOnChallengeSecondUpdated(uint64 feeTakeOnChallengeSecond);
    event MaxMDCLimitUpdated(uint64 maxMDCLimit);
    event SpvDataContractUpdated(address spvDataContract);
    event ExtraTransferContractsUpdated(uint64[] chainIds, uint256[] extraTransferContracts);

    function registerChains(uint64 enableTime, BridgeLib.ChainInfo[] calldata chains_) external;

    function getPriorityFee() external view returns (uint64);

    function getChallengeGasUsed() external view returns (uint32);

    function getChallengeWithdrawDelay() external view returns (uint32);

    function updatePriorityFee(uint64 priorityFee) external;

    function updateChallengeBasefee(uint32 challengeBasefee) external;

    function updateChallengeWithdrawDelay(uint32 challengeWithdrawDelay) external;

    function updateChainSpvs(uint64 enableTime, uint64 id, address[] calldata spvs, uint256[] calldata indexs) external;

    function getChainInfo(uint64 id) external view returns (BridgeLib.ChainInfo memory);

    function updateChainTokens(
        uint64 enableTime,
        uint64[] calldata ids,
        BridgeLib.TokenInfo[] calldata tokenInfos
    ) external;

    function getChainTokenInfo(uint64 id, uint256 token) external view returns (BridgeLib.TokenInfo memory);

    function ebcIncludes(address ebc) external view returns (bool);

    function updateEbcs(address[] calldata ebcs_, bool[] calldata statuses) external;

    function submitter() external view returns (address);

    function updateSubmitter(uint64 enableTime, address submitter_) external;

    function protocolFee() external view returns (uint64);

    function updateProtocolFee(uint64 enableTime, uint64 protocolFee_) external;

    function minChallengeRatio() external view returns (uint64);

    function updateMinChallengeRatio(uint64 enableTime, uint64 minChallengeRatio_) external;

    function challengeUserRatio() external view returns (uint64);

    function updateChallengeUserRatio(uint64 enableTime, uint64 challengeUserRatio_) external;

    function feeChallengeSecond() external view returns (uint64);

    function updateFeeChallengeSecond(uint64 enableTime, uint64 feeChallengeSecond_) external;

    function feeTakeOnChallengeSecond() external view returns (uint64);

    function updateFeeTakeOnChallengeSecond(uint64 enableTime, uint64 feeTakeOnChallengeSecond_) external;

    function maxMDCLimit() external view returns (uint64);

    function updateMaxMDCLimit(uint64 maxMDCLimit_) external;

    function spvDataContract() external view returns (address);

    function updateSpvDataContract(address spvDataContract_) external;

    function updateSpvBlockInterval(uint64 spvBlockInterval_) external;

    function updateSpvDataInjectOwner(address injectOwner_) external;

    function getExtraTransferContract(uint64 chainId) external view returns (uint256);

    function updateExtraTransferContracts(
        uint64 enableTime,
        uint64[] calldata chainIds,
        uint256[] calldata extraTransferContracts
    ) external;

    function getRulesDecoder() external view returns (address);
}

// File: contracts/interface/IORMDCFactory.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "./IORManager.sol";

interface IORMDCFactory {
    event MDCCreated(address maker, address mdc);

    function manager() external view returns (address);

    function implementation() external view returns (address);

    function mdcCreatedTotal() external view returns (uint256);

    function createMDC() external;

    function predictMDCAddress() external view returns (address);
}

// File: contracts/interface/IORSpvData.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IORSpvData {
    struct InjectionBlocksRoot {
        uint256 startBlockNumber;
        bytes32 blocksRoot;
    }

    event BlockIntervalUpdated(uint64 blockInterval);
    event InjectOwnerUpdated(address injectOwner);
    event HistoryBlocksRootSaved(uint256 indexed startBlockNumber, bytes32 blocksRoot, uint256 blockInterval);

    function blockInterval() external view returns (uint64);

    function updateBlockInterval(uint64 blockInterval_) external;

    function saveHistoryBlocksRoots() external;

    function getStartBlockNumber(bytes32 blocksRoot) external view returns (uint);

    function injectOwner() external view returns (address);

    function updateInjectOwner(address injectOwner_) external;

    function injectBlocksRoots(
        bytes32 blocksRoot0,
        bytes32 blocksRoot1,
        InjectionBlocksRoot[] calldata injectionBlocksRoots
    ) external;
}

// File: contracts/library/BridgeLib.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

library BridgeLib {
    struct TokenInfo {
        uint256 token; // uint160(address) will overflow in the token used for starknet
        address mainnetToken;
        uint8 decimals;
    }

    struct ChainInfo {
        uint64 id;
        uint192 batchLimit;
        uint64 minVerifyChallengeSourceTxSecond;
        uint64 maxVerifyChallengeSourceTxSecond;
        uint64 minVerifyChallengeDestTxSecond;
        uint64 maxVerifyChallengeDestTxSecond;
        uint256 nativeToken;
        address[] spvs;
    }
}

// File: contracts/library/ChallengeSpvLib.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

library Era2MainnetLib {
    uint256 constant ProofLength = 384;
    uint256 constant SplitStep = 32;
    uint256 constant TransactionSplitStart = ProofLength;
    uint256 constant TrackBlockSplitStart = TransactionSplitStart + SplitStep * 14;
    uint256 constant MdcContractSplitStart = TrackBlockSplitStart + SplitStep * 20;

    function checkSourceTxProof(bytes calldata proofData) internal pure returns (bool proofMatch) {
        bytes32 ob_mdc_contracts_current_block_hash = bytes32(
            ((uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 28:MdcContractSplitStart + SplitStep * 29])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 29:MdcContractSplitStart + SplitStep * 30])
                ))
        );
        bytes32 ob_mdc_contracts_next_block_hash = bytes32(
            ((uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 30:MdcContractSplitStart + SplitStep * 31])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 31:MdcContractSplitStart + SplitStep * 32])
                ))
        );
        bytes32 ob_manager_contracts_current_block_hash = bytes32(
            ((uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 32:MdcContractSplitStart + SplitStep * 33])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 33:MdcContractSplitStart + SplitStep * 34])
                ))
        );
        bytes32 ob_manager_contracts_next_block_hash = bytes32(
            ((uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 34:MdcContractSplitStart + SplitStep * 35])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 35:MdcContractSplitStart + SplitStep * 36])
                ))
        );

        bytes32 ob_mdc_contracts_current_batch_target_block_hash = bytes32(
            ((uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 6:TrackBlockSplitStart + SplitStep * 7])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 7:TrackBlockSplitStart + SplitStep * 8])))
        );

        bytes32 ob_mdc_contracts_next_batch_target_block_hash = bytes32(
            ((uint256(
                bytes32(proofData[TrackBlockSplitStart + SplitStep * 10:TrackBlockSplitStart + SplitStep * 11])
            ) << 128) |
                uint256(
                    bytes32(proofData[TrackBlockSplitStart + SplitStep * 11:TrackBlockSplitStart + SplitStep * 12])
                ))
        );

        bytes32 ob_manager_contracts_current_batch_target_block_hash = bytes32(
            ((uint256(
                bytes32(proofData[TrackBlockSplitStart + SplitStep * 14:TrackBlockSplitStart + SplitStep * 15])
            ) << 128) |
                uint256(
                    bytes32(proofData[TrackBlockSplitStart + SplitStep * 15:TrackBlockSplitStart + SplitStep * 16])
                ))
        );

        bytes32 ob_manager_contracts_next_batch_target_block_hash = bytes32(
            ((uint256(
                bytes32(proofData[TrackBlockSplitStart + SplitStep * 18:TrackBlockSplitStart + SplitStep * 19])
            ) << 128) |
                uint256(
                    bytes32(proofData[TrackBlockSplitStart + SplitStep * 19:TrackBlockSplitStart + SplitStep * 20])
                ))
        );
        bytes8 mdc_current_rule_enable_time = bytes8(
            bytes8(
                proofData[MdcContractSplitStart + SplitStep * 6 + SplitStep / 2:MdcContractSplitStart +
                    SplitStep *
                    6 +
                    SplitStep /
                    2 +
                    SplitStep /
                    4]
            )
        );
        bytes8 time_stamp = bytes8(
            uint64(
                uint256(
                    bytes32(proofData[TransactionSplitStart + SplitStep * 11:TransactionSplitStart + SplitStep * 12])
                )
            )
        );
        bytes8 mdc_next_rule_enable_time = (
            bytes8(
                proofData[MdcContractSplitStart + SplitStep * 12 + SplitStep / 2:MdcContractSplitStart +
                    SplitStep *
                    12 +
                    SplitStep /
                    2 +
                    SplitStep /
                    4]
            )
        );

        proofMatch =
            ob_mdc_contracts_current_batch_target_block_hash == ob_mdc_contracts_current_block_hash &&
            ob_mdc_contracts_next_batch_target_block_hash == ob_mdc_contracts_next_block_hash &&
            ob_manager_contracts_current_batch_target_block_hash == ob_manager_contracts_current_block_hash &&
            ob_manager_contracts_next_batch_target_block_hash == ob_manager_contracts_next_block_hash &&
            ((mdc_current_rule_enable_time <= time_stamp && time_stamp < mdc_next_rule_enable_time) ||
                (mdc_current_rule_enable_time == mdc_next_rule_enable_time && mdc_next_rule_enable_time < time_stamp));
    }

    function checkDestTxProof(bytes calldata proofData) internal pure returns (bool proofMatch) {
        proofMatch =
            ((uint256(bytes32(proofData[TransactionSplitStart:TransactionSplitStart + SplitStep])) << 128) |
                uint256(bytes32(proofData[TransactionSplitStart + SplitStep:TransactionSplitStart + SplitStep * 2]))) ==
            ((uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 2:TrackBlockSplitStart + SplitStep * 3])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 3:TrackBlockSplitStart + SplitStep * 4])));
    }

    function parsePublicInputSource(
        bytes calldata proofData
    ) internal pure returns (PublicInputParseLib.PublicInputDataSource memory publicInputSource) {
        uint256 manage_current_source_chain_info = uint256(
            (uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 16:MdcContractSplitStart + SplitStep * 17])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 17:MdcContractSplitStart + SplitStep * 18])
                )
        );
        publicInputSource = PublicInputParseLib.PublicInputDataSource({
            tx_hash: bytes32(
                (uint256(
                    bytes32(proofData[TransactionSplitStart + SplitStep * 2:TransactionSplitStart + SplitStep * 3])
                ) << 128) |
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 3:TransactionSplitStart + SplitStep * 4])
                    )
            ),
            chain_id: uint64(
                uint256(bytes32(proofData[TransactionSplitStart + SplitStep * 4:TransactionSplitStart + SplitStep * 5]))
            ),
            index: uint256(
                bytes32(proofData[TransactionSplitStart + SplitStep * 5:TransactionSplitStart + SplitStep * 6])
            ),
            from: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 6:TransactionSplitStart + SplitStep * 7])
                    )
                )
            ),
            to: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 7:TransactionSplitStart + SplitStep * 8])
                    )
                )
            ),
            token: address(
                uint160(
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 8:TransactionSplitStart + SplitStep * 9])
                    )
                )
            ),
            amount: uint256(
                bytes32(proofData[TransactionSplitStart + SplitStep * 9:TransactionSplitStart + SplitStep * 10])
            ),
            nonce: uint256(
                bytes32(proofData[TransactionSplitStart + SplitStep * 10:TransactionSplitStart + SplitStep * 11])
            ),
            time_stamp: uint64(
                uint256(
                    bytes32(proofData[TransactionSplitStart + SplitStep * 11:TransactionSplitStart + SplitStep * 12])
                )
            ),
            dest: address(
                uint160(
                    uint256(
                        bytes32(
                            proofData[TransactionSplitStart + SplitStep * 12:TransactionSplitStart + SplitStep * 13]
                        )
                    )
                )
            ),
            dest_token: address(
                uint160(
                    uint256(
                        bytes32(
                            proofData[TransactionSplitStart + SplitStep * 13:TransactionSplitStart + SplitStep * 14]
                        )
                    )
                )
            ),
            mdc_contract_address: address(
                uint160(uint256(bytes32(proofData[MdcContractSplitStart:MdcContractSplitStart + SplitStep])))
            ),
            manage_contract_address: address(
                uint160(
                    uint256(bytes32(proofData[MdcContractSplitStart + SplitStep:MdcContractSplitStart + SplitStep * 2]))
                )
            ),
            mdc_rule_root_slot: ((uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 2:MdcContractSplitStart + SplitStep * 3])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 3:MdcContractSplitStart + SplitStep * 4])
                )),
            mdc_current_rule_root: bytes32(
                (uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 4:MdcContractSplitStart + SplitStep * 5])
                ) << 128) |
                    uint256(
                        bytes32(proofData[MdcContractSplitStart + SplitStep * 5:MdcContractSplitStart + SplitStep * 6])
                    )
            ),
            mdc_current_rule_enable_time: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 6 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        6 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            mdc_current_column_array_hash: (
                bytes32(
                    (uint256(
                        bytes32(proofData[MdcContractSplitStart + SplitStep * 8:MdcContractSplitStart + SplitStep * 9])
                    ) << 128) |
                        uint256(
                            bytes32(
                                proofData[MdcContractSplitStart + SplitStep * 9:MdcContractSplitStart + SplitStep * 10]
                            )
                        )
                )
            ),
            mdc_current_response_makers_hash: uint256(
                bytes32(
                    (uint256(
                        bytes32(
                            proofData[MdcContractSplitStart + SplitStep * 10:MdcContractSplitStart + SplitStep * 11]
                        )
                    ) << 128) |
                        uint256(
                            bytes32(
                                proofData[MdcContractSplitStart + SplitStep * 11:MdcContractSplitStart + SplitStep * 12]
                            )
                        )
                )
            ),
            mdc_next_rule_enable_time: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 12 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        12 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            manager_current_enable_time: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 14 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        14 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            manage_current_source_chain_mainnet_token: address(
                uint160(
                    uint256(
                        bytes32(
                            (uint256(
                                bytes32(
                                    proofData[MdcContractSplitStart + SplitStep * 18:MdcContractSplitStart +
                                        SplitStep *
                                        19]
                                )
                            ) << 128) |
                                uint256(
                                    bytes32(
                                        proofData[MdcContractSplitStart + SplitStep * 19:MdcContractSplitStart +
                                            SplitStep *
                                            20]
                                    )
                                )
                        )
                    )
                )
            ),
            manage_current_dest_chain_mainnet_token: address(
                uint160(
                    uint256(
                        bytes32(
                            (uint256(
                                bytes32(
                                    proofData[MdcContractSplitStart + SplitStep * 20:MdcContractSplitStart +
                                        SplitStep *
                                        21]
                                )
                            ) << 128) |
                                uint256(
                                    bytes32(
                                        proofData[MdcContractSplitStart + SplitStep * 21:MdcContractSplitStart +
                                            SplitStep *
                                            22]
                                    )
                                )
                        )
                    )
                )
            ),
            manage_current_challenge_user_ratio: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 23 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        23 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            manager_next_enable_time: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 24 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        24 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            mdc_current_rule_value_hash: bytes32(
                (uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 26:MdcContractSplitStart + SplitStep * 27])
                ) << 128) |
                    uint256(
                        bytes32(
                            proofData[MdcContractSplitStart + SplitStep * 27:MdcContractSplitStart + SplitStep * 28]
                        )
                    )
            ),
            min_verify_challenge_src_tx_second: uint64((manage_current_source_chain_info << 192) >> 192),
            max_verify_challenge_src_tx_second: uint64((manage_current_source_chain_info << 128) >> 192),
            min_verify_challenge_dest_tx_second: uint64((manage_current_source_chain_info << 64) >> 192),
            max_verify_challenge_dest_tx_second: uint64(manage_current_source_chain_info >> 192),
            merkle_roots: new bytes32[](4)
        });

        publicInputSource.merkle_roots[0] = bytes32(
            ((uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 4:TrackBlockSplitStart + SplitStep * 5])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 5:TrackBlockSplitStart + SplitStep * 6])))
        );
        publicInputSource.merkle_roots[1] = bytes32(
            ((uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 8:TrackBlockSplitStart + SplitStep * 9])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 9:TrackBlockSplitStart + SplitStep * 10])))
        );
        publicInputSource.merkle_roots[2] = bytes32(
            ((uint256(
                bytes32(proofData[TrackBlockSplitStart + SplitStep * 12:TrackBlockSplitStart + SplitStep * 13])
            ) << 128) |
                uint256(
                    bytes32(proofData[TrackBlockSplitStart + SplitStep * 13:TrackBlockSplitStart + SplitStep * 14])
                ))
        );
        publicInputSource.merkle_roots[3] = bytes32(
            ((uint256(
                bytes32(proofData[TrackBlockSplitStart + SplitStep * 16:TrackBlockSplitStart + SplitStep * 17])
            ) << 128) |
                uint256(
                    bytes32(proofData[TrackBlockSplitStart + SplitStep * 17:TrackBlockSplitStart + SplitStep * 18])
                ))
        );
    }

    function parsePublicInputDest(
        bytes calldata proofData
    ) internal pure returns (PublicInputParseLib.PublicInputDataDest memory publicInputDest) {
        publicInputDest = PublicInputParseLib.PublicInputDataDest({
            chain_id: uint64(
                uint256(bytes32(proofData[TransactionSplitStart + SplitStep * 4:TransactionSplitStart + SplitStep * 5]))
            ),
            from: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 6:TransactionSplitStart + SplitStep * 7])
                    )
                )
            ),
            to: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 7:TransactionSplitStart + SplitStep * 8])
                    )
                )
            ),
            token: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 8:TransactionSplitStart + SplitStep * 9])
                    )
                )
            ),
            amount: uint256(
                bytes32(proofData[TransactionSplitStart + SplitStep * 9:TransactionSplitStart + SplitStep * 10])
            ),
            time_stamp: uint64(
                uint256(
                    bytes32(proofData[TransactionSplitStart + SplitStep * 11:TransactionSplitStart + SplitStep * 12])
                )
            ),
            merkle_roots: new bytes32[](1)
        });
        publicInputDest.merkle_roots[0] = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart:TrackBlockSplitStart + SplitStep])) << 128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep:TrackBlockSplitStart + SplitStep * 2]))
        );
    }
}

library Mainnet2EraLib {
    uint256 constant ProofLength = 384;
    uint256 constant SplitStep = 32;
    uint256 constant TransactionSplitStart = ProofLength;
    uint256 constant TrackBlockSplitStart = TransactionSplitStart + SplitStep * 14;
    uint256 constant TrackBlockSplitStartDest = TransactionSplitStart + SplitStep * 17;
    uint256 constant MdcContractSplitStart = TrackBlockSplitStart + SplitStep * 20;

    function checkSourceTxProof(bytes calldata proofData) internal pure returns (bool proofMatch) {
        bytes32 tx_block_hash = bytes32(
            (uint256(bytes32(proofData[TransactionSplitStart:TransactionSplitStart + SplitStep])) << 128) |
                uint256(bytes32(proofData[TransactionSplitStart + SplitStep:TransactionSplitStart + SplitStep * 2]))
        );

        bytes32 ob_mdc_contracts_current_block_hash = bytes32(
            (uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 28:MdcContractSplitStart + SplitStep * 29])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 29:MdcContractSplitStart + SplitStep * 30])
                )
        );

        bytes32 ob_mdc_contracts_next_block_hash = bytes32(
            (uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 30:MdcContractSplitStart + SplitStep * 31])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 31:MdcContractSplitStart + SplitStep * 32])
                )
        );

        bytes32 ob_manager_contracts_current_block_hash = bytes32(
            (uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 32:MdcContractSplitStart + SplitStep * 33])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 33:MdcContractSplitStart + SplitStep * 34])
                )
        );

        bytes32 ob_manager_contracts_next_block_hash = bytes32(
            (uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 34:MdcContractSplitStart + SplitStep * 35])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 35:MdcContractSplitStart + SplitStep * 36])
                )
        );

        bytes32 tx_batch_target_block_hash = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 2:TrackBlockSplitStart + SplitStep * 3])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 3:TrackBlockSplitStart + SplitStep * 4]))
        );

        bytes32 ob_mdc_contracts_current_batch_target_block_hash = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 6:TrackBlockSplitStart + SplitStep * 7])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 7:TrackBlockSplitStart + SplitStep * 8]))
        );

        bytes32 ob_mdc_contracts_next_batch_target_block_hash = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 10:TrackBlockSplitStart + SplitStep * 11])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 11:TrackBlockSplitStart + SplitStep * 12]))
        );

        bytes32 ob_manager_contracts_current_batch_target_block_hash = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 14:TrackBlockSplitStart + SplitStep * 15])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 15:TrackBlockSplitStart + SplitStep * 16]))
        );

        bytes32 ob_manager_contracts_next_batch_target_block_hash = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 18:TrackBlockSplitStart + SplitStep * 19])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 19:TrackBlockSplitStart + SplitStep * 20]))
        );

        bytes8 time_stamp = bytes8(
            uint64(
                uint256(
                    bytes32(proofData[TransactionSplitStart + SplitStep * 11:TransactionSplitStart + SplitStep * 12])
                )
            )
        );

        bytes8 mdc_current_rule_enable_time = bytes8(
            bytes8(
                proofData[MdcContractSplitStart + SplitStep * 6 + SplitStep / 2:MdcContractSplitStart +
                    SplitStep *
                    6 +
                    SplitStep /
                    2 +
                    SplitStep /
                    4]
            )
        );

        bytes8 mdc_next_rule_enable_time = (
            bytes8(
                proofData[MdcContractSplitStart + SplitStep * 12 + SplitStep / 2:MdcContractSplitStart +
                    SplitStep *
                    12 +
                    SplitStep /
                    2 +
                    SplitStep /
                    4]
            )
        );

        proofMatch =
            tx_batch_target_block_hash == tx_block_hash &&
            ob_mdc_contracts_current_batch_target_block_hash == ob_mdc_contracts_current_block_hash &&
            ob_mdc_contracts_next_batch_target_block_hash == ob_mdc_contracts_next_block_hash &&
            ob_manager_contracts_current_batch_target_block_hash == ob_manager_contracts_current_block_hash &&
            ob_manager_contracts_next_batch_target_block_hash == ob_manager_contracts_next_block_hash &&
            ((mdc_current_rule_enable_time <= time_stamp && time_stamp < mdc_next_rule_enable_time) ||
                (mdc_current_rule_enable_time == mdc_next_rule_enable_time && mdc_next_rule_enable_time < time_stamp));
    }

    function checkDestTxProof(bytes calldata proofData) internal pure returns (bool proofMatch) {
        proofMatch =
            (uint256(
                bytes32(proofData[TransactionSplitStart + SplitStep * 14:TransactionSplitStart + SplitStep * 15])
            ) << 128) |
                uint256(
                    bytes32(proofData[TransactionSplitStart + SplitStep * 15:TransactionSplitStart + SplitStep * 16])
                ) ==
            ((uint256(
                bytes32(proofData[TrackBlockSplitStartDest + SplitStep * 2:TrackBlockSplitStartDest + SplitStep * 3])
            ) << 128) |
                uint256(
                    bytes32(
                        proofData[TrackBlockSplitStartDest + SplitStep * 3:TrackBlockSplitStartDest + SplitStep * 4]
                    )
                ));
    }

    function parsePublicInputSource(
        bytes calldata proofData
    ) internal pure returns (PublicInputParseLib.PublicInputDataSource memory publicInputSource) {
        uint256 manage_current_source_chain_info = uint256(
            (uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 16:MdcContractSplitStart + SplitStep * 17])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 17:MdcContractSplitStart + SplitStep * 18])
                )
        );

        publicInputSource = PublicInputParseLib.PublicInputDataSource({
            tx_hash: bytes32(
                (uint256(
                    bytes32(proofData[TransactionSplitStart + SplitStep * 2:TransactionSplitStart + SplitStep * 3])
                ) << 128) |
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 3:TransactionSplitStart + SplitStep * 4])
                    )
            ),
            chain_id: uint64(
                uint256(bytes32(proofData[TransactionSplitStart + SplitStep * 4:TransactionSplitStart + SplitStep * 5]))
            ),
            index: uint256(
                bytes32(proofData[TransactionSplitStart + SplitStep * 5:TransactionSplitStart + SplitStep * 6])
            ),
            from: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 6:TransactionSplitStart + SplitStep * 7])
                    )
                )
            ),
            to: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 7:TransactionSplitStart + SplitStep * 8])
                    )
                )
            ),
            token: address(
                uint160(
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 8:TransactionSplitStart + SplitStep * 9])
                    )
                )
            ),
            amount: uint256(
                bytes32(proofData[TransactionSplitStart + SplitStep * 9:TransactionSplitStart + SplitStep * 10])
            ),
            nonce: uint256(
                bytes32(proofData[TransactionSplitStart + SplitStep * 10:TransactionSplitStart + SplitStep * 11])
            ),
            time_stamp: uint64(
                uint256(
                    bytes32(proofData[TransactionSplitStart + SplitStep * 11:TransactionSplitStart + SplitStep * 12])
                )
            ),
            dest: address(
                uint160(
                    uint256(
                        bytes32(
                            proofData[TransactionSplitStart + SplitStep * 12:TransactionSplitStart + SplitStep * 13]
                        )
                    )
                )
            ),
            dest_token: address(
                uint160(
                    uint256(
                        bytes32(
                            proofData[TransactionSplitStart + SplitStep * 13:TransactionSplitStart + SplitStep * 14]
                        )
                    )
                )
            ),
            mdc_contract_address: address(
                uint160(uint256(bytes32(proofData[MdcContractSplitStart:MdcContractSplitStart + SplitStep])))
            ),
            manage_contract_address: address(
                uint160(
                    uint256(bytes32(proofData[MdcContractSplitStart + SplitStep:MdcContractSplitStart + SplitStep * 2]))
                )
            ),
            mdc_rule_root_slot: ((uint256(
                bytes32(proofData[MdcContractSplitStart + SplitStep * 2:MdcContractSplitStart + SplitStep * 3])
            ) << 128) |
                uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 3:MdcContractSplitStart + SplitStep * 4])
                )),
            mdc_current_rule_root: bytes32(
                (uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 4:MdcContractSplitStart + SplitStep * 5])
                ) << 128) |
                    uint256(
                        bytes32(proofData[MdcContractSplitStart + SplitStep * 5:MdcContractSplitStart + SplitStep * 6])
                    )
            ),
            mdc_current_rule_enable_time: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 6 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        6 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            mdc_current_column_array_hash: (
                bytes32(
                    (uint256(
                        bytes32(proofData[MdcContractSplitStart + SplitStep * 8:MdcContractSplitStart + SplitStep * 9])
                    ) << 128) |
                        uint256(
                            bytes32(
                                proofData[MdcContractSplitStart + SplitStep * 9:MdcContractSplitStart + SplitStep * 10]
                            )
                        )
                )
            ),
            mdc_current_response_makers_hash: uint256(
                bytes32(
                    (uint256(
                        bytes32(
                            proofData[MdcContractSplitStart + SplitStep * 10:MdcContractSplitStart + SplitStep * 11]
                        )
                    ) << 128) |
                        uint256(
                            bytes32(
                                proofData[MdcContractSplitStart + SplitStep * 11:MdcContractSplitStart + SplitStep * 12]
                            )
                        )
                )
            ),
            mdc_next_rule_enable_time: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 12 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        12 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            manager_current_enable_time: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 14 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        14 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            manage_current_source_chain_mainnet_token: address(
                uint160(
                    uint256(
                        bytes32(
                            (uint256(
                                bytes32(
                                    proofData[MdcContractSplitStart + SplitStep * 18:MdcContractSplitStart +
                                        SplitStep *
                                        19]
                                )
                            ) << 128) |
                                uint256(
                                    bytes32(
                                        proofData[MdcContractSplitStart + SplitStep * 19:MdcContractSplitStart +
                                            SplitStep *
                                            20]
                                    )
                                )
                        )
                    )
                )
            ),
            manage_current_dest_chain_mainnet_token: address(
                uint160(
                    uint256(
                        bytes32(
                            (uint256(
                                bytes32(
                                    proofData[MdcContractSplitStart + SplitStep * 20:MdcContractSplitStart +
                                        SplitStep *
                                        21]
                                )
                            ) << 128) |
                                uint256(
                                    bytes32(
                                        proofData[MdcContractSplitStart + SplitStep * 21:MdcContractSplitStart +
                                            SplitStep *
                                            22]
                                    )
                                )
                        )
                    )
                )
            ),
            manage_current_challenge_user_ratio: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 23 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        23 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            manager_next_enable_time: uint64(
                bytes8(
                    proofData[MdcContractSplitStart + SplitStep * 24 + SplitStep / 2:MdcContractSplitStart +
                        SplitStep *
                        24 +
                        SplitStep /
                        2 +
                        SplitStep /
                        4]
                )
            ),
            mdc_current_rule_value_hash: bytes32(
                (uint256(
                    bytes32(proofData[MdcContractSplitStart + SplitStep * 26:MdcContractSplitStart + SplitStep * 27])
                ) << 128) |
                    uint256(
                        bytes32(
                            proofData[MdcContractSplitStart + SplitStep * 27:MdcContractSplitStart + SplitStep * 28]
                        )
                    )
            ),
            min_verify_challenge_src_tx_second: uint64((manage_current_source_chain_info << 192) >> 192),
            max_verify_challenge_src_tx_second: uint64((manage_current_source_chain_info << 128) >> 192),
            min_verify_challenge_dest_tx_second: uint64((manage_current_source_chain_info << 64) >> 192),
            max_verify_challenge_dest_tx_second: uint64(manage_current_source_chain_info >> 192),
            merkle_roots: new bytes32[](5)
        });

        publicInputSource.merkle_roots[0] = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart:TrackBlockSplitStart + SplitStep])) << 128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep:TrackBlockSplitStart + SplitStep * 2]))
        );
        publicInputSource.merkle_roots[1] = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 4:TrackBlockSplitStart + SplitStep * 5])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 5:TrackBlockSplitStart + SplitStep * 6]))
        );
        publicInputSource.merkle_roots[2] = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 8:TrackBlockSplitStart + SplitStep * 9])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 9:TrackBlockSplitStart + SplitStep * 10]))
        );
        publicInputSource.merkle_roots[3] = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 12:TrackBlockSplitStart + SplitStep * 13])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 13:TrackBlockSplitStart + SplitStep * 14]))
        );
        publicInputSource.merkle_roots[4] = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 16:TrackBlockSplitStart + SplitStep * 17])) <<
                128) |
                uint256(bytes32(proofData[TrackBlockSplitStart + SplitStep * 17:TrackBlockSplitStart + SplitStep * 18]))
        );
    }

    function parsePublicInputDest(
        bytes calldata proofData
    ) internal pure returns (PublicInputParseLib.PublicInputDataDest memory publicInputDest) {
        publicInputDest = PublicInputParseLib.PublicInputDataDest({
            chain_id: uint64(
                uint256(bytes32(proofData[TransactionSplitStart + SplitStep * 4:TransactionSplitStart + SplitStep * 5]))
            ),
            from: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 6:TransactionSplitStart + SplitStep * 7])
                    )
                )
            ),
            to: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 7:TransactionSplitStart + SplitStep * 8])
                    )
                )
            ),
            token: (
                (
                    uint256(
                        bytes32(proofData[TransactionSplitStart + SplitStep * 8:TransactionSplitStart + SplitStep * 9])
                    )
                )
            ),
            amount: uint256(
                bytes32(proofData[TransactionSplitStart + SplitStep * 9:TransactionSplitStart + SplitStep * 10])
            ),
            time_stamp: uint64(
                uint256(
                    bytes32(proofData[TransactionSplitStart + SplitStep * 11:TransactionSplitStart + SplitStep * 12])
                )
            ),
            merkle_roots: new bytes32[](1)
        });
        publicInputDest.merkle_roots[0] = bytes32(
            (uint256(bytes32(proofData[TrackBlockSplitStartDest:TrackBlockSplitStartDest + SplitStep])) << 128) |
                uint256(
                    bytes32(proofData[TrackBlockSplitStartDest + SplitStep:TrackBlockSplitStartDest + SplitStep * 2])
                )
        );
    }
}

library PublicInputParseLib {
    struct PublicInputDataSource {
        bytes32 tx_hash;
        uint64 chain_id;
        uint256 index;
        uint256 from;
        uint256 to;
        address token;
        uint256 amount;
        uint256 nonce;
        uint64 time_stamp;
        address dest;
        address dest_token;
        address mdc_contract_address;
        address manage_contract_address;
        uint256 mdc_rule_root_slot;
        bytes32 mdc_current_rule_root;
        uint64 mdc_current_rule_enable_time;
        bytes32 mdc_current_column_array_hash;
        uint256 mdc_current_response_makers_hash;
        uint64 mdc_next_rule_enable_time;
        uint64 manager_current_enable_time;
        // bytes32 manage_current_source_chain_info;
        address manage_current_source_chain_mainnet_token;
        address manage_current_dest_chain_mainnet_token;
        uint64 manage_current_challenge_user_ratio;
        uint64 manager_next_enable_time;
        bytes32 mdc_current_rule_value_hash;
        uint64 min_verify_challenge_src_tx_second;
        uint64 max_verify_challenge_src_tx_second;
        uint64 min_verify_challenge_dest_tx_second;
        uint64 max_verify_challenge_dest_tx_second;
        bytes32[] merkle_roots;
    }

    struct PublicInputDataDest {
        uint64 chain_id;
        uint256 from;
        uint256 to;
        uint256 token;
        uint256 amount;
        uint64 time_stamp;
        bytes32[] merkle_roots;
    }
}

// File: contracts/library/ConstantsLib.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

library ConstantsLib {
    uint256 constant RATIO_MULTIPLE = 1000000;

    uint256 constant MIN_ENABLE_DELAY = 120; // Unit: second

    uint256 constant MAX_ENABLE_DELAY = 1800; // Unit: second

    uint256 constant DEALER_WITHDRAW_DELAY = 3600; // Unit: second

    uint256 constant WITHDRAW_DURATION = 3360; // Unit: second

    uint256 constant LOCK_DURATION = 240; // Unit: second

    uint constant EBC_AMOUNT_PARAMS_MODULUS = 100000;

    uint constant MIN_CHALLENGE_DEPOSIT_AMOUNT = 0.005 ether;
}

// File: contracts/library/HelperLib.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

library HelperLib {
    function hash(bytes memory data) internal pure returns (bytes32) {
        return keccak256(data);
    }

    function includes(uint256[] memory arr, uint256 element) internal pure returns (bool) {
        for (uint256 i = 0; i < arr.length; ) {
            if (element == arr[i]) {
                return true;
            }
            unchecked {
                i++;
            }
        }
        return false;
    }

    function arrayIncludes(uint256[] memory arr, uint256[] memory elements) internal pure returns (bool) {
        for (uint256 i = 0; i < elements.length; i++) {
            bool ic = false;
            for (uint256 j = 0; j < arr.length; ) {
                if (elements[i] == arr[j]) {
                    ic = true;
                    break;
                }
                unchecked {
                    j++;
                }
            }

            if (!ic) return false;

            unchecked {
                i++;
            }
        }
        return true;
    }

    function includes(address[] memory arr, address element) internal pure returns (bool) {
        for (uint256 i = 0; i < arr.length; ) {
            if (element == arr[i]) {
                return true;
            }
            unchecked {
                i++;
            }
        }
        return false;
    }

    function arrayIncludes(address[] memory arr, address[] memory elements) internal pure returns (bool) {
        for (uint256 i = 0; i < elements.length; i++) {
            bool ic = false;
            for (uint256 j = 0; j < arr.length; ) {
                if (elements[i] == arr[j]) {
                    ic = true;
                    break;
                }
                unchecked {
                    j++;
                }
            }

            if (!ic) return false;

            unchecked {
                i++;
            }
        }
        return true;
    }

    function calculateChallengeIdentNum(
        uint64 sourceTxTime,
        uint64 sourceChainId,
        uint64 sourceTxBlockNum,
        uint64 sourceTxIndex
    ) internal pure returns (uint256) {
        uint256 challengeIdentNum;

        assembly {
            challengeIdentNum := add(
                shl(192, sourceTxTime),
                add(shl(128, sourceChainId), add(shl(64, sourceTxBlockNum), sourceTxIndex))
            )
        }
        return challengeIdentNum;
    }
}

// File: contracts/library/RuleLib.sol



// SPDX-License-Identifier: MIT

pragma solidity ^0.8.17;

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

library RuleLib {
    struct Rule {
        uint64 chainId0; // 59144
        uint64 chainId1; // 10
        uint8 status0;
        uint8 status1;
        uint256 token0;
        uint256 token1;
        uint128 minPrice0;
        uint128 minPrice1;
        uint128 maxPrice0;
        uint128 maxPrice1;
        uint128 withholdingFee0;
        uint128 withholdingFee1;
        uint32 tradingFee0;
        uint32 tradingFee1;
        uint32 responseTime0;
        uint32 responseTime1;
        uint32 compensationRatio0;
        uint32 compensationRatio1;
    }

    struct RootWithVersion {
        bytes32 root;
        uint32 version;
    }

    struct RuleOneway {
        uint64 sourceChainId;
        uint64 destChainId;
        uint8 status;
        uint256 sourceToken;
        uint256 destToken;
        uint128 minPrice;
        uint128 maxPrice;
        uint128 withholdingFee;
        uint32 tradingFee;
        uint32 responseTime;
        uint32 compensationRatio;
    }

    function checkChainIds(uint64 chainId0, uint64 chainId1) internal pure {
        require(chainId0 < chainId1, "C0LC1");
    }

    function checkWithholdingFees(uint128 withholdingFee0, uint128 withholdingFee1) internal pure {
        require(withholdingFee0 % ConstantsLib.EBC_AMOUNT_PARAMS_MODULUS == 0, "WFI0");
        require(withholdingFee1 % ConstantsLib.EBC_AMOUNT_PARAMS_MODULUS == 0, "WFI1");
    }

    function convertToOneway(
        Rule memory rule,
        uint64 sourceChainId
    ) internal pure returns (RuleOneway memory ruleOneway) {
        require(sourceChainId == rule.chainId0 || sourceChainId == rule.chainId1, "SCI");

        if (sourceChainId == rule.chainId0) {
            return
                RuleOneway(
                    rule.chainId0,
                    rule.chainId1,
                    rule.status0,
                    rule.token0,
                    rule.token1,
                    rule.minPrice0,
                    rule.maxPrice0,
                    rule.withholdingFee0,
                    rule.tradingFee0,
                    rule.responseTime0,
                    rule.compensationRatio0
                );
        } else {
            return
                RuleOneway(
                    rule.chainId1,
                    rule.chainId0,
                    rule.status1,
                    rule.token1,
                    rule.token0,
                    rule.minPrice1,
                    rule.maxPrice1,
                    rule.withholdingFee1,
                    rule.tradingFee1,
                    rule.responseTime1,
                    rule.compensationRatio1
                );
        }
    }
}

// File: contracts/ORMDCFactory.sol



// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/proxy/Clones.sol";
import "./interface/IORMDCFactory.sol";
import "./interface/IORMakerDeposit.sol";
import "./interface/IORManager.sol";
import {HelperLib} from "./library/HelperLib.sol";

contract ORMDCFactory is IORMDCFactory {
    using HelperLib for bytes;

    IORManager private _manager;
    address private _implementation;
    uint256 private _mdcCreatedTotal;

    constructor(address manager_, address implementation_) {
        require(manager_ != address(0), "MZ");
        require(implementation_ != address(0), "IZ");

        _manager = IORManager(manager_);
        _implementation = implementation_;
    }

    function manager() external view returns (address) {
        return address(_manager);
    }

    function implementation() external view returns (address) {
        return _implementation;
    }

    function mdcCreatedTotal() external view returns (uint256) {
        return _mdcCreatedTotal;
    }

    function createMDC() external {
        require(_mdcCreatedTotal < _manager.maxMDCLimit(), "MML");
        address mdcAddress = Clones.cloneDeterministic(_implementation, abi.encode(address(this), msg.sender).hash());

        unchecked {
            ++_mdcCreatedTotal;
        }

        IORMakerDeposit(mdcAddress).initialize(msg.sender);

        emit MDCCreated(msg.sender, mdcAddress);
    }

    function predictMDCAddress() external view returns (address) {
        address mdcAddress = Clones.predictDeterministicAddress(
            _implementation,
            abi.encode(address(this), msg.sender).hash()
        );
        return mdcAddress;
    }
}