S Price: $0.872759 (+0.82%)

Contract

0x65065EE6D500fD9601568FFFbc7269aD5fF8D784

Overview

S Balance

Sonic LogoSonic LogoSonic Logo0 S

S Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EmoliumBridgeDeposit

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : BridgeDeposit.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./sources/IMintableERC20.sol";
import "./sources/OZ/IERC20.sol";
import "./sources/OZ/ReentrancyGuard.sol";
import "./sources/OZ/ERC20Burnable.sol";
import "./sources/OZ/Ownable.sol";
import "./chiefValidator.sol";
import "./sources/IWETH.sol";
import "./chainRouter.sol";

contract EmoliumBridgeDeposit is ReentrancyGuard, Ownable {
    ChiefValidator public chiefValidator;
    IWETH public weth;
    ChainRouter public chainRouter;
    uint256 defaultNetworkId = 1;

    // Store Deposit Proofs
    mapping(bytes32 => bool) public depositProofs;

    // Event to generate proof
    event DepositProofGenerated(address indexed depositor, bytes32 proofHash, string proofData);

    // Event for ERC20 or WETH deposit
    event ERC20Deposited(address indexed user, address indexed token, uint256 amount);
    event ETHDeposited(address indexed user, uint256 amount);
    event ERC20Bridged(address indexed token, uint256 amount);

    constructor(address payable _chiefValidator, address _initialOwner, address _weth, address _chainRouter) Ownable(_initialOwner) {
        chiefValidator = ChiefValidator(_chiefValidator);
        weth = IWETH(_weth);
        chainRouter = ChainRouter(_chainRouter);
        transferOwnership(_initialOwner);
    }

    // Deposit ETH and generate proof
    function depositETH(string memory chainDestination, uint256 networkId) external payable nonReentrant {
        require(msg.value > 0, "Must send ETH");

        require(chainRouter.isChainRegistered(networkId), "Destination chain not registered");

        weth.deposit{value: msg.value}();

        uint256 amount = msg.value;
        require(weth.transfer(address(chiefValidator), amount), "Transfer to ChiefValidator failed");

        string memory proofData = _generateProofData(msg.sender, address(weth), amount, chainDestination);
        bytes32 proofHash = keccak256(abi.encodePacked(proofData));

        depositProofs[proofHash] = true;

        emit ETHDeposited(msg.sender, amount);
        emit DepositProofGenerated(msg.sender, proofHash, proofData);
    }

    // Deposit ERC20 and generate proof
    function depositERC20(address token, uint256 amount, string memory chainDestination, uint256 networkId) external nonReentrant {
        require(amount > 0, "Amount must be greater than 0");

        require(chainRouter.isChainRegistered(networkId), "Destination chain not registered");

        require(IERC20(token).transferFrom(msg.sender, address(this), amount), "Transfer failed");

        string memory proofData = _generateProofData(msg.sender, token, amount, chainDestination);
        bytes32 proofHash = keccak256(abi.encodePacked(proofData));

        depositProofs[proofHash] = true;

        if (chiefValidator.isBridgeTokenRegistered(token)) {
            _burnERC20(token, amount);
        } else {
            require(IERC20(token).transfer(address(chiefValidator), amount), "Transfer to ChiefValidator failed");
            emit ERC20Deposited(msg.sender, token, amount);
        }

        emit DepositProofGenerated(msg.sender, proofHash, proofData);
    }

    // Function to burn ERC20 tokens
    function _burnERC20(address token, uint256 amount) internal {
        ERC20Burnable burnableToken = ERC20Burnable(token);
        burnableToken.burn(amount);
        emit ERC20Bridged(token, amount);
    }

    // Generate a string with the deposit information
    function _generateProofData(address depositor, address token, uint256 amount, string memory chainDestination) internal view returns (string memory) {
        return string(abi.encodePacked(
            toAsciiString(depositor), ",", 
            toAsciiString(token), ",", 
            uint2str(amount), ",", 
            uint2str(block.timestamp), ",", 
            chainDestination
        ));
    }

    // Function to verify a proof
    function verifyDepositProof(bytes32 proofHash) external view returns (bool) {
        return depositProofs[proofHash];
    }

    // Allow the contract admin to save ERC20 tokens not burned
    function withdrawERC20(address token, uint256 amount) external onlyOwner {
        require(IERC20(token).balanceOf(address(this)) >= amount, "Insufficient balance");
        IERC20(token).transfer(owner(), amount);
    }

    // Allow the contract admin to save WETH
    function withdrawWETH(uint256 amount) external onlyOwner {
        require(weth.balanceOf(address(this)) >= amount, "Insufficient WETH balance");
        weth.transfer(owner(), amount);
    }

    // Function to receive ETH without automatically wrapping them
    receive() external payable {
        revert("Please use depositETH function with chainDestination and networkId");
    }

    // Utility : Convert an address to string (hexadecimal)
    function toAsciiString(address x) internal pure returns (string memory) {
        bytes memory s = new bytes(40);
        for (uint256 i = 0; i < 20; i++) {
            bytes1 b = bytes1(uint8(uint256(uint160(x)) / (2**(8*(19 - i)))));
            bytes1 hi = bytes1(uint8(b) / 16);
            bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));
            s[2*i] = char(hi);
            s[2*i+1] = char(lo);
        }
        return string(s);
    }

    function char(bytes1 b) internal pure returns (bytes1 c) {
        if (uint8(b) < 10) return bytes1(uint8(b) + 0x30);
        else return bytes1(uint8(b) + 0x57);
    }

    // Utility : Convert a uint to string
    function uint2str(uint256 _i) internal pure returns (string memory str) {
        if (_i == 0) return "0";
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len;
        while (_i != 0) {
            k = k-1;
            uint8 temp = (48 + uint8(_i - _i / 10 * 10));
            bytes1 b1 = bytes1(temp);
            bstr[k] = b1;
            _i /= 10;
        }
        str = string(bstr);
    }

    function setChiefValidator(address payable _chiefValidator) external onlyOwner {
        require(_chiefValidator != address(0), "Invalid address");
        uint256 codeSize;
        assembly {
            codeSize := extcodesize(_chiefValidator)
        }
        require(codeSize > 0, "Address is not a contract");

        chiefValidator = ChiefValidator(_chiefValidator);
    }
}

File 2 of 18 : chainRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract ChainRouter {

    struct ChainInfo {
        string chainName;
        uint256 networkId;
    }

    // Mapping to store registered chains
    mapping(uint256 => ChainInfo) public registeredChains;
    uint256[] public networkIds;

    // Event for chain management
    event ChainRegistered(string chainName, uint256 networkId);
    event ChainUnregistered(string chainName, uint256 networkId);

    // Contract admin for chain registration
    address public owner;

    modifier onlyOwner() {
        require(msg.sender == owner, "Not authorized");
        _;
    }

    constructor() {
        owner = msg.sender;
    }

    // Function to register a new destination chain
    function registerChain(string calldata chainName, uint256 networkId) external onlyOwner {
        require(registeredChains[networkId].networkId == 0, "Chain already registered");

        registeredChains[networkId] = ChainInfo(chainName, networkId);
        networkIds.push(networkId);

        emit ChainRegistered(chainName, networkId);
    }

    // Function to unregister a chain
    function unregisterChain(uint256 networkId) external onlyOwner {
        require(registeredChains[networkId].networkId != 0, "Chain not registered");

        string memory chainName = registeredChains[networkId].chainName;
        delete registeredChains[networkId];

        // Remove networkId from the array
        for (uint256 i = 0; i < networkIds.length; i++) {
            if (networkIds[i] == networkId) {
                networkIds[i] = networkIds[networkIds.length - 1];
                networkIds.pop();
                break;
            }
        }

        emit ChainUnregistered(chainName, networkId);
    }

    // Function to check if a chain is registered
    function isChainRegistered(uint256 networkId) external view returns (bool) {
        return registeredChains[networkId].networkId != 0;
    }

    // Function to get chain info
    function getChainInfo(uint256 networkId) external view returns (string memory, uint256) {
        require(registeredChains[networkId].networkId != 0, "Chain not registered");

        ChainInfo memory chain = registeredChains[networkId];
        return (chain.chainName, chain.networkId);
    }

    // Function to get all registered chains
    function getAllRegisteredChains() external view returns (ChainInfo[] memory) {
        ChainInfo[] memory chains = new ChainInfo[](networkIds.length);
        for (uint256 i = 0; i < networkIds.length; i++) {
            chains[i] = registeredChains[networkIds[i]];
        }
        return chains;
    }
}

File 3 of 18 : IWETH.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IWETH {
    function deposit() external payable;
    function withdraw(uint256 wad) external;
    function balanceOf(address guy) external view returns (uint256);
    function transfer(address dst, uint256 wad) external returns (bool);
    function approve(address usr, uint256 wad) external returns (bool);
    function transferFrom(address src, address dst, uint256 wad) external returns (bool);
    function allowance(address src, address dst) external view returns (uint256);
    event Deposit(address indexed dst, uint256 wad);
    event Withdrawal(address indexed src, uint256 wad);
}

File 4 of 18 : chiefValidator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./sources/OZ/Ownable.sol";
import "./sources/OZ/ReentrancyGuard.sol";
import "./sources/OZ/IERC20.sol";
import "./sources/OZ/Address.sol";
import "./sources/IWETH.sol";
import "./sources/IMintableERC20.sol";
import "./sources/IBridgedToken.sol";
import "./validatorFactory.sol";
import "./validator.sol";


interface IBurnableERC20 {
    function burn(uint256 amount) external;
}
contract ChiefValidator is Ownable, ReentrancyGuard {
    address public EMLTokenAddress;
    ValidatorFactory public validatorFactory;
    uint256 public emlRewardAmount;
    address public bridgeDeposit;
    address public wethAddress;
    address public devAddress;
    IWETH public weth;
    
    // Retreive Bridge Tokens
    mapping(address => bool) public bridgeTokens;
    // Store Proofs
    mapping(bytes32 => bool) public proofs; // bool => true (legit) or false (not submitted or fraud)
    // Mapping of authorized Contracts
    mapping(address => bool) public authorizedContracts;

    // Events
    event TokenDeployed(address indexed initialOwner, address indexed tokenAddress, string name, string symbol);
    event ProofVerified(bytes32 indexed proofHash, bool valid);
    event EMLMinted(address indexed validator, uint256 amount);
    event BridgeTokenRegistered(address indexed tokenAddress);
    event BridgedETH(address to, uint256 amount);
    event BridgeFee(address to, uint256 amount);
    event TokenBridgedIn(address indexed tokenAddress, address to, uint256 amount);
    event BridgedTokenTransfered(address indexed tokenAddress, address to, uint256 amount);
    event DeployerAuthorized(address indexed contractAddress, bool isAuthorized);

    // Modifier
    modifier onlyAuthorized() {
        require(authorizedContracts[msg.sender], "Caller is not authorized");
        _;
    }

    constructor(
        address _EMLTokenAddress,
        address _wethAddress,
        address _devAddress,
        address _initialOwner,
        address _validatorFactory
    ) Ownable(_initialOwner) 
    {
        EMLTokenAddress = _EMLTokenAddress;
        validatorFactory = ValidatorFactory(_validatorFactory);
        wethAddress = _wethAddress;
        devAddress = _devAddress;
        transferOwnership(_initialOwner);
    }

    // Autorize contracts for validator creation
    function setAuthorization(address _contract, bool _isAuthorized) external onlyOwner {
        authorizedContracts[_contract] = _isAuthorized;
        emit DeployerAuthorized(_contract, _isAuthorized);
    }

    // Register Bridge Tokens
    function registerBridgeTokens(address[] calldata tokens) external onlyAuthorized {
        for (uint256 i = 0; i < tokens.length; i++) {
            bridgeTokens[tokens[i]] = true;
            emit BridgeTokenRegistered(tokens[i]);
        }
    }

    // Update Bridge Tokens
    function updateBridgeTokens(address tokenAddress, bool isRegistered) external onlyOwner {
        bridgeTokens[tokenAddress] = isRegistered;
    }

    function isBridgeTokenRegistered(address token) external view returns (bool) {
        return bridgeTokens[token];
    }
    
    // Verify Proof & Mint EML Rewards to validators
    function verifyProof(string[] calldata proofData, bytes32 proofHash) external nonReentrant onlyOwner {
        require(proofData.length == 6, "Invalid proof data length");
        require(!proofs[proofHash], "Proof already submitted");

        address[] memory validators = validatorFactory.getDeployedValidators();
        uint256 activeValidatorCount = 0;
        address[] memory activeValidators = new address[](validators.length);

        for (uint256 i = 0; i < validators.length; i++) {
            if (Validator(validators[i]).isActive()) {
                activeValidators[activeValidatorCount] = validators[i];
                activeValidatorCount++;
            }
        }

        require(activeValidatorCount > 0, "No active validators found");

        bool proofValid = false;
        for (uint256 i = 0; i < activeValidatorCount; i++) {
            bytes32 keccakResult = Validator(activeValidators[i]).calculateKeccak256(proofData);
            if (keccakResult == proofHash) {
                proofValid = true;
                break;
            }
        }

        if (proofValid) {
            mintEMLRewards();
            handleBridgedToken(proofData);
            proofs[proofHash] = true;
            emit ProofVerified(proofHash, true);
        } else {
            emit ProofVerified(proofHash, false);
        }
    }

    // Mint EML Rewards
    function mintEMLRewards() internal {
        address[] memory validators = validatorFactory.getDeployedValidators();
        uint256 totalActiveValidators = 0;

        // Number of active Validators
        for (uint256 i = 0; i < validators.length; i++) {
            if (Validator(validators[i]).isActive()) {
                totalActiveValidators++;
            }
        }

        require(totalActiveValidators > 0, "No active validators found");

        uint256 rewardPerValidator = emlRewardAmount / totalActiveValidators;

        // EML Mint to Active Validators only & equally 
        for (uint256 i = 0; i < validators.length; i++) {
            if (Validator(validators[i]).isActive()) {
                address validatorOwner = Validator(validators[i]).getValidatorOwner();
                // Call EML Mint function
                IMintableERC20(EMLTokenAddress).mint(validatorOwner, rewardPerValidator);
                emit EMLMinted(validatorOwner, rewardPerValidator);
            }
        }
    }

    // Handle Bridge Operations
    function handleBridgedToken(string[] calldata proofData) internal {
        address tokenAddress = parseAddress(proofData[0]);
        uint256 amount = parseUint(proofData[1]);
        address destination = parseAddress(proofData[2]);
        uint256 timestamp = parseUint(proofData[3]);
        string memory emoliumSaltData = proofData[4];
        uint256 providedFee = parseUint(proofData[5]);

        require(timestamp >= 0, "Invalid timestamp");
        require(bytes(emoliumSaltData).length > 0, "Invalid salt data");
        require(providedFee >= 0, "Invalid fee");

        // Fee calculation and validation
        uint256 calculatedFee = (amount * providedFee) / 10000;
        uint256 netAmount = amount - calculatedFee;
        
        // Handle ETH & WETH
        if (tokenAddress == wethAddress) {
            IWETH(wethAddress).withdraw(amount);
            payable(devAddress).transfer(calculatedFee);
            payable(destination).transfer(netAmount);
            emit BridgedETH(destination, netAmount);
            if (calculatedFee > 0) emit BridgeFee(devAddress, calculatedFee);
        }
        // Handle Emolium Bridge Registered Token
        else if (bridgeTokens[tokenAddress]) {
            IBridgedToken(tokenAddress).mint(destination, netAmount);
            IBridgedToken(tokenAddress).mint(devAddress, calculatedFee);
            emit TokenBridgedIn(tokenAddress, destination, netAmount);
            if (calculatedFee > 0) emit BridgeFee(devAddress, calculatedFee);
        }
        // Handle all other ERC20 tokens
        else {
            IERC20(tokenAddress).transfer(destination, netAmount);
            IERC20(tokenAddress).transfer(devAddress, calculatedFee);
            emit BridgedTokenTransfered(tokenAddress, destination, netAmount);
            if (calculatedFee > 0) emit BridgeFee(devAddress, calculatedFee);
        }
    }

    // Convert string to uint
    function parseUint(string memory _value) internal pure returns (uint256) {
        bytes memory b = bytes(_value);
        uint256 number = 0;
        for (uint256 i = 0; i < b.length; i++) {
            number = number * 10 + (uint256(uint8(b[i])) - 48);
        }
        return number;
    }

    // Convert string to address
    function parseAddress(string memory _value) internal pure returns (address) {
        bytes memory b = bytes(_value);
        require(b.length == 42, "Invalid address length"); // Inclut '0x' au début

        uint160 number;
        for (uint256 i = 2; i < b.length; i++) { // Skip '0x'
            number *= 16;
            uint8 c = uint8(b[i]);
            if (c >= 48 && c <= 57) {
                number += c - 48;
            } else if (c >= 97 && c <= 102) {
                number += c - 87;
            } else if (c >= 65 && c <= 70) {
                number += c - 55;
            }
        }
        return address(number);
    }

    // Setters for addresses
    function setBridgeDeposit(address _bridgeDeposit) external onlyOwner {
        bridgeDeposit = _bridgeDeposit;
    }

    function setWethAddress(address _wethAddress) external onlyOwner {
        wethAddress = _wethAddress;
    }

    // Set EML Reward Amount
    function setEMLRewardAmount(uint256 _amount) external onlyOwner {
        emlRewardAmount = _amount;
    }

    // Get Proof Status
    function getProofStatus(bytes32 proofHash) external view returns (bool) {
        return proofs[proofHash];
    }

    // Emergency & Rescue Functions
    function rescueETH() external onlyOwner {
        require(address(this).balance > 0, "Insufficient ETH balance");
        payable(devAddress).transfer(address(this).balance);
    }

    function rescueERC20(address token, uint256 amount) external onlyOwner {
        IERC20 erc20 = IERC20(token);
        require(erc20.balanceOf(address(this)) >= amount, "Insufficient token balance");
        erc20.transfer(devAddress, amount);
    }

    function rescueWETH(uint256 amount) external onlyOwner {
        require(weth.balanceOf(address(this)) >= amount, "Insufficient WETH balance");
        weth.transfer(devAddress, amount);
    }

    receive() external payable {}

}

File 5 of 18 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import  "./Context.sol";

abstract contract Ownable is Context {
    address private _owner;

    error OwnableUnauthorizedAccount(address account);
    error OwnableInvalidOwner(address owner);

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

    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    function owner() public view virtual returns (address) {
        return _owner;
    }

    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    function transferOwnership(address newOwner) public virtual onlyOwner {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 6 of 18 : ERC20Burnable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.20;

import "./ERC20.sol";
import "./Context.sol";

abstract contract ERC20Burnable is Context, ERC20 {

    function burn(uint256 value) public virtual {
        _burn(_msgSender(), value);
    }

    function burnFrom(address account, uint256 value) public virtual {
        _spendAllowance(account, _msgSender(), value);
        _burn(account, value);
    }
}

File 7 of 18 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

abstract contract ReentrancyGuard {

    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;
    uint256 private _status;

    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }
    
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        _status = NOT_ENTERED;
    }

    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}

File 8 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

interface IERC20 {

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
    
    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function transfer(address to, uint256 value) external returns (bool);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

File 9 of 18 : IMintableERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IMintableERC20 {
    function mint(address to, uint256 amount) external;
    function burn(address from, uint256 amount) external;
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function decimals() external view returns (uint8);
    function symbol() external view returns (string memory);
    function name() external view returns (string memory);
    function tokenAddress() external view returns (address);
    function mintable() external view returns (bool);
    function burnable() external view returns (bool);
}

File 10 of 18 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

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

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 11 of 18 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import "./IERC20.sol";
import "./IERC20Metadata.sol";
import "./Context.sol";
import "./draft-IERC6093.sol";

abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {

    mapping(address account => uint256) private _balances;
    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    function name() public view virtual returns (string memory) {
        return _name;
    }

    function symbol() public view virtual returns (string memory) {
        return _symbol;
    }

    function decimals() public view virtual returns (uint8) {
        return 18;
    }

    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view virtual returns (uint256) {
        return _balances[account];
    }

    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        return true;
    }

    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                _totalSupply -= value;
            }
        } else {
            unchecked {
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

File 12 of 18 : validator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./sources/OZ/IERC20.sol";
import "./sources/OZ/Ownable.sol";

contract Validator is Ownable {
    address public EMLTokenAddress;
    address public validatorFactory;
    uint256 public validatorPrice;
    address public admin;
    bool public active = false;

    // Validator Current Owner
    mapping(address => address) public validatorOwners;

    // Mapping to associate the contract address with the validator address
    mapping(address => address) public validatorContracts;
    // Events
    event EMLBalanceChecked(uint256 balance);
    event ValidatorCount(uint256 activeCount, uint256 maxCount);
    event ValidatorClosed(address indexed owner, uint256 amount);
    event ValidatorOpened();
    event ValidatorClosedEvent();

    constructor(address _EMLTokenAddress, address _initialOwner, address _validatorFactory) Ownable(_initialOwner) {
        EMLTokenAddress = _EMLTokenAddress;
        admin = _initialOwner;
        validatorFactory = _validatorFactory; // Set the validatorFactory by default
        validatorContracts[address(this)] = address(this);
        validatorOwners[address(this)] = _initialOwner;
    }
    
    // Keccak hash function for an array of strings
    function calculateKeccak256(string[] calldata inputs) external view returns (bytes32) {
        require(active, "Validator is not active"); // Check if the validator is active

        // Concatenate all strings in the array
        bytes memory concatenatedString;
        for (uint256 i = 0; i < inputs.length; i++) {
            concatenatedString = abi.encodePacked(concatenatedString, inputs[i]);
        }

        // Calculate the Keccak256 hash of the concatenated string
        bytes32 hash = keccak256(concatenatedString);
        return hash;
    }

    // Set a new validator factory
    function setValidatorFactory(address _validatorFactory) external onlyOwner {
        require(_validatorFactory != address(0), "Invalid validator factory address");
        validatorFactory = _validatorFactory;
    }

    // Return the validator contract address
    function getValidatorContractAddress() external view returns (address) {
        return validatorContracts[address(this)];
    }

    // Return the current validator owner
    function getValidatorOwner() external view returns (address) {
        return validatorOwners[address(this)];
    }

    // Return the amount of EML available in the contract
    function getEMLBalance() external view returns (uint256) {
        return IERC20(EMLTokenAddress).balanceOf(address(this));
    }

    // Function to close the validator and send the EML balance to the owner
    function closeValidator() external onlyOwner {
        uint256 balance = IERC20(EMLTokenAddress).balanceOf(address(this));
        require(balance > 0, "No EML tokens to transfer");

        IERC20(EMLTokenAddress).transfer(owner(), balance);
        active = false;

        emit ValidatorClosed(owner(), balance);
        emit ValidatorClosedEvent();
    }

    // Open the validator if it holds at least 20,000 EML
    function openValidator() external onlyOwner {
        uint256 emlBalance = IERC20(EMLTokenAddress).balanceOf(address(this));
        emit EMLBalanceChecked(emlBalance); // Log la balance

        require(emlBalance >= 20000 * 10**18, "Validator must hold at least 20,000 EML");
        active = true;
        emit ValidatorOpened();
    }

    // Function to check if the validator is active
    function isActive() external view returns (bool) {
        return active;
    }

    // Function to get the admin address
    function getAdmin() external view returns (address) {
        return admin;
    }
}

File 13 of 18 : validatorFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./sources/OZ/Ownable.sol";
import "./validator.sol";

contract ValidatorFactory is Ownable {

    // Mapping to store the addresses of deployed validators
    mapping(address => bool) public validators;
    // Mapping of authorized Contracts
    mapping(address => bool) public authorizedContracts;
    // List of deployed validators
    address[] public deployedValidators;
    // Maximum number of active validators
    uint256 public constant MAX_ACTIVE_VALIDATORS = 25;

    // Events
    event ValidatorCreated(address indexed validatorAddress);
    event ContractAuthorized(address indexed contractAddress, bool isAuthorized);

    // Modifier
    modifier onlyAuthorized() {
        require(authorizedContracts[msg.sender], "Caller is not authorized");
        _;
    }

    constructor(address _initialOwner) Ownable(_initialOwner) {
    } 

    // Autorize contracts for validator creation
    function setAuthorization(address _contract, bool _isAuthorized) external onlyOwner {
        authorizedContracts[_contract] = _isAuthorized;
        emit ContractAuthorized(_contract, _isAuthorized);
    }

    // Function to create a single Validator and assign ownership to the provided owner
    function createValidator(address _EMLTokenAddress, address _owner) external onlyAuthorized returns (address) {
        // Check the number of active validators
        uint256 activeValidatorCount = 0;
        for (uint256 i = 0; i < deployedValidators.length; i++) {
            if (Validator(deployedValidators[i]).isActive()) {
                activeValidatorCount++;
            }
        }

        require(
            activeValidatorCount < MAX_ACTIVE_VALIDATORS,
            "Maximum number of active validators reached"
        );

        // Create the validator and pass this factory address in the constructor
        Validator newValidator = new Validator(_EMLTokenAddress, _owner, address(this));

        // Register the new validator in the factory
        address validatorAddress = address(newValidator);
        validators[validatorAddress] = true;
        deployedValidators.push(validatorAddress);

        emit ValidatorCreated(validatorAddress);
        return validatorAddress;
    }

    // Create a batch of Validators
    function createInitialValidators(address _EMLTokenAddress, uint256 numberOfValidators) external onlyOwner {
        require(numberOfValidators > 0, "Number of validators must be greater than 0");
        require(numberOfValidators <= MAX_ACTIVE_VALIDATORS, "Cannot create more than the maximum allowed validators");
        
        // Check active Validators number
        uint256 activeValidatorCount = 0;
        for (uint256 i = 0; i < deployedValidators.length; i++) {
            if (Validator(deployedValidators[i]).isActive()) {
                activeValidatorCount++;
            }
        }

        require(
            deployedValidators.length + numberOfValidators <= MAX_ACTIVE_VALIDATORS || activeValidatorCount < MAX_ACTIVE_VALIDATORS,
            "Cannot exceed the maximum number of validators"
        );

        for (uint256 i = 0; i < numberOfValidators; i++) {
            Validator newValidator = new Validator(_EMLTokenAddress, msg.sender, address(this));
            address validatorAddress = address(newValidator);
            
            validators[validatorAddress] = true;
            deployedValidators.push(validatorAddress);

            emit ValidatorCreated(validatorAddress);
        }
    }

    // Check if a validator is active
    function isValidatorActive(address validatorAddress) external view returns (bool) {
        require(validators[validatorAddress], "Validator not found");
        return Validator(validatorAddress).isActive();
    }

    // Get the owner of a validator
    function getValidatorOwner(address validatorAddress) external view returns (address) {
        require(validators[validatorAddress], "Validator not found");
        return Validator(validatorAddress).getValidatorOwner();
    }

    // Get the list of deployed validators
    function getDeployedValidators() external view returns (address[] memory) {
        return deployedValidators;
    }
}

File 14 of 18 : IBridgedToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IBridgedToken {
    function mint(address to, uint256 amount) external;
    function burn(address from, uint256 amount) external;
    function burnFrom(address from, uint256 amount) external;
    function transfer(address to, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function decimals() external view returns (uint8);
    function symbol() external view returns (string memory);
    function name() external view returns (string memory);
    function tokenAddress() external view returns (address);
    function mintable() external view returns (bool);
    function burnable() external view returns (bool);
}

File 15 of 18 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

import "./Errors.sol";

library Address {
    error AddressEmptyCode(address target);
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert Errors.FailedCall();
        }
    }

    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            assembly ("memory-safe") {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}

File 16 of 18 : draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

interface IERC20Errors {

    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
    error ERC20InvalidSender(address sender);
    error ERC20InvalidReceiver(address receiver);
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
    error ERC20InvalidApprover(address approver);
    error ERC20InvalidSpender(address spender);
}

interface IERC721Errors {

    error ERC721InvalidOwner(address owner);
    error ERC721NonexistentToken(uint256 tokenId);
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
    error ERC721InvalidSender(address sender);
    error ERC721InvalidReceiver(address receiver);
    error ERC721InsufficientApproval(address operator, uint256 tokenId);
    error ERC721InvalidApprover(address approver);
    error ERC721InvalidOperator(address operator);
}

interface IERC1155Errors {

    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
    error ERC1155InvalidSender(address sender);
    error ERC1155InvalidReceiver(address receiver);
    error ERC1155MissingApprovalForAll(address operator, address owner);
    error ERC1155InvalidApprover(address approver);
    error ERC1155InvalidOperator(address operator);
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

File 17 of 18 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import "./IERC20.sol";

interface IERC20Metadata is IERC20 {
    
    function name() external view returns (string memory);

    function symbol() external view returns (string memory);

    function decimals() external view returns (uint8);
}

File 18 of 18 : Errors.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

library Errors {
    
    error InsufficientBalance(uint256 balance, uint256 needed);
    error FailedCall();
    error FailedDeployment();
    error MissingPrecompile(address);
}

Settings
{
  "optimizer": {
    "enabled": false,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "remappings": []
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address payable","name":"_chiefValidator","type":"address"},{"internalType":"address","name":"_initialOwner","type":"address"},{"internalType":"address","name":"_weth","type":"address"},{"internalType":"address","name":"_chainRouter","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"bytes32","name":"proofHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"proofData","type":"string"}],"name":"DepositProofGenerated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20Bridged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"chainRouter","outputs":[{"internalType":"contract ChainRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chiefValidator","outputs":[{"internalType":"contract ChiefValidator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"chainDestination","type":"string"},{"internalType":"uint256","name":"networkId","type":"uint256"}],"name":"depositERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"chainDestination","type":"string"},{"internalType":"uint256","name":"networkId","type":"uint256"}],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"depositProofs","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_chiefValidator","type":"address"}],"name":"setChiefValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"proofHash","type":"bytes32"}],"name":"verifyDepositProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawWETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040526001600555348015610014575f80fd5b50604051612caa380380612caa8339818101604052810190610036919061044a565b8260015f819055505f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036100ae575f6040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526004016100a591906104bd565b60405180910390fd5b6100bd8161019660201b60201c565b508360025f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160035f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060045f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061018d8361025960201b60201c565b505050506104d6565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6102676102e960201b60201c565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036102d7575f6040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526004016102ce91906104bd565b60405180910390fd5b6102e68161019660201b60201c565b50565b6102f761038260201b60201c565b73ffffffffffffffffffffffffffffffffffffffff1661031b61038960201b60201c565b73ffffffffffffffffffffffffffffffffffffffff16146103805761034461038260201b60201c565b6040517f118cdaa700000000000000000000000000000000000000000000000000000000815260040161037791906104bd565b60405180910390fd5b565b5f33905090565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b5f80fd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6103de826103b5565b9050919050565b6103ee816103d4565b81146103f8575f80fd5b50565b5f81519050610409816103e5565b92915050565b5f610419826103b5565b9050919050565b6104298161040f565b8114610433575f80fd5b50565b5f8151905061044481610420565b92915050565b5f805f8060808587031215610462576104616103b1565b5b5f61046f878288016103fb565b945050602061048087828801610436565b935050604061049187828801610436565b92505060606104a287828801610436565b91505092959194509250565b6104b78161040f565b82525050565b5f6020820190506104d05f8301846104ae565b92915050565b6127c7806104e35f395ff3fe6080604052600436106100c5575f3560e01c80638da5cb5b1161007e578063ca080d0a11610058578063ca080d0a14610281578063eb246296146102ab578063f2fde38b146102d3578063fc4dd333146102fb57610105565b80638da5cb5b14610205578063a1db97821461022f578063a2e03da41461025757610105565b80631d01ac0e146101095780633fc8cef3146101455780635c1b40161461016f578063630a47c714610197578063672f345d146101d3578063715018a6146101ef57610105565b36610105576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100fc90611794565b60405180910390fd5b5f80fd5b348015610114575f80fd5b5061012f600480360381019061012a91906117f6565b610323565b60405161013c919061183b565b60405180910390f35b348015610150575f80fd5b50610159610340565b60405161016691906118ce565b60405180910390f35b34801561017a575f80fd5b5061019560048036038101906101909190611a91565b610365565b005b3480156101a2575f80fd5b506101bd60048036038101906101b891906117f6565b6107f3565b6040516101ca919061183b565b60405180910390f35b6101ed60048036038101906101e89190611b11565b610819565b005b3480156101fa575f80fd5b50610203610be9565b005b348015610210575f80fd5b50610219610bfc565b6040516102269190611b7a565b60405180910390f35b34801561023a575f80fd5b5061025560048036038101906102509190611b93565b610c24565b005b348015610262575f80fd5b5061026b610d6d565b6040516102789190611c02565b60405180910390f35b34801561028c575f80fd5b50610295610d92565b6040516102a29190611c3b565b60405180910390f35b3480156102b6575f80fd5b506102d160048036038101906102cc9190611c8f565b610db7565b005b3480156102de575f80fd5b506102f960048036038101906102f49190611cba565b610eb8565b005b348015610306575f80fd5b50610321600480360381019061031c9190611ce5565b610f3c565b005b6006602052805f5260405f205f915054906101000a900460ff1681565b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61036d6110c6565b5f83116103af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a690611d5a565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b9e06402826040518263ffffffff1660e01b81526004016104099190611d87565b602060405180830381865afa158015610424573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104489190611dca565b610487576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161047e90611e3f565b60405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff1660e01b81526004016104c493929190611e5d565b6020604051808303815f875af11580156104e0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105049190611dca565b610543576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053a90611edc565b60405180910390fd5b5f6105503386868661110a565b90505f816040516020016105649190611f4c565b604051602081830303815290604052805190602001209050600160065f8381526020019081526020015f205f6101000a81548160ff02191690831515021790555060025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636866a817876040518263ffffffff1660e01b81526004016105ff9190611b7a565b602060405180830381865afa15801561061a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061063e9190611dca565b156106525761064d868661115e565b610793565b8573ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16876040518363ffffffff1660e01b81526004016106ae929190611f62565b6020604051808303815f875af11580156106ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ee9190611dca565b61072d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072490611ff9565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fe33e9822e3317b004d587136bab2627ea1ecfbba4eb79abddd0a56cfdd09c0e18760405161078a9190611d87565b60405180910390a35b3373ffffffffffffffffffffffffffffffffffffffff167ff8ec0b7ce5fdd783b80282fd8869c4b656af961aac24ac89c89fb8d94b9b809f82846040516107db92919061205e565b60405180910390a250506107ed61121b565b50505050565b5f60065f8381526020019081526020015f205f9054906101000a900460ff169050919050565b6108216110c6565b5f3411610863576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161085a906120d6565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b9e06402826040518263ffffffff1660e01b81526004016108bd9190611d87565b602060405180830381865afa1580156108d8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108fc9190611dca565b61093b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093290611e3f565b60405180910390fd5b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b1580156109a2575f80fd5b505af11580156109b4573d5f803e3d5ffd5b50505050505f34905060035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610a3a929190611f62565b6020604051808303815f875af1158015610a56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7a9190611dca565b610ab9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ab090611ff9565b60405180910390fd5b5f610ae73360035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16848761110a565b90505f81604051602001610afb9190611f4c565b604051602081830303815290604052805190602001209050600160065f8381526020019081526020015f205f6101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167f6c703791f399558807424f489ccd811c72b4ff0b74af547264fad7c646776df084604051610b829190611d87565b60405180910390a23373ffffffffffffffffffffffffffffffffffffffff167ff8ec0b7ce5fdd783b80282fd8869c4b656af961aac24ac89c89fb8d94b9b809f8284604051610bd292919061205e565b60405180910390a2505050610be561121b565b5050565b610bf1611224565b610bfa5f6112ab565b565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b610c2c611224565b808273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610c669190611b7a565b602060405180830381865afa158015610c81573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ca59190612108565b1015610ce6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cdd9061217d565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb610d0a610bfc565b836040518363ffffffff1660e01b8152600401610d28929190611f62565b6020604051808303815f875af1158015610d44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d689190611dca565b505050565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610dbf611224565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610e2d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e24906121e5565b60405180910390fd5b5f813b90505f8111610e74576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6b9061224d565b60405180910390fd5b8160025f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b610ec0611224565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610f30575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401610f279190611b7a565b60405180910390fd5b610f39816112ab565b50565b610f44611224565b8060035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610f9f9190611b7a565b602060405180830381865afa158015610fba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fde9190612108565b101561101f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611016906122b5565b60405180910390fd5b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb611064610bfc565b836040518363ffffffff1660e01b8152600401611082929190611f62565b6020604051808303815f875af115801561109e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110c29190611dca565b5050565b60025f5403611101576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f81905550565b60606111158561136e565b61111e8561136e565b61112785611524565b61113042611524565b8560405160200161114595949392919061231d565b6040516020818303038152906040529050949350505050565b5f8290508073ffffffffffffffffffffffffffffffffffffffff166342966c68836040518263ffffffff1660e01b815260040161119b9190611d87565b5f604051808303815f87803b1580156111b2575f80fd5b505af11580156111c4573d5f803e3d5ffd5b505050508273ffffffffffffffffffffffffffffffffffffffff167f5138d4c70db2cb3c71272ed7eb2caca17373b1a6f0cc5a0b632fb82b2a2871af8360405161120e9190611d87565b60405180910390a2505050565b60015f81905550565b61122c6116a2565b73ffffffffffffffffffffffffffffffffffffffff1661124a610bfc565b73ffffffffffffffffffffffffffffffffffffffff16146112a95761126d6116a2565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016112a09190611b7a565b60405180910390fd5b565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60605f602867ffffffffffffffff81111561138c5761138b61196d565b5b6040519080825280601f01601f1916602001820160405280156113be5781602001600182028036833780820191505090505b5090505f5b601481101561151a575f8160136113da91906123c0565b60086113e691906123f3565b60026113f29190612563565b8573ffffffffffffffffffffffffffffffffffffffff1661141391906125da565b60f81b90505f60108260f81c6114299190612616565b60f81b90505f8160f81c601061143f9190612646565b8360f81c61144d9190612682565b60f81b905061145b826116a9565b8585600261146991906123f3565b8151811061147a576114796126b6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053506114b1816116a9565b8560018660026114c191906123f3565b6114cb91906126e3565b815181106114dc576114db6126b6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535050505080806001019150506113c3565b5080915050919050565b60605f820361156a576040518060400160405280600181526020017f3000000000000000000000000000000000000000000000000000000000000000815250905061169d565b5f8290505f5b5f821461159957808061158290612716565b915050600a8261159291906125da565b9150611570565b5f8167ffffffffffffffff8111156115b4576115b361196d565b5b6040519080825280601f01601f1916602001820160405280156115e65781602001600182028036833780820191505090505b5090505f8290505b5f86146116955760018161160291906123c0565b90505f600a808861161391906125da565b61161d91906123f3565b8761162891906123c0565b6030611634919061275d565b90505f8160f81b905080848481518110611651576116506126b6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350600a8861168c91906125da565b975050506115ee565b819450505050505b919050565b5f33905090565b5f600a8260f81c60ff1610156116d35760308260f81c6116c9919061275d565b60f81b90506116e9565b60578260f81c6116e3919061275d565b60f81b90505b919050565b5f82825260208201905092915050565b7f506c6561736520757365206465706f7369744554482066756e6374696f6e20775f8201527f69746820636861696e44657374696e6174696f6e20616e64206e6574776f726b60208201527f4964000000000000000000000000000000000000000000000000000000000000604082015250565b5f61177e6042836116ee565b9150611789826116fe565b606082019050919050565b5f6020820190508181035f8301526117ab81611772565b9050919050565b5f604051905090565b5f80fd5b5f80fd5b5f819050919050565b6117d5816117c3565b81146117df575f80fd5b50565b5f813590506117f0816117cc565b92915050565b5f6020828403121561180b5761180a6117bb565b5b5f611818848285016117e2565b91505092915050565b5f8115159050919050565b61183581611821565b82525050565b5f60208201905061184e5f83018461182c565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f819050919050565b5f61189661189161188c84611854565b611873565b611854565b9050919050565b5f6118a78261187c565b9050919050565b5f6118b88261189d565b9050919050565b6118c8816118ae565b82525050565b5f6020820190506118e15f8301846118bf565b92915050565b5f6118f182611854565b9050919050565b611901816118e7565b811461190b575f80fd5b50565b5f8135905061191c816118f8565b92915050565b5f819050919050565b61193481611922565b811461193e575f80fd5b50565b5f8135905061194f8161192b565b92915050565b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6119a38261195d565b810181811067ffffffffffffffff821117156119c2576119c161196d565b5b80604052505050565b5f6119d46117b2565b90506119e0828261199a565b919050565b5f67ffffffffffffffff8211156119ff576119fe61196d565b5b611a088261195d565b9050602081019050919050565b828183375f83830152505050565b5f611a35611a30846119e5565b6119cb565b905082815260208101848484011115611a5157611a50611959565b5b611a5c848285611a15565b509392505050565b5f82601f830112611a7857611a77611955565b5b8135611a88848260208601611a23565b91505092915050565b5f805f8060808587031215611aa957611aa86117bb565b5b5f611ab68782880161190e565b9450506020611ac787828801611941565b935050604085013567ffffffffffffffff811115611ae857611ae76117bf565b5b611af487828801611a64565b9250506060611b0587828801611941565b91505092959194509250565b5f8060408385031215611b2757611b266117bb565b5b5f83013567ffffffffffffffff811115611b4457611b436117bf565b5b611b5085828601611a64565b9250506020611b6185828601611941565b9150509250929050565b611b74816118e7565b82525050565b5f602082019050611b8d5f830184611b6b565b92915050565b5f8060408385031215611ba957611ba86117bb565b5b5f611bb68582860161190e565b9250506020611bc785828601611941565b9150509250929050565b5f611bdb8261187c565b9050919050565b5f611bec82611bd1565b9050919050565b611bfc81611be2565b82525050565b5f602082019050611c155f830184611bf3565b92915050565b5f611c258261189d565b9050919050565b611c3581611c1b565b82525050565b5f602082019050611c4e5f830184611c2c565b92915050565b5f611c5e82611854565b9050919050565b611c6e81611c54565b8114611c78575f80fd5b50565b5f81359050611c8981611c65565b92915050565b5f60208284031215611ca457611ca36117bb565b5b5f611cb184828501611c7b565b91505092915050565b5f60208284031215611ccf57611cce6117bb565b5b5f611cdc8482850161190e565b91505092915050565b5f60208284031215611cfa57611cf96117bb565b5b5f611d0784828501611941565b91505092915050565b7f416d6f756e74206d7573742062652067726561746572207468616e20300000005f82015250565b5f611d44601d836116ee565b9150611d4f82611d10565b602082019050919050565b5f6020820190508181035f830152611d7181611d38565b9050919050565b611d8181611922565b82525050565b5f602082019050611d9a5f830184611d78565b92915050565b611da981611821565b8114611db3575f80fd5b50565b5f81519050611dc481611da0565b92915050565b5f60208284031215611ddf57611dde6117bb565b5b5f611dec84828501611db6565b91505092915050565b7f44657374696e6174696f6e20636861696e206e6f7420726567697374657265645f82015250565b5f611e296020836116ee565b9150611e3482611df5565b602082019050919050565b5f6020820190508181035f830152611e5681611e1d565b9050919050565b5f606082019050611e705f830186611b6b565b611e7d6020830185611b6b565b611e8a6040830184611d78565b949350505050565b7f5472616e73666572206661696c656400000000000000000000000000000000005f82015250565b5f611ec6600f836116ee565b9150611ed182611e92565b602082019050919050565b5f6020820190508181035f830152611ef381611eba565b9050919050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f611f2682611efa565b611f308185611f04565b9350611f40818560208601611f0e565b80840191505092915050565b5f611f578284611f1c565b915081905092915050565b5f604082019050611f755f830185611b6b565b611f826020830184611d78565b9392505050565b7f5472616e7366657220746f20436869656656616c696461746f72206661696c655f8201527f6400000000000000000000000000000000000000000000000000000000000000602082015250565b5f611fe36021836116ee565b9150611fee82611f89565b604082019050919050565b5f6020820190508181035f83015261201081611fd7565b9050919050565b612020816117c3565b82525050565b5f61203082611efa565b61203a81856116ee565b935061204a818560208601611f0e565b6120538161195d565b840191505092915050565b5f6040820190506120715f830185612017565b81810360208301526120838184612026565b90509392505050565b7f4d7573742073656e6420455448000000000000000000000000000000000000005f82015250565b5f6120c0600d836116ee565b91506120cb8261208c565b602082019050919050565b5f6020820190508181035f8301526120ed816120b4565b9050919050565b5f815190506121028161192b565b92915050565b5f6020828403121561211d5761211c6117bb565b5b5f61212a848285016120f4565b91505092915050565b7f496e73756666696369656e742062616c616e63650000000000000000000000005f82015250565b5f6121676014836116ee565b915061217282612133565b602082019050919050565b5f6020820190508181035f8301526121948161215b565b9050919050565b7f496e76616c6964206164647265737300000000000000000000000000000000005f82015250565b5f6121cf600f836116ee565b91506121da8261219b565b602082019050919050565b5f6020820190508181035f8301526121fc816121c3565b9050919050565b7f41646472657373206973206e6f74206120636f6e7472616374000000000000005f82015250565b5f6122376019836116ee565b915061224282612203565b602082019050919050565b5f6020820190508181035f8301526122648161222b565b9050919050565b7f496e73756666696369656e7420574554482062616c616e6365000000000000005f82015250565b5f61229f6019836116ee565b91506122aa8261226b565b602082019050919050565b5f6020820190508181035f8301526122cc81612293565b9050919050565b7f2c000000000000000000000000000000000000000000000000000000000000005f82015250565b5f612307600183611f04565b9150612312826122d3565b600182019050919050565b5f6123288288611f1c565b9150612333826122fb565b915061233f8287611f1c565b915061234a826122fb565b91506123568286611f1c565b9150612361826122fb565b915061236d8285611f1c565b9150612378826122fb565b91506123848284611f1c565b91508190509695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6123ca82611922565b91506123d583611922565b92508282039050818111156123ed576123ec612393565b5b92915050565b5f6123fd82611922565b915061240883611922565b925082820261241681611922565b9150828204841483151761242d5761242c612393565b5b5092915050565b5f8160011c9050919050565b5f808291508390505b60018511156124895780860481111561246557612464612393565b5b60018516156124745780820291505b808102905061248285612434565b9450612449565b94509492505050565b5f826124a1576001905061255c565b816124ae575f905061255c565b81600181146124c457600281146124ce576124fd565b600191505061255c565b60ff8411156124e0576124df612393565b5b8360020a9150848211156124f7576124f6612393565b5b5061255c565b5060208310610133831016604e8410600b84101617156125325782820a90508381111561252d5761252c612393565b5b61255c565b61253f8484846001612440565b9250905081840481111561255657612555612393565b5b81810290505b9392505050565b5f61256d82611922565b915061257883611922565b92506125a57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484612492565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f6125e482611922565b91506125ef83611922565b9250826125ff576125fe6125ad565b5b828204905092915050565b5f60ff82169050919050565b5f6126208261260a565b915061262b8361260a565b92508261263b5761263a6125ad565b5b828204905092915050565b5f6126508261260a565b915061265b8361260a565b92508282026126698161260a565b915080821461267b5761267a612393565b5b5092915050565b5f61268c8261260a565b91506126978361260a565b9250828203905060ff8111156126b0576126af612393565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6126ed82611922565b91506126f883611922565b92508282019050808211156127105761270f612393565b5b92915050565b5f61272082611922565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361275257612751612393565b5b600182019050919050565b5f6127678261260a565b91506127728361260a565b9250828201905060ff81111561278b5761278a612393565b5b9291505056fea26469706673582212202bee3823fa9b27b04bac80a8cad53b0740dc067fef843f0af8e4dba64c03f56a64736f6c634300081a003300000000000000000000000062c517854f73515bca2179ef147ab45ef53b48bc00000000000000000000000092eed0282c6665c9bcc81605a13a5c3b1e4dc7f2000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38000000000000000000000000bdfa3a2feb0673740dd6abe69a2db2c3b6459e17

Deployed Bytecode

0x6080604052600436106100c5575f3560e01c80638da5cb5b1161007e578063ca080d0a11610058578063ca080d0a14610281578063eb246296146102ab578063f2fde38b146102d3578063fc4dd333146102fb57610105565b80638da5cb5b14610205578063a1db97821461022f578063a2e03da41461025757610105565b80631d01ac0e146101095780633fc8cef3146101455780635c1b40161461016f578063630a47c714610197578063672f345d146101d3578063715018a6146101ef57610105565b36610105576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100fc90611794565b60405180910390fd5b5f80fd5b348015610114575f80fd5b5061012f600480360381019061012a91906117f6565b610323565b60405161013c919061183b565b60405180910390f35b348015610150575f80fd5b50610159610340565b60405161016691906118ce565b60405180910390f35b34801561017a575f80fd5b5061019560048036038101906101909190611a91565b610365565b005b3480156101a2575f80fd5b506101bd60048036038101906101b891906117f6565b6107f3565b6040516101ca919061183b565b60405180910390f35b6101ed60048036038101906101e89190611b11565b610819565b005b3480156101fa575f80fd5b50610203610be9565b005b348015610210575f80fd5b50610219610bfc565b6040516102269190611b7a565b60405180910390f35b34801561023a575f80fd5b5061025560048036038101906102509190611b93565b610c24565b005b348015610262575f80fd5b5061026b610d6d565b6040516102789190611c02565b60405180910390f35b34801561028c575f80fd5b50610295610d92565b6040516102a29190611c3b565b60405180910390f35b3480156102b6575f80fd5b506102d160048036038101906102cc9190611c8f565b610db7565b005b3480156102de575f80fd5b506102f960048036038101906102f49190611cba565b610eb8565b005b348015610306575f80fd5b50610321600480360381019061031c9190611ce5565b610f3c565b005b6006602052805f5260405f205f915054906101000a900460ff1681565b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b61036d6110c6565b5f83116103af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016103a690611d5a565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b9e06402826040518263ffffffff1660e01b81526004016104099190611d87565b602060405180830381865afa158015610424573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104489190611dca565b610487576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161047e90611e3f565b60405180910390fd5b8373ffffffffffffffffffffffffffffffffffffffff166323b872dd3330866040518463ffffffff1660e01b81526004016104c493929190611e5d565b6020604051808303815f875af11580156104e0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105049190611dca565b610543576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161053a90611edc565b60405180910390fd5b5f6105503386868661110a565b90505f816040516020016105649190611f4c565b604051602081830303815290604052805190602001209050600160065f8381526020019081526020015f205f6101000a81548160ff02191690831515021790555060025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636866a817876040518263ffffffff1660e01b81526004016105ff9190611b7a565b602060405180830381865afa15801561061a573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061063e9190611dca565b156106525761064d868661115e565b610793565b8573ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16876040518363ffffffff1660e01b81526004016106ae929190611f62565b6020604051808303815f875af11580156106ca573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106ee9190611dca565b61072d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161072490611ff9565b60405180910390fd5b8573ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fe33e9822e3317b004d587136bab2627ea1ecfbba4eb79abddd0a56cfdd09c0e18760405161078a9190611d87565b60405180910390a35b3373ffffffffffffffffffffffffffffffffffffffff167ff8ec0b7ce5fdd783b80282fd8869c4b656af961aac24ac89c89fb8d94b9b809f82846040516107db92919061205e565b60405180910390a250506107ed61121b565b50505050565b5f60065f8381526020019081526020015f205f9054906101000a900460ff169050919050565b6108216110c6565b5f3411610863576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161085a906120d6565b60405180910390fd5b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b9e06402826040518263ffffffff1660e01b81526004016108bd9190611d87565b602060405180830381865afa1580156108d8573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108fc9190611dca565b61093b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161093290611e3f565b60405180910390fd5b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d0e30db0346040518263ffffffff1660e01b81526004015f604051808303818588803b1580156109a2575f80fd5b505af11580156109b4573d5f803e3d5ffd5b50505050505f34905060035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b8152600401610a3a929190611f62565b6020604051808303815f875af1158015610a56573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7a9190611dca565b610ab9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ab090611ff9565b60405180910390fd5b5f610ae73360035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16848761110a565b90505f81604051602001610afb9190611f4c565b604051602081830303815290604052805190602001209050600160065f8381526020019081526020015f205f6101000a81548160ff0219169083151502179055503373ffffffffffffffffffffffffffffffffffffffff167f6c703791f399558807424f489ccd811c72b4ff0b74af547264fad7c646776df084604051610b829190611d87565b60405180910390a23373ffffffffffffffffffffffffffffffffffffffff167ff8ec0b7ce5fdd783b80282fd8869c4b656af961aac24ac89c89fb8d94b9b809f8284604051610bd292919061205e565b60405180910390a2505050610be561121b565b5050565b610bf1611224565b610bfa5f6112ab565b565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b610c2c611224565b808273ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610c669190611b7a565b602060405180830381865afa158015610c81573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ca59190612108565b1015610ce6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610cdd9061217d565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1663a9059cbb610d0a610bfc565b836040518363ffffffff1660e01b8152600401610d28929190611f62565b6020604051808303815f875af1158015610d44573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d689190611dca565b505050565b60025f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60045f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b610dbf611224565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610e2d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e24906121e5565b60405180910390fd5b5f813b90505f8111610e74576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6b9061224d565b60405180910390fd5b8160025f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050565b610ec0611224565b5f73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610f30575f6040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401610f279190611b7a565b60405180910390fd5b610f39816112ab565b50565b610f44611224565b8060035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401610f9f9190611b7a565b602060405180830381865afa158015610fba573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fde9190612108565b101561101f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611016906122b5565b60405180910390fd5b60035f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb611064610bfc565b836040518363ffffffff1660e01b8152600401611082929190611f62565b6020604051808303815f875af115801561109e573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110c29190611dca565b5050565b60025f5403611101576040517f3ee5aeb500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60025f81905550565b60606111158561136e565b61111e8561136e565b61112785611524565b61113042611524565b8560405160200161114595949392919061231d565b6040516020818303038152906040529050949350505050565b5f8290508073ffffffffffffffffffffffffffffffffffffffff166342966c68836040518263ffffffff1660e01b815260040161119b9190611d87565b5f604051808303815f87803b1580156111b2575f80fd5b505af11580156111c4573d5f803e3d5ffd5b505050508273ffffffffffffffffffffffffffffffffffffffff167f5138d4c70db2cb3c71272ed7eb2caca17373b1a6f0cc5a0b632fb82b2a2871af8360405161120e9190611d87565b60405180910390a2505050565b60015f81905550565b61122c6116a2565b73ffffffffffffffffffffffffffffffffffffffff1661124a610bfc565b73ffffffffffffffffffffffffffffffffffffffff16146112a95761126d6116a2565b6040517f118cdaa70000000000000000000000000000000000000000000000000000000081526004016112a09190611b7a565b60405180910390fd5b565b5f60015f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690508160015f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60605f602867ffffffffffffffff81111561138c5761138b61196d565b5b6040519080825280601f01601f1916602001820160405280156113be5781602001600182028036833780820191505090505b5090505f5b601481101561151a575f8160136113da91906123c0565b60086113e691906123f3565b60026113f29190612563565b8573ffffffffffffffffffffffffffffffffffffffff1661141391906125da565b60f81b90505f60108260f81c6114299190612616565b60f81b90505f8160f81c601061143f9190612646565b8360f81c61144d9190612682565b60f81b905061145b826116a9565b8585600261146991906123f3565b8151811061147a576114796126b6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a9053506114b1816116a9565b8560018660026114c191906123f3565b6114cb91906126e3565b815181106114dc576114db6126b6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a90535050505080806001019150506113c3565b5080915050919050565b60605f820361156a576040518060400160405280600181526020017f3000000000000000000000000000000000000000000000000000000000000000815250905061169d565b5f8290505f5b5f821461159957808061158290612716565b915050600a8261159291906125da565b9150611570565b5f8167ffffffffffffffff8111156115b4576115b361196d565b5b6040519080825280601f01601f1916602001820160405280156115e65781602001600182028036833780820191505090505b5090505f8290505b5f86146116955760018161160291906123c0565b90505f600a808861161391906125da565b61161d91906123f3565b8761162891906123c0565b6030611634919061275d565b90505f8160f81b905080848481518110611651576116506126b6565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff191690815f1a905350600a8861168c91906125da565b975050506115ee565b819450505050505b919050565b5f33905090565b5f600a8260f81c60ff1610156116d35760308260f81c6116c9919061275d565b60f81b90506116e9565b60578260f81c6116e3919061275d565b60f81b90505b919050565b5f82825260208201905092915050565b7f506c6561736520757365206465706f7369744554482066756e6374696f6e20775f8201527f69746820636861696e44657374696e6174696f6e20616e64206e6574776f726b60208201527f4964000000000000000000000000000000000000000000000000000000000000604082015250565b5f61177e6042836116ee565b9150611789826116fe565b606082019050919050565b5f6020820190508181035f8301526117ab81611772565b9050919050565b5f604051905090565b5f80fd5b5f80fd5b5f819050919050565b6117d5816117c3565b81146117df575f80fd5b50565b5f813590506117f0816117cc565b92915050565b5f6020828403121561180b5761180a6117bb565b5b5f611818848285016117e2565b91505092915050565b5f8115159050919050565b61183581611821565b82525050565b5f60208201905061184e5f83018461182c565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f819050919050565b5f61189661189161188c84611854565b611873565b611854565b9050919050565b5f6118a78261187c565b9050919050565b5f6118b88261189d565b9050919050565b6118c8816118ae565b82525050565b5f6020820190506118e15f8301846118bf565b92915050565b5f6118f182611854565b9050919050565b611901816118e7565b811461190b575f80fd5b50565b5f8135905061191c816118f8565b92915050565b5f819050919050565b61193481611922565b811461193e575f80fd5b50565b5f8135905061194f8161192b565b92915050565b5f80fd5b5f80fd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6119a38261195d565b810181811067ffffffffffffffff821117156119c2576119c161196d565b5b80604052505050565b5f6119d46117b2565b90506119e0828261199a565b919050565b5f67ffffffffffffffff8211156119ff576119fe61196d565b5b611a088261195d565b9050602081019050919050565b828183375f83830152505050565b5f611a35611a30846119e5565b6119cb565b905082815260208101848484011115611a5157611a50611959565b5b611a5c848285611a15565b509392505050565b5f82601f830112611a7857611a77611955565b5b8135611a88848260208601611a23565b91505092915050565b5f805f8060808587031215611aa957611aa86117bb565b5b5f611ab68782880161190e565b9450506020611ac787828801611941565b935050604085013567ffffffffffffffff811115611ae857611ae76117bf565b5b611af487828801611a64565b9250506060611b0587828801611941565b91505092959194509250565b5f8060408385031215611b2757611b266117bb565b5b5f83013567ffffffffffffffff811115611b4457611b436117bf565b5b611b5085828601611a64565b9250506020611b6185828601611941565b9150509250929050565b611b74816118e7565b82525050565b5f602082019050611b8d5f830184611b6b565b92915050565b5f8060408385031215611ba957611ba86117bb565b5b5f611bb68582860161190e565b9250506020611bc785828601611941565b9150509250929050565b5f611bdb8261187c565b9050919050565b5f611bec82611bd1565b9050919050565b611bfc81611be2565b82525050565b5f602082019050611c155f830184611bf3565b92915050565b5f611c258261189d565b9050919050565b611c3581611c1b565b82525050565b5f602082019050611c4e5f830184611c2c565b92915050565b5f611c5e82611854565b9050919050565b611c6e81611c54565b8114611c78575f80fd5b50565b5f81359050611c8981611c65565b92915050565b5f60208284031215611ca457611ca36117bb565b5b5f611cb184828501611c7b565b91505092915050565b5f60208284031215611ccf57611cce6117bb565b5b5f611cdc8482850161190e565b91505092915050565b5f60208284031215611cfa57611cf96117bb565b5b5f611d0784828501611941565b91505092915050565b7f416d6f756e74206d7573742062652067726561746572207468616e20300000005f82015250565b5f611d44601d836116ee565b9150611d4f82611d10565b602082019050919050565b5f6020820190508181035f830152611d7181611d38565b9050919050565b611d8181611922565b82525050565b5f602082019050611d9a5f830184611d78565b92915050565b611da981611821565b8114611db3575f80fd5b50565b5f81519050611dc481611da0565b92915050565b5f60208284031215611ddf57611dde6117bb565b5b5f611dec84828501611db6565b91505092915050565b7f44657374696e6174696f6e20636861696e206e6f7420726567697374657265645f82015250565b5f611e296020836116ee565b9150611e3482611df5565b602082019050919050565b5f6020820190508181035f830152611e5681611e1d565b9050919050565b5f606082019050611e705f830186611b6b565b611e7d6020830185611b6b565b611e8a6040830184611d78565b949350505050565b7f5472616e73666572206661696c656400000000000000000000000000000000005f82015250565b5f611ec6600f836116ee565b9150611ed182611e92565b602082019050919050565b5f6020820190508181035f830152611ef381611eba565b9050919050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f611f2682611efa565b611f308185611f04565b9350611f40818560208601611f0e565b80840191505092915050565b5f611f578284611f1c565b915081905092915050565b5f604082019050611f755f830185611b6b565b611f826020830184611d78565b9392505050565b7f5472616e7366657220746f20436869656656616c696461746f72206661696c655f8201527f6400000000000000000000000000000000000000000000000000000000000000602082015250565b5f611fe36021836116ee565b9150611fee82611f89565b604082019050919050565b5f6020820190508181035f83015261201081611fd7565b9050919050565b612020816117c3565b82525050565b5f61203082611efa565b61203a81856116ee565b935061204a818560208601611f0e565b6120538161195d565b840191505092915050565b5f6040820190506120715f830185612017565b81810360208301526120838184612026565b90509392505050565b7f4d7573742073656e6420455448000000000000000000000000000000000000005f82015250565b5f6120c0600d836116ee565b91506120cb8261208c565b602082019050919050565b5f6020820190508181035f8301526120ed816120b4565b9050919050565b5f815190506121028161192b565b92915050565b5f6020828403121561211d5761211c6117bb565b5b5f61212a848285016120f4565b91505092915050565b7f496e73756666696369656e742062616c616e63650000000000000000000000005f82015250565b5f6121676014836116ee565b915061217282612133565b602082019050919050565b5f6020820190508181035f8301526121948161215b565b9050919050565b7f496e76616c6964206164647265737300000000000000000000000000000000005f82015250565b5f6121cf600f836116ee565b91506121da8261219b565b602082019050919050565b5f6020820190508181035f8301526121fc816121c3565b9050919050565b7f41646472657373206973206e6f74206120636f6e7472616374000000000000005f82015250565b5f6122376019836116ee565b915061224282612203565b602082019050919050565b5f6020820190508181035f8301526122648161222b565b9050919050565b7f496e73756666696369656e7420574554482062616c616e6365000000000000005f82015250565b5f61229f6019836116ee565b91506122aa8261226b565b602082019050919050565b5f6020820190508181035f8301526122cc81612293565b9050919050565b7f2c000000000000000000000000000000000000000000000000000000000000005f82015250565b5f612307600183611f04565b9150612312826122d3565b600182019050919050565b5f6123288288611f1c565b9150612333826122fb565b915061233f8287611f1c565b915061234a826122fb565b91506123568286611f1c565b9150612361826122fb565b915061236d8285611f1c565b9150612378826122fb565b91506123848284611f1c565b91508190509695505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6123ca82611922565b91506123d583611922565b92508282039050818111156123ed576123ec612393565b5b92915050565b5f6123fd82611922565b915061240883611922565b925082820261241681611922565b9150828204841483151761242d5761242c612393565b5b5092915050565b5f8160011c9050919050565b5f808291508390505b60018511156124895780860481111561246557612464612393565b5b60018516156124745780820291505b808102905061248285612434565b9450612449565b94509492505050565b5f826124a1576001905061255c565b816124ae575f905061255c565b81600181146124c457600281146124ce576124fd565b600191505061255c565b60ff8411156124e0576124df612393565b5b8360020a9150848211156124f7576124f6612393565b5b5061255c565b5060208310610133831016604e8410600b84101617156125325782820a90508381111561252d5761252c612393565b5b61255c565b61253f8484846001612440565b9250905081840481111561255657612555612393565b5b81810290505b9392505050565b5f61256d82611922565b915061257883611922565b92506125a57fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8484612492565b905092915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f6125e482611922565b91506125ef83611922565b9250826125ff576125fe6125ad565b5b828204905092915050565b5f60ff82169050919050565b5f6126208261260a565b915061262b8361260a565b92508261263b5761263a6125ad565b5b828204905092915050565b5f6126508261260a565b915061265b8361260a565b92508282026126698161260a565b915080821461267b5761267a612393565b5b5092915050565b5f61268c8261260a565b91506126978361260a565b9250828203905060ff8111156126b0576126af612393565b5b92915050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f6126ed82611922565b91506126f883611922565b92508282019050808211156127105761270f612393565b5b92915050565b5f61272082611922565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361275257612751612393565b5b600182019050919050565b5f6127678261260a565b91506127728361260a565b9250828201905060ff81111561278b5761278a612393565b5b9291505056fea26469706673582212202bee3823fa9b27b04bac80a8cad53b0740dc067fef843f0af8e4dba64c03f56a64736f6c634300081a0033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000062c517854f73515bca2179ef147ab45ef53b48bc00000000000000000000000092eed0282c6665c9bcc81605a13a5c3b1e4dc7f2000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38000000000000000000000000bdfa3a2feb0673740dd6abe69a2db2c3b6459e17

-----Decoded View---------------
Arg [0] : _chiefValidator (address): 0x62C517854f73515bCa2179eF147Ab45EF53b48bC
Arg [1] : _initialOwner (address): 0x92eED0282c6665c9bcc81605A13a5C3b1E4Dc7F2
Arg [2] : _weth (address): 0x039e2fB66102314Ce7b64Ce5Ce3E5183bc94aD38
Arg [3] : _chainRouter (address): 0xBdFA3A2FeB0673740dD6abe69a2dB2C3B6459E17

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000062c517854f73515bca2179ef147ab45ef53b48bc
Arg [1] : 00000000000000000000000092eed0282c6665c9bcc81605a13a5c3b1e4dc7f2
Arg [2] : 000000000000000000000000039e2fb66102314ce7b64ce5ce3e5183bc94ad38
Arg [3] : 000000000000000000000000bdfa3a2feb0673740dd6abe69a2db2c3b6459e17


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.