POL Price: $0.742647 (+7.75%)
 

Overview

POL Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 POL

POL Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Approve647277632024-11-25 20:43:298 days ago1732567409IN
0x4Ab94673...518793801
0 POL0.0014983532.44242673
Approve647275012024-11-25 20:34:008 days ago1732566840IN
0x4Ab94673...518793801
0 POL0.0010223735.13662271
Permit642434352024-11-13 17:37:4320 days ago1731519463IN
0x4Ab94673...518793801
0 POL0.01051642139.92422095
Approve629962172024-10-13 17:56:1051 days ago1728842170IN
0x4Ab94673...518793801
0 POL0.0013855530.00000002
Approve629961472024-10-13 17:53:4251 days ago1728842022IN
0x4Ab94673...518793801
0 POL0.0013859130.00000002
Transfer629851512024-10-13 11:24:0452 days ago1728818644IN
0x4Ab94673...518793801
0 POL0.0011946633.00000004
Transfer626990802024-10-06 9:58:0459 days ago1728208684IN
0x4Ab94673...518793801
0 POL0.0017585733.00000073
Approve626796252024-10-05 22:22:5159 days ago1728166971IN
0x4Ab94673...518793801
0 POL0.0014176330.68678144
Approve626787492024-10-05 21:51:4959 days ago1728165109IN
0x4Ab94673...518793801
0 POL0.001524533.00000002
Transfer626785892024-10-05 21:46:0959 days ago1728164769IN
0x4Ab94673...518793801
0 POL0.0015990630.00000002
Approve625947662024-10-03 20:07:3061 days ago1727986050IN
0x4Ab94673...518793801
0 POL0.0007889130.00000009
Approve625947382024-10-03 20:06:3261 days ago1727985992IN
0x4Ab94673...518793801
0 POL0.0007889130.0000001
Approve625947302024-10-03 20:06:0461 days ago1727985964IN
0x4Ab94673...518793801
0 POL0.0016131934.92000006
Transfer625333102024-10-02 7:37:3463 days ago1727854654IN
0x4Ab94673...518793801
0 POL0.0017585733.00000014
Approve625314342024-10-02 6:31:0463 days ago1727850664IN
0x4Ab94673...518793801
0 POL0.001434431.04969998
Approve625307352024-10-02 6:06:1563 days ago1727849175IN
0x4Ab94673...518793801
0 POL0.0014111830.55500003
Transfer625279022024-10-02 4:25:5563 days ago1727843155IN
0x4Ab94673...518793801
0 POL0.000941730.00000003
Transfer625134502024-10-01 19:53:2363 days ago1727812403IN
0x4Ab94673...518793801
0 POL0.0016282730.555
Transfer624184592024-09-29 11:36:2266 days ago1727609782IN
0x4Ab94673...518793801
0 POL0.0009591230.55500007
Transfer624183832024-09-29 11:33:0866 days ago1727609588IN
0x4Ab94673...518793801
0 POL0.0016282730.55500002
Transfer610157302024-08-25 9:13:36101 days ago1724577216IN
0x4Ab94673...518793801
0 POL0.001598730.00000006
Approve605154212024-08-12 22:05:13113 days ago1723500313IN
0x4Ab94673...518793801
0 POL0.0008729130.00000002
Approve602224262024-08-05 12:27:39121 days ago1722860859IN
0x4Ab94673...518793801
0 POL0.0115844250.760949
Approve601040512024-08-02 11:29:16124 days ago1722598156IN
0x4Ab94673...518793801
0 POL0.0009136731.01740682
Transfer And Cal...599122422024-07-28 14:02:13129 days ago1722175333IN
0x4Ab94673...518793801
0 POL0.0022626330.00000003
View all transactions

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

Contract Source Code Verified (Exact Match)

Contract Name:
DraggableShares

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion, None license
File 1 of 20 : DraggableShares.sol
/**
* SPDX-License-Identifier: LicenseRef-Aktionariat
*
* MIT License with Automated License Fee Payments
*
* Copyright (c) 2022 Aktionariat AG (aktionariat.com)
*
* Permission is hereby granted to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* - The above copyright notice and this permission notice shall be included in
*   all copies or substantial portions of the Software.
* - All automated license fee payments integrated into this and related Software
*   are preserved.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
pragma solidity ^0.8.0;

import "../recovery/ERC20Recoverable.sol";
import "../draggable/ERC20Draggable.sol";
import "../ERC20/ERC20PermitLight.sol";
import "../ERC20/ERC20Permit2.sol";

/**
 * @title CompanyName AG Shares SHA
 * @author Luzius Meisser, [email protected]
 *
 * This is an ERC-20 token representing share tokens of CompanyName AG that are bound to
 * a shareholder agreement that can be found at the URL defined in the constant 'terms'.
 */
contract DraggableShares is ERC20Draggable, ERC20Recoverable, ERC20PermitLight, ERC20Permit2 {

    // Version history:
    // 1: pre permit
    // 2: includes permit
    // 3: added permit2 allowance, VERSION field
    uint8 public constant VERSION = 3;

    string public terms;

    /// Event when the terms are changed with setTerms().
    event ChangeTerms(string terms); 

    constructor(
        string memory _terms,
        DraggableParams memory _params,
        IRecoveryHub _recoveryHub,
        IOfferFactory _offerFactory,
        address _oracle,
        Permit2Hub _permit2Hub
    )
        ERC20Draggable(_params, _offerFactory, _oracle)
        ERC20Recoverable(_recoveryHub)
        ERC20PermitLight() 
        ERC20Permit2(_permit2Hub)

    {
        terms = _terms; // to update the terms, migrate to a new contract. That way it is ensured that the terms can only be updated when the quorom agrees.
        _recoveryHub.setRecoverable(false);
    }

    function transfer(address to, uint256 value) virtual override(IERC20, ERC20Flaggable, ERC20Recoverable) public returns (bool) {
        return super.transfer(to, value);
    }

    /**
     * Let the oracle act as deleter of invalid claims. In earlier versions, this was referring to the claim deleter
     * of the wrapped token. But that stops working after a successful acquisition as the acquisition currency most
     * likely does not have a claim deleter.
     */
    function getClaimDeleter() public view override returns (address) {
        return oracle;
    }

    function getCollateralRate(IERC20 collateralType) public view override returns (uint256) {
        uint256 rate = super.getCollateralRate(collateralType);
        if (rate > 0) {
            return rate;
        } else {
            // as long as it is binding, the conversion rate is 1:1
            uint256 factor = isBinding() ? 1 : unwrapConversionFactor;
            if (address(collateralType) == address(wrapped)) {
                // allow wrapped token as collateral
                return factor;
            } else {
                // If the wrapped contract allows for a specific collateral, we should too.
                // If the wrapped contract is not IRecoverable, we will fail here, but would fail anyway.
                return IRecoverable(address(wrapped)).getCollateralRate(collateralType) * factor;
            }
        }
    }

    /**
     * @notice This function allows the oracle to set the terms.
     * @param _terms The new terms.
     */
    function setTerms(string calldata _terms) external override onlyOracle {
        terms = _terms;
        emit ChangeTerms(terms);
    }

    function _beforeTokenTransfer(address from, address to, uint256 amount) virtual override(ERC20Flaggable, ERC20Draggable) internal {
        super._beforeTokenTransfer(from, to, amount);
    }

    function allowance(address owner, address spender) public view virtual override(ERC20Permit2, ERC20Flaggable, IERC20) returns (uint256) {
        return super.allowance(owner, spender);
    }

}

File 2 of 20 : ERC20Errors.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

/// @title Standard ERC20 Errors
/// @dev See https://eips.ethereum.org/EIPS/eip-20
///  https://eips.ethereum.org/EIPS/eip-6093
interface ERC20Errors {
    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);
}

File 3 of 20 : ERC20Flaggable.sol
// SPDX-License-Identifier: MIT
// Copied and adjusted from OpenZeppelin
// Adjustments:
// - modifications to support ERC-677
// - removed unnecessary require statements
// - removed GSN Context
// - upgraded to 0.8 to drop SafeMath
// - let name() and symbol() be implemented by subclass
// - infinite allowance support, with 2^255 and above considered infinite
// - use upper 32 bits of balance for flags
// - add a global settings variable

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./ERC20Errors.sol";
import "./IERC677Receiver.sol";
/**
 * @dev Implementation of the `IERC20` interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using `_mint`.
 * For a generic mechanism see `ERC20Mintable`.
 *
 * *For a detailed writeup see our guide [How to implement supply
 * mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).*
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an `Approval` event is emitted on calls to `transferFrom`.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard `decreaseAllowance` and `increaseAllowance`
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See `IERC20.approve`.
 */

abstract contract ERC20Flaggable is IERC20, ERC20Errors {

    // as Documented in /doc/infiniteallowance.md
    // 0x8000000000000000000000000000000000000000000000000000000000000000
    uint256 constant private INFINITE_ALLOWANCE = 2**255;

    uint256 private constant FLAGGING_MASK = 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000;

    // Documentation of flags used by subclasses:
    // NOTE: flags denote the bit number that is being used and must be smaller than 32
    // ERC20Draggable: uint8 private constant FLAG_INDEX_VOTED = 1;
    // ERC20Recoverable: uint8 private constant FLAG_INDEX_CLAIM_PRESENT = 10;
    // ERCAllowlistable: uint8 private constant FLAG_INDEX_ALLOWLIST = 20;
    // ERCAllowlistable: uint8 private constant FLAG_INDEX_FORBIDDEN = 21;
    // ERCAllowlistable: uint8 private constant FLAG_INDEX_POWERLIST = 22;

    mapping (address => uint256) private _balances; // upper 32 bits reserved for flags

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    uint8 public override decimals;

    event NameChanged(string name, string symbol);

    /// Overflow on minting, transfer. 
    /// @param receiver The address were the balance overflows. 
    /// @param balance The current balance of the receiver. 
    /// @param amount The amount added, which result in the overflow. 
    error ERC20BalanceOverflow(address receiver, uint256 balance, uint256 amount);

    constructor(uint8 _decimals) {
        decimals = _decimals;
    }

    /**
     * @dev See `IERC20.totalSupply`.
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See `IERC20.balanceOf`.
     */
    function balanceOf(address account) public view override returns (uint256) {
        return uint224 (_balances [account]);
    }

    function hasFlag(address account, uint8 number) external view returns (bool) {
        return hasFlagInternal(account, number);
    }

    function setFlag(address account, uint8 index, bool value) internal {
        uint256 flagMask = 1 << (index + 224);
        uint256 balance = _balances [account];
        if ((balance & flagMask == flagMask) != value) {
            _balances [account] = balance ^ flagMask;
        }
    }

    function hasFlagInternal(address account, uint8 number) internal view returns (bool) {
        uint256 flag = 0x1 << (number + 224);
        return _balances[account] & flag == flag;
    }

    /**
     * @dev See `IERC20.transfer`.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    /**
     * @dev See `IERC20.allowance`.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See `IERC20.approve`.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) external override returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }

    /**
     * @dev See `IERC20.transferFrom`.
     *
     * Emits an `Approval` event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of `ERC20`;
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `value`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external override returns (bool) {
        _transfer(sender, recipient, amount);
        uint256 currentAllowance = allowance(sender, msg.sender);
        if (currentAllowance < INFINITE_ALLOWANCE){
            // Only decrease the allowance if it was not set to 'infinite'
            // Documented in /doc/infiniteallowance.md
            _allowances[sender][msg.sender] = currentAllowance - amount;
        }
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to `transfer`, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a `Transfer` event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        _beforeTokenTransfer(sender, recipient, amount);
        decreaseBalance(sender, amount);
        increaseBalance(recipient, amount);
        emit Transfer(sender, recipient, amount);
    }

    // ERC-677 functionality, can be useful for swapping and wrapping tokens
    function transferAndCall(address recipient, uint amount, bytes calldata data) external virtual returns (bool) {
        return transfer (recipient, amount) 
            && IERC677Receiver (recipient).onTokenTransfer (msg.sender, amount, data);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a `Transfer` event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address recipient, uint256 amount) internal virtual {
        _beforeTokenTransfer(address(0), recipient, amount);
        _totalSupply += amount;
        increaseBalance(recipient, amount);
        emit Transfer(address(0), recipient, amount);
    }

    function increaseBalance(address recipient, uint256 amount) private {
        if (recipient == address(0x0)) {
            revert ERC20InvalidReceiver(recipient); //use burn instead
        }
        uint256 oldBalance = _balances[recipient];
        uint256 newBalance = oldBalance + amount;
        if (oldBalance & FLAGGING_MASK != newBalance & FLAGGING_MASK) {
            revert ERC20BalanceOverflow(recipient, oldBalance, amount);
        }
        _balances[recipient] = newBalance;
    }

     /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a `Transfer` event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        _beforeTokenTransfer(account, address(0), amount);

        _totalSupply -= amount;
        decreaseBalance(account, amount);
        emit Transfer(account, address(0), amount);
    }

    function decreaseBalance(address sender, uint256 amount) private {
        uint256 oldBalance = _balances[sender];
        uint256 newBalance = oldBalance - amount;
        if (oldBalance & FLAGGING_MASK != newBalance & FLAGGING_MASK) {
            revert ERC20InsufficientBalance(sender, balanceOf(sender), amount);
        }
        _balances[sender] = newBalance;
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an `Approval` event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _allowances[owner][spender] = value;
        emit Approval(owner, spender, value);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
     // solhint-disable-next-line no-empty-blocks
    function _beforeTokenTransfer(address from, address to, uint256 amount) virtual internal {
        // intentionally left blank
    }

    /**
     * Checks if msg.sender is an authorized address.
     * @param validSender The authorized address.
     */
    function _checkSender(address validSender) internal view {
        if (msg.sender != validSender) {
            revert ERC20InvalidSender(msg.sender);
        }
    }

}

File 4 of 20 : ERC20Permit2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "./ERC20Flaggable.sol";
import "../utils/Permit2Hub.sol";

/// @title ERC20Permit2
/// @dev This abstract contract extends the ERC20Flaggable contract and introduces the Permit2Hub.
abstract contract ERC20Permit2 is ERC20Flaggable {
    
    /// @dev The Permit2Hub contract instance.
    Permit2Hub public immutable permit2Hub;

    /// @dev Initializes the ERC20Permit2 contract.
    /// @param _permit2Hub The address of the Permit2Hub contract.
    constructor(Permit2Hub _permit2Hub) {
        permit2Hub = _permit2Hub;
    }

    /// @inheritdoc ERC20Flaggable
    function allowance(address owner, address spender) public view virtual override(ERC20Flaggable) returns (uint256) {
        if (permit2Hub.isPermit2Enabled(owner, spender)) 
            return type(uint256).max;  // If permit is enabled, return the maximum value of uint256
        else 
            return super.allowance(owner, spender);  // Otherwise, call the parent(ERC20Flaggable) allowance function
    }
}

File 5 of 20 : ERC20PermitLight.sol
// SPDX-License-Identifier: MIT
// Copied from https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol
// and modified it.

pragma solidity ^0.8.0;

import "./ERC20Flaggable.sol";
import "./IERC20Permit.sol";
abstract contract ERC20PermitLight is ERC20Flaggable, IERC20Permit {

   /*//////////////////////////////////////////////////////////////
                            EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(address => uint256) public override nonces;

  /*//////////////////////////////////////////////////////////////
                             EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public override {
        if (deadline < block.timestamp) {
            revert Permit_DeadlineExpired(deadline, block.timestamp);
        }

        unchecked { // unchecked to save a little gas with the nonce increment...
            address recoveredAddress = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"),
                                bytes32(0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9),
                                owner,
                                spender,
                                value,
                                nonces[owner]++,
                                deadline
                            )
                        )
                    )
                ),
                v,
                r,
                s
            );

            if (recoveredAddress == address(0) || recoveredAddress != owner) {
                revert Permit_InvalidSigner(recoveredAddress);
            }
            _approve(recoveredAddress, spender, value);
        }
    }

    function DOMAIN_SEPARATOR() public view override returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    //keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
                    bytes32(0x47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a79469218),
                    block.chainid,
                    address(this)
                )
            );
    }

}

File 6 of 20 : IERC20.sol
/**
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2016-2019 zOS Global Limited
*
*/
pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see `ERC20Detailed`.
 */

interface IERC20 {

    // Optional functions
    function name() external view returns (string memory);

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

    function decimals() external view returns (uint8);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through `transferFrom`. This is
     * zero by default.
     *
     * This value changes when `approve` or `transferFrom` are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * > Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an `Approval` event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to `approve`. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

}

File 7 of 20 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
// Copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/draft-IERC20Permit.sol

pragma solidity ^0.8.0;

import "./IERC20.sol";

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit is IERC20 {

    /*//////////////////////////////////////////////////////////////
                            Custom errors
	//////////////////////////////////////////////////////////////*/
    /// Block timestamp must to be before deadline.
    /// @param deadline The deadline of the permit.
    /// @param blockTimestamp The timestamp of the execution block.
    error Permit_DeadlineExpired(uint256 deadline, uint256 blockTimestamp);
    /// Recovered address must be owner and not zero address.
    /// @param signerAddress The recovered signer address.
    error Permit_InvalidSigner(address signerAddress);

    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 8 of 20 : IERC677Receiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Given that development on ERC 677 has stalled, we should consider supporting EIP 1363: https://eips.ethereum.org/EIPS/eip-1363
interface IERC677Receiver {

    error IERC677_OnTokenTransferFailed();
    
    function onTokenTransfer(address from, uint256 amount, bytes calldata data) external returns (bool);

}

File 9 of 20 : ERC20Draggable.sol
/**
 * SPDX-License-Identifier: LicenseRef-Aktionariat
 *
 * MIT License with Automated License Fee Payments
 *
 * Copyright (c) 2022 Aktionariat AG (aktionariat.com)
 *
 * Permission is hereby granted to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies of the
 * Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * - The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 * - All automated license fee payments integrated into this and related Software
 *   are preserved.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
pragma solidity ^0.8.0;

/**
 * @title ERC-20 tokens subject to a drag-along agreement
 * @author Luzius Meisser, [email protected]
 *
 * This is an ERC-20 token that is bound to a shareholder or other agreement that contains
 * a drag-along clause. The smart contract can help enforce this drag-along clause in case
 * an acquirer makes an offer using the provided functionality. If a large enough quorum of
 * token holders agree, the remaining token holders can be automatically "dragged along" or
 * squeezed out. For shares non-tokenized shares, the contract relies on an external Oracle
 * to provide the votes of those.
 *
 * Subclasses should provide a link to a human-readable form of the agreement.
 */

import "./IDraggable.sol";
import "../ERC20/ERC20Flaggable.sol";
import "../ERC20/IERC20.sol";
import "../ERC20/IERC677Receiver.sol";
import "./IOffer.sol";
import "./IOfferFactory.sol";
import "../shares/IShares.sol";
import "../utils/SafeERC20.sol";

abstract contract ERC20Draggable is IERC677Receiver, IDraggable, ERC20Flaggable {

	using SafeERC20 for IERC20;
    
	// If flag is not present, one can be sure that the address did not vote. If the 
	// flag is present, the address might have voted and one needs to check with the
	// current offer (if any) when transferring tokens.
	uint8 private constant FLAG_VOTE_HINT = 1;

	IERC20 public override wrapped; // The wrapped contract
	IOfferFactory public immutable factory;

	// If the wrapped tokens got replaced in an acquisition, unwrapping might yield many currency tokens
	uint256 public unwrapConversionFactor = 0;

	// The current acquisition attempt, if any. See initiateAcquisition to see the requirements to make a public offer.
	IOffer public override offer;

	uint256 private constant QUORUM_MULTIPLIER = 10000;

	uint256 public immutable quorumMigration; // used for contract migartion, in BPS (out of 10'000)
	uint256 public immutable quorum; // used for drag-along at acquisition offers, in BPS (out of 10'000)
	uint256 public immutable votePeriod; // In seconds

	address public override oracle;

	struct DraggableParams {
		IERC20 wrappedToken;
		uint256 quorumDrag;
		uint256 quorumMigration;
		uint256 votePeriod;
	}

	event MigrationSucceeded(address newContractAddress, uint256 yesVotes, uint256 oracleVotes, uint256 totalVotingPower);
	event ChangeOracle(address oracle);

    /**
	 * Note that the Brokerbot only supports tokens that revert on failure and where transfer never returns false.
     */
	constructor(
		DraggableParams memory _params,
		IOfferFactory _offerFactory,
		address _oracle
	) 
		ERC20Flaggable(0)
	{
		wrapped = _params.wrappedToken;
		quorum = _params.quorumDrag;
		quorumMigration = _params.quorumMigration;
		votePeriod = _params.votePeriod;
		factory = _offerFactory;
		oracle = _oracle;
	}

	modifier onlyOracle {
		_checkSender(oracle);
		_;
	}

	modifier onlyWrappedToken {
		_checkSender(address(wrapped));
		_;
	}

	modifier onlyOffer(){
		_checkSender(address(offer));
		_;
	}

	modifier checkBinding(bool expected) {
		if (expected != isBinding()) {
			if(expected) {
				revert Draggable_NotBinding();
			}
			if(!expected) {
				revert Draggable_IsBinding();
			}
		} 
		_;
	}

	function onTokenTransfer(
		address from, 
		uint256 amount, 
		bytes calldata
	) external override onlyWrappedToken returns (bool) {
		_mint(from, amount);
		return true;
	}

	/** Wraps additional tokens, thereby creating more ERC20Draggable tokens. */
	function wrap(address shareholder, uint256 amount) external {
		wrapped.safeTransferFrom(msg.sender, address(this), amount);
		_mint(shareholder, amount);
	}

	/**
	 * Indicates that the token holders are bound to the token terms and that:
	 * - Conversion back to the wrapped token (unwrap) is not allowed
	 * - A drag-along can be performed by making an according offer
	 * - They can be migrated to a new version of this contract in accordance with the terms
	 */
	function isBinding() public view returns (bool) {
		return unwrapConversionFactor == 0;
	}

    /**
	 * Current recommended naming convention is to add the postfix "SHA" to the plain shares
	 * in order to indicate that this token represents shares bound to a shareholder agreement.
	 */
	function name() public view override returns (string memory) {
		string memory wrappedName = wrapped.name();
		if (isBinding()) {
			return string(abi.encodePacked(wrappedName, " SHA"));
		} else {
			return string(abi.encodePacked(wrappedName, " (Wrapped)"));
		}
	}

	function symbol() public view override returns (string memory) {
		// ticker should be less dynamic than name
		return string(abi.encodePacked(wrapped.symbol(), "S"));
	}

	/**
	 * Deactivates the drag-along mechanism and enables the unwrap function.
	 */
	function _deactivate(uint256 factor) internal {
		if (factor == 0) {
			revert Draggable_FactorZero();
		}
		unwrapConversionFactor = factor;
	}

	/** Decrease the number of drag-along tokens. The user gets back their shares in return */
	function unwrap(uint256 amount) external override checkBinding(false) {
		_unwrap(msg.sender, amount, unwrapConversionFactor);
	}

	function _unwrap(address owner, uint256 amount, uint256 factor) internal {
		_burn(owner, amount);
		wrapped.safeTransfer(owner, amount * factor);
	}

	/**
	 * Burns both the token itself as well as the wrapped token!
	 * If you want to get out of the shareholder agreement, use unwrap after it has been
	 * deactivated by a majority vote or acquisition.
	 *
	 * Burning only works if wrapped token supports burning. Also, the exact meaning of this
	 * operation might depend on the circumstances. Burning and reussing the wrapped token
	 * does not free the sender from the legal obligations of the shareholder agreement.
	 */
	function burn(uint256 amount) external {
		_burn(msg.sender, amount);
		IShares(address(wrapped)).burn(isBinding() ? amount : amount * unwrapConversionFactor);
	}

	function makeAcquisitionOffer(
		bytes32 salt, 
		uint256 pricePerShare, 
		IERC20 currency
	) external payable checkBinding(true) {
		IOffer newOffer = factory.create{value: msg.value}(
			salt, msg.sender, pricePerShare, currency, quorum, votePeriod);

		if (_offerExists()) {
			offer.makeCompetingOffer(newOffer);
		}
		offer = newOffer;
	}

	function drag(address buyer, IERC20 currency) external override onlyOffer {
		_unwrap(buyer, balanceOf(buyer), 1);
		_replaceWrapped(currency, buyer);
	}

	function notifyOfferEnded() external override onlyOffer {
		offer = IOffer(address(0));
	}

	function _replaceWrapped(IERC20 newWrapped, address oldWrappedDestination) internal checkBinding(true) {
		// Free all old wrapped tokens we have
		wrapped.safeTransfer(oldWrappedDestination, wrapped.balanceOf(address(this)));
		// Count the new wrapped tokens
		wrapped = newWrapped;
		if (totalSupply() > 0) // if there are no tokens, no need to deactivate
			_deactivate(newWrapped.balanceOf(address(this)) / totalSupply());
		emit NameChanged(name(), symbol());
	}

	function setOracle(address newOracle) external override onlyOracle {
		oracle = newOracle;
		emit ChangeOracle(oracle);
	}

	function migrateWithExternalApproval(address successor, uint256 additionalVotes) external override onlyOracle {
		// Additional votes cannot be higher than the votes not represented by these tokens.
		// The assumption here is that more shareholders are bound to the shareholder agreement
		// that this contract helps enforce and a vote among all parties is necessary to change
		// it, with an oracle counting and reporting the votes of the others.
		if (totalSupply() + additionalVotes > totalVotingTokens()) {
			revert Draggable_TooManyVotes(totalVotingTokens(), totalSupply() + additionalVotes);
		}
		_migrate(successor, additionalVotes);
	}

	function migrate() external override {
		_migrate(msg.sender, 0);
	}

	function _migrate(address successor, uint256 additionalVotes) internal {
		uint256 yesVotes = additionalVotes + balanceOf(successor);
		uint256 totalVotes = totalVotingTokens();
		if (yesVotes > totalVotes) {
			revert Draggable_TooManyVotes(totalVotes, yesVotes);
		}
		if (_offerExists()) {
			// if you have the quorum, you can cancel the offer first if necessary
			revert Draggable_OpenOffer();
		}
		if (yesVotes * QUORUM_MULTIPLIER < totalVotes * quorumMigration) {
			revert Draggable_QuorumNotReached(totalVotes * quorumMigration, yesVotes * QUORUM_MULTIPLIER);
		}
		_replaceWrapped(IERC20(successor), successor);
		emit MigrationSucceeded(successor, yesVotes, additionalVotes, totalVotes);
	}

	function votingPower(address voter) external view override returns (uint256) {
		return balanceOf(voter);
	}

	function totalVotingTokens() public view override returns (uint256) {
		return IShares(address(wrapped)).totalShares();
	}

	function _hasVoted(address voter) internal view returns (bool) {
		return hasFlagInternal(voter, FLAG_VOTE_HINT);
	}

	function notifyVoted(address voter) external override onlyOffer {
		setFlag(voter, FLAG_VOTE_HINT, true);
	}

	function _beforeTokenTransfer(address from, address to,	uint256 amount) internal virtual override {
		if (_hasVoted(from) || _hasVoted(to)) {
			if (_offerExists()) {
				offer.notifyMoved(from, to, amount);
			} else {
				setFlag(from, FLAG_VOTE_HINT, false);
				setFlag(to, FLAG_VOTE_HINT, false);
			}
		}
		super._beforeTokenTransfer(from, to, amount);
	}

	function _offerExists() internal view returns (bool) {
		return address(offer) != address(0) && ! offer.isKilled();		// needs to have contract deployed AND offer needs to be not in deleted state
	}
}

File 10 of 20 : IDraggable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../ERC20/IERC20.sol";
import "./IOffer.sol";
interface IDraggable is IERC20 {

    /*//////////////////////////////////////////////////////////////
                            Custom errors
    //////////////////////////////////////////////////////////////*/
    /// conversion factor has to be > 0 for this transaction.
    error Draggable_NotBinding();
    /// conversion factor has to be = 0 for this transaction.
    error Draggable_IsBinding();
    /// conversion factor can't be 0 if binding gets deactivated.
    error Draggable_FactorZero();
    /// the reported votes can't be > max voting tokens.
    /// @param maxVotes The max voting tokens.
    /// @param reportedVotes The actual reported votes.
    error Draggable_TooManyVotes(uint256 maxVotes, uint256 reportedVotes);
    /// there is still an open offer that has to be canceled first
    error Draggable_OpenOffer();
    /// For migration the quorum needs to be reached.
    /// @param needed The needed quorum.
    /// @param actual The current yes votes.
    error Draggable_QuorumNotReached(uint256 needed, uint256 actual);
    
    function wrapped() external view returns (IERC20);
    function unwrap(uint256 amount) external;
    function offer() external view returns (IOffer);
    function oracle() external view returns (address);
    function drag(address buyer, IERC20 currency) external;
    function notifyOfferEnded() external;
    function votingPower(address voter) external returns (uint256);
    function totalVotingTokens() external view returns (uint256);
    function notifyVoted(address voter) external;
    function migrate() external;
    function setOracle(address newOracle) external;
    function migrateWithExternalApproval(address successor, uint256 additionalVotes) external;
    function setTerms(string calldata _terms) external;


}

File 11 of 20 : IOffer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../ERC20/IERC20.sol";

interface IOffer {

	/*//////////////////////////////////////////////////////////////
                            Custom errors
  //////////////////////////////////////////////////////////////*/
	/// Invalid msg.sender.
	/// @param sender The msg.sender of the transaction.
	error Offer_InvalidSender(address sender);
	/// Offer needs to be still open.
	error Offer_AlreadyAccepted();
	/// Offer needs to be not accepted yet.
	error Offer_NotAccepted();
	/// Sender of the offer needs to have needed funds in his account.
	error Offer_NotWellFunded();
	/// New offer not valid. `newPrice` needs to be higher than `oldPrice`.
	/// @param oldPrice Price of the old offer.
	/// @param newPrice Price of the new offer.
	error Offer_OldOfferBetter(uint256 oldPrice, uint256 newPrice);
	/// Voting needs to be still open.
	error Offer_VotingEnded();
	/// Too many (External) reported votes. `reportedVotes` needs to be less or equal to `maxVotes`.
	/// @param maxVotes The max possible votes for the token.
	/// @param reportedVotes The external reported votes + circulating supply of the token.
	error Offer_TooManyVotes(uint256 maxVotes, uint256 reportedVotes);
	/// Competing offer needs to be in the same currency.
	error Offer_OfferInWrongCurrency();
	/// Offer got already killed.
	error Offer_IsKilled();

	/*//////////////////////////////////////////////////////////////
                            Function Interfaces
	//////////////////////////////////////////////////////////////*/

	function makeCompetingOffer(IOffer newOffer) external;

	// if there is a token transfer while an offer is open, the votes get transfered too
	function notifyMoved(address from, address to, uint256 value) external;

	function currency() external view returns (IERC20);

	function price() external view returns (uint256);

	function isWellFunded() external view returns (bool);

	function voteYes() external;

	function voteNo() external;

	function isKilled() external view returns (bool);
}

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

import "../ERC20/IERC20.sol";
import "./IOffer.sol";

interface IOfferFactory {

	function create(
		bytes32 salt, address buyer, uint256 pricePerShare,	IERC20 currency,	uint256 quorum,	uint256 votePeriod
	) external payable returns (IOffer);
}

File 13 of 20 : ERC20Recoverable.sol
/**
* SPDX-License-Identifier: LicenseRef-Aktionariat
*
* MIT License with Automated License Fee Payments
*
* Copyright (c) 2022 Aktionariat AG (aktionariat.com)
*
* Permission is hereby granted to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* - The above copyright notice and this permission notice shall be included in
*   all copies or substantial portions of the Software.
* - All automated license fee payments integrated into this and related Software
*   are preserved.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
pragma solidity ^0.8.0;

import "../ERC20/ERC20Flaggable.sol";
import "./IRecoveryHub.sol";
import "./IRecoverable.sol";

/**
 * @title Recoverable
 * In case of tokens that represent real-world assets such as shares of a company, one needs a way
 * to handle lost private keys. With physical certificates, courts can declare share certificates as
 * invalid so the company can issue replacements. Here, we want a solution that does not depend on
 * third parties to resolve such cases. Instead, when someone has lost a private key, he can use the
 * declareLost function on the recovery hub to post a deposit and claim that the shares assigned to a
 * specific address are lost.
 * If an attacker trying to claim shares belonging to someone else, they risk losing the deposit
 * as it can be claimed at anytime by the rightful owner.
 * Furthermore, if "getClaimDeleter" is defined in the subclass, the returned address is allowed to
 * delete claims, returning the collateral. This can help to prevent obvious cases of abuse of the claim
 * function, e.g. cases of front-running.
 * Most functionality is implemented in a shared RecoveryHub.
 */
abstract contract ERC20Recoverable is ERC20Flaggable, IRecoverable {

    uint8 private constant FLAG_CLAIM_PRESENT = 10;

    // ERC-20 token that can be used as collateral or 0x0 if disabled
    IERC20 public customCollateralAddress;
    // Rate the custom collateral currency is multiplied to be valued like one share.
    uint256 public customCollateralRate;

    uint256 constant CLAIM_PERIOD = 180 days;

    IRecoveryHub public override immutable recovery;

    constructor(IRecoveryHub recoveryHub){
        recovery = recoveryHub;
    }

    modifier onlyRecovery {
        _checkSender(address(recovery));
        _;
    }

    /**
     * Returns the collateral rate for the given collateral type and 0 if that type
     * of collateral is not accepted. By default, only the token itself is accepted at
     * a rate of 1:1.
     *
     * Subclasses should override this method if they want to add additional types of
     * collateral.
     */
    function getCollateralRate(IERC20 collateralType) public override virtual view returns (uint256) {
        if (address(collateralType) == address(this)) {
            return 1;
        } else if (collateralType == customCollateralAddress) {
            return customCollateralRate;
        } else {
            return 0;
        }
    }

    function claimPeriod() external pure override returns (uint256){
        return CLAIM_PERIOD;
    }

    /**
     * Allows subclasses to set a custom collateral besides the token itself.
     * The collateral must be an ERC-20 token that returns true on successful transfers and
     * throws an exception or returns false on failure.
     * Also, do not forget to multiply the rate in accordance with the number of decimals of the collateral.
     * For example, rate should be 7*10**18 for 7 units of a collateral with 18 decimals.
     */
    function _setCustomClaimCollateral(IERC20 collateral, uint256 rate) internal {
        customCollateralAddress = collateral;
        if (address(customCollateralAddress) == address(0)) {
            customCollateralRate = 0; // disabled
        } else {
            if (rate == 0) {
                revert Recoverable_RateZero();
            }
            customCollateralRate = rate;
        }
    }

    function getClaimDeleter() virtual public view returns (address);

    function transfer(address recipient, uint256 amount) override(ERC20Flaggable, IERC20) virtual public returns (bool) {
        super.transfer(recipient, amount); // no need for safe transfer, as it's our own token
        if (hasFlagInternal(msg.sender, FLAG_CLAIM_PRESENT)){
            recovery.clearClaimFromToken(msg.sender);
        }
        return true;
    }

    function notifyClaimMade(address target) external override onlyRecovery {
        setFlag(target, FLAG_CLAIM_PRESENT, true);
    }

    function notifyClaimDeleted(address target) external override onlyRecovery {
        setFlag(target, FLAG_CLAIM_PRESENT, false);
    }

    function deleteClaim(address lostAddress) external {
        _checkSender(getClaimDeleter());
        recovery.deleteClaim(lostAddress);
    }

    function recover(address oldAddress, address newAddress) external override onlyRecovery {
        _transfer(oldAddress, newAddress, balanceOf(oldAddress));
    }

}

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

import "../ERC20/IERC20.sol";
import "./IRecoveryHub.sol";

interface IRecoverable is IERC20{

	/*//////////////////////////////////////////////////////////////
                            Custom errors
    //////////////////////////////////////////////////////////////*/
    /// The new custom claim collateral rate has to be always > 0. 
    error Recoverable_RateZero();

    // returns the recovery hub
    function recovery() external view returns (IRecoveryHub);

    function claimPeriod() external view returns (uint256);
    
    function notifyClaimMade(address target) external;

    function notifyClaimDeleted(address target) external;

    function getCollateralRate(IERC20 collateral) external view returns(uint256);

    function recover(address oldAddress, address newAddress) external;

}

File 15 of 20 : IRecoveryHub.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./IRecoverable.sol";
import "../ERC20/IERC20.sol";

interface IRecoveryHub {

	/*//////////////////////////////////////////////////////////////
                            Custom errors
    //////////////////////////////////////////////////////////////*/
    /// Recovery can be disabled per address.
    /// @param lostAddress The address for which the recovery is disabled.
    error RecoveryHub_RecoveryDisabled(address lostAddress);
    /// No valid collateral type
    /// @param collateralType The address of collateral type token
    error RecoveryHub_BadCollateral(IERC20 collateralType);
    /// No token to able to recover on the lost address
    /// @param token The token address which is checked for recovery.
    /// @param lostAddress The lost address.
    error RecoveryHub_NothingToRecover(IERC20 token, address lostAddress);
    /// The was already a claim for this token and address.
    /// @param token The token address.
    /// @param lostAddress The lost address.
    error RecoveryHub_AlreadyClaimed(IERC20 token, address lostAddress);
    /// Sender has to be claimant
    /// @param sender The msg.sender of the call
    error RecoveryHub_InvalidSender(address sender);
    /// No claim for this address exists
    /// @param lostAddress The checked address 
    error RecoveryHub_ClaimNotFound(address lostAddress);
    /// Recover can only be called after the claim period
    /// @param claimPeriodEnd The timestamp when the period ends
    /// @param currentTimestamp The block timestamp of the call
    error RecoveryHub_InClaimPeriod(uint256 claimPeriodEnd, uint256 currentTimestamp);

    function setRecoverable(bool flag) external;
    
    // deletes claim and transfers collateral back to claimer
    function deleteClaim(address target) external;

    // clears claim and transfers collateral to holder
    function clearClaimFromToken(address holder) external;

    function clearClaimFromUser(IRecoverable token) external;

}

File 16 of 20 : IShares.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "../ERC20/IERC20.sol";

interface IShares is IERC20 {

	/*//////////////////////////////////////////////////////////////
                            Custom errors
	//////////////////////////////////////////////////////////////*/
	/// New total shares can't be below current valid supply
	/// @param totalSupply  The current valid supply. 
	/// @param newTotalShares  The new max shares. 
	error Shares_InvalidTotalShares(uint256 totalSupply, uint256 newTotalShares);
	/// Array lengths have to be equal. 
	/// @param targets Array length of targets. 
	/// @param amount Array length of amounts. 
	error Shares_UnequalLength(uint256 targets, uint256 amount);
	/// It isn't possible to mint more share token than max shares in existens. 
	/// @param totalShares The max amount of shares. 
	/// @param needed The max amount of shares needed (current valid supply + new mint amount). 
	error Shares_InsufficientTotalShares(uint256 totalShares, uint256 needed);

	function burn(uint256) external;

	function totalShares() external view returns (uint256);
}

File 17 of 20 : Address.sol
// SPDX-License-Identifier: MIT
// Copied from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol
// and modified it.

pragma solidity ^0.8.0;

library Address {

    /// @param target Target address to call the function on.
    error Address_NotTransferNorContract(address target);

    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.
        return account.code.length > 0;
    }
    
    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    function functionCallWithValue(address target, bytes memory data, uint256 weiValue) internal returns (bytes memory) {
        if (data.length != 0 && !isContract(target)) {
            revert Address_NotTransferNorContract(target);
        }
        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        if (success) {
            return returndata;
        } else if (returndata.length > 0) {
            assembly{
                revert (add (returndata, 0x20), mload (returndata))
            }
        } else {
           revert("failed");
        }
    }
}

File 18 of 20 : Ownable.sol
// SPDX-License-Identifier: MIT
//
// From https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol
//
// Modifications:
// - Replaced Context._msgSender() with msg.sender
// - Made leaner
// - Extracted interface

pragma solidity ^0.8.0;

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
contract Ownable {

    address public owner;

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

    error Ownable_NotOwner(address sender);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor (address initialOwner) {
        owner = initialOwner;
        emit OwnershipTransferred(address(0), owner);
    }

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) external onlyOwner {
        emit OwnershipTransferred(owner, newOwner);
        owner = newOwner;
    }

    function _checkOwner() internal view {
        if (msg.sender != owner) {
            revert Ownable_NotOwner(msg.sender);
        }
    }
}

File 19 of 20 : Permit2Hub.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import "../utils/Ownable.sol";

/// @title Permit2Hub
/// @dev This contract manages the Permit2 functionality and access control.
contract Permit2Hub is Ownable {
  
  /// @dev The address of the Permit2 contract.
  address public immutable permit2;
  /// @dev Flag to indicate whether Permit2 is disabled.
  bool public permit2Disabled = false;

  /// @dev Mapping to track addresses for which Permit2 is disabled.
  mapping(address => bool) public permit2DisabledForAddress;

  /// @dev Emitted when the Permit2 setting is changed.
  event ChangedPermit2(bool newSetting);

  /// @dev Initializes the Permit2Hub contract with the provided Permit2 address and owner address.
  /// @param _permit2 The address of the Permit2 contract.
  /// @param _owner The address of the owner.
  constructor(address _permit2, address _owner) Ownable(_owner) {
    permit2 = _permit2;
  }

  /// @dev Checks if Permit2 is enabled for the given owner and spender addresses.
  /// @param owner The owner address.
  /// @param spender The spender address, needs to be the permit2 contract.
  /// @return A boolean indicating whether Permit2 is enabled.
  function isPermit2Enabled(address owner, address spender) public view returns (bool){
    return spender == permit2 && !permit2Disabled && !permit2DisabledForAddress[owner];
  }

  /// @dev Toggles the global Permit2 setting. Can only be called by the owner.
  function togglePermit2() external onlyOwner {
    permit2Disabled = !permit2Disabled;
    emit ChangedPermit2(permit2Disabled);
  }

  /// @dev Sets the Permit2 status for a specific address.
  /// @param enabled The status to set for the address.
  function setPermit2(bool enabled) external {
    permit2DisabledForAddress[msg.sender] = !enabled;
  }
}

File 20 of 20 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// coppied and adjusted from OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../ERC20/IERC20.sol";
import {IERC20Permit} from "../ERC20/IERC20Permit.sol";
import {Address} from "./Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        if (nonceAfter != nonceBefore + 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

Settings
{
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"_terms","type":"string"},{"components":[{"internalType":"contract IERC20","name":"wrappedToken","type":"address"},{"internalType":"uint256","name":"quorumDrag","type":"uint256"},{"internalType":"uint256","name":"quorumMigration","type":"uint256"},{"internalType":"uint256","name":"votePeriod","type":"uint256"}],"internalType":"struct ERC20Draggable.DraggableParams","name":"_params","type":"tuple"},{"internalType":"contract IRecoveryHub","name":"_recoveryHub","type":"address"},{"internalType":"contract IOfferFactory","name":"_offerFactory","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"contract Permit2Hub","name":"_permit2Hub","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"Address_NotTransferNorContract","type":"error"},{"inputs":[],"name":"Draggable_FactorZero","type":"error"},{"inputs":[],"name":"Draggable_IsBinding","type":"error"},{"inputs":[],"name":"Draggable_NotBinding","type":"error"},{"inputs":[],"name":"Draggable_OpenOffer","type":"error"},{"inputs":[{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"Draggable_QuorumNotReached","type":"error"},{"inputs":[{"internalType":"uint256","name":"maxVotes","type":"uint256"},{"internalType":"uint256","name":"reportedVotes","type":"uint256"}],"name":"Draggable_TooManyVotes","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20BalanceOverflow","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"IERC677_OnTokenTransferFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint256","name":"blockTimestamp","type":"uint256"}],"name":"Permit_DeadlineExpired","type":"error"},{"inputs":[{"internalType":"address","name":"signerAddress","type":"address"}],"name":"Permit_InvalidSigner","type":"error"},{"inputs":[],"name":"Recoverable_RateZero","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oracle","type":"address"}],"name":"ChangeOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"terms","type":"string"}],"name":"ChangeTerms","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newContractAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"yesVotes","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oracleVotes","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalVotingPower","type":"uint256"}],"name":"MigrationSucceeded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"}],"name":"NameChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"customCollateralAddress","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"customCollateralRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"lostAddress","type":"address"}],"name":"deleteClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"buyer","type":"address"},{"internalType":"contract IERC20","name":"currency","type":"address"}],"name":"drag","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"contract IOfferFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getClaimDeleter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"collateralType","type":"address"}],"name":"getCollateralRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint8","name":"number","type":"uint8"}],"name":"hasFlag","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isBinding","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256","name":"pricePerShare","type":"uint256"},{"internalType":"contract IERC20","name":"currency","type":"address"}],"name":"makeAcquisitionOffer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"successor","type":"address"},{"internalType":"uint256","name":"additionalVotes","type":"uint256"}],"name":"migrateWithExternalApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"notifyClaimDeleted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"notifyClaimMade","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"notifyOfferEnded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"voter","type":"address"}],"name":"notifyVoted","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"offer","outputs":[{"internalType":"contract IOffer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onTokenTransfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"permit2Hub","outputs":[{"internalType":"contract Permit2Hub","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quorum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quorumMigration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"oldAddress","type":"address"},{"internalType":"address","name":"newAddress","type":"address"}],"name":"recover","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"recovery","outputs":[{"internalType":"contract IRecoveryHub","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOracle","type":"address"}],"name":"setOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_terms","type":"string"}],"name":"setTerms","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"terms","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalVotingTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"transferAndCall","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unwrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unwrapConversionFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"votePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"voter","type":"address"}],"name":"votingPower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"shareholder","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"wrap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrapped","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

610140604052600060045534801561001657600080fd5b50604051612f49380380612f49833981016040819052610035916101ec565b6003805486516001600160a81b03199091166101006001600160a01b03928316810291909117909255602087015160c052604087015160a052606087015160e052848116608052600680546001600160a01b031916858316179055858116909152811661012052600a6100a88782610377565b50604051636427ed9760e01b8152600060048201526001600160a01b03851690636427ed9790602401600060405180830381600087803b1580156100eb57600080fd5b505af11580156100ff573d6000803e3d6000fd5b50505050505050505050610436565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b038111828210171561014c5761014c61010e565b604052919050565b6001600160a01b038116811461016957600080fd5b50565b60006080828403121561017e57600080fd5b604051608081016001600160401b03811182821017156101a0576101a061010e565b806040525080915082516101b381610154565b808252506020830151602082015260408301516040820152606083015160608201525092915050565b80516101e781610154565b919050565b600080600080600080610120878903121561020657600080fd5b86516001600160401b038082111561021d57600080fd5b818901915089601f83011261023157600080fd5b8151818111156102435761024361010e565b60209150610259601f8201601f19168301610124565b8181528b8383860101111561026d57600080fd5b60005b8281101561028b578481018401518282018501528301610270565b50600083838301015280995050506102a58a828b0161016c565b965050506102b560a088016101dc565b93506102c360c088016101dc565b92506102d160e088016101dc565b91506102e061010088016101dc565b90509295509295509295565b600181811c9082168061030057607f821691505b60208210810361032057634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610372576000816000526020600020601f850160051c8101602086101561034f5750805b601f850160051c820191505b8181101561036e5782815560010161035b565b5050505b505050565b81516001600160401b038111156103905761039061010e565b6103a48161039e84546102ec565b84610326565b602080601f8311600181146103d957600084156103c15750858301515b600019600386901b1c1916600185901b17855561036e565b600085815260208120601f198616915b82811015610408578886015182559484019460019091019084016103e9565b50858210156104265787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805160a05160c05160e0516101005161012051612a776104d2600039600081816103f50152611bdc01526000818161086d01528181610bd801528181610dd3015281816110fe015281816115be0152611a430152600081816106fd015261141e0152600081816103ac01526113f80152600081816108e10152818161173401526117700152600081816107d101526114470152612a776000f3fe6080604052600436106102c95760003560e01c80637dc0d1d011610175578063c18172c4116100dc578063ddceafa911610095578063efa405121161006f578063efa40512146108cf578063f5c0b95f14610903578063fcb79a7e14610923578063ffa1ad741461094357600080fd5b8063ddceafa91461085b578063de0e9a3e1461088f578063e5b824ec146108af57600080fd5b8063c18172c41461079f578063c45a0155146107bf578063d5025625146107f3578063d505accf14610808578063dcc7d4ad14610828578063dd62ed3e1461083b57600080fd5b8063a4c0ed361161012e578063a4c0ed36146106cb578063a7813587146106eb578063a9059cbb1461071f578063bf376c7a1461073f578063c028df061461075f578063c07473f61461077f57600080fd5b80637dc0d1d0146106285780637dc2cd98146106485780637ecebe001461065e5780638fd3ab801461068b57806395d89b41146106a05780639e4b5745146106b557600080fd5b806332a7ae951161023457806350e70d48116101ed57806370a08231116101c757806370a08231146105a857806377e071ad146105c857806378f86afc146105e85780637adbf9731461060857600080fd5b806350e70d481461054d5780636091811714610572578063648bf7741461058857600080fd5b806332a7ae95146104a357806332bc320b146104c35780633644e515146104d85780634000aea0146104ed57806342966c681461050d57806345c8a62b1461052d57600080fd5b806318160ddd1161028657806318160ddd146103ce57806318efcce5146103e3578063198453541461041757806323b872dd146104395780632a0a4ed514610459578063313ce5671461047757600080fd5b806306fdde03146102ce5780630832e470146102f9578063095ea7b31461031d5780630a81b2de1461034d5780630c6f0e5d146103625780631703a0181461039a575b600080fd5b3480156102da57600080fd5b506102e3610958565b6040516102f091906122e8565b60405180910390f35b34801561030557600080fd5b5061030f60045481565b6040519081526020016102f0565b34801561032957600080fd5b5061033d610338366004612310565b610a1f565b60405190151581526020016102f0565b34801561035957600080fd5b5061030f610a36565b34801561036e57600080fd5b50600754610382906001600160a01b031681565b6040516001600160a01b0390911681526020016102f0565b3480156103a657600080fd5b5061030f7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103da57600080fd5b5060025461030f565b3480156103ef57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b34801561042357600080fd5b50610437610432366004612310565b610ab4565b005b34801561044557600080fd5b5061033d61045436600461233c565b610b3c565b34801561046557600080fd5b506006546001600160a01b0316610382565b34801561048357600080fd5b506003546104919060ff1681565b60405160ff90911681526020016102f0565b3480156104af57600080fd5b506104376104be36600461237d565b610b9f565b3480156104cf57600080fd5b50610437610c38565b3480156104e457600080fd5b5061030f610c5f565b3480156104f957600080fd5b5061033d6105083660046123e3565b610cb8565b34801561051957600080fd5b5061043761052836600461243f565b610d49565b34801561053957600080fd5b5061043761054836600461237d565b610daa565b34801561055957600080fd5b506003546103829061010090046001600160a01b031681565b34801561057e57600080fd5b5061030f60085481565b34801561059457600080fd5b506104376105a3366004612458565b610dce565b3480156105b457600080fd5b5061030f6105c336600461237d565b610e0a565b3480156105d457600080fd5b5061030f6105e336600461237d565b610e2e565b3480156105f457600080fd5b50610437610603366004612491565b610f13565b34801561061457600080fd5b5061043761062336600461237d565b610f72565b34801561063457600080fd5b50600654610382906001600160a01b031681565b34801561065457600080fd5b5062ed4e0061030f565b34801561066a57600080fd5b5061030f61067936600461237d565b60096020526000908152604090205481565b34801561069757600080fd5b50610437610fdb565b3480156106ac57600080fd5b506102e3610fe8565b3480156106c157600080fd5b506004541561033d565b3480156106d757600080fd5b5061033d6106e63660046123e3565b611089565b3480156106f757600080fd5b5061030f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561072b57600080fd5b5061033d61073a366004612310565b6110bb565b34801561074b57600080fd5b5061043761075a366004612310565b6110c7565b34801561076b57600080fd5b50600554610382906001600160a01b031681565b34801561078b57600080fd5b5061030f61079a36600461237d565b6110ee565b3480156107ab57600080fd5b506104376107ba36600461237d565b6110f9565b3480156107cb57600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b3480156107ff57600080fd5b506102e361112f565b34801561081457600080fd5b506104376108233660046124e4565b6111bd565b610437610836366004612552565b611372565b34801561084757600080fd5b5061030f610856366004612458565b61154d565b34801561086757600080fd5b506103827f000000000000000000000000000000000000000000000000000000000000000081565b34801561089b57600080fd5b506104376108aa36600461243f565b611559565b3480156108bb57600080fd5b506104376108ca36600461237d565b6115b9565b3480156108db57600080fd5b5061030f7f000000000000000000000000000000000000000000000000000000000000000081565b34801561090f57600080fd5b5061033d61091e36600461258b565b6115ef565b34801561092f57600080fd5b5061043761093e366004612458565b6115fb565b34801561094f57600080fd5b50610491600381565b60606000600360019054906101000a90046001600160a01b03166001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156109af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109d791908101906125d6565b90506109e36004541590565b15610a0e57806040516020016109f99190612683565b60405160208183030381529060405291505090565b806040516020016109f991906126ab565b6000610a2c33848461162e565b5060015b92915050565b6000600360019054906101000a90046001600160a01b03166001600160a01b0316633a98ef396040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aaf91906126d9565b905090565b600654610ac9906001600160a01b0316611690565b610ad1610a36565b81610adb60025490565b610ae59190612708565b1115610b2e57610af3610a36565b81610afd60025490565b610b079190612708565b604051630429590f60e41b8152600481019290925260248201526044015b60405180910390fd5b610b3882826116bb565b5050565b6000610b49848484611824565b6000610b55853361154d565b9050600160ff1b811015610b9257610b6d838261271b565b6001600160a01b03861660009081526001602090815260408083203384529091529020555b60019150505b9392505050565b610bb9610bb46006546001600160a01b031690565b611690565b6040516332a7ae9560e01b81526001600160a01b0382811660048301527f000000000000000000000000000000000000000000000000000000000000000016906332a7ae95906024015b600060405180830381600087803b158015610c1d57600080fd5b505af1158015610c31573d6000803e3d6000fd5b5050505050565b600554610c4d906001600160a01b0316611690565b600580546001600160a01b0319169055565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b6000610cc485856110bb565b8015610d405750604051635260769b60e11b81526001600160a01b0386169063a4c0ed3690610cfd90339088908890889060040161272e565b6020604051808303816000875af1158015610d1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d409190612776565b95945050505050565b610d533382611888565b6003546001600160a01b03610100909104166342966c68610d746004541590565b610d8a57600454610d859084612798565b610d8c565b825b6040518263ffffffff1660e01b8152600401610c0391815260200190565b600554610dbf906001600160a01b0316611690565b610dcb816001806118fc565b50565b610df77f0000000000000000000000000000000000000000000000000000000000000000611690565b610b388282610e0585610e0a565b611824565b6001600160a01b03166000908152602081905260409020546001600160e01b031690565b600080610e3a83611960565b90508015610e485792915050565b6000610e546004541590565b610e6057600454610e63565b60015b6003549091506001600160a01b03610100909104811690851603610e88579392505050565b6003546040516377e071ad60e01b81526001600160a01b0386811660048301528392610100900416906377e071ad90602401602060405180830381865afa158015610ed7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610efb91906126d9565b610f059190612798565b949350505050565b50919050565b600654610f28906001600160a01b0316611690565b600a610f35828483612833565b507fe9f2468ecc8d3dff15a70a5909151e6297cee4cf05268eff3d7ef0c696ec50f2600a604051610f6691906128f3565b60405180910390a15050565b600654610f87906001600160a01b0316611690565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527fc3977c9522c218453912bcab15964a7788968fbf3fe4d4e2965252c9f07055de9060200160405180910390a150565b610fe63360006116bb565b565b6060600360019054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561103d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261106591908101906125d6565b6040516020016110759190612983565b604051602081830303815290604052905090565b6003546000906110a69061010090046001600160a01b0316611690565b6110b085856119a5565b506001949350505050565b6000610b988383611a11565b6003546110e49061010090046001600160a01b0316333084611ab0565b610b3882826119a5565b6000610a3082610e0a565b6111227f0000000000000000000000000000000000000000000000000000000000000000611690565b610dcb81600a60016118fc565b600a805461113c906127af565b80601f0160208091040260200160405190810160405280929190818152602001828054611168906127af565b80156111b55780601f1061118a576101008083540402835291602001916111b5565b820191906000526020600020905b81548152906001019060200180831161119857829003601f168201915b505050505081565b428410156111e757604051630b99fc4b60e31b815260048101859052426024820152604401610b25565b600060016111f3610c5f565b6001600160a01b038a811660008181526009602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156112ff573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615806113345750876001600160a01b0316816001600160a01b031614155b1561135d57604051632f52260d60e11b81526001600160a01b0382166004820152602401610b25565b61136881888861162e565b5050505050505050565b600161137e6004541590565b1515811515146113c55780156113a7576040516305a34cd360e01b815260040160405180910390fd5b806113c55760405163291c3d8560e01b815260040160405180910390fd5b604051634dc5e43160e01b815260048101859052336024820152604481018490526001600160a01b0383811660648301527f000000000000000000000000000000000000000000000000000000000000000060848301527f000000000000000000000000000000000000000000000000000000000000000060a48301526000917f000000000000000000000000000000000000000000000000000000000000000090911690634dc5e43190349060c40160206040518083038185885af1158015611493573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906114b891906129a8565b90506114c2611b1d565b1561152757600554604051637b64620f60e11b81526001600160a01b0383811660048301529091169063f6c8c41e90602401600060405180830381600087803b15801561150e57600080fd5b505af1158015611522573d6000803e3d6000fd5b505050505b600580546001600160a01b0319166001600160a01b039290921691909117905550505050565b6000610b988383611bb2565b60006115656004541590565b1515811515146115ac57801561158e576040516305a34cd360e01b815260040160405180910390fd5b806115ac5760405163291c3d8560e01b815260040160405180910390fd5b610b383383600454611c83565b6115e27f0000000000000000000000000000000000000000000000000000000000000000611690565b610dcb81600a60006118fc565b6000610b988383611cb8565b600554611610906001600160a01b0316611690565b6116248261161d84610e0a565b6001611c83565b610b388183611cf8565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b336001600160a01b03821614610dcb57604051634b637e8f60e11b8152336004820152602401610b25565b60006116c683610e0a565b6116d09083612708565b905060006116dc610a36565b90508082111561170957604051630429590f60e41b81526004810182905260248101839052604401610b25565b611711611b1d565b1561172f576040516331dec02560e21b815260040160405180910390fd5b6117597f000000000000000000000000000000000000000000000000000000000000000082612798565b61176561271084612798565b10156117c3576117957f000000000000000000000000000000000000000000000000000000000000000082612798565b6117a161271084612798565b604051634b2737cf60e11b815260048101929092526024820152604401610b25565b6117cd8485611cf8565b604080516001600160a01b038616815260208101849052908101849052606081018290527f85e5711a70a7d2bae18e1232af474d82c98600b0e62fe079a28208520b58568e9060800160405180910390a150505050565b61182f838383611ebb565b6118398382611ec6565b6118438282611f63565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161168391815260200190565b61189482600083611ebb565b80600260008282546118a6919061271b565b909155506118b690508282611ec6565b6040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b60006119098360e06129c5565b6001600160a01b038516600090815260208190526040902054600160ff929092169190911b9150808216821483151514610c31576001600160a01b0394909416600090815260208190526040902093189092555050565b6000306001600160a01b0383160361197a57506001919050565b6007546001600160a01b039081169083160361199857505060085490565b506000919050565b919050565b6119b160008383611ebb565b80600260008282546119c39190612708565b909155506119d390508282611f63565b6040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016118f0565b6000611a1d8383612008565b50611a2933600a611cb8565b15610a2c576040516304d301a360e41b81523360048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690634d301a3090602401600060405180830381600087803b158015611a8f57600080fd5b505af1158015611aa3573d6000803e3d6000fd5b5050505050600192915050565b6040516001600160a01b038481166024830152838116604483015260648201839052611b179186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612015565b50505050565b6005546000906001600160a01b031615801590610aaf5750600560009054906101000a90046001600160a01b03166001600160a01b0316638fe8a1016040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bac9190612776565b15905090565b604051632fb6b53160e11b81526001600160a01b03838116600483015282811660248301526000917f000000000000000000000000000000000000000000000000000000000000000090911690635f6d6a6290604401602060405180830381865afa158015611c25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c499190612776565b15611c575750600019610a30565b506001600160a01b03828116600090815260016020908152604080832093851683529290522054610a30565b611c8d8383611888565b611cb383611c9b8385612798565b60035461010090046001600160a01b03169190612078565b505050565b600080611cc68360e06129c5565b6001600160a01b038516600090815260208190526040902054600160ff929092169190911b9081161491505092915050565b6001611d046004541590565b151581151514611d4b578015611d2d576040516305a34cd360e01b815260040160405180910390fd5b80611d4b5760405163291c3d8560e01b815260040160405180910390fd5b6003546040516370a0823160e01b8152306004820152611dc19184916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015611d9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9b91906126d9565b60038054610100600160a81b0319166101006001600160a01b0386160217905560025460001015611e6f57611e6f611df860025490565b6040516370a0823160e01b81523060048201526001600160a01b038616906370a0823190602401602060405180830381865afa158015611e3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6091906126d9565b611e6a91906129de565b6120a9565b7f6c20b91d1723b78732eba64ff11ebd7966a6e4af568a00fa4f6b72c20f58b02a611e98610958565b611ea0610fe8565b604051611eae929190612a00565b60405180910390a1505050565b611cb38383836120cf565b6001600160a01b03821660009081526020819052604081205490611eea838361271b565b90506001600160e01b031981166001600160e01b0319831614611f425783611f1185610e0a565b60405163391434e360e21b81526001600160a01b039092166004830152602482015260448101849052606401610b25565b6001600160a01b039093166000908152602081905260409020929092555050565b6001600160a01b038216611f955760405163ec442f0560e01b81526001600160a01b0383166004820152602401610b25565b6001600160a01b03821660009081526020819052604081205490611fb98383612708565b90506001600160e01b031981166001600160e01b0319831614611f4257604051634a2e08e560e01b81526001600160a01b03851660048201526024810183905260448101849052606401610b25565b6000610a2c338484611824565b600061202a6001600160a01b03841683612186565b9050805160001415801561204f57508080602001905181019061204d9190612776565b155b15611cb357604051635274afe760e01b81526001600160a01b0384166004820152602401610b25565b6040516001600160a01b03838116602483015260448201839052611cb391859182169063a9059cbb90606401611ae5565b806000036120ca57604051631dca7a7560e11b815260040160405180910390fd5b600455565b6120d883612194565b806120e757506120e782612194565b15611cb3576120f4611b1d565b1561216c5760055460405163e1a1810f60e01b81526001600160a01b0385811660048301528481166024830152604482018490529091169063e1a1810f90606401600060405180830381600087803b15801561214f57600080fd5b505af1158015612163573d6000803e3d6000fd5b50505050505050565b61217983600160006118fc565b611cb382600160006118fc565b6060610b98838360006121a1565b6000610a30826001611cb8565b606082516000141580156121bd57506001600160a01b0384163b155b156121e657604051639eb1341360e01b81526001600160a01b0385166004820152602401610b25565b600080856001600160a01b031684866040516122029190612a25565b60006040518083038185875af1925050503d806000811461223f576040519150601f19603f3d011682016040523d82523d6000602084013e612244565b606091505b50915091508115612258579150610b989050565b80511561226757805160208201fd5b60405162461bcd60e51b815260206004820152600660248201526519985a5b195960d21b6044820152606401610b25565b60005b838110156122b357818101518382015260200161229b565b50506000910152565b600081518084526122d4816020860160208601612298565b601f01601f19169290920160200192915050565b602081526000610b9860208301846122bc565b6001600160a01b0381168114610dcb57600080fd5b6000806040838503121561232357600080fd5b823561232e816122fb565b946020939093013593505050565b60008060006060848603121561235157600080fd5b833561235c816122fb565b9250602084013561236c816122fb565b929592945050506040919091013590565b60006020828403121561238f57600080fd5b8135610b98816122fb565b60008083601f8401126123ac57600080fd5b50813567ffffffffffffffff8111156123c457600080fd5b6020830191508360208285010111156123dc57600080fd5b9250929050565b600080600080606085870312156123f957600080fd5b8435612404816122fb565b935060208501359250604085013567ffffffffffffffff81111561242757600080fd5b6124338782880161239a565b95989497509550505050565b60006020828403121561245157600080fd5b5035919050565b6000806040838503121561246b57600080fd5b8235612476816122fb565b91506020830135612486816122fb565b809150509250929050565b600080602083850312156124a457600080fd5b823567ffffffffffffffff8111156124bb57600080fd5b6124c78582860161239a565b90969095509350505050565b803560ff811681146119a057600080fd5b600080600080600080600060e0888a0312156124ff57600080fd5b873561250a816122fb565b9650602088013561251a816122fb565b95506040880135945060608801359350612536608089016124d3565b925060a0880135915060c0880135905092959891949750929550565b60008060006060848603121561256757600080fd5b83359250602084013591506040840135612580816122fb565b809150509250925092565b6000806040838503121561259e57600080fd5b82356125a9816122fb565b91506125b7602084016124d3565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156125e857600080fd5b815167ffffffffffffffff8082111561260057600080fd5b818401915084601f83011261261457600080fd5b815181811115612626576126266125c0565b604051601f8201601f19908116603f0116810190838211818310171561264e5761264e6125c0565b8160405282815287602084870101111561266757600080fd5b612678836020830160208801612298565b979650505050505050565b60008251612695818460208701612298565b632053484160e01b920191825250600401919050565b600082516126bd818460208701612298565b692028577261707065642960b01b920191825250600a01919050565b6000602082840312156126eb57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610a3057610a306126f2565b81810381811115610a3057610a306126f2565b6001600160a01b0385168152602081018490526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b60006020828403121561278857600080fd5b81518015158114610b9857600080fd5b8082028115828204841417610a3057610a306126f2565b600181811c908216806127c357607f821691505b602082108103610f0d57634e487b7160e01b600052602260045260246000fd5b601f821115611cb3576000816000526020600020601f850160051c8101602086101561280c5750805b601f850160051c820191505b8181101561282b57828155600101612818565b505050505050565b67ffffffffffffffff83111561284b5761284b6125c0565b61285f8361285983546127af565b836127e3565b6000601f841160018114612893576000851561287b5750838201355b600019600387901b1c1916600186901b178355610c31565b600083815260209020601f19861690835b828110156128c457868501358255602094850194600190920191016128a4565b50868210156128e15760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6000602080835260008454612907816127af565b8060208701526040600180841660008114612929576001811461294557612975565b60ff19851660408a0152604084151560051b8a01019550612975565b89600052602060002060005b8581101561296c5781548b8201860152908301908801612951565b8a016040019650505b509398975050505050505050565b60008251612995818460208701612298565b605360f81b920191825250600101919050565b6000602082840312156129ba57600080fd5b8151610b98816122fb565b60ff8181168382160190811115610a3057610a306126f2565b6000826129fb57634e487b7160e01b600052601260045260246000fd5b500490565b604081526000612a1360408301856122bc565b8281036020840152610d4081856122bc565b60008251612a37818460208701612298565b919091019291505056fea26469706673582212205773848da731617132592685253616952f1e4c94479c7f92400be4798657177164736f6c634300081900330000000000000000000000000000000000000000000000000000000000000120000000000000000000000000e2cafdbb2551cd81429ef20e54a48fcca76a6efd0000000000000000000000000000000000000000000000000000000000001a0b0000000000000000000000000000000000000000000000000000000000001a0b0000000000000000000000000000000000000000000000000000000000278d00000000000000000000000000aea2886cb865bab01fc43f3c3f51b27b720ae185000000000000000000000000339891af65dfc0ca929e5521978e07d162514f92000000000000000000000000cafdc612c321c8f22bae3922e1f4bff2bfa97d75000000000000000000000000c5e049019fd4c21de3685f60993fd41d3098dca50000000000000000000000000000000000000000000000000000000000000017696e766573742e6f706572616c2e736f6c7574696f6e73000000000000000000

Deployed Bytecode

0x6080604052600436106102c95760003560e01c80637dc0d1d011610175578063c18172c4116100dc578063ddceafa911610095578063efa405121161006f578063efa40512146108cf578063f5c0b95f14610903578063fcb79a7e14610923578063ffa1ad741461094357600080fd5b8063ddceafa91461085b578063de0e9a3e1461088f578063e5b824ec146108af57600080fd5b8063c18172c41461079f578063c45a0155146107bf578063d5025625146107f3578063d505accf14610808578063dcc7d4ad14610828578063dd62ed3e1461083b57600080fd5b8063a4c0ed361161012e578063a4c0ed36146106cb578063a7813587146106eb578063a9059cbb1461071f578063bf376c7a1461073f578063c028df061461075f578063c07473f61461077f57600080fd5b80637dc0d1d0146106285780637dc2cd98146106485780637ecebe001461065e5780638fd3ab801461068b57806395d89b41146106a05780639e4b5745146106b557600080fd5b806332a7ae951161023457806350e70d48116101ed57806370a08231116101c757806370a08231146105a857806377e071ad146105c857806378f86afc146105e85780637adbf9731461060857600080fd5b806350e70d481461054d5780636091811714610572578063648bf7741461058857600080fd5b806332a7ae95146104a357806332bc320b146104c35780633644e515146104d85780634000aea0146104ed57806342966c681461050d57806345c8a62b1461052d57600080fd5b806318160ddd1161028657806318160ddd146103ce57806318efcce5146103e3578063198453541461041757806323b872dd146104395780632a0a4ed514610459578063313ce5671461047757600080fd5b806306fdde03146102ce5780630832e470146102f9578063095ea7b31461031d5780630a81b2de1461034d5780630c6f0e5d146103625780631703a0181461039a575b600080fd5b3480156102da57600080fd5b506102e3610958565b6040516102f091906122e8565b60405180910390f35b34801561030557600080fd5b5061030f60045481565b6040519081526020016102f0565b34801561032957600080fd5b5061033d610338366004612310565b610a1f565b60405190151581526020016102f0565b34801561035957600080fd5b5061030f610a36565b34801561036e57600080fd5b50600754610382906001600160a01b031681565b6040516001600160a01b0390911681526020016102f0565b3480156103a657600080fd5b5061030f7f0000000000000000000000000000000000000000000000000000000000001a0b81565b3480156103da57600080fd5b5060025461030f565b3480156103ef57600080fd5b506103827f000000000000000000000000c5e049019fd4c21de3685f60993fd41d3098dca581565b34801561042357600080fd5b50610437610432366004612310565b610ab4565b005b34801561044557600080fd5b5061033d61045436600461233c565b610b3c565b34801561046557600080fd5b506006546001600160a01b0316610382565b34801561048357600080fd5b506003546104919060ff1681565b60405160ff90911681526020016102f0565b3480156104af57600080fd5b506104376104be36600461237d565b610b9f565b3480156104cf57600080fd5b50610437610c38565b3480156104e457600080fd5b5061030f610c5f565b3480156104f957600080fd5b5061033d6105083660046123e3565b610cb8565b34801561051957600080fd5b5061043761052836600461243f565b610d49565b34801561053957600080fd5b5061043761054836600461237d565b610daa565b34801561055957600080fd5b506003546103829061010090046001600160a01b031681565b34801561057e57600080fd5b5061030f60085481565b34801561059457600080fd5b506104376105a3366004612458565b610dce565b3480156105b457600080fd5b5061030f6105c336600461237d565b610e0a565b3480156105d457600080fd5b5061030f6105e336600461237d565b610e2e565b3480156105f457600080fd5b50610437610603366004612491565b610f13565b34801561061457600080fd5b5061043761062336600461237d565b610f72565b34801561063457600080fd5b50600654610382906001600160a01b031681565b34801561065457600080fd5b5062ed4e0061030f565b34801561066a57600080fd5b5061030f61067936600461237d565b60096020526000908152604090205481565b34801561069757600080fd5b50610437610fdb565b3480156106ac57600080fd5b506102e3610fe8565b3480156106c157600080fd5b506004541561033d565b3480156106d757600080fd5b5061033d6106e63660046123e3565b611089565b3480156106f757600080fd5b5061030f7f0000000000000000000000000000000000000000000000000000000000278d0081565b34801561072b57600080fd5b5061033d61073a366004612310565b6110bb565b34801561074b57600080fd5b5061043761075a366004612310565b6110c7565b34801561076b57600080fd5b50600554610382906001600160a01b031681565b34801561078b57600080fd5b5061030f61079a36600461237d565b6110ee565b3480156107ab57600080fd5b506104376107ba36600461237d565b6110f9565b3480156107cb57600080fd5b506103827f000000000000000000000000339891af65dfc0ca929e5521978e07d162514f9281565b3480156107ff57600080fd5b506102e361112f565b34801561081457600080fd5b506104376108233660046124e4565b6111bd565b610437610836366004612552565b611372565b34801561084757600080fd5b5061030f610856366004612458565b61154d565b34801561086757600080fd5b506103827f000000000000000000000000aea2886cb865bab01fc43f3c3f51b27b720ae18581565b34801561089b57600080fd5b506104376108aa36600461243f565b611559565b3480156108bb57600080fd5b506104376108ca36600461237d565b6115b9565b3480156108db57600080fd5b5061030f7f0000000000000000000000000000000000000000000000000000000000001a0b81565b34801561090f57600080fd5b5061033d61091e36600461258b565b6115ef565b34801561092f57600080fd5b5061043761093e366004612458565b6115fb565b34801561094f57600080fd5b50610491600381565b60606000600360019054906101000a90046001600160a01b03166001600160a01b03166306fdde036040518163ffffffff1660e01b8152600401600060405180830381865afa1580156109af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109d791908101906125d6565b90506109e36004541590565b15610a0e57806040516020016109f99190612683565b60405160208183030381529060405291505090565b806040516020016109f991906126ab565b6000610a2c33848461162e565b5060015b92915050565b6000600360019054906101000a90046001600160a01b03166001600160a01b0316633a98ef396040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aaf91906126d9565b905090565b600654610ac9906001600160a01b0316611690565b610ad1610a36565b81610adb60025490565b610ae59190612708565b1115610b2e57610af3610a36565b81610afd60025490565b610b079190612708565b604051630429590f60e41b8152600481019290925260248201526044015b60405180910390fd5b610b3882826116bb565b5050565b6000610b49848484611824565b6000610b55853361154d565b9050600160ff1b811015610b9257610b6d838261271b565b6001600160a01b03861660009081526001602090815260408083203384529091529020555b60019150505b9392505050565b610bb9610bb46006546001600160a01b031690565b611690565b6040516332a7ae9560e01b81526001600160a01b0382811660048301527f000000000000000000000000aea2886cb865bab01fc43f3c3f51b27b720ae18516906332a7ae95906024015b600060405180830381600087803b158015610c1d57600080fd5b505af1158015610c31573d6000803e3d6000fd5b5050505050565b600554610c4d906001600160a01b0316611690565b600580546001600160a01b0319169055565b604080517f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692186020820152469181019190915230606082015260009060800160405160208183030381529060405280519060200120905090565b6000610cc485856110bb565b8015610d405750604051635260769b60e11b81526001600160a01b0386169063a4c0ed3690610cfd90339088908890889060040161272e565b6020604051808303816000875af1158015610d1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d409190612776565b95945050505050565b610d533382611888565b6003546001600160a01b03610100909104166342966c68610d746004541590565b610d8a57600454610d859084612798565b610d8c565b825b6040518263ffffffff1660e01b8152600401610c0391815260200190565b600554610dbf906001600160a01b0316611690565b610dcb816001806118fc565b50565b610df77f000000000000000000000000aea2886cb865bab01fc43f3c3f51b27b720ae185611690565b610b388282610e0585610e0a565b611824565b6001600160a01b03166000908152602081905260409020546001600160e01b031690565b600080610e3a83611960565b90508015610e485792915050565b6000610e546004541590565b610e6057600454610e63565b60015b6003549091506001600160a01b03610100909104811690851603610e88579392505050565b6003546040516377e071ad60e01b81526001600160a01b0386811660048301528392610100900416906377e071ad90602401602060405180830381865afa158015610ed7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610efb91906126d9565b610f059190612798565b949350505050565b50919050565b600654610f28906001600160a01b0316611690565b600a610f35828483612833565b507fe9f2468ecc8d3dff15a70a5909151e6297cee4cf05268eff3d7ef0c696ec50f2600a604051610f6691906128f3565b60405180910390a15050565b600654610f87906001600160a01b0316611690565b600680546001600160a01b0319166001600160a01b0383169081179091556040519081527fc3977c9522c218453912bcab15964a7788968fbf3fe4d4e2965252c9f07055de9060200160405180910390a150565b610fe63360006116bb565b565b6060600360019054906101000a90046001600160a01b03166001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa15801561103d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261106591908101906125d6565b6040516020016110759190612983565b604051602081830303815290604052905090565b6003546000906110a69061010090046001600160a01b0316611690565b6110b085856119a5565b506001949350505050565b6000610b988383611a11565b6003546110e49061010090046001600160a01b0316333084611ab0565b610b3882826119a5565b6000610a3082610e0a565b6111227f000000000000000000000000aea2886cb865bab01fc43f3c3f51b27b720ae185611690565b610dcb81600a60016118fc565b600a805461113c906127af565b80601f0160208091040260200160405190810160405280929190818152602001828054611168906127af565b80156111b55780601f1061118a576101008083540402835291602001916111b5565b820191906000526020600020905b81548152906001019060200180831161119857829003601f168201915b505050505081565b428410156111e757604051630b99fc4b60e31b815260048101859052426024820152604401610b25565b600060016111f3610c5f565b6001600160a01b038a811660008181526009602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e08301909152805192019190912061190160f01b6101008301526101028201929092526101228101919091526101420160408051601f198184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa1580156112ff573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615806113345750876001600160a01b0316816001600160a01b031614155b1561135d57604051632f52260d60e11b81526001600160a01b0382166004820152602401610b25565b61136881888861162e565b5050505050505050565b600161137e6004541590565b1515811515146113c55780156113a7576040516305a34cd360e01b815260040160405180910390fd5b806113c55760405163291c3d8560e01b815260040160405180910390fd5b604051634dc5e43160e01b815260048101859052336024820152604481018490526001600160a01b0383811660648301527f0000000000000000000000000000000000000000000000000000000000001a0b60848301527f0000000000000000000000000000000000000000000000000000000000278d0060a48301526000917f000000000000000000000000339891af65dfc0ca929e5521978e07d162514f9290911690634dc5e43190349060c40160206040518083038185885af1158015611493573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906114b891906129a8565b90506114c2611b1d565b1561152757600554604051637b64620f60e11b81526001600160a01b0383811660048301529091169063f6c8c41e90602401600060405180830381600087803b15801561150e57600080fd5b505af1158015611522573d6000803e3d6000fd5b505050505b600580546001600160a01b0319166001600160a01b039290921691909117905550505050565b6000610b988383611bb2565b60006115656004541590565b1515811515146115ac57801561158e576040516305a34cd360e01b815260040160405180910390fd5b806115ac5760405163291c3d8560e01b815260040160405180910390fd5b610b383383600454611c83565b6115e27f000000000000000000000000aea2886cb865bab01fc43f3c3f51b27b720ae185611690565b610dcb81600a60006118fc565b6000610b988383611cb8565b600554611610906001600160a01b0316611690565b6116248261161d84610e0a565b6001611c83565b610b388183611cf8565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a3505050565b336001600160a01b03821614610dcb57604051634b637e8f60e11b8152336004820152602401610b25565b60006116c683610e0a565b6116d09083612708565b905060006116dc610a36565b90508082111561170957604051630429590f60e41b81526004810182905260248101839052604401610b25565b611711611b1d565b1561172f576040516331dec02560e21b815260040160405180910390fd5b6117597f0000000000000000000000000000000000000000000000000000000000001a0b82612798565b61176561271084612798565b10156117c3576117957f0000000000000000000000000000000000000000000000000000000000001a0b82612798565b6117a161271084612798565b604051634b2737cf60e11b815260048101929092526024820152604401610b25565b6117cd8485611cf8565b604080516001600160a01b038616815260208101849052908101849052606081018290527f85e5711a70a7d2bae18e1232af474d82c98600b0e62fe079a28208520b58568e9060800160405180910390a150505050565b61182f838383611ebb565b6118398382611ec6565b6118438282611f63565b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161168391815260200190565b61189482600083611ebb565b80600260008282546118a6919061271b565b909155506118b690508282611ec6565b6040518181526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b60006119098360e06129c5565b6001600160a01b038516600090815260208190526040902054600160ff929092169190911b9150808216821483151514610c31576001600160a01b0394909416600090815260208190526040902093189092555050565b6000306001600160a01b0383160361197a57506001919050565b6007546001600160a01b039081169083160361199857505060085490565b506000919050565b919050565b6119b160008383611ebb565b80600260008282546119c39190612708565b909155506119d390508282611f63565b6040518181526001600160a01b038316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020016118f0565b6000611a1d8383612008565b50611a2933600a611cb8565b15610a2c576040516304d301a360e41b81523360048201527f000000000000000000000000aea2886cb865bab01fc43f3c3f51b27b720ae1856001600160a01b031690634d301a3090602401600060405180830381600087803b158015611a8f57600080fd5b505af1158015611aa3573d6000803e3d6000fd5b5050505050600192915050565b6040516001600160a01b038481166024830152838116604483015260648201839052611b179186918216906323b872dd906084015b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050612015565b50505050565b6005546000906001600160a01b031615801590610aaf5750600560009054906101000a90046001600160a01b03166001600160a01b0316638fe8a1016040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bac9190612776565b15905090565b604051632fb6b53160e11b81526001600160a01b03838116600483015282811660248301526000917f000000000000000000000000c5e049019fd4c21de3685f60993fd41d3098dca590911690635f6d6a6290604401602060405180830381865afa158015611c25573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c499190612776565b15611c575750600019610a30565b506001600160a01b03828116600090815260016020908152604080832093851683529290522054610a30565b611c8d8383611888565b611cb383611c9b8385612798565b60035461010090046001600160a01b03169190612078565b505050565b600080611cc68360e06129c5565b6001600160a01b038516600090815260208190526040902054600160ff929092169190911b9081161491505092915050565b6001611d046004541590565b151581151514611d4b578015611d2d576040516305a34cd360e01b815260040160405180910390fd5b80611d4b5760405163291c3d8560e01b815260040160405180910390fd5b6003546040516370a0823160e01b8152306004820152611dc19184916101009091046001600160a01b0316906370a0823190602401602060405180830381865afa158015611d9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c9b91906126d9565b60038054610100600160a81b0319166101006001600160a01b0386160217905560025460001015611e6f57611e6f611df860025490565b6040516370a0823160e01b81523060048201526001600160a01b038616906370a0823190602401602060405180830381865afa158015611e3c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e6091906126d9565b611e6a91906129de565b6120a9565b7f6c20b91d1723b78732eba64ff11ebd7966a6e4af568a00fa4f6b72c20f58b02a611e98610958565b611ea0610fe8565b604051611eae929190612a00565b60405180910390a1505050565b611cb38383836120cf565b6001600160a01b03821660009081526020819052604081205490611eea838361271b565b90506001600160e01b031981166001600160e01b0319831614611f425783611f1185610e0a565b60405163391434e360e21b81526001600160a01b039092166004830152602482015260448101849052606401610b25565b6001600160a01b039093166000908152602081905260409020929092555050565b6001600160a01b038216611f955760405163ec442f0560e01b81526001600160a01b0383166004820152602401610b25565b6001600160a01b03821660009081526020819052604081205490611fb98383612708565b90506001600160e01b031981166001600160e01b0319831614611f4257604051634a2e08e560e01b81526001600160a01b03851660048201526024810183905260448101849052606401610b25565b6000610a2c338484611824565b600061202a6001600160a01b03841683612186565b9050805160001415801561204f57508080602001905181019061204d9190612776565b155b15611cb357604051635274afe760e01b81526001600160a01b0384166004820152602401610b25565b6040516001600160a01b03838116602483015260448201839052611cb391859182169063a9059cbb90606401611ae5565b806000036120ca57604051631dca7a7560e11b815260040160405180910390fd5b600455565b6120d883612194565b806120e757506120e782612194565b15611cb3576120f4611b1d565b1561216c5760055460405163e1a1810f60e01b81526001600160a01b0385811660048301528481166024830152604482018490529091169063e1a1810f90606401600060405180830381600087803b15801561214f57600080fd5b505af1158015612163573d6000803e3d6000fd5b50505050505050565b61217983600160006118fc565b611cb382600160006118fc565b6060610b98838360006121a1565b6000610a30826001611cb8565b606082516000141580156121bd57506001600160a01b0384163b155b156121e657604051639eb1341360e01b81526001600160a01b0385166004820152602401610b25565b600080856001600160a01b031684866040516122029190612a25565b60006040518083038185875af1925050503d806000811461223f576040519150601f19603f3d011682016040523d82523d6000602084013e612244565b606091505b50915091508115612258579150610b989050565b80511561226757805160208201fd5b60405162461bcd60e51b815260206004820152600660248201526519985a5b195960d21b6044820152606401610b25565b60005b838110156122b357818101518382015260200161229b565b50506000910152565b600081518084526122d4816020860160208601612298565b601f01601f19169290920160200192915050565b602081526000610b9860208301846122bc565b6001600160a01b0381168114610dcb57600080fd5b6000806040838503121561232357600080fd5b823561232e816122fb565b946020939093013593505050565b60008060006060848603121561235157600080fd5b833561235c816122fb565b9250602084013561236c816122fb565b929592945050506040919091013590565b60006020828403121561238f57600080fd5b8135610b98816122fb565b60008083601f8401126123ac57600080fd5b50813567ffffffffffffffff8111156123c457600080fd5b6020830191508360208285010111156123dc57600080fd5b9250929050565b600080600080606085870312156123f957600080fd5b8435612404816122fb565b935060208501359250604085013567ffffffffffffffff81111561242757600080fd5b6124338782880161239a565b95989497509550505050565b60006020828403121561245157600080fd5b5035919050565b6000806040838503121561246b57600080fd5b8235612476816122fb565b91506020830135612486816122fb565b809150509250929050565b600080602083850312156124a457600080fd5b823567ffffffffffffffff8111156124bb57600080fd5b6124c78582860161239a565b90969095509350505050565b803560ff811681146119a057600080fd5b600080600080600080600060e0888a0312156124ff57600080fd5b873561250a816122fb565b9650602088013561251a816122fb565b95506040880135945060608801359350612536608089016124d3565b925060a0880135915060c0880135905092959891949750929550565b60008060006060848603121561256757600080fd5b83359250602084013591506040840135612580816122fb565b809150509250925092565b6000806040838503121561259e57600080fd5b82356125a9816122fb565b91506125b7602084016124d3565b90509250929050565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156125e857600080fd5b815167ffffffffffffffff8082111561260057600080fd5b818401915084601f83011261261457600080fd5b815181811115612626576126266125c0565b604051601f8201601f19908116603f0116810190838211818310171561264e5761264e6125c0565b8160405282815287602084870101111561266757600080fd5b612678836020830160208801612298565b979650505050505050565b60008251612695818460208701612298565b632053484160e01b920191825250600401919050565b600082516126bd818460208701612298565b692028577261707065642960b01b920191825250600a01919050565b6000602082840312156126eb57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610a3057610a306126f2565b81810381811115610a3057610a306126f2565b6001600160a01b0385168152602081018490526060604082018190528101829052818360808301376000818301608090810191909152601f909201601f191601019392505050565b60006020828403121561278857600080fd5b81518015158114610b9857600080fd5b8082028115828204841417610a3057610a306126f2565b600181811c908216806127c357607f821691505b602082108103610f0d57634e487b7160e01b600052602260045260246000fd5b601f821115611cb3576000816000526020600020601f850160051c8101602086101561280c5750805b601f850160051c820191505b8181101561282b57828155600101612818565b505050505050565b67ffffffffffffffff83111561284b5761284b6125c0565b61285f8361285983546127af565b836127e3565b6000601f841160018114612893576000851561287b5750838201355b600019600387901b1c1916600186901b178355610c31565b600083815260209020601f19861690835b828110156128c457868501358255602094850194600190920191016128a4565b50868210156128e15760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6000602080835260008454612907816127af565b8060208701526040600180841660008114612929576001811461294557612975565b60ff19851660408a0152604084151560051b8a01019550612975565b89600052602060002060005b8581101561296c5781548b8201860152908301908801612951565b8a016040019650505b509398975050505050505050565b60008251612995818460208701612298565b605360f81b920191825250600101919050565b6000602082840312156129ba57600080fd5b8151610b98816122fb565b60ff8181168382160190811115610a3057610a306126f2565b6000826129fb57634e487b7160e01b600052601260045260246000fd5b500490565b604081526000612a1360408301856122bc565b8281036020840152610d4081856122bc565b60008251612a37818460208701612298565b919091019291505056fea26469706673582212205773848da731617132592685253616952f1e4c94479c7f92400be4798657177164736f6c63430008190033

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

0000000000000000000000000000000000000000000000000000000000000120000000000000000000000000e2cafdbb2551cd81429ef20e54a48fcca76a6efd0000000000000000000000000000000000000000000000000000000000001a0b0000000000000000000000000000000000000000000000000000000000001a0b0000000000000000000000000000000000000000000000000000000000278d00000000000000000000000000aea2886cb865bab01fc43f3c3f51b27b720ae185000000000000000000000000339891af65dfc0ca929e5521978e07d162514f92000000000000000000000000cafdc612c321c8f22bae3922e1f4bff2bfa97d75000000000000000000000000c5e049019fd4c21de3685f60993fd41d3098dca50000000000000000000000000000000000000000000000000000000000000017696e766573742e6f706572616c2e736f6c7574696f6e73000000000000000000

-----Decoded View---------------
Arg [0] : _terms (string): invest.operal.solutions
Arg [1] : _params (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [2] : _recoveryHub (address): 0xAEa2886Cb865BaB01Fc43f3c3F51B27B720aE185
Arg [3] : _offerFactory (address): 0x339891Af65dFc0Ca929E5521978e07D162514f92
Arg [4] : _oracle (address): 0xCaFdC612c321c8F22bAe3922E1f4bFf2BfA97D75
Arg [5] : _permit2Hub (address): 0xc5E049019fD4c21dE3685F60993Fd41d3098DcA5

-----Encoded View---------------
11 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [1] : 000000000000000000000000e2cafdbb2551cd81429ef20e54a48fcca76a6efd
Arg [2] : 0000000000000000000000000000000000000000000000000000000000001a0b
Arg [3] : 0000000000000000000000000000000000000000000000000000000000001a0b
Arg [4] : 0000000000000000000000000000000000000000000000000000000000278d00
Arg [5] : 000000000000000000000000aea2886cb865bab01fc43f3c3f51b27b720ae185
Arg [6] : 000000000000000000000000339891af65dfc0ca929e5521978e07d162514f92
Arg [7] : 000000000000000000000000cafdc612c321c8f22bae3922e1f4bff2bfa97d75
Arg [8] : 000000000000000000000000c5e049019fd4c21de3685f60993fd41d3098dca5
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000017
Arg [10] : 696e766573742e6f706572616c2e736f6c7574696f6e73000000000000000000


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
[ Download: CSV Export  ]

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.