ETH Price: $2,401.49 (+7.11%)

Transaction Decoder

Block:
19405357 at Mar-10-2024 02:41:47 PM +UTC
Transaction Fee:
0.008334309883227327 ETH $20.01
Gas Used:
112,419 Gas / 74.136132533 Gwei

Emitted Events:

226 veSYNC.Approval( owner=[Sender] 0x9057cb12392539c553ebe2148627f3d79f310553, spender=[Receiver] SyncusStaking, value=115792089237316195423570985008687907853269984665640564039457583428470674371695 )
227 veSYNC.Transfer( from=[Sender] 0x9057cb12392539c553ebe2148627f3d79f310553, to=[Receiver] SyncusStaking, value=200442455268240 )
228 Syncus.Transfer( from=[Receiver] SyncusStaking, to=[Sender] 0x9057cb12392539c553ebe2148627f3d79f310553, value=100221227634120 )
229 Syncus.Transfer( from=[Receiver] SyncusStaking, to=SyncusTreasury, value=100221227634120 )

Account State Difference:

  Address   Before After State Difference Code
0x216c9bb7...38d7e1Dc8
(Titan Builder)
19.625456117915653278 Eth19.625466378094251978 Eth0.0000102601785987
0x9057Cb12...79f310553
0.045321439542208751 Eth
Nonce: 152
0.036987129658981424 Eth
Nonce: 153
0.008334309883227327
0xa41d2f8E...c3287b7F0

Execution Trace

SyncusStaking.unstake( _amount=200442455268240, _trigger=True )
  • veSYNC.transferFrom( from=0x9057Cb12392539C553ebE2148627F3D79f310553, to=0xc738CDb5140d6b7F688ba05a25c8a51568622D96, value=200442455268240 ) => ( True )
  • Syncus.transfer( recipient=0x9057Cb12392539C553ebE2148627F3D79f310553, amount=100221227634120 ) => ( True )
  • Syncus.transfer( recipient=0xC00EC94e7746C6b695869580d6D2DB50cda86094, amount=100221227634120 ) => ( True )
    File 1 of 4: SyncusStaking
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/SafeMath.sol";
    import "./lib/Address.sol";
    import "./lib/SafeERC20.sol";
    import "./OwnableManagement.sol";
    import "./lib/IERC20.sol";
    import "./lib/ISyncus.sol";
    import "./lib/IVESYNC.sol";
    import "./lib/IDistributor.sol";
    import "./lib/IWarmup.sol";
    contract SyncusStaking is OwnableManagement {
        using SafeMath for uint256;
        using SafeMath for uint32;
        using SafeERC20 for IERC20;
        address public immutable Sync;
        address public immutable veSync;
        struct Epoch {
            uint number;
            uint distribute;
            uint32 length;
            uint32 endTime;
        }
        Epoch public epoch;
        address public distributor;
        address public locker;
        uint public totalBonus;
        address public warmupContract;
        uint public warmupPeriod;
        address taxReceiver;
        uint public taxOnStake = 250; // 2.5%
        uint public taxOnUnstake = 250; // 2.5%
        function setTaxOnStake(uint _taxOnStake) external onlyManager {
            require(_taxOnStake <= 10000, "Tax cannot be greater than 100%");
            taxOnStake = _taxOnStake;
        }
        function setTaxOnUnstake(uint _taxOnUnstake) external onlyManager {
            require(_taxOnUnstake <= 10000, "Tax cannot be greater than 100%");
            taxOnUnstake = _taxOnUnstake;
        }
        function setTaxReceiver(address _taxReceiver) external onlyManager {
            taxReceiver = _taxReceiver;
        }
        modifier onlyDistributor() {
            require(msg.sender == distributor, "Only distributor");
            _;
        }
        constructor(
            address _Sync,
            address _veSync,
            uint32 _epochLength,
            uint _firstEpochNumber,
            uint32 _firstEpochTime,
            address _taxReceiver
        ) {
            require(_Sync != address(0));
            Sync = _Sync;
            require(_veSync != address(0));
            veSync = _veSync;
            epoch = Epoch({
                length: _epochLength,
                number: _firstEpochNumber,
                endTime: _firstEpochTime,
                distribute: 0
            });
            taxReceiver = _taxReceiver;
        }
        struct Claim {
            uint deposit;
            uint gons;
            uint expiry;
            bool lock; // prevents malicious delays
        }
        mapping(address => Claim) public warmupInfo;
        /**
            @notice stake SYNC to enter warmup
            @param _amount uint
            @return bool
         */
        function stake(uint _amount, address _recipient) external returns (bool) {
            rebase();
            uint tax = _amount.mul(taxOnStake).div(10000);
            uint amountAfterTax = _amount.sub(tax);
            IERC20(Sync).safeTransferFrom(
                msg.sender,
                address(this),
                amountAfterTax
            );
            IERC20(Sync).safeTransferFrom(msg.sender, taxReceiver, tax);
            Claim memory info = warmupInfo[_recipient];
            require(!info.lock, "Deposits for account are locked");
            warmupInfo[_recipient] = Claim({
                deposit: info.deposit.add(amountAfterTax),
                gons: info.gons.add(IVESYNC(veSync).gonsForBalance(amountAfterTax)),
                expiry: epoch.number.add(warmupPeriod),
                lock: false
            });
            IERC20(veSync).safeTransfer(warmupContract, amountAfterTax);
            return true;
        }
        /**
            @notice retrieve veSYNC from warmup
            @param _recipient address
         */
        function claim(address _recipient) public {
            Claim memory info = warmupInfo[_recipient];
            if (epoch.number >= info.expiry && info.expiry != 0) {
                delete warmupInfo[_recipient];
                IWarmup(warmupContract).retrieve(
                    _recipient,
                    IVESYNC(veSync).balanceForGons(info.gons)
                );
            }
        }
        /**
            @notice forfeit veSYNC in warmup and retrieve SYNC
         */
        function forfeit() external {
            Claim memory info = warmupInfo[msg.sender];
            delete warmupInfo[msg.sender];
            IWarmup(warmupContract).retrieve(
                address(this),
                IVESYNC(veSync).balanceForGons(info.gons)
            );
            IERC20(Sync).safeTransfer(msg.sender, info.deposit);
        }
        /**
            @notice prevent new deposits to address (protection from malicious activity)
         */
        function toggleDepositLock() external {
            warmupInfo[msg.sender].lock = !warmupInfo[msg.sender].lock;
        }
        /**
            @notice redeem veSYNC for SYNC
            @param _amount uint
            @param _trigger bool
         */
        function unstake(uint _amount, bool _trigger) external {
            if (_trigger) {
                rebase();
            }
            IERC20(veSync).safeTransferFrom(msg.sender, address(this), _amount);
            uint tax = _amount.mul(taxOnUnstake).div(10000);
            uint amountAfterTax = _amount.sub(tax);
            IERC20(Sync).safeTransfer(msg.sender, amountAfterTax);
            IERC20(Sync).safeTransfer(taxReceiver, tax);
        }
        /**
            @notice returns the veSYNC index, which tracks rebase growth
            @return uint
         */
        function index() public view returns (uint) {
            return IVESYNC(veSync).index();
        }
        /**
            @notice trigger rebase if epoch over
         */
        function rebase() public {
            if (epoch.endTime <= uint32(block.timestamp)) {
                IVESYNC(veSync).rebase(epoch.distribute, epoch.number);
                epoch.endTime = epoch.endTime.add32(epoch.length);
                epoch.number++;
                if (distributor != address(0)) {
                    IDistributor(distributor).distribute();
                }
                uint balance = contractBalance();
                uint staked = IVESYNC(veSync).circulatingSupply();
                if (balance <= staked) {
                    epoch.distribute = 0;
                } else {
                    epoch.distribute = balance.sub(staked);
                }
            }
        }
        /**
            @notice returns contract SYNC holdings, including bonuses provided
            @return uint
         */
        function contractBalance() public view returns (uint) {
            return IERC20(Sync).balanceOf(address(this)).add(totalBonus);
        }
        /**
            @notice provide bonus to locked staking contract
            @param _amount uint
         */
        function giveLockBonus(uint _amount) external {
            require(msg.sender == locker);
            totalBonus = totalBonus.add(_amount);
            IERC20(veSync).safeTransfer(locker, _amount);
        }
        /**
            @notice reclaim bonus from locked staking contract
            @param _amount uint
         */
        function returnLockBonus(uint _amount) external {
            require(msg.sender == locker);
            totalBonus = totalBonus.sub(_amount);
            IERC20(veSync).safeTransferFrom(locker, address(this), _amount);
        }
        enum CONTRACTS {
            DISTRIBUTOR,
            WARMUP,
            LOCKER
        }
        /**
            @notice sets the contract address for LP staking
            @param _contract address
         */
        function setContract(
            CONTRACTS _contract,
            address _address
        ) external onlyManager {
            if (_contract == CONTRACTS.DISTRIBUTOR) {
                // 0
                distributor = _address;
            } else if (_contract == CONTRACTS.WARMUP) {
                // 1
                require(
                    warmupContract == address(0),
                    "Warmup cannot be set more than once"
                );
                warmupContract = _address;
            } else if (_contract == CONTRACTS.LOCKER) {
                // 2
                require(
                    locker == address(0),
                    "Locker cannot be set more than once"
                );
                locker = _address;
            }
        }
        /**
         * @notice set warmup period in epoch's numbers for new stakers
         * @param _warmupPeriod uint
         */
        function setWarmup(uint _warmupPeriod) external onlyManager {
            warmupPeriod = _warmupPeriod;
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    library SafeMath {
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        function add32(uint32 a, uint32 b) internal pure returns (uint32) {
            uint32 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
        function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
            return c;
        }
        function sub32(uint32 a, uint32 b) internal pure returns (uint32) {
            return sub32(a, b, "SafeMath: subtraction overflow");
        }
        function sub32(
            uint32 a,
            uint32 b,
            string memory errorMessage
        ) internal pure returns (uint32) {
            require(b <= a, errorMessage);
            uint32 c = a - b;
            return c;
        }
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) {
                return 0;
            }
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
        function mul32(uint32 a, uint32 b) internal pure returns (uint32) {
            if (a == 0) {
                return 0;
            }
            uint32 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
        function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            return c;
        }
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
        function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
        function sqrrt(uint256 a) internal pure returns (uint c) {
            if (a > 3) {
                c = a;
                uint b = add(div(a, 2), 1);
                while (b < c) {
                    c = b;
                    b = div(add(div(a, b), b), 2);
                }
            } else if (a != 0) {
                c = 1;
            }
        }
        function percentageAmount(
            uint256 total_,
            uint8 percentage_
        ) internal pure returns (uint256 percentAmount_) {
            return div(mul(total_, percentage_), 1000);
        }
        function substractPercentage(
            uint256 total_,
            uint8 percentageToSub_
        ) internal pure returns (uint256 result_) {
            return sub(total_, div(mul(total_, percentageToSub_), 1000));
        }
        function percentageOfTotal(
            uint256 part_,
            uint256 total_
        ) internal pure returns (uint256 percent_) {
            return div(mul(part_, 100), total_);
        }
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow, so we distribute
            return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
        }
        function quadraticPricing(
            uint256 payment_,
            uint256 multiplier_
        ) internal pure returns (uint256) {
            return sqrrt(mul(multiplier_, payment_));
        }
        function bondingCurve(
            uint256 supply_,
            uint256 multiplier_
        ) internal pure returns (uint256) {
            return mul(multiplier_, supply_);
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    library Address {
        /**
         * @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 in extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
            uint256 size;
            // solhint-disable-next-line no-inline-assembly
            assembly {
                size := extcodesize(account)
            }
            return size > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard}
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(
                address(this).balance >= amount,
                "Address: insufficient balance"
            );
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{value: amount}("");
            require(
                success,
                "Address: unable to send value, recipient may have reverted"
            );
        }
        /**
         * @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, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data
        ) internal returns (bytes memory) {
            return functionCall(target, data, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return _functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value
        ) internal returns (bytes memory) {
            return
                functionCallWithValue(
                    target,
                    data,
                    value,
                    "Address: low-level call with value failed"
                );
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(
                address(this).balance >= value,
                "Address: insufficient balance for call"
            );
            require(isContract(target), "Address: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{value: value}(
                data
            );
            return _verifyCallResult(success, returndata, errorMessage);
        }
        function _functionCallWithValue(
            address target,
            bytes memory data,
            uint256 weiValue,
            string memory errorMessage
        ) private returns (bytes memory) {
            require(isContract(target), "Address: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{value: weiValue}(
                data
            );
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data
        ) internal view returns (bytes memory) {
            return
                functionStaticCall(
                    target,
                    data,
                    "Address: low-level static call failed"
                );
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            require(isContract(target), "Address: static call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.staticcall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.3._
         */
        function functionDelegateCall(
            address target,
            bytes memory data
        ) internal returns (bytes memory) {
            return
                functionDelegateCall(
                    target,
                    data,
                    "Address: low-level delegate call failed"
                );
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.3._
         */
        function functionDelegateCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(isContract(target), "Address: delegate call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        function _verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) private pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
        function addressToString(
            address _address
        ) internal pure returns (string memory) {
            bytes32 _bytes = bytes32(uint256(_address));
            bytes memory HEX = "0123456789abcdef";
            bytes memory _addr = new bytes(42);
            _addr[0] = "0";
            _addr[1] = "x";
            for (uint256 i = 0; i < 20; i++) {
                _addr[2 + i * 2] = HEX[uint8(_bytes[i + 12] >> 4)];
                _addr[3 + i * 2] = HEX[uint8(_bytes[i + 12] & 0x0f)];
            }
            return string(_addr);
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./SafeMath.sol";
    import "./Address.sol";
    import "./IERC20.sol";
    library SafeERC20 {
        using SafeMath for uint256;
        using Address for address;
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
        function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
        function safeApprove(IERC20 token, address spender, uint256 value) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            // solhint-disable-next-line max-line-length
            require((value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
        function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).add(value);
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
        function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
        /**
         * @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.
            // A Solidity high level call has three parts:
            //  1. The target address is checked to verify it contains contract code
            //  2. The call itself is made, and success asserted
            //  3. The return value is decoded, which in turn checks the size of the returned data.
            // solhint-disable-next-line max-line-length
            require(address(token).isContract(), "SafeERC20: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = address(token).call(data);
            require(success, "SafeERC20: low-level call failed");
            if (returndata.length > 0) { // Return data is optional
                // solhint-disable-next-line max-line-length
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
            }
        }
    }// SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/IOwnableManagement.sol";
    contract OwnableManagement is IOwnableManagement {
          address internal _owner;
        address internal _newOwner;
        event OwnershipPushed(address indexed previousOwner, address indexed newOwner);
        event OwnershipPulled(address indexed previousOwner, address indexed newOwner);
        constructor () {
            _owner = msg.sender;
            emit OwnershipPushed( address(0), _owner );
        }
        function manager() public view override returns (address) {
            return _owner;
        }
        modifier onlyManager() {
            require( _owner == msg.sender, "Ownable: caller is not the owner" );
            _;
        }
        function renounceManagement() public virtual override onlyManager() {
            emit OwnershipPushed( _owner, address(0) );
            _owner = address(0);
        }
        function pushManagement( address newOwner_ ) public virtual override onlyManager() {
            require( newOwner_ != address(0), "Ownable: new owner is the zero address");
            emit OwnershipPushed( _owner, newOwner_ );
            _newOwner = newOwner_;
        }
        
        function pullManagement() public virtual override {
            require( msg.sender == _newOwner, "Ownable: must be new owner to pull");
            emit OwnershipPulled( _owner, _newOwner );
            _owner = _newOwner;
        }
    }// SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IERC20 {
        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.
         *
         * IMPORTANT: 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
        );
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface ISyncus {
        function burn(uint256 amount) external;
        function burnFrom(address account_, uint256 amount_) external;
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IVESYNC {
        function rebase( uint256 ohmProfit_, uint epoch_) external returns (uint256);
        function circulatingSupply() external view returns (uint256);
        function balanceOf(address who) external view returns (uint256);
        function gonsForBalance( uint amount ) external view returns ( uint );
        function balanceForGons( uint gons ) external view returns ( uint );
        
        function index() external view returns ( uint );
    }// SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IDistributor {
        function nextRewardAt(uint _rate) external view returns (uint);
        function nextRewardFor(address _recipient) external view returns (uint);
        function distribute() external returns (bool);
        function addRecipient(address _recipient, uint _rewardRate) external;
        function removeRecipient(uint _index, address _recipient) external;
        function setAdjustment(
            uint _index,
            bool _add,
            uint _rate,
            uint _target
        ) external;
        function updateCurrentRate(uint _index, uint _rate) external;
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IWarmup {
        function retrieve( address staker_, uint amount_ ) external;
    }// SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IOwnableManagement {
        function manager() external view returns (address);
        function renounceManagement() external;
        function pushManagement(address newOwner_) external;
        function pullManagement() external;
    }
    

    File 2 of 4: veSYNC
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./ERC20Permit.sol";
    import "./lib/IOwnable.sol";
    import "./OwnableManagement.sol";
    contract veSYNC is ERC20Permit, OwnableManagement {
        using SafeMath for uint256;
        modifier onlyStakingContract() {
            require(msg.sender == stakingContract);
            _;
        }
        address public stakingContract;
        address public initializer;
        event LogSupply(
            uint256 indexed epoch,
            uint256 timestamp,
            uint256 totalSupply
        );
        event LogRebase(uint256 indexed epoch, uint256 rebase, uint256 index);
        event LogStakingContractUpdated(address stakingContract);
        struct Rebase {
            uint epoch;
            uint rebase; // 18 decimals
            uint totalStakedBefore;
            uint totalStakedAfter;
            uint amountRebased;
            uint index;
            uint32 timeOccured;
        }
        Rebase[] public rebases;
        uint public INDEX;
        uint256 private constant MAX_UINT256 = ~uint256(0);
        uint256 private constant INITIAL_FRAGMENTS_SUPPLY =
            5_000_000_000_000 * 10 ** 9;
        // TOTAL_GONS is a multiple of INITIAL_FRAGMENTS_SUPPLY so that _gonsPerFragment is an integer.
        // Use the highest value that fits in a uint256 for max granularity.
        uint256 private constant TOTAL_GONS =
            MAX_UINT256 - (MAX_UINT256 % INITIAL_FRAGMENTS_SUPPLY);
        // MAX_SUPPLY = maximum integer < (sqrt(4*TOTAL_GONS + 1) - 1) / 2
        uint256 private constant MAX_SUPPLY = ~uint128(0); // (2^128) - 1
        uint256 private _gonsPerFragment;
        mapping(address => uint256) private _gonBalances;
        mapping(address => mapping(address => uint256)) private _allowedValue;
        constructor() ERC20("Vote-escrowed SYNC", "veSYNC", 9) ERC20Permit() {
            initializer = msg.sender;
            _totalSupply = INITIAL_FRAGMENTS_SUPPLY;
            _gonsPerFragment = TOTAL_GONS.div(_totalSupply);
        }
        function initialize(address stakingContract_) external returns (bool) {
            require(msg.sender == initializer);
            require(stakingContract_ != address(0));
            stakingContract = stakingContract_;
            _gonBalances[stakingContract] = TOTAL_GONS;
            emit Transfer(address(0x0), stakingContract, _totalSupply);
            emit LogStakingContractUpdated(stakingContract_);
            initializer = address(0);
            return true;
        }
        function setIndex(uint _INDEX) external onlyManager returns (bool) {
            require(INDEX == 0);
            INDEX = gonsForBalance(_INDEX);
            return true;
        }
        /**
            @notice increases veSYNC supply to increase staking balances relative to profit_
            @param profit_ uint256
            @return uint256
         */
        function rebase(
            uint256 profit_,
            uint epoch_
        ) public onlyStakingContract returns (uint256) {
            uint256 rebaseAmount;
            uint256 circulatingSupply_ = circulatingSupply();
            if (profit_ == 0) {
                emit LogSupply(epoch_, block.timestamp, _totalSupply);
                emit LogRebase(epoch_, 0, index());
                return _totalSupply;
            } else if (circulatingSupply_ > 0) {
                rebaseAmount = profit_.mul(_totalSupply).div(circulatingSupply_);
            } else {
                rebaseAmount = profit_;
            }
            _totalSupply = _totalSupply.add(rebaseAmount);
            if (_totalSupply > MAX_SUPPLY) {
                _totalSupply = MAX_SUPPLY;
            }
            _gonsPerFragment = TOTAL_GONS.div(_totalSupply);
            _storeRebase(circulatingSupply_, profit_, epoch_);
            return _totalSupply;
        }
        /**
            @notice emits event with data about rebase
            @param previousCirculating_ uint
            @param profit_ uint
            @param epoch_ uint
            @return bool
         */
        function _storeRebase(
            uint previousCirculating_,
            uint profit_,
            uint epoch_
        ) internal returns (bool) {
            uint rebasePercent = profit_.mul(1e18).div(previousCirculating_);
            rebases.push(
                Rebase({
                    epoch: epoch_,
                    rebase: rebasePercent, // 18 decimals
                    totalStakedBefore: previousCirculating_,
                    totalStakedAfter: circulatingSupply(),
                    amountRebased: profit_,
                    index: index(),
                    timeOccured: uint32(block.timestamp)
                })
            );
            emit LogSupply(epoch_, block.timestamp, _totalSupply);
            emit LogRebase(epoch_, rebasePercent, index());
            return true;
        }
        function balanceOf(address who) public view override returns (uint256) {
            return _gonBalances[who].div(_gonsPerFragment);
        }
        function gonsForBalance(uint amount) public view returns (uint) {
            return amount.mul(_gonsPerFragment);
        }
        function balanceForGons(uint gons) public view returns (uint) {
            return gons.div(_gonsPerFragment);
        }
        // Staking contract holds excess veSYNC
        function circulatingSupply() public view returns (uint) {
            return _totalSupply.sub(balanceOf(stakingContract));
        }
        function index() public view returns (uint) {
            return balanceForGons(INDEX);
        }
        function transfer(
            address to,
            uint256 value
        ) public override returns (bool) {
            uint256 gonValue = value.mul(_gonsPerFragment);
            _gonBalances[msg.sender] = _gonBalances[msg.sender].sub(gonValue);
            _gonBalances[to] = _gonBalances[to].add(gonValue);
            emit Transfer(msg.sender, to, value);
            return true;
        }
        function allowance(
            address owner_,
            address spender
        ) public view override returns (uint256) {
            return _allowedValue[owner_][spender];
        }
        function transferFrom(
            address from,
            address to,
            uint256 value
        ) public override returns (bool) {
            _allowedValue[from][msg.sender] = _allowedValue[from][msg.sender].sub(
                value
            );
            emit Approval(from, msg.sender, _allowedValue[from][msg.sender]);
            uint256 gonValue = gonsForBalance(value);
            _gonBalances[from] = _gonBalances[from].sub(gonValue);
            _gonBalances[to] = _gonBalances[to].add(gonValue);
            emit Transfer(from, to, value);
            return true;
        }
        function approve(
            address spender,
            uint256 value
        ) public override returns (bool) {
            _allowedValue[msg.sender][spender] = value;
            emit Approval(msg.sender, spender, value);
            return true;
        }
        // What gets called in a permit
        function _approve(
            address owner,
            address spender,
            uint256 value
        ) internal virtual override {
            _allowedValue[owner][spender] = value;
            emit Approval(owner, spender, value);
        }
        function increaseAllowance(
            address spender,
            uint256 addedValue
        ) public override returns (bool) {
            _allowedValue[msg.sender][spender] = _allowedValue[msg.sender][spender]
                .add(addedValue);
            emit Approval(msg.sender, spender, _allowedValue[msg.sender][spender]);
            return true;
        }
        function decreaseAllowance(
            address spender,
            uint256 subtractedValue
        ) public override returns (bool) {
            uint256 oldValue = _allowedValue[msg.sender][spender];
            if (subtractedValue >= oldValue) {
                _allowedValue[msg.sender][spender] = 0;
            } else {
                _allowedValue[msg.sender][spender] = oldValue.sub(subtractedValue);
            }
            emit Approval(msg.sender, spender, _allowedValue[msg.sender][spender]);
            return true;
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/IERC20.sol";
    import "./lib/IERC2612Permit.sol";
    import "./lib/Counters.sol";
    import "./ERC20.sol";
    abstract contract ERC20Permit is ERC20, IERC2612Permit {
        using Counters for Counters.Counter;
        mapping(address => Counters.Counter) private _nonces;
        // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
        bytes32 public constant PERMIT_TYPEHASH =
            0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
        bytes32 public DOMAIN_SEPARATOR;
        constructor() {
            uint256 chainID;
            assembly {
                chainID := chainid()
            }
            DOMAIN_SEPARATOR = keccak256(
                abi.encode(
                    keccak256(
                        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                    ),
                    keccak256(bytes(name())),
                    keccak256(bytes("1")), // Version
                    chainID,
                    address(this)
                )
            );
        }
        /**
         * @dev See {IERC2612Permit-permit}.
         *
         */
        function permit(
            address owner,
            address spender,
            uint256 amount,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) public virtual override {
            require(block.timestamp <= deadline, "Permit: expired deadline");
            bytes32 hashStruct = keccak256(
                abi.encode(
                    PERMIT_TYPEHASH,
                    owner,
                    spender,
                    amount,
                    _nonces[owner].current(),
                    deadline
                )
            );
            bytes32 _hash = keccak256(
                abi.encodePacked(uint16(0x1901), DOMAIN_SEPARATOR, hashStruct)
            );
            address signer = ecrecover(_hash, v, r, s);
            require(
                signer != address(0) && signer == owner,
                "ZeroSwapPermit: Invalid signature"
            );
            _nonces[owner].increment();
            _approve(owner, spender, amount);
        }
        /**
         * @dev See {IERC2612Permit-nonces}.
         */
        function nonces(address owner) public view override returns (uint256) {
            return _nonces[owner].current();
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IOwnable {
        function owner() external view returns (address);
        function renounceOwnership() external;
        function transferOwnership(address newOwner_) external;
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/IOwnableManagement.sol";
    contract OwnableManagement is IOwnableManagement {
          address internal _owner;
        address internal _newOwner;
        event OwnershipPushed(address indexed previousOwner, address indexed newOwner);
        event OwnershipPulled(address indexed previousOwner, address indexed newOwner);
        constructor () {
            _owner = msg.sender;
            emit OwnershipPushed( address(0), _owner );
        }
        function manager() public view override returns (address) {
            return _owner;
        }
        modifier onlyManager() {
            require( _owner == msg.sender, "Ownable: caller is not the owner" );
            _;
        }
        function renounceManagement() public virtual override onlyManager() {
            emit OwnershipPushed( _owner, address(0) );
            _owner = address(0);
        }
        function pushManagement( address newOwner_ ) public virtual override onlyManager() {
            require( newOwner_ != address(0), "Ownable: new owner is the zero address");
            emit OwnershipPushed( _owner, newOwner_ );
            _newOwner = newOwner_;
        }
        
        function pullManagement() public virtual override {
            require( msg.sender == _newOwner, "Ownable: must be new owner to pull");
            emit OwnershipPulled( _owner, _newOwner );
            _owner = _newOwner;
        }
    }// SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IERC20 {
        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.
         *
         * IMPORTANT: 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
        );
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IERC2612Permit {
        function permit(
            address owner,
            address spender,
            uint256 amount,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) external;
        function nonces(address owner) external view returns (uint256);
    }// SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./SafeMath.sol";
    library Counters {
        using SafeMath for uint256;
        struct Counter {
            uint256 _value; // default: 0
        }
        function current(Counter storage counter) internal view returns (uint256) {
            return counter._value;
        }
        function increment(Counter storage counter) internal {
            counter._value += 1;
        }
        function decrement(Counter storage counter) internal {
            counter._value = counter._value.sub(1);
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/IERC20.sol";
    import "./lib/SafeMath.sol";
    abstract contract ERC20 is IERC20 {
        using SafeMath for uint256;
        // TODO comment actual hash value.
        bytes32 private constant ERC20TOKEN_ERC1820_INTERFACE_ID =
            keccak256("ERC20Token");
        // Present in ERC777
        mapping(address => uint256) internal _balances;
        // Present in ERC777
        mapping(address => mapping(address => uint256)) internal _allowances;
        // Present in ERC777
        uint256 internal _totalSupply;
        // Present in ERC777
        string internal _name;
        // Present in ERC777
        string internal _symbol;
        // Present in ERC777
        uint8 internal _decimals;
        constructor(string memory name_, string memory symbol_, uint8 decimals_) {
            _name = name_;
            _symbol = symbol_;
            _decimals = decimals_;
        }
        function name() public view returns (string memory) {
            return _name;
        }
        function symbol() public view returns (string memory) {
            return _symbol;
        }
        function decimals() public view override returns (uint8) {
            return _decimals;
        }
        function totalSupply() public view override returns (uint256) {
            return _totalSupply;
        }
        function balanceOf(
            address account
        ) public view virtual override returns (uint256) {
            return _balances[account];
        }
        function transfer(
            address recipient,
            uint256 amount
        ) public virtual override returns (bool) {
            _transfer(msg.sender, recipient, amount);
            return true;
        }
        function allowance(
            address owner,
            address spender
        ) public view virtual override returns (uint256) {
            return _allowances[owner][spender];
        }
        function approve(
            address spender,
            uint256 amount
        ) public virtual override returns (bool) {
            _approve(msg.sender, spender, amount);
            return true;
        }
        function transferFrom(
            address sender,
            address recipient,
            uint256 amount
        ) public virtual override returns (bool) {
            _transfer(sender, recipient, amount);
            _approve(
                sender,
                msg.sender,
                _allowances[sender][msg.sender].sub(
                    amount,
                    "ERC20: transfer amount exceeds allowance"
                )
            );
            return true;
        }
        function increaseAllowance(
            address spender,
            uint256 addedValue
        ) public virtual returns (bool) {
            _approve(
                msg.sender,
                spender,
                _allowances[msg.sender][spender].add(addedValue)
            );
            return true;
        }
        function decreaseAllowance(
            address spender,
            uint256 subtractedValue
        ) public virtual returns (bool) {
            _approve(
                msg.sender,
                spender,
                _allowances[msg.sender][spender].sub(
                    subtractedValue,
                    "ERC20: decreased allowance below zero"
                )
            );
            return true;
        }
        function _transfer(
            address sender,
            address recipient,
            uint256 amount
        ) internal virtual {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
            _beforeTokenTransfer(sender, recipient, amount);
            _balances[sender] = _balances[sender].sub(
                amount,
                "ERC20: transfer amount exceeds balance"
            );
            _balances[recipient] = _balances[recipient].add(amount);
            emit Transfer(sender, recipient, amount);
        }
        function _mint(address account_, uint256 amount_) internal virtual {
            require(account_ != address(0), "ERC20: mint to the zero address");
            _beforeTokenTransfer(address(this), account_, amount_);
            _totalSupply = _totalSupply.add(amount_);
            _balances[account_] = _balances[account_].add(amount_);
            emit Transfer(address(this), account_, amount_);
        }
        function _burn(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: burn from the zero address");
            _beforeTokenTransfer(account, address(0), amount);
            _balances[account] = _balances[account].sub(
                amount,
                "ERC20: burn amount exceeds balance"
            );
            _totalSupply = _totalSupply.sub(amount);
            emit Transfer(account, address(0), amount);
        }
        function _approve(
            address owner,
            address spender,
            uint256 amount
        ) internal virtual {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
        function _beforeTokenTransfer(
            address from_,
            address to_,
            uint256 amount_
        ) internal virtual {}
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IOwnableManagement {
        function manager() external view returns (address);
        function renounceManagement() external;
        function pushManagement(address newOwner_) external;
        function pullManagement() external;
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    library SafeMath {
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        function add32(uint32 a, uint32 b) internal pure returns (uint32) {
            uint32 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
        function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
            return c;
        }
        function sub32(uint32 a, uint32 b) internal pure returns (uint32) {
            return sub32(a, b, "SafeMath: subtraction overflow");
        }
        function sub32(
            uint32 a,
            uint32 b,
            string memory errorMessage
        ) internal pure returns (uint32) {
            require(b <= a, errorMessage);
            uint32 c = a - b;
            return c;
        }
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) {
                return 0;
            }
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
        function mul32(uint32 a, uint32 b) internal pure returns (uint32) {
            if (a == 0) {
                return 0;
            }
            uint32 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
        function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            return c;
        }
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
        function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
        function sqrrt(uint256 a) internal pure returns (uint c) {
            if (a > 3) {
                c = a;
                uint b = add(div(a, 2), 1);
                while (b < c) {
                    c = b;
                    b = div(add(div(a, b), b), 2);
                }
            } else if (a != 0) {
                c = 1;
            }
        }
        function percentageAmount(
            uint256 total_,
            uint8 percentage_
        ) internal pure returns (uint256 percentAmount_) {
            return div(mul(total_, percentage_), 1000);
        }
        function substractPercentage(
            uint256 total_,
            uint8 percentageToSub_
        ) internal pure returns (uint256 result_) {
            return sub(total_, div(mul(total_, percentageToSub_), 1000));
        }
        function percentageOfTotal(
            uint256 part_,
            uint256 total_
        ) internal pure returns (uint256 percent_) {
            return div(mul(part_, 100), total_);
        }
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow, so we distribute
            return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
        }
        function quadraticPricing(
            uint256 payment_,
            uint256 multiplier_
        ) internal pure returns (uint256) {
            return sqrrt(mul(multiplier_, payment_));
        }
        function bondingCurve(
            uint256 supply_,
            uint256 multiplier_
        ) internal pure returns (uint256) {
            return mul(multiplier_, supply_);
        }
    }
    

    File 3 of 4: Syncus
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma abicoder v2;
    pragma solidity 0.7.5;
    import "./lib/EnumerableSet.sol";
    import "./lib/IERC2612Permit.sol";
    import "./lib/IERC20.sol";
    import "./ERC20Permit.sol";
    import "./VaultOwned.sol";
    import "./lib/IWETH.sol";
    import "./lib/IUniswapV2Router.sol";
    import "./lib/IUniswapV2Factory.sol";
    contract Syncus is ERC20Permit, VaultOwned {
        using SafeMath for uint256;
        IUniswapV2Router public router =
            IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
        address public uniswapV2Pair;
        address private treasury;
        uint256 public buyTax = 5;
        uint256 public sellTax = 15;
        mapping(address => bool) private _isExcludedFromTaxes;
        mapping(address => bool) public automatedMarketMakerPairs;
        receive() external payable {}
        constructor() ERC20("Syncus", "SYNC", 9) {
            _mint(msg.sender, 4_000_000_000 * 1e9);
            uniswapV2Pair = IUniswapV2Factory(router.factory()).createPair(
                address(this),
                router.WETH()
            );
            _setAutomatedMarketMakerPair(address(uniswapV2Pair), true);
            treasury = msg.sender;
            excludeFromTaxes(owner(), true);
            excludeFromTaxes(address(this), true);
            excludeFromTaxes(address(0xdead), true);
        }
        function mint(address account_, uint256 amount_) external onlyVault {
            _mint(account_, amount_);
        }
        function burn(uint256 amount) public virtual {
            _burn(msg.sender, amount);
        }
        function burnFrom(address account_, uint256 amount_) public virtual {
            _burnFrom(account_, amount_);
        }
        function _burnFrom(address account_, uint256 amount_) public virtual {
            uint256 decreasedAllowance_ = allowance(account_, msg.sender).sub(
                amount_,
                "ERC20: burn amount exceeds allowance"
            );
            _approve(account_, msg.sender, decreasedAllowance_);
            _burn(account_, amount_);
        }
        function excludeFromTaxes(address account, bool excluded) public onlyOwner {
            _isExcludedFromTaxes[account] = excluded;
        }
        function setAutomatedMarketMakerPair(
            address pair,
            bool value
        ) public onlyOwner {
            _setAutomatedMarketMakerPair(pair, value);
        }
        function _setAutomatedMarketMakerPair(address pair, bool value) private {
            automatedMarketMakerPairs[pair] = value;
        }
        function updateBuyTax(uint256 _buyTax) external onlyOwner {
            require(_buyTax <= 100, "Cannot set tax higher than 100%");
            buyTax = _buyTax;
        }
        function updateSellTax(uint256 _sellTax) external onlyOwner {
            require(_sellTax <= 100, "Cannot set tax higher than 100%");
            sellTax = _sellTax;
        }
        function updateTaxes(uint256 _buyTax, uint256 _sellTax) external onlyOwner {
            require(
                _sellTax <= 100 && _buyTax <= 100,
                "Cannot set taxes higher than 100%"
            );
            buyTax = _buyTax;
            sellTax = _sellTax;
        }
        function _transfer(
            address from,
            address to,
            uint256 amount
        ) internal override {
            require(from != address(0), "ERC20: transfer from the zero address");
            require(to != address(0), "ERC20: transfer to the zero address");
            if (amount == 0) {
                super._transfer(from, to, 0);
                return;
            }
            bool takeTax = true;
            if (_isExcludedFromTaxes[from] || _isExcludedFromTaxes[to]) {
                takeTax = false;
            }
            uint256 taxes = 0;
            if (takeTax) {
                if (automatedMarketMakerPairs[to] && sellTax > 0) {
                    taxes = amount.mul(sellTax).div(100);
                } else if (automatedMarketMakerPairs[from] && buyTax > 0) {
                    taxes = amount.mul(buyTax).div(100);
                }
                if (taxes > 0) {
                    super._transfer(from, treasury, taxes);
                }
                amount -= taxes;
            }
            super._transfer(from, to, amount);
        }
        function setTreasury(address _treasury) external onlyOwner {
            treasury = _treasury;
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    library EnumerableSet {
        // To implement this library for multiple types with as little code
        // repetition as possible, we write it in terms of a generic Set type with
        // bytes32 values.
        // The Set implementation uses private functions, and user-facing
        // implementations (such as AddressSet) are just wrappers around the
        // underlying Set.
        // This means that we can only create new EnumerableSets for types that fit
        // in bytes32.
        struct Set {
            // Storage of set values
            bytes32[] _values;
            // Position of the value in the `values` array, plus 1 because index 0
            // means a value is not in the set.
            mapping(bytes32 => uint256) _indexes;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function _add(Set storage set, bytes32 value) private returns (bool) {
            if (!_contains(set, value)) {
                set._values.push(value);
                // The value is stored at length-1, but we add 1 to all indexes
                // and use 0 as a sentinel value
                set._indexes[value] = set._values.length;
                return true;
            } else {
                return false;
            }
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function _remove(Set storage set, bytes32 value) private returns (bool) {
            // We read and store the value's index to prevent multiple reads from the same storage slot
            uint256 valueIndex = set._indexes[value];
            if (valueIndex != 0) {
                // Equivalent to contains(set, value)
                // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                // the array, and then remove the last element (sometimes called as 'swap and pop').
                // This modifies the order of the array, as noted in {at}.
                uint256 toDeleteIndex = valueIndex - 1;
                uint256 lastIndex = set._values.length - 1;
                // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
                // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
                bytes32 lastvalue = set._values[lastIndex];
                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastvalue;
                // Update the index for the moved value
                set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
                // Delete the slot where the moved value was stored
                set._values.pop();
                // Delete the index for the deleted slot
                delete set._indexes[value];
                return true;
            } else {
                return false;
            }
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function _contains(
            Set storage set,
            bytes32 value
        ) private view returns (bool) {
            return set._indexes[value] != 0;
        }
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function _length(Set storage set) private view returns (uint256) {
            return set._values.length;
        }
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function _at(
            Set storage set,
            uint256 index
        ) private view returns (bytes32) {
            require(
                set._values.length > index,
                "EnumerableSet: index out of bounds"
            );
            return set._values[index];
        }
        function _getValues(
            Set storage set_
        ) private view returns (bytes32[] storage) {
            return set_._values;
        }
        // TODO needs insert function that maintains order.
        // TODO needs NatSpec documentation comment.
        /**
         * Inserts new value by moving existing value at provided index to end
         * of array and setting provided value at provided index
         */
        function _insert(
            Set storage set_,
            uint256 index_,
            bytes32 valueToInsert_
        ) private returns (bool) {
            require(set_._values.length > index_);
            require(
                !_contains(set_, valueToInsert_),
                "Remove value you wish to insert if you wish to reorder array."
            );
            bytes32 existingValue_ = _at(set_, index_);
            set_._values[index_] = valueToInsert_;
            return _add(set_, existingValue_);
        }
        struct Bytes4Set {
            Set _inner;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(Bytes4Set storage set, bytes4 value) internal returns (bool) {
            return _add(set._inner, value);
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(
            Bytes4Set storage set,
            bytes4 value
        ) internal returns (bool) {
            return _remove(set._inner, value);
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(
            Bytes4Set storage set,
            bytes4 value
        ) internal view returns (bool) {
            return _contains(set._inner, value);
        }
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function length(Bytes4Set storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(
            Bytes4Set storage set,
            uint256 index
        ) internal view returns (bytes4) {
            return bytes4(_at(set._inner, index));
        }
        function getValues(
            Bytes4Set storage set_
        ) internal view returns (bytes4[] memory) {
            bytes4[] memory bytes4Array_;
            for (
                uint256 iteration_ = 0;
                _length(set_._inner) > iteration_;
                iteration_++
            ) {
                bytes4Array_[iteration_] = bytes4(_at(set_._inner, iteration_));
            }
            return bytes4Array_;
        }
        function insert(
            Bytes4Set storage set_,
            uint256 index_,
            bytes4 valueToInsert_
        ) internal returns (bool) {
            return _insert(set_._inner, index_, valueToInsert_);
        }
        struct Bytes32Set {
            Set _inner;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(
            Bytes32Set storage set,
            bytes32 value
        ) internal returns (bool) {
            return _add(set._inner, value);
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(
            Bytes32Set storage set,
            bytes32 value
        ) internal returns (bool) {
            return _remove(set._inner, value);
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(
            Bytes32Set storage set,
            bytes32 value
        ) internal view returns (bool) {
            return _contains(set._inner, value);
        }
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function length(Bytes32Set storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(
            Bytes32Set storage set,
            uint256 index
        ) internal view returns (bytes32) {
            return _at(set._inner, index);
        }
        function getValues(
            Bytes32Set storage set_
        ) internal view returns (bytes4[] memory) {
            bytes4[] memory bytes4Array_;
            for (
                uint256 iteration_ = 0;
                _length(set_._inner) >= iteration_;
                iteration_++
            ) {
                bytes4Array_[iteration_] = bytes4(at(set_, iteration_));
            }
            return bytes4Array_;
        }
        function insert(
            Bytes32Set storage set_,
            uint256 index_,
            bytes32 valueToInsert_
        ) internal returns (bool) {
            return _insert(set_._inner, index_, valueToInsert_);
        }
        // AddressSet
        struct AddressSet {
            Set _inner;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(
            AddressSet storage set,
            address value
        ) internal returns (bool) {
            return _add(set._inner, bytes32(uint256(value)));
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(
            AddressSet storage set,
            address value
        ) internal returns (bool) {
            return _remove(set._inner, bytes32(uint256(value)));
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(
            AddressSet storage set,
            address value
        ) internal view returns (bool) {
            return _contains(set._inner, bytes32(uint256(value)));
        }
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(AddressSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(
            AddressSet storage set,
            uint256 index
        ) internal view returns (address) {
            return address(uint256(_at(set._inner, index)));
        }
        /**
         * TODO Might require explicit conversion of bytes32[] to address[].
         *  Might require iteration.
         */
        function getValues(
            AddressSet storage set_
        ) internal view returns (address[] memory) {
            address[] memory addressArray;
            for (
                uint256 iteration_ = 0;
                _length(set_._inner) >= iteration_;
                iteration_++
            ) {
                addressArray[iteration_] = at(set_, iteration_);
            }
            return addressArray;
        }
        function insert(
            AddressSet storage set_,
            uint256 index_,
            address valueToInsert_
        ) internal returns (bool) {
            return _insert(set_._inner, index_, bytes32(uint256(valueToInsert_)));
        }
        // UintSet
        struct UintSet {
            Set _inner;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(UintSet storage set, uint256 value) internal returns (bool) {
            return _add(set._inner, bytes32(value));
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(
            UintSet storage set,
            uint256 value
        ) internal returns (bool) {
            return _remove(set._inner, bytes32(value));
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(
            UintSet storage set,
            uint256 value
        ) internal view returns (bool) {
            return _contains(set._inner, bytes32(value));
        }
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function length(UintSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(
            UintSet storage set,
            uint256 index
        ) internal view returns (uint256) {
            return uint256(_at(set._inner, index));
        }
        struct UInt256Set {
            Set _inner;
        }
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(
            UInt256Set storage set,
            uint256 value
        ) internal returns (bool) {
            return _add(set._inner, bytes32(value));
        }
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(
            UInt256Set storage set,
            uint256 value
        ) internal returns (bool) {
            return _remove(set._inner, bytes32(value));
        }
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(
            UInt256Set storage set,
            uint256 value
        ) internal view returns (bool) {
            return _contains(set._inner, bytes32(value));
        }
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function length(UInt256Set storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(
            UInt256Set storage set,
            uint256 index
        ) internal view returns (uint256) {
            return uint256(_at(set._inner, index));
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IERC2612Permit {
        function permit(
            address owner,
            address spender,
            uint256 amount,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) external;
        function nonces(address owner) external view returns (uint256);
    }// SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IERC20 {
        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.
         *
         * IMPORTANT: 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
        );
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/IERC20.sol";
    import "./lib/IERC2612Permit.sol";
    import "./lib/Counters.sol";
    import "./ERC20.sol";
    abstract contract ERC20Permit is ERC20, IERC2612Permit {
        using Counters for Counters.Counter;
        mapping(address => Counters.Counter) private _nonces;
        // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
        bytes32 public constant PERMIT_TYPEHASH =
            0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
        bytes32 public DOMAIN_SEPARATOR;
        constructor() {
            uint256 chainID;
            assembly {
                chainID := chainid()
            }
            DOMAIN_SEPARATOR = keccak256(
                abi.encode(
                    keccak256(
                        "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                    ),
                    keccak256(bytes(name())),
                    keccak256(bytes("1")), // Version
                    chainID,
                    address(this)
                )
            );
        }
        /**
         * @dev See {IERC2612Permit-permit}.
         *
         */
        function permit(
            address owner,
            address spender,
            uint256 amount,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) public virtual override {
            require(block.timestamp <= deadline, "Permit: expired deadline");
            bytes32 hashStruct = keccak256(
                abi.encode(
                    PERMIT_TYPEHASH,
                    owner,
                    spender,
                    amount,
                    _nonces[owner].current(),
                    deadline
                )
            );
            bytes32 _hash = keccak256(
                abi.encodePacked(uint16(0x1901), DOMAIN_SEPARATOR, hashStruct)
            );
            address signer = ecrecover(_hash, v, r, s);
            require(
                signer != address(0) && signer == owner,
                "ZeroSwapPermit: Invalid signature"
            );
            _nonces[owner].increment();
            _approve(owner, spender, amount);
        }
        /**
         * @dev See {IERC2612Permit-nonces}.
         */
        function nonces(address owner) public view override returns (uint256) {
            return _nonces[owner].current();
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./Ownable.sol";
    contract VaultOwned is Ownable {
        address internal _vault;
        function setVault(address vault_) external onlyOwner returns (bool) {
            _vault = vault_;
            return true;
        }
        function vault() public view returns (address) {
            return _vault;
        }
        modifier onlyVault() {
            require(_vault == msg.sender, "VaultOwned: caller is not the Vault");
            _;
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IWETH {
        /**
         * @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
        );
        /**
         * @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 `to`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address to, 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.
         *
         * IMPORTANT: 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 `from` to `to` 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 from,
            address to,
            uint256 amount
        ) external returns (bool);
        /// @notice Deposit ether to get wrapped ether
        function deposit() external payable;
        /// @notice Withdraw wrapped ether to get ether
        function withdraw(uint256) external;
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IUniswapV2Router {
        function factory() external pure returns (address);
        function WETH() external pure returns (address);
        function addLiquidity(
            address tokenA,
            address tokenB,
            uint amountADesired,
            uint amountBDesired,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline
        ) external returns (uint amountA, uint amountB, uint liquidity);
        function addLiquidityETH(
            address token,
            uint amountTokenDesired,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        )
            external
            payable
            returns (uint amountToken, uint amountETH, uint liquidity);
        function removeLiquidity(
            address tokenA,
            address tokenB,
            uint liquidity,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline
        ) external returns (uint amountA, uint amountB);
        function removeLiquidityETH(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external returns (uint amountToken, uint amountETH);
        function removeLiquidityWithPermit(
            address tokenA,
            address tokenB,
            uint liquidity,
            uint amountAMin,
            uint amountBMin,
            address to,
            uint deadline,
            bool approveMax,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) external returns (uint amountA, uint amountB);
        function removeLiquidityETHWithPermit(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline,
            bool approveMax,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) external returns (uint amountToken, uint amountETH);
        function swapExactTokensForTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
        function swapTokensForExactTokens(
            uint amountOut,
            uint amountInMax,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
        function swapExactETHForTokens(
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external payable returns (uint[] memory amounts);
        function swapTokensForExactETH(
            uint amountOut,
            uint amountInMax,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
        function swapExactTokensForETH(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external returns (uint[] memory amounts);
        function swapETHForExactTokens(
            uint amountOut,
            address[] calldata path,
            address to,
            uint deadline
        ) external payable returns (uint[] memory amounts);
        function quote(
            uint amountA,
            uint reserveA,
            uint reserveB
        ) external pure returns (uint amountB);
        function getAmountOut(
            uint amountIn,
            uint reserveIn,
            uint reserveOut
        ) external pure returns (uint amountOut);
        function getAmountIn(
            uint amountOut,
            uint reserveIn,
            uint reserveOut
        ) external pure returns (uint amountIn);
        function getAmountsOut(
            uint amountIn,
            address[] calldata path
        ) external view returns (uint[] memory amounts);
        function getAmountsIn(
            uint amountOut,
            address[] calldata path
        ) external view returns (uint[] memory amounts);
        function removeLiquidityETHSupportingFeeOnTransferTokens(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline
        ) external returns (uint amountETH);
        function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
            address token,
            uint liquidity,
            uint amountTokenMin,
            uint amountETHMin,
            address to,
            uint deadline,
            bool approveMax,
            uint8 v,
            bytes32 r,
            bytes32 s
        ) external returns (uint amountETH);
        function swapExactTokensForTokensSupportingFeeOnTransferTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external;
        function swapExactETHForTokensSupportingFeeOnTransferTokens(
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external payable;
        function swapExactTokensForETHSupportingFeeOnTransferTokens(
            uint amountIn,
            uint amountOutMin,
            address[] calldata path,
            address to,
            uint deadline
        ) external;
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IUniswapV2Factory {
        event PairCreated(
            address indexed token0,
            address indexed token1,
            address pair,
            uint
        );
        function getPair(
            address tokenA,
            address tokenB
        ) external view returns (address pair);
        function allPairs(uint) external view returns (address pair);
        function allPairsLength() external view returns (uint);
        function feeTo() external view returns (address);
        function feeToSetter() external view returns (address);
        function createPair(
            address tokenA,
            address tokenB
        ) external returns (address pair);
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./SafeMath.sol";
    library Counters {
        using SafeMath for uint256;
        struct Counter {
            uint256 _value; // default: 0
        }
        function current(Counter storage counter) internal view returns (uint256) {
            return counter._value;
        }
        function increment(Counter storage counter) internal {
            counter._value += 1;
        }
        function decrement(Counter storage counter) internal {
            counter._value = counter._value.sub(1);
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/IERC20.sol";
    import "./lib/SafeMath.sol";
    abstract contract ERC20 is IERC20 {
        using SafeMath for uint256;
        // TODO comment actual hash value.
        bytes32 private constant ERC20TOKEN_ERC1820_INTERFACE_ID =
            keccak256("ERC20Token");
        // Present in ERC777
        mapping(address => uint256) internal _balances;
        // Present in ERC777
        mapping(address => mapping(address => uint256)) internal _allowances;
        // Present in ERC777
        uint256 internal _totalSupply;
        // Present in ERC777
        string internal _name;
        // Present in ERC777
        string internal _symbol;
        // Present in ERC777
        uint8 internal _decimals;
        constructor(string memory name_, string memory symbol_, uint8 decimals_) {
            _name = name_;
            _symbol = symbol_;
            _decimals = decimals_;
        }
        function name() public view returns (string memory) {
            return _name;
        }
        function symbol() public view returns (string memory) {
            return _symbol;
        }
        function decimals() public view override returns (uint8) {
            return _decimals;
        }
        function totalSupply() public view override returns (uint256) {
            return _totalSupply;
        }
        function balanceOf(
            address account
        ) public view virtual override returns (uint256) {
            return _balances[account];
        }
        function transfer(
            address recipient,
            uint256 amount
        ) public virtual override returns (bool) {
            _transfer(msg.sender, recipient, amount);
            return true;
        }
        function allowance(
            address owner,
            address spender
        ) public view virtual override returns (uint256) {
            return _allowances[owner][spender];
        }
        function approve(
            address spender,
            uint256 amount
        ) public virtual override returns (bool) {
            _approve(msg.sender, spender, amount);
            return true;
        }
        function transferFrom(
            address sender,
            address recipient,
            uint256 amount
        ) public virtual override returns (bool) {
            _transfer(sender, recipient, amount);
            _approve(
                sender,
                msg.sender,
                _allowances[sender][msg.sender].sub(
                    amount,
                    "ERC20: transfer amount exceeds allowance"
                )
            );
            return true;
        }
        function increaseAllowance(
            address spender,
            uint256 addedValue
        ) public virtual returns (bool) {
            _approve(
                msg.sender,
                spender,
                _allowances[msg.sender][spender].add(addedValue)
            );
            return true;
        }
        function decreaseAllowance(
            address spender,
            uint256 subtractedValue
        ) public virtual returns (bool) {
            _approve(
                msg.sender,
                spender,
                _allowances[msg.sender][spender].sub(
                    subtractedValue,
                    "ERC20: decreased allowance below zero"
                )
            );
            return true;
        }
        function _transfer(
            address sender,
            address recipient,
            uint256 amount
        ) internal virtual {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
            _beforeTokenTransfer(sender, recipient, amount);
            _balances[sender] = _balances[sender].sub(
                amount,
                "ERC20: transfer amount exceeds balance"
            );
            _balances[recipient] = _balances[recipient].add(amount);
            emit Transfer(sender, recipient, amount);
        }
        function _mint(address account_, uint256 amount_) internal virtual {
            require(account_ != address(0), "ERC20: mint to the zero address");
            _beforeTokenTransfer(address(this), account_, amount_);
            _totalSupply = _totalSupply.add(amount_);
            _balances[account_] = _balances[account_].add(amount_);
            emit Transfer(address(this), account_, amount_);
        }
        function _burn(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: burn from the zero address");
            _beforeTokenTransfer(account, address(0), amount);
            _balances[account] = _balances[account].sub(
                amount,
                "ERC20: burn amount exceeds balance"
            );
            _totalSupply = _totalSupply.sub(amount);
            emit Transfer(account, address(0), amount);
        }
        function _approve(
            address owner,
            address spender,
            uint256 amount
        ) internal virtual {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
        function _beforeTokenTransfer(
            address from_,
            address to_,
            uint256 amount_
        ) internal virtual {}
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/IOwnable.sol";
    contract Ownable is IOwnable {
        address internal _owner;
        event OwnershipTransferred(
            address indexed previousOwner,
            address indexed newOwner
        );
        constructor() {
            _owner = msg.sender;
            emit OwnershipTransferred(address(0), _owner);
        }
        function owner() public view override returns (address) {
            return _owner;
        }
        modifier onlyOwner() {
            require(_owner == msg.sender, "Ownable: caller is not the owner");
            _;
        }
        function renounceOwnership() public virtual override onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
        function transferOwnership(
            address newOwner_
        ) public virtual override onlyOwner {
            require(
                newOwner_ != address(0),
                "Ownable: new owner is the zero address"
            );
            emit OwnershipTransferred(_owner, newOwner_);
            _owner = newOwner_;
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    library SafeMath {
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        function add32(uint32 a, uint32 b) internal pure returns (uint32) {
            uint32 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
        function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
            return c;
        }
        function sub32(uint32 a, uint32 b) internal pure returns (uint32) {
            return sub32(a, b, "SafeMath: subtraction overflow");
        }
        function sub32(
            uint32 a,
            uint32 b,
            string memory errorMessage
        ) internal pure returns (uint32) {
            require(b <= a, errorMessage);
            uint32 c = a - b;
            return c;
        }
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) {
                return 0;
            }
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
        function mul32(uint32 a, uint32 b) internal pure returns (uint32) {
            if (a == 0) {
                return 0;
            }
            uint32 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
        function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            return c;
        }
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
        function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
        function sqrrt(uint256 a) internal pure returns (uint c) {
            if (a > 3) {
                c = a;
                uint b = add(div(a, 2), 1);
                while (b < c) {
                    c = b;
                    b = div(add(div(a, b), b), 2);
                }
            } else if (a != 0) {
                c = 1;
            }
        }
        function percentageAmount(
            uint256 total_,
            uint8 percentage_
        ) internal pure returns (uint256 percentAmount_) {
            return div(mul(total_, percentage_), 1000);
        }
        function substractPercentage(
            uint256 total_,
            uint8 percentageToSub_
        ) internal pure returns (uint256 result_) {
            return sub(total_, div(mul(total_, percentageToSub_), 1000));
        }
        function percentageOfTotal(
            uint256 part_,
            uint256 total_
        ) internal pure returns (uint256 percent_) {
            return div(mul(part_, 100), total_);
        }
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow, so we distribute
            return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
        }
        function quadraticPricing(
            uint256 payment_,
            uint256 multiplier_
        ) internal pure returns (uint256) {
            return sqrrt(mul(multiplier_, payment_));
        }
        function bondingCurve(
            uint256 supply_,
            uint256 multiplier_
        ) internal pure returns (uint256) {
            return mul(multiplier_, supply_);
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IOwnable {
        function owner() external view returns (address);
        function renounceOwnership() external;
        function transferOwnership(address newOwner_) external;
    }
    

    File 4 of 4: SyncusTreasury
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/SafeMath.sol";
    import "./lib/Address.sol";
    import "./lib/IERC20.sol";
    import "./lib/SafeERC20.sol";
    import "./lib/ISyncus.sol";
    import "./lib/IERC20Mintable.sol";
    import "./lib/ISyncusCalculator.sol";
    import "./lib/IOwnable.sol";
    import "./OwnableManagement.sol";
    contract SyncusTreasury is OwnableManagement {
        using SafeMath for uint;
        using SafeMath for uint32;
        using SafeERC20 for IERC20;
        event Deposit(address indexed token, uint amount, uint value);
        event Withdrawal(address indexed token, uint amount, uint value);
        event CreateDebt(
            address indexed debtor,
            address indexed token,
            uint amount,
            uint value
        );
        event RepayDebt(
            address indexed debtor,
            address indexed token,
            uint amount,
            uint value
        );
        event ReservesManaged(address indexed token, uint amount);
        event ReservesUpdated(uint indexed totalReserves);
        event ReservesAudited(uint indexed totalReserves);
        event RewardsMinted(
            address indexed caller,
            address indexed recipient,
            uint amount
        );
        event ChangeQueued(MANAGING indexed managing, address queued);
        event ChangeActivated(
            MANAGING indexed managing,
            address activated,
            bool result
        );
        enum MANAGING {
            RESERVEDEPOSITOR,
            RESERVESPENDER,
            RESERVETOKEN,
            RESERVEMANAGER,
            LIQUIDITYDEPOSITOR,
            LIQUIDITYTOKEN,
            LIQUIDITYMANAGER,
            DEBTOR,
            REWARDMANAGER,
            VESYNC
        }
        address public immutable Sync;
        uint32 public secondsNeededForQueue;
        address[] public reserveTokens; // Push only, beware false-positives.
        mapping(address => bool) public isReserveToken;
        mapping(address => uint32) public reserveTokenQueue; // Delays changes to mapping.
        address[] public reserveDepositors; // Push only, beware false-positives. Only for viewing.
        mapping(address => bool) public isReserveDepositor;
        mapping(address => uint32) public reserveDepositorQueue; // Delays changes to mapping.
        address[] public reserveSpenders; // Push only, beware false-positives. Only for viewing.
        mapping(address => bool) public isReserveSpender;
        mapping(address => uint32) public reserveSpenderQueue; // Delays changes to mapping.
        address[] public liquidityTokens; // Push only, beware false-positives.
        mapping(address => bool) public isLiquidityToken;
        mapping(address => uint32) public LiquidityTokenQueue; // Delays changes to mapping.
        address[] public liquidityDepositors; // Push only, beware false-positives. Only for viewing.
        mapping(address => bool) public isLiquidityDepositor;
        mapping(address => uint32) public LiquidityDepositorQueue; // Delays changes to mapping.
        mapping(address => address) public syncusCalculator; //  calculator for liquidity token
        address[] public reserveManagers; // Push only, beware false-positives. Only for viewing.
        mapping(address => bool) public isReserveManager;
        mapping(address => uint32) public ReserveManagerQueue; // Delays changes to mapping.
        address[] public liquidityManagers; // Push only, beware false-positives. Only for viewing.
        mapping(address => bool) public isLiquidityManager;
        mapping(address => uint32) public LiquidityManagerQueue; // Delays changes to mapping.
        address[] public debtors; // Push only, beware false-positives. Only for viewing.
        mapping(address => bool) public isDebtor;
        mapping(address => uint32) public debtorQueue; // Delays changes to mapping.
        mapping(address => uint) public debtorBalance;
        address[] public rewardManagers; // Push only, beware false-positives. Only for viewing.
        mapping(address => bool) public isRewardManager;
        mapping(address => uint32) public rewardManagerQueue; // Delays changes to mapping.
        address public veSYNC;
        uint public veSYNCQueue; // Delays change to veSYNC address
        uint public totalReserves; // Risk-free value of all assets
        uint public totalDebt;
        bool isBackingEnabled = false;
        receive() external payable {}
        constructor(address _Sync, address _USDC, address _etherCalculator) {
            require(_Sync != address(0));
            require(_USDC != address(0));
            require(_etherCalculator != address(0));
            Sync = _Sync;
            isReserveToken[_USDC] = true;
            reserveTokens.push(_USDC);
            syncusCalculator[address(0)] = _etherCalculator;
        }
        /**
            @notice allow approved address to deposit an asset for SYNC
            @param _amount uint
            @param _token address
            @param _profit uint
            @return send_ uint
         */
        function deposit(
            uint _amount,
            address _token,
            uint _profit //profit in SYNC, 9 decimals needed
        ) external returns (uint send_) {
            require(
                isReserveToken[_token] || isLiquidityToken[_token],
                "Not accepted"
            );
            IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
            if (isReserveToken[_token]) {
                require(isReserveDepositor[msg.sender], "Not approved");
            } else {
                require(isLiquidityDepositor[msg.sender], "Not approved");
            }
            uint value = valueOf(_token, _amount);
            // mint SYNC needed and store amount of rewards for distribution
            send_ = value.sub(_profit);
            IERC20Mintable(Sync).mint(msg.sender, send_);
            totalReserves = totalReserves.add(value);
            emit ReservesUpdated(totalReserves);
            emit Deposit(_token, _amount, value);
        }
        /**
            @notice allow approved address to burn SYNC for reserves
            @param _amount uint
            @param _token address
         */
        function withdraw(uint _amount, address _token) external {
            require(isReserveToken[_token], "Not accepted"); // Only reserves can be used for redemptions
            require(isReserveSpender[msg.sender] == true, "Not approved");
            uint value = valueOf(_token, _amount);
            ISyncus(Sync).burnFrom(msg.sender, value);
            totalReserves = totalReserves.sub(value);
            emit ReservesUpdated(totalReserves);
            IERC20(_token).safeTransfer(msg.sender, _amount);
            emit Withdrawal(_token, _amount, value);
        }
        /**
            @notice allow approved address to borrow reserves
            @param _amount uint
            @param _token address
         */
        function incurDebt(uint _amount, address _token) external {
            require(isDebtor[msg.sender], "Not approved");
            require(isReserveToken[_token], "Not accepted");
            uint value = valueOf(_token, _amount);
            uint maximumDebt = IERC20(veSYNC).balanceOf(msg.sender); // Can only borrow against veSYNC held
            uint availableDebt = maximumDebt.sub(debtorBalance[msg.sender]);
            require(value <= availableDebt, "Exceeds debt limit");
            debtorBalance[msg.sender] = debtorBalance[msg.sender].add(value);
            totalDebt = totalDebt.add(value);
            totalReserves = totalReserves.sub(value);
            emit ReservesUpdated(totalReserves);
            IERC20(_token).transfer(msg.sender, _amount);
            emit CreateDebt(msg.sender, _token, _amount, value);
        }
        /**
            @notice allow approved address to repay borrowed reserves with reserves
            @param _amount uint
            @param _token address
         */
        function repayDebtWithReserve(uint _amount, address _token) external {
            require(isDebtor[msg.sender], "Not approved");
            require(isReserveToken[_token], "Not accepted");
            IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
            uint value = valueOf(_token, _amount);
            debtorBalance[msg.sender] = debtorBalance[msg.sender].sub(value);
            totalDebt = totalDebt.sub(value);
            totalReserves = totalReserves.add(value);
            emit ReservesUpdated(totalReserves);
            emit RepayDebt(msg.sender, _token, _amount, value);
        }
        /**
            @notice allow approved address to repay borrowed reserves with SYNC
            @param _amount uint
         */
        function repayDebtWithSYNC(uint _amount) external {
            require(isDebtor[msg.sender], "Not approved");
            ISyncus(Sync).burnFrom(msg.sender, _amount);
            debtorBalance[msg.sender] = debtorBalance[msg.sender].sub(_amount);
            totalDebt = totalDebt.sub(_amount);
            emit RepayDebt(msg.sender, Sync, _amount, _amount);
        }
        /**
            @notice allow approved address to withdraw assets
            @param _token address
            @param _amount uint
         */
        function manage(address _token, uint _amount) external {
            if (isLiquidityToken[_token]) {
                require(isLiquidityManager[msg.sender], "Not approved");
            } else {
                require(isReserveManager[msg.sender], "Not approved");
            }
            uint value = valueOf(_token, _amount);
            if (isBackingEnabled) {
                require(value <= excessReserves(), "Insufficient reserves");
            }
            totalReserves = totalReserves.sub(value);
            emit ReservesUpdated(totalReserves);
            IERC20(_token).safeTransfer(msg.sender, _amount);
            emit ReservesManaged(_token, _amount);
        }
        /**
            @notice send epoch reward to staking contract
         */
        function mintRewards(address _recipient, uint _amount) external {
            require(isRewardManager[msg.sender], "Not approved");
            if (isBackingEnabled) {
                require(_amount <= excessReserves(), "Insufficient reserves");
            }
            IERC20Mintable(Sync).mint(_recipient, _amount);
            emit RewardsMinted(msg.sender, _recipient, _amount);
        }
        /**
            @notice returns excess reserves not backing tokens
            @return uint
         */
        function excessReserves() public view returns (uint) {
            uint supply = IERC20(Sync).totalSupply().sub(totalDebt);
            if (supply > totalReserves) {
                return 0;
            }
            return totalReserves.sub(supply);
        }
        /**
            @notice takes inventory of all tracked assets
            @notice always consolidate to recognized reserves before audit
         */
        function auditReserves() external onlyManager {
            uint reserves;
            for (uint i = 0; i < reserveTokens.length; i++) {
                reserves = reserves.add(
                    valueOf(
                        reserveTokens[i],
                        IERC20(reserveTokens[i]).balanceOf(address(this))
                    )
                );
            }
            for (uint i = 0; i < liquidityTokens.length; i++) {
                reserves = reserves.add(
                    valueOf(
                        liquidityTokens[i],
                        IERC20(liquidityTokens[i]).balanceOf(address(this))
                    )
                );
            }
            reserves = reserves.add(valueOf(address(0), address(this).balance));
            totalReserves = reserves;
            emit ReservesUpdated(reserves);
            emit ReservesAudited(reserves);
        }
        /**
            @notice returns SYNC valuation of asset
            @param _token address
            @param _amount uint
            @return value_ uint
         */
        function valueOf(
            address _token,
            uint _amount
        ) public view returns (uint value_) {
            if (_token == address(0)) {
                value_ = ISyncusCalculator(syncusCalculator[_token]).valuationEther(
                    _amount
                );
            } else if (isReserveToken[_token]) {
                // convert amount to match SYNC decimals
                value_ = _amount.mul(10 ** IERC20(Sync).decimals()).div(
                    10 ** IERC20(_token).decimals()
                );
            } else if (isLiquidityToken[_token]) {
                value_ = ISyncusCalculator(syncusCalculator[_token]).valuation(
                    _token,
                    _amount
                );
            }
        }
        /**
            @notice queue address to change boolean in mapping
            @param _managing MANAGING
            @param _address address
            @return bool
         */
        function queue(
            MANAGING _managing,
            address _address
        ) external onlyManager returns (bool) {
            require(_address != address(0));
            if (_managing == MANAGING.RESERVEDEPOSITOR) {
                // 0
                reserveDepositorQueue[_address] = uint32(block.timestamp).add32(
                    secondsNeededForQueue
                );
            } else if (_managing == MANAGING.RESERVESPENDER) {
                // 1
                reserveSpenderQueue[_address] = uint32(block.timestamp).add32(
                    secondsNeededForQueue
                );
            } else if (_managing == MANAGING.RESERVETOKEN) {
                // 2
                reserveTokenQueue[_address] = uint32(block.timestamp).add32(
                    secondsNeededForQueue
                );
            } else if (_managing == MANAGING.RESERVEMANAGER) {
                // 3
                ReserveManagerQueue[_address] = uint32(block.timestamp).add32(
                    secondsNeededForQueue.mul32(2)
                );
            } else if (_managing == MANAGING.LIQUIDITYDEPOSITOR) {
                // 4
                LiquidityDepositorQueue[_address] = uint32(block.timestamp).add32(
                    secondsNeededForQueue
                );
            } else if (_managing == MANAGING.LIQUIDITYTOKEN) {
                // 5
                LiquidityTokenQueue[_address] = uint32(block.timestamp).add32(
                    secondsNeededForQueue
                );
            } else if (_managing == MANAGING.LIQUIDITYMANAGER) {
                // 6
                LiquidityManagerQueue[_address] = uint32(block.timestamp).add32(
                    secondsNeededForQueue.mul32(2)
                );
            } else if (_managing == MANAGING.DEBTOR) {
                // 7
                debtorQueue[_address] = uint32(block.timestamp).add32(
                    secondsNeededForQueue
                );
            } else if (_managing == MANAGING.REWARDMANAGER) {
                // 8
                rewardManagerQueue[_address] = uint32(block.timestamp).add32(
                    secondsNeededForQueue
                );
            } else if (_managing == MANAGING.VESYNC) {
                // 9
                veSYNCQueue = uint32(block.timestamp).add32(secondsNeededForQueue);
            } else return false;
            emit ChangeQueued(_managing, _address);
            return true;
        }
        /**
            @notice verify queue then set boolean in mapping
            @param _managing MANAGING
            @param _address address
            @param _calculator address
            @return bool
         */
        function toggle(
            MANAGING _managing,
            address _address,
            address _calculator
        ) external onlyManager returns (bool) {
            require(_address != address(0));
            bool result;
            if (_managing == MANAGING.RESERVEDEPOSITOR) {
                // 0
                if (
                    requirements(
                        reserveDepositorQueue,
                        isReserveDepositor,
                        _address
                    )
                ) {
                    reserveDepositorQueue[_address] = 0;
                    if (!listContains(reserveDepositors, _address)) {
                        reserveDepositors.push(_address);
                    }
                }
                result = !isReserveDepositor[_address];
                isReserveDepositor[_address] = result;
            } else if (_managing == MANAGING.RESERVESPENDER) {
                // 1
                if (requirements(reserveSpenderQueue, isReserveSpender, _address)) {
                    reserveSpenderQueue[_address] = 0;
                    if (!listContains(reserveSpenders, _address)) {
                        reserveSpenders.push(_address);
                    }
                }
                result = !isReserveSpender[_address];
                isReserveSpender[_address] = result;
            } else if (_managing == MANAGING.RESERVETOKEN) {
                // 2
                if (requirements(reserveTokenQueue, isReserveToken, _address)) {
                    reserveTokenQueue[_address] = 0;
                    if (!listContains(reserveTokens, _address)) {
                        reserveTokens.push(_address);
                    }
                }
                result = !isReserveToken[_address];
                isReserveToken[_address] = result;
            } else if (_managing == MANAGING.RESERVEMANAGER) {
                // 3
                if (requirements(ReserveManagerQueue, isReserveManager, _address)) {
                    reserveManagers.push(_address);
                    ReserveManagerQueue[_address] = 0;
                    if (!listContains(reserveManagers, _address)) {
                        reserveManagers.push(_address);
                    }
                }
                result = !isReserveManager[_address];
                isReserveManager[_address] = result;
            } else if (_managing == MANAGING.LIQUIDITYDEPOSITOR) {
                // 4
                if (
                    requirements(
                        LiquidityDepositorQueue,
                        isLiquidityDepositor,
                        _address
                    )
                ) {
                    liquidityDepositors.push(_address);
                    LiquidityDepositorQueue[_address] = 0;
                    if (!listContains(liquidityDepositors, _address)) {
                        liquidityDepositors.push(_address);
                    }
                }
                result = !isLiquidityDepositor[_address];
                isLiquidityDepositor[_address] = result;
            } else if (_managing == MANAGING.LIQUIDITYTOKEN) {
                // 5
                if (requirements(LiquidityTokenQueue, isLiquidityToken, _address)) {
                    LiquidityTokenQueue[_address] = 0;
                    if (!listContains(liquidityTokens, _address)) {
                        liquidityTokens.push(_address);
                    }
                }
                result = !isLiquidityToken[_address];
                isLiquidityToken[_address] = result;
                syncusCalculator[_address] = _calculator;
            } else if (_managing == MANAGING.LIQUIDITYMANAGER) {
                // 6
                if (
                    requirements(
                        LiquidityManagerQueue,
                        isLiquidityManager,
                        _address
                    )
                ) {
                    LiquidityManagerQueue[_address] = 0;
                    if (!listContains(liquidityManagers, _address)) {
                        liquidityManagers.push(_address);
                    }
                }
                result = !isLiquidityManager[_address];
                isLiquidityManager[_address] = result;
            } else if (_managing == MANAGING.DEBTOR) {
                // 7
                if (requirements(debtorQueue, isDebtor, _address)) {
                    debtorQueue[_address] = 0;
                    if (!listContains(debtors, _address)) {
                        debtors.push(_address);
                    }
                }
                result = !isDebtor[_address];
                isDebtor[_address] = result;
            } else if (_managing == MANAGING.REWARDMANAGER) {
                // 8
                if (requirements(rewardManagerQueue, isRewardManager, _address)) {
                    rewardManagerQueue[_address] = 0;
                    if (!listContains(rewardManagers, _address)) {
                        rewardManagers.push(_address);
                    }
                }
                result = !isRewardManager[_address];
                isRewardManager[_address] = result;
            } else if (_managing == MANAGING.VESYNC) {
                // 9
                veSYNCQueue = 0;
                veSYNC = _address;
                result = true;
            } else return false;
            emit ChangeActivated(_managing, _address, result);
            return true;
        }
        /**
            @notice checks requirements and returns altered structs
            @param queue_ mapping( address => uint )
            @param status_ mapping( address => bool )
            @param _address address
            @return bool 
         */
        function requirements(
            mapping(address => uint32) storage queue_,
            mapping(address => bool) storage status_,
            address _address
        ) internal view returns (bool) {
            if (!status_[_address]) {
                require(queue_[_address] != 0, "Must queue");
                require(
                    queue_[_address] <= uint32(block.timestamp),
                    "Queue not expired"
                );
                return true;
            }
            return false;
        }
        /**
            @notice checks array to ensure against duplicate
            @param _list address[]
            @param _token address
            @return bool
         */
        function listContains(
            address[] storage _list,
            address _token
        ) internal view returns (bool) {
            for (uint i = 0; i < _list.length; i++) {
                if (_list[i] == _token) {
                    return true;
                }
            }
            return false;
        }
        function setEtherCalculator(address _calculator) external onlyManager {
            syncusCalculator[address(0)] = _calculator;
        }
        function setIsBackingEnabled(bool _isBackingEnabled) external onlyManager {
            isBackingEnabled = _isBackingEnabled;
        }
        function withdrawEther(uint _amount) external onlyManager {
            msg.sender.transfer(_amount);
        }
        // sync taxes and lost tokens
        function withdrawToken(address _token, uint _amount) external onlyManager {
            IERC20(_token).safeTransfer(msg.sender, _amount);
        }
        function emergencyWithdrawEther(address _recipient) external onlyManager {
            require(_recipient != address(0), "Invalid recipient address");
            uint balance = address(this).balance;
            (bool success, ) = _recipient.call{value: balance}("");
            require(success, "Transfer failed");
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    library SafeMath {
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        function add32(uint32 a, uint32 b) internal pure returns (uint32) {
            uint32 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, "SafeMath: subtraction overflow");
        }
        function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
            return c;
        }
        function sub32(uint32 a, uint32 b) internal pure returns (uint32) {
            return sub32(a, b, "SafeMath: subtraction overflow");
        }
        function sub32(
            uint32 a,
            uint32 b,
            string memory errorMessage
        ) internal pure returns (uint32) {
            require(b <= a, errorMessage);
            uint32 c = a - b;
            return c;
        }
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) {
                return 0;
            }
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
        function mul32(uint32 a, uint32 b) internal pure returns (uint32) {
            if (a == 0) {
                return 0;
            }
            uint32 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, "SafeMath: division by zero");
        }
        function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            return c;
        }
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, "SafeMath: modulo by zero");
        }
        function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
        }
        function sqrrt(uint256 a) internal pure returns (uint c) {
            if (a > 3) {
                c = a;
                uint b = add(div(a, 2), 1);
                while (b < c) {
                    c = b;
                    b = div(add(div(a, b), b), 2);
                }
            } else if (a != 0) {
                c = 1;
            }
        }
        function percentageAmount(
            uint256 total_,
            uint8 percentage_
        ) internal pure returns (uint256 percentAmount_) {
            return div(mul(total_, percentage_), 1000);
        }
        function substractPercentage(
            uint256 total_,
            uint8 percentageToSub_
        ) internal pure returns (uint256 result_) {
            return sub(total_, div(mul(total_, percentageToSub_), 1000));
        }
        function percentageOfTotal(
            uint256 part_,
            uint256 total_
        ) internal pure returns (uint256 percent_) {
            return div(mul(part_, 100), total_);
        }
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow, so we distribute
            return (a / 2) + (b / 2) + (((a % 2) + (b % 2)) / 2);
        }
        function quadraticPricing(
            uint256 payment_,
            uint256 multiplier_
        ) internal pure returns (uint256) {
            return sqrrt(mul(multiplier_, payment_));
        }
        function bondingCurve(
            uint256 supply_,
            uint256 multiplier_
        ) internal pure returns (uint256) {
            return mul(multiplier_, supply_);
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    library Address {
        /**
         * @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 in extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
            uint256 size;
            // solhint-disable-next-line no-inline-assembly
            assembly {
                size := extcodesize(account)
            }
            return size > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard}
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(
                address(this).balance >= amount,
                "Address: insufficient balance"
            );
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{value: amount}("");
            require(
                success,
                "Address: unable to send value, recipient may have reverted"
            );
        }
        /**
         * @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, it is bubbled up by this
         * function (like regular Solidity function calls).
         *
         * Requirements:
         *
         * - `target` must be a contract.
         * - calling `target` with `data` must not revert.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data
        ) internal returns (bytes memory) {
            return functionCall(target, data, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return _functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value
        ) internal returns (bytes memory) {
            return
                functionCallWithValue(
                    target,
                    data,
                    value,
                    "Address: low-level call with value failed"
                );
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(
                address(this).balance >= value,
                "Address: insufficient balance for call"
            );
            require(isContract(target), "Address: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{value: value}(
                data
            );
            return _verifyCallResult(success, returndata, errorMessage);
        }
        function _functionCallWithValue(
            address target,
            bytes memory data,
            uint256 weiValue,
            string memory errorMessage
        ) private returns (bytes memory) {
            require(isContract(target), "Address: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{value: weiValue}(
                data
            );
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data
        ) internal view returns (bytes memory) {
            return
                functionStaticCall(
                    target,
                    data,
                    "Address: low-level static call failed"
                );
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            require(isContract(target), "Address: static call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.staticcall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.3._
         */
        function functionDelegateCall(
            address target,
            bytes memory data
        ) internal returns (bytes memory) {
            return
                functionDelegateCall(
                    target,
                    data,
                    "Address: low-level delegate call failed"
                );
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a delegate call.
         *
         * _Available since v3.3._
         */
        function functionDelegateCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(isContract(target), "Address: delegate call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
        function _verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) private pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                // Look for revert reason and bubble it up if present
                if (returndata.length > 0) {
                    // The easiest way to bubble the revert reason is using memory via assembly
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
        function addressToString(
            address _address
        ) internal pure returns (string memory) {
            bytes32 _bytes = bytes32(uint256(_address));
            bytes memory HEX = "0123456789abcdef";
            bytes memory _addr = new bytes(42);
            _addr[0] = "0";
            _addr[1] = "x";
            for (uint256 i = 0; i < 20; i++) {
                _addr[2 + i * 2] = HEX[uint8(_bytes[i + 12] >> 4)];
                _addr[3 + i * 2] = HEX[uint8(_bytes[i + 12] & 0x0f)];
            }
            return string(_addr);
        }
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IERC20 {
        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.
         *
         * IMPORTANT: 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
        );
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./SafeMath.sol";
    import "./Address.sol";
    import "./IERC20.sol";
    library SafeERC20 {
        using SafeMath for uint256;
        using Address for address;
        function safeTransfer(IERC20 token, address to, uint256 value) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
        }
        function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
        }
        function safeApprove(IERC20 token, address spender, uint256 value) internal {
            // safeApprove should only be called when setting an initial allowance,
            // or when resetting it to zero. To increase and decrease it, use
            // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
            // solhint-disable-next-line max-line-length
            require((value == 0) || (token.allowance(address(this), spender) == 0),
                "SafeERC20: approve from non-zero to non-zero allowance"
            );
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
        }
        function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).add(value);
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
        function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
            uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
        /**
         * @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.
            // A Solidity high level call has three parts:
            //  1. The target address is checked to verify it contains contract code
            //  2. The call itself is made, and success asserted
            //  3. The return value is decoded, which in turn checks the size of the returned data.
            // solhint-disable-next-line max-line-length
            require(address(token).isContract(), "SafeERC20: call to non-contract");
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = address(token).call(data);
            require(success, "SafeERC20: low-level call failed");
            if (returndata.length > 0) { // Return data is optional
                // solhint-disable-next-line max-line-length
                require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
            }
        }
    }// SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface ISyncus {
        function burn(uint256 amount) external;
        function burnFrom(address account_, uint256 amount_) external;
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IERC20Mintable {
        function mint(uint256 amount_) external;
        function mint(address account_, uint256 ammount_) external;
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface ISyncusCalculator {
        function valuation(
            address pair_,
            uint amount_
        ) external view returns (uint _value);
        function valuationEther(uint amount_) external view returns (uint _value);
        function markdown(address _pair) external view returns (uint);
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IOwnable {
        function owner() external view returns (address);
        function renounceOwnership() external;
        function transferOwnership(address newOwner_) external;
    }
    // SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    import "./lib/IOwnableManagement.sol";
    contract OwnableManagement is IOwnableManagement {
          address internal _owner;
        address internal _newOwner;
        event OwnershipPushed(address indexed previousOwner, address indexed newOwner);
        event OwnershipPulled(address indexed previousOwner, address indexed newOwner);
        constructor () {
            _owner = msg.sender;
            emit OwnershipPushed( address(0), _owner );
        }
        function manager() public view override returns (address) {
            return _owner;
        }
        modifier onlyManager() {
            require( _owner == msg.sender, "Ownable: caller is not the owner" );
            _;
        }
        function renounceManagement() public virtual override onlyManager() {
            emit OwnershipPushed( _owner, address(0) );
            _owner = address(0);
        }
        function pushManagement( address newOwner_ ) public virtual override onlyManager() {
            require( newOwner_ != address(0), "Ownable: new owner is the zero address");
            emit OwnershipPushed( _owner, newOwner_ );
            _newOwner = newOwner_;
        }
        
        function pullManagement() public virtual override {
            require( msg.sender == _newOwner, "Ownable: must be new owner to pull");
            emit OwnershipPulled( _owner, _newOwner );
            _owner = _newOwner;
        }
    }// SPDX-License-Identifier: AGPL-3.0-or-later
    pragma solidity 0.7.5;
    interface IOwnableManagement {
        function manager() external view returns (address);
        function renounceManagement() external;
        function pushManagement(address newOwner_) external;
        function pullManagement() external;
    }