ETH Price: $3,373.91 (-0.04%)
Gas: 9.53 Gwei

Contract

0x31285A87fB70a62b5AaA43199e53221c197E1e3f
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60a06040154778992022-09-05 12:32:31809 days ago1662381151IN
 Create: BasicBuyCommand
0 ETH0.0179777912.12634005

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BasicBuyCommand

Compiler Version
v0.8.13+commit.abaa5c0e

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 19 : BasicBuyCommand.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

/// BasicBuyCommand.sol

// Copyright (C) 2021-2021 Oazo Apps Limited

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;

import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol";
import { ManagerLike } from "../interfaces/ManagerLike.sol";
import { MPALike } from "../interfaces/MPALike.sol";
import { SpotterLike } from "../interfaces/SpotterLike.sol";
import { RatioUtils } from "../libs/RatioUtils.sol";
import { ServiceRegistry } from "../ServiceRegistry.sol";
import { McdView } from "../McdView.sol";
import { BaseMPACommand } from "./BaseMPACommand.sol";

contract BasicBuyCommand is BaseMPACommand {
    using SafeMath for uint256;
    using RatioUtils for uint256;

    struct BasicBuyTriggerData {
        uint256 cdpId;
        uint16 triggerType;
        uint256 execCollRatio;
        uint256 targetCollRatio;
        uint256 maxBuyPrice;
        bool continuous;
        uint64 deviation;
        uint32 maxBaseFeeInGwei;
    }

    constructor(ServiceRegistry _serviceRegistry) BaseMPACommand(_serviceRegistry) {}

    function decode(bytes memory triggerData) public pure returns (BasicBuyTriggerData memory) {
        return abi.decode(triggerData, (BasicBuyTriggerData));
    }

    function isTriggerDataValid(uint256 _cdpId, bytes memory triggerData)
        external
        view
        returns (bool)
    {
        BasicBuyTriggerData memory trigger = decode(triggerData);

        ManagerLike manager = ManagerLike(serviceRegistry.getRegisteredService(CDP_MANAGER_KEY));
        bytes32 ilk = manager.ilks(trigger.cdpId);
        SpotterLike spot = SpotterLike(serviceRegistry.getRegisteredService(MCD_SPOT_KEY));
        (, uint256 liquidationRatio) = spot.ilks(ilk);

        (uint256 lowerTarget, uint256 upperTarget) = trigger.targetCollRatio.bounds(
            trigger.deviation
        );
        return
            _cdpId == trigger.cdpId &&
            trigger.triggerType == 3 &&
            trigger.execCollRatio > upperTarget &&
            lowerTarget.ray() > liquidationRatio &&
            deviationIsValid(trigger.deviation);
    }

    function isExecutionLegal(uint256 cdpId, bytes memory triggerData)
        external
        view
        returns (bool)
    {
        BasicBuyTriggerData memory trigger = decode(triggerData);

        (
            ,
            uint256 nextCollRatio,
            uint256 currPrice,
            uint256 nextPrice,
            bytes32 ilk
        ) = getVaultAndMarketInfo(cdpId);

        SpotterLike spot = SpotterLike(serviceRegistry.getRegisteredService(MCD_SPOT_KEY));
        (, uint256 liquidationRatio) = spot.ilks(ilk);

        return
            nextCollRatio >= trigger.execCollRatio.wad() &&
            nextPrice <= trigger.maxBuyPrice &&
            trigger.targetCollRatio.wad().mul(currPrice).div(nextPrice) >
            liquidationRatio.rayToWad() &&
            baseFeeIsValid(trigger.maxBaseFeeInGwei);
    }

    function execute(
        bytes calldata executionData,
        uint256 cdpId,
        bytes memory triggerData
    ) external {
        BasicBuyTriggerData memory trigger = decode(triggerData);

        validateTriggerType(trigger.triggerType, 3);
        validateSelector(MPALike.increaseMultiple.selector, executionData);

        executeMPAMethod(executionData);

        if (trigger.continuous) {
            recreateTrigger(cdpId, trigger.triggerType, triggerData);
        }
    }

    function isExecutionCorrect(uint256 cdpId, bytes memory triggerData)
        external
        view
        returns (bool)
    {
        BasicBuyTriggerData memory trigger = decode(triggerData);

        McdView mcdView = McdView(serviceRegistry.getRegisteredService(MCD_VIEW_KEY));
        uint256 nextCollRatio = mcdView.getRatio(cdpId, true);

        (uint256 lowerTarget, uint256 upperTarget) = trigger.targetCollRatio.bounds(
            trigger.deviation
        );

        return nextCollRatio <= upperTarget.wad() && nextCollRatio >= lowerTarget.wad();
    }
}

File 2 of 19 : SafeMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeMath.sol)

pragma solidity ^0.8.0;

// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.

/**
 * @dev Wrappers over Solidity's arithmetic operations.
 *
 * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
 * now has built in overflow checking.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return a + b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return a - b;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

File 3 of 19 : ManagerLike.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface ManagerLike {
    function cdpCan(
        address owner,
        uint256 cdpId,
        address allowedAddr
    ) external view returns (uint256);

    function vat() external view returns (address);

    function ilks(uint256) external view returns (bytes32);

    function owns(uint256) external view returns (address);

    function urns(uint256) external view returns (address);

    function cdpAllow(
        uint256 cdp,
        address usr,
        uint256 ok
    ) external;

    function frob(
        uint256,
        int256,
        int256
    ) external;

    function flux(
        uint256,
        address,
        uint256
    ) external;

    function move(
        uint256,
        address,
        uint256
    ) external;

    function exit(
        address,
        uint256,
        address,
        uint256
    ) external;
}

File 4 of 19 : MPALike.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface MPALike {
    struct CdpData {
        address gemJoin;
        address payable fundsReceiver;
        uint256 cdpId;
        bytes32 ilk;
        uint256 requiredDebt;
        uint256 borrowCollateral;
        uint256 withdrawCollateral;
        uint256 withdrawDai;
        uint256 depositDai;
        uint256 depositCollateral;
        bool skipFL;
        string methodName;
    }

    struct AddressRegistry {
        address jug;
        address manager;
        address multiplyProxyActions;
        address lender;
        address exchange;
    }

    struct ExchangeData {
        address fromTokenAddress;
        address toTokenAddress;
        uint256 fromTokenAmount;
        uint256 toTokenAmount;
        uint256 minToTokenAmount;
        address exchangeAddress;
        bytes _exchangeCalldata;
    }

    function increaseMultiple(
        ExchangeData calldata exchangeData,
        CdpData memory cdpData,
        AddressRegistry calldata addressRegistry
    ) external;

    function decreaseMultiple(
        ExchangeData calldata exchangeData,
        CdpData memory cdpData,
        AddressRegistry calldata addressRegistry
    ) external;

    function closeVaultExitCollateral(
        ExchangeData calldata exchangeData,
        CdpData memory cdpData,
        AddressRegistry calldata addressRegistry
    ) external;

    function closeVaultExitDai(
        ExchangeData calldata exchangeData,
        CdpData memory cdpData,
        AddressRegistry calldata addressRegistry
    ) external;
}

File 5 of 19 : SpotterLike.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface IPipInterface {
    function read() external returns (bytes32);
}

interface SpotterLike {
    function ilks(bytes32) external view returns (IPipInterface pip, uint256 mat);

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

File 6 of 19 : RatioUtils.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

/// BasicBuyCommand.sol

// Copyright (C) 2021-2021 Oazo Apps Limited

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;

import { SafeMath } from "@openzeppelin/contracts/utils/math/SafeMath.sol";

library RatioUtils {
    using SafeMath for uint256;

    uint256 public constant RATIO = 10**4;
    uint256 public constant WAD = 10**18;
    uint256 public constant RAY = 10**27;
    uint256 public constant RAD = 10**45;

    // convert base units to ratio
    function toRatio(uint256 units) internal pure returns (uint256) {
        return units.mul(RATIO);
    }

    function wad(uint256 ratio) internal pure returns (uint256) {
        return ratio.mul(WAD).div(RATIO);
    }

    function ray(uint256 ratio) internal pure returns (uint256) {
        return ratio.mul(RAY).div(RATIO);
    }

    function bounds(uint256 ratio, uint64 deviation)
        internal
        pure
        returns (uint256 lower, uint256 upper)
    {
        uint256 offset = ratio.mul(deviation).div(RATIO);
        return (ratio.sub(offset), ratio.add(offset));
    }

    function rayToWad(uint256 _ray) internal pure returns (uint256 _wad) {
        _wad = _ray.mul(WAD).div(RAY);
    }

    function wadToRay(uint256 _wad) internal pure returns (uint256 _ray) {
        _ray = _wad.mul(RAY).div(WAD);
    }

    function radToWad(uint256 _rad) internal pure returns (uint256 _wad) {
        _wad = _rad.mul(WAD).div(RAD);
    }

    function wadToRad(uint256 _wad) internal pure returns (uint256 _rad) {
        _rad = _wad.mul(RAD).div(WAD);
    }
}

File 7 of 19 : ServiceRegistry.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

/// ServiceRegistry.sol

// Copyright (C) 2021-2021 Oazo Apps Limited

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;

contract ServiceRegistry {
    uint256 public constant MAX_DELAY = 30 days;

    mapping(bytes32 => uint256) public lastExecuted;
    mapping(bytes32 => address) private namedService;
    address public owner;
    uint256 public requiredDelay;

    modifier validateInput(uint256 len) {
        require(msg.data.length == len, "registry/illegal-padding");
        _;
    }

    modifier delayedExecution() {
        bytes32 operationHash = keccak256(msg.data);
        uint256 reqDelay = requiredDelay;

        /* solhint-disable not-rely-on-time */
        if (lastExecuted[operationHash] == 0 && reqDelay > 0) {
            // not called before, scheduled for execution
            lastExecuted[operationHash] = block.timestamp;
            emit ChangeScheduled(operationHash, block.timestamp + reqDelay, msg.data);
        } else {
            require(
                block.timestamp - reqDelay > lastExecuted[operationHash],
                "registry/delay-too-small"
            );
            emit ChangeApplied(operationHash, block.timestamp, msg.data);
            _;
            lastExecuted[operationHash] = 0;
        }
        /* solhint-enable not-rely-on-time */
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "registry/only-owner");
        _;
    }

    constructor(uint256 initialDelay) {
        require(initialDelay <= MAX_DELAY, "registry/invalid-delay");
        requiredDelay = initialDelay;
        owner = msg.sender;
    }

    function transferOwnership(address newOwner)
        external
        onlyOwner
        validateInput(36)
        delayedExecution
    {
        owner = newOwner;
    }

    function changeRequiredDelay(uint256 newDelay)
        external
        onlyOwner
        validateInput(36)
        delayedExecution
    {
        require(newDelay <= MAX_DELAY, "registry/invalid-delay");
        requiredDelay = newDelay;
    }

    function getServiceNameHash(string memory name) external pure returns (bytes32) {
        return keccak256(abi.encodePacked(name));
    }

    function addNamedService(bytes32 serviceNameHash, address serviceAddress)
        external
        onlyOwner
        validateInput(68)
        delayedExecution
    {
        require(namedService[serviceNameHash] == address(0), "registry/service-override");
        namedService[serviceNameHash] = serviceAddress;
    }

    function updateNamedService(bytes32 serviceNameHash, address serviceAddress)
        external
        onlyOwner
        validateInput(68)
        delayedExecution
    {
        require(namedService[serviceNameHash] != address(0), "registry/service-does-not-exist");
        namedService[serviceNameHash] = serviceAddress;
    }

    function removeNamedService(bytes32 serviceNameHash) external onlyOwner validateInput(36) {
        require(namedService[serviceNameHash] != address(0), "registry/service-does-not-exist");
        namedService[serviceNameHash] = address(0);
        emit NamedServiceRemoved(serviceNameHash);
    }

    function getRegisteredService(string memory serviceName) external view returns (address) {
        return namedService[keccak256(abi.encodePacked(serviceName))];
    }

    function getServiceAddress(bytes32 serviceNameHash) external view returns (address) {
        return namedService[serviceNameHash];
    }

    function clearScheduledExecution(bytes32 scheduledExecution)
        external
        onlyOwner
        validateInput(36)
    {
        require(lastExecuted[scheduledExecution] > 0, "registry/execution-not-scheduled");
        lastExecuted[scheduledExecution] = 0;
        emit ChangeCancelled(scheduledExecution);
    }

    event ChangeScheduled(bytes32 dataHash, uint256 scheduledFor, bytes data);
    event ChangeApplied(bytes32 dataHash, uint256 appliedAt, bytes data);
    event ChangeCancelled(bytes32 dataHash);
    event NamedServiceRemoved(bytes32 nameHash);
}

File 8 of 19 : McdView.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

/// McdView.sol

// Copyright (C) 2021-2021 Oazo Apps Limited

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;
import "./interfaces/ManagerLike.sol";
import "./interfaces/ICommand.sol";
import "./interfaces/BotLike.sol";
import "./ServiceRegistry.sol";

import "./interfaces/SpotterLike.sol";
import "./interfaces/VatLike.sol";
import "./interfaces/OsmMomLike.sol";
import "./interfaces/OsmLike.sol";
import "./external/DSMath.sol";

/// @title Getter contract for Vault info from Maker protocol
contract McdView is DSMath {
    ManagerLike public manager;
    VatLike public vat;
    SpotterLike public spotter;
    OsmMomLike public osmMom;
    address public owner;
    mapping(address => bool) public whitelisted;

    constructor(
        address _vat,
        address _manager,
        address _spotter,
        address _mom,
        address _owner
    ) {
        manager = ManagerLike(_manager);
        vat = VatLike(_vat);
        spotter = SpotterLike(_spotter);
        osmMom = OsmMomLike(_mom);
        owner = _owner;
    }

    function approve(address _allowedReader, bool isApproved) external {
        require(msg.sender == owner, "mcd-view/not-authorised");
        whitelisted[_allowedReader] = isApproved;
    }

    /// @notice Gets Vault info (collateral, debt)
    /// @param vaultId Id of the Vault
    function getVaultInfo(uint256 vaultId) public view returns (uint256, uint256) {
        address urn = manager.urns(vaultId);
        bytes32 ilk = manager.ilks(vaultId);

        (uint256 collateral, uint256 debt) = vat.urns(ilk, urn);
        (, uint256 rate, , , ) = vat.ilks(ilk);

        return (collateral, rmul(debt, rate));
    }

    /// @notice Gets a price of the asset
    /// @param ilk Ilk of the Vault
    function getPrice(bytes32 ilk) public view returns (uint256) {
        (, uint256 mat) = spotter.ilks(ilk);
        (, , uint256 spot, , ) = vat.ilks(ilk);

        return div(rmul(rmul(spot, spotter.par()), mat), 10**9);
    }

    /// @notice Gets oracle next price of the asset
    /// @param ilk Ilk of the Vault
    function getNextPrice(bytes32 ilk) public view returns (uint256) {
        require(whitelisted[msg.sender], "mcd-view/not-whitelisted");
        OsmLike osm = OsmLike(osmMom.osms(ilk));
        (bytes32 val, bool status) = osm.peep();
        require(status, "mcd-view/osm-price-error");
        return uint256(val);
    }

    /// @notice Gets Vaults ratio
    /// @param vaultId Id of the Vault
    function getRatio(uint256 vaultId, bool useNextPrice) public view returns (uint256) {
        bytes32 ilk = manager.ilks(vaultId);
        uint256 price = useNextPrice ? getNextPrice(ilk) : getPrice(ilk);
        (uint256 collateral, uint256 debt) = getVaultInfo(vaultId);
        if (debt == 0) return 0;
        return wdiv(wmul(collateral, price), debt);
    }
}

File 9 of 19 : BaseMPACommand.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

/// BaseMPACommand.sol

// Copyright (C) 2021-2021 Oazo Apps Limited

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

pragma solidity ^0.8.0;

import { RatioUtils } from "../libs/RatioUtils.sol";
import { ICommand } from "../interfaces/ICommand.sol";
import { ManagerLike } from "../interfaces/ManagerLike.sol";
import { ServiceRegistry } from "../ServiceRegistry.sol";
import { McdView } from "../McdView.sol";
import { AutomationBot } from "../AutomationBot.sol";

abstract contract BaseMPACommand is ICommand {
    using RatioUtils for uint256;

    string public constant MCD_VIEW_KEY = "MCD_VIEW";
    string public constant CDP_MANAGER_KEY = "CDP_MANAGER";
    string public constant MPA_KEY = "MULTIPLY_PROXY_ACTIONS";
    string public constant MCD_SPOT_KEY = "MCD_SPOT";
    string public constant MCD_VAT_KEY = "MCD_VAT";
    string private constant AUTOMATION_BOT_KEY = "AUTOMATION_BOT";

    uint256 public constant MIN_ALLOWED_DEVIATION = 50;

    ServiceRegistry public immutable serviceRegistry;

    constructor(ServiceRegistry _serviceRegistry) {
        serviceRegistry = _serviceRegistry;
    }

    function getVaultAndMarketInfo(uint256 cdpId)
        public
        view
        returns (
            uint256 collRatio,
            uint256 nextCollRatio,
            uint256 currPrice,
            uint256 nextPrice,
            bytes32 ilk
        )
    {
        ManagerLike manager = ManagerLike(serviceRegistry.getRegisteredService(CDP_MANAGER_KEY));
        ilk = manager.ilks(cdpId);

        McdView mcdView = McdView(serviceRegistry.getRegisteredService(MCD_VIEW_KEY));
        collRatio = mcdView.getRatio(cdpId, false);
        nextCollRatio = mcdView.getRatio(cdpId, true);
        currPrice = mcdView.getPrice(ilk);
        nextPrice = mcdView.getNextPrice(ilk);
    }

    function getVaultDebt(uint256 cdpId) internal view returns (uint256) {
        McdView mcdView = McdView(serviceRegistry.getRegisteredService(MCD_VIEW_KEY));
        (, uint256 debt) = mcdView.getVaultInfo(cdpId);
        return debt;
    }

    function baseFeeIsValid(uint256 maxAcceptableBaseFeeInGwei) public view returns (bool) {
        return block.basefee <= maxAcceptableBaseFeeInGwei * (10**9);
    }

    function deviationIsValid(uint256 deviation) public pure returns (bool) {
        return deviation >= MIN_ALLOWED_DEVIATION;
    }

    function validateTriggerType(uint16 triggerType, uint16 expectedTriggerType) public pure {
        require(triggerType == expectedTriggerType, "base-mpa-command/type-not-supported");
    }

    function validateSelector(bytes4 expectedSelector, bytes memory executionData) public pure {
        bytes4 selector = abi.decode(executionData, (bytes4));
        require(selector == expectedSelector, "base-mpa-command/invalid-selector");
    }

    function executeMPAMethod(bytes memory executionData) internal {
        (bool status, bytes memory reason) = serviceRegistry
            .getRegisteredService(MPA_KEY)
            .delegatecall(executionData);
        require(status, string(reason));
    }

    function recreateTrigger(
        uint256 cdpId,
        uint16 triggerType,
        bytes memory triggerData
    ) internal virtual {
        address automationBot = serviceRegistry.getRegisteredService(AUTOMATION_BOT_KEY);
        (bool status, ) = (automationBot).delegatecall(
            abi.encodeWithSelector(
                AutomationBot(msg.sender).addTrigger.selector,
                cdpId,
                triggerType,
                0,
                triggerData
            )
        );
        require(status, "base-mpa-command/trigger-recreation-failed");
    }
}

File 10 of 19 : ICommand.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface ICommand {
    function isTriggerDataValid(uint256 _cdpId, bytes memory triggerData)
        external
        view
        returns (bool);

    function isExecutionCorrect(uint256 cdpId, bytes memory triggerData)
        external
        view
        returns (bool);

    function isExecutionLegal(uint256 cdpId, bytes memory triggerData) external view returns (bool);

    function execute(
        bytes calldata executionData,
        uint256 cdpId,
        bytes memory triggerData
    ) external;
}

File 11 of 19 : BotLike.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface BotLike {
    function addRecord(
        uint256 cdpId,
        uint256 triggerType,
        uint256 replacedTriggerId,
        bytes memory triggerData
    ) external;

    function removeRecord(
        // This function should be executed allways in a context of AutomationBot address not DsProxy,
        //msg.sender should be dsProxy
        uint256 cdpId,
        uint256 triggerId
    ) external;

    function execute(
        bytes calldata executionData,
        uint256 cdpId,
        bytes calldata triggerData,
        address commandAddress,
        uint256 triggerId,
        uint256 daiCoverage
    ) external;
}

File 12 of 19 : VatLike.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface VatLike {
    function urns(bytes32, address) external view returns (uint256 ink, uint256 art);

    function ilks(bytes32)
        external
        view
        returns (
            uint256 art, // Total Normalised Debt      [wad]
            uint256 rate, // Accumulated Rates         [ray]
            uint256 spot, // Price with Safety Margin  [ray]
            uint256 line, // Debt Ceiling              [rad]
            uint256 dust // Urn Debt Floor             [rad]
        );

    function gem(bytes32, address) external view returns (uint256); // [wad]

    function can(address, address) external view returns (uint256);

    function dai(address) external view returns (uint256);

    function frob(
        bytes32,
        address,
        address,
        address,
        int256,
        int256
    ) external;

    function hope(address) external;

    function move(
        address,
        address,
        uint256
    ) external;

    function fork(
        bytes32,
        address,
        address,
        int256,
        int256
    ) external;
}

File 13 of 19 : OsmMomLike.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface OsmMomLike {
    function osms(bytes32) external view returns (address);
}

File 14 of 19 : OsmLike.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

interface OsmLike {
    function peep() external view returns (bytes32, bool);

    function bud(address) external view returns (uint256);

    function kiss(address a) external;
}

File 15 of 19 : DSMath.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

contract DSMath {
    function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x + y) >= x, "");
    }

    function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require((z = x - y) <= x, "");
    }

    function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        require(y == 0 || (z = x * y) / y == x, "");
    }

    function div(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x / y;
    }

    function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x <= y ? x : y;
    }

    function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
        return x >= y ? x : y;
    }

    function imin(int256 x, int256 y) internal pure returns (int256 z) {
        return x <= y ? x : y;
    }

    function imax(int256 x, int256 y) internal pure returns (int256 z) {
        return x >= y ? x : y;
    }

    uint256 internal constant WAD = 10**18;
    uint256 internal constant RAY = 10**27;

    function wmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, y), WAD / 2) / WAD;
    }

    function rmul(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, y), RAY / 2) / RAY;
    }

    function wdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, WAD), y / 2) / y;
    }

    function rdiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        z = add(mul(x, RAY), y / 2) / y;
    }

    // This famous algorithm is called "exponentiation by squaring"
    // and calculates x^n with x as fixed-point and n as regular unsigned.
    //
    // It's O(log n), instead of O(n) for naive repeated multiplication.
    //
    // These facts are why it works:
    //
    //  If n is even, then x^n = (x^2)^(n/2).
    //  If n is odd,  then x^n = x * x^(n-1),
    //   and applying the equation for even x gives
    //    x^n = x * (x^2)^((n-1) / 2).
    //
    //  Also, EVM division is flooring and
    //    floor[(n-1) / 2] = floor[n / 2].
    //
    function rpow(uint256 x, uint256 n) internal pure returns (uint256 z) {
        z = n % 2 != 0 ? x : RAY;

        for (n /= 2; n != 0; n /= 2) {
            x = rmul(x, x);

            if (n % 2 != 0) {
                z = rmul(z, x);
            }
        }
    }
}

File 16 of 19 : AutomationBot.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

/// AutomationBot.sol

// Copyright (C) 2021-2021 Oazo Apps Limited

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;

import "./interfaces/ManagerLike.sol";
import "./interfaces/ICommand.sol";
import "./interfaces/BotLike.sol";
import "./ServiceRegistry.sol";
import "./McdUtils.sol";

contract AutomationBot {
    struct TriggerRecord {
        bytes32 triggerHash;
        uint256 cdpId;
    }

    string private constant CDP_MANAGER_KEY = "CDP_MANAGER";
    string private constant AUTOMATION_BOT_KEY = "AUTOMATION_BOT";
    string private constant AUTOMATION_EXECUTOR_KEY = "AUTOMATION_EXECUTOR";
    string private constant MCD_UTILS_KEY = "MCD_UTILS";

    mapping(uint256 => TriggerRecord) public activeTriggers;

    uint256 public triggersCounter = 0;

    ServiceRegistry public immutable serviceRegistry;
    address public immutable self;

    constructor(ServiceRegistry _serviceRegistry) {
        serviceRegistry = _serviceRegistry;
        self = address(this);
    }

    modifier auth(address caller) {
        require(
            serviceRegistry.getRegisteredService(AUTOMATION_EXECUTOR_KEY) == caller,
            "bot/not-executor"
        );
        _;
    }

    modifier onlyDelegate() {
        require(address(this) != self, "bot/only-delegate");
        _;
    }

    // works correctly in any context
    function validatePermissions(
        uint256 cdpId,
        address operator,
        ManagerLike manager
    ) private view {
        require(isCdpOwner(cdpId, operator, manager), "bot/no-permissions");
    }

    // works correctly in any context
    function isCdpAllowed(
        uint256 cdpId,
        address operator,
        ManagerLike manager
    ) public view returns (bool) {
        address cdpOwner = manager.owns(cdpId);
        return (manager.cdpCan(cdpOwner, cdpId, operator) == 1) || (operator == cdpOwner);
    }

    // works correctly in any context
    function isCdpOwner(
        uint256 cdpId,
        address operator,
        ManagerLike manager
    ) private view returns (bool) {
        return (operator == manager.owns(cdpId));
    }

    // works correctly in any context
    function getCommandAddress(uint256 triggerType) public view returns (address) {
        bytes32 commandHash = keccak256(abi.encode("Command", triggerType));

        address commandAddress = serviceRegistry.getServiceAddress(commandHash);

        return commandAddress;
    }

    // works correctly in any context
    function getTriggersHash(
        uint256 cdpId,
        bytes memory triggerData,
        address commandAddress
    ) private view returns (bytes32) {
        bytes32 triggersHash = keccak256(
            abi.encodePacked(cdpId, triggerData, serviceRegistry, commandAddress)
        );

        return triggersHash;
    }

    // works correctly in context of Automation Bot
    function checkTriggersExistenceAndCorrectness(
        uint256 cdpId,
        uint256 triggerId,
        address commandAddress,
        bytes memory triggerData
    ) private view {
        bytes32 triggersHash = activeTriggers[triggerId].triggerHash;

        require(
            triggersHash != bytes32(0) &&
                triggersHash == getTriggersHash(cdpId, triggerData, commandAddress),
            "bot/invalid-trigger"
        );
    }

    function checkTriggersExistenceAndCorrectness(uint256 cdpId, uint256 triggerId) private view {
        require(activeTriggers[triggerId].cdpId == cdpId, "bot/invalid-trigger");
    }

    // works correctly in context of automationBot
    function addRecord(
        // This function should be executed allways in a context of AutomationBot address not DsProxy,
        // msg.sender should be dsProxy
        uint256 cdpId,
        uint256 triggerType,
        uint256 replacedTriggerId,
        bytes memory triggerData
    ) external {
        ManagerLike manager = ManagerLike(serviceRegistry.getRegisteredService(CDP_MANAGER_KEY));
        address commandAddress = getCommandAddress(triggerType);

        require(
            ICommand(commandAddress).isTriggerDataValid(cdpId, triggerData),
            "bot/invalid-trigger-data"
        );

        require(isCdpAllowed(cdpId, msg.sender, manager), "bot/no-permissions");

        triggersCounter = triggersCounter + 1;
        activeTriggers[triggersCounter] = TriggerRecord(
            getTriggersHash(cdpId, triggerData, commandAddress),
            cdpId
        );

        if (replacedTriggerId != 0) {
            require(
                activeTriggers[replacedTriggerId].cdpId == cdpId,
                "bot/trigger-removal-illegal"
            );
            activeTriggers[replacedTriggerId] = TriggerRecord(0, 0);
            emit TriggerRemoved(cdpId, replacedTriggerId);
        }
        emit TriggerAdded(triggersCounter, commandAddress, cdpId, triggerData);
    }

    // works correctly in context of automationBot
    function removeRecord(
        // This function should be executed allways in a context of AutomationBot address not DsProxy,
        // msg.sender should be dsProxy
        uint256 cdpId,
        uint256 triggerId
    ) external {
        address managerAddress = serviceRegistry.getRegisteredService(CDP_MANAGER_KEY);

        require(isCdpAllowed(cdpId, msg.sender, ManagerLike(managerAddress)), "bot/no-permissions");
        // validatePermissions(cdpId, msg.sender, ManagerLike(managerAddress));

        checkTriggersExistenceAndCorrectness(cdpId, triggerId);

        activeTriggers[triggerId] = TriggerRecord(0, 0);
        emit TriggerRemoved(cdpId, triggerId);
    }

    //works correctly in context of dsProxy
    function addTrigger(
        uint256 cdpId,
        uint256 triggerType,
        uint256 replacedTriggerId,
        bytes memory triggerData
    ) external onlyDelegate {
        // TODO: consider adding isCdpAllow add flag in tx payload, make sense from extensibility perspective
        ManagerLike manager = ManagerLike(serviceRegistry.getRegisteredService(CDP_MANAGER_KEY));

        address automationBot = serviceRegistry.getRegisteredService(AUTOMATION_BOT_KEY);
        BotLike(automationBot).addRecord(cdpId, triggerType, replacedTriggerId, triggerData);
        if (!isCdpAllowed(cdpId, automationBot, manager)) {
            manager.cdpAllow(cdpId, automationBot, 1);
            emit ApprovalGranted(cdpId, automationBot);
        }
    }

    //works correctly in context of dsProxy

    // TODO: removeAllowance parameter of this method moves responsibility to decide on this to frontend.
    // In case of a bug on frontend allowance might be revoked by setting this parameter to `true`
    // despite there still be some active triggers which will be disables by this call.
    // One of the solutions is to add counter of active triggers and revoke allowance only if last trigger is being deleted
    function removeTrigger(
        uint256 cdpId,
        uint256 triggerId,
        bool removeAllowance
    ) external onlyDelegate {
        address managerAddress = serviceRegistry.getRegisteredService(CDP_MANAGER_KEY);
        ManagerLike manager = ManagerLike(managerAddress);

        address automationBot = serviceRegistry.getRegisteredService(AUTOMATION_BOT_KEY);

        BotLike(automationBot).removeRecord(cdpId, triggerId);

        if (removeAllowance) {
            manager.cdpAllow(cdpId, automationBot, 0);
            emit ApprovalRemoved(cdpId, automationBot);
        }

        emit TriggerRemoved(cdpId, triggerId);
    }

    //works correctly in context of dsProxy
    function removeApproval(ServiceRegistry _serviceRegistry, uint256 cdpId) external onlyDelegate {
        address approvedEntity = changeApprovalStatus(_serviceRegistry, cdpId, 0);
        emit ApprovalRemoved(cdpId, approvedEntity);
    }

    //works correctly in context of dsProxy
    function grantApproval(ServiceRegistry _serviceRegistry, uint256 cdpId) external onlyDelegate {
        address approvedEntity = changeApprovalStatus(_serviceRegistry, cdpId, 1);
        emit ApprovalGranted(cdpId, approvedEntity);
    }

    //works correctly in context of dsProxy
    function changeApprovalStatus(
        ServiceRegistry _serviceRegistry,
        uint256 cdpId,
        uint256 status
    ) private returns (address) {
        address managerAddress = _serviceRegistry.getRegisteredService(CDP_MANAGER_KEY);
        ManagerLike manager = ManagerLike(managerAddress);
        address automationBot = _serviceRegistry.getRegisteredService(AUTOMATION_BOT_KEY);
        require(
            isCdpAllowed(cdpId, automationBot, manager) != (status == 1),
            "bot/approval-unchanged"
        );
        validatePermissions(cdpId, address(this), manager);
        manager.cdpAllow(cdpId, automationBot, status);
        return automationBot;
    }

    function drawDaiFromVault(
        uint256 cdpId,
        ManagerLike manager,
        uint256 daiCoverage
    ) internal {
        address utilsAddress = serviceRegistry.getRegisteredService(MCD_UTILS_KEY);

        McdUtils utils = McdUtils(utilsAddress);
        manager.cdpAllow(cdpId, utilsAddress, 1);
        utils.drawDebt(daiCoverage, cdpId, manager, msg.sender);
        manager.cdpAllow(cdpId, utilsAddress, 0);
    }

    //works correctly in context of automationBot
    function execute(
        bytes calldata executionData,
        uint256 cdpId,
        bytes calldata triggerData,
        address commandAddress,
        uint256 triggerId,
        uint256 daiCoverage
    ) external auth(msg.sender) {
        checkTriggersExistenceAndCorrectness(cdpId, triggerId, commandAddress, triggerData);
        ManagerLike manager = ManagerLike(serviceRegistry.getRegisteredService(CDP_MANAGER_KEY));
        drawDaiFromVault(cdpId, manager, daiCoverage);

        ICommand command = ICommand(commandAddress);
        require(command.isExecutionLegal(cdpId, triggerData), "bot/trigger-execution-illegal");

        manager.cdpAllow(cdpId, commandAddress, 1);
        command.execute(executionData, cdpId, triggerData);
        activeTriggers[triggerId] = TriggerRecord(0, 0);
        manager.cdpAllow(cdpId, commandAddress, 0);

        require(command.isExecutionCorrect(cdpId, triggerData), "bot/trigger-execution-wrong");

        emit TriggerExecuted(triggerId, cdpId, executionData);
    }

    event ApprovalRemoved(uint256 indexed cdpId, address approvedEntity);

    event ApprovalGranted(uint256 indexed cdpId, address approvedEntity);

    event TriggerRemoved(uint256 indexed cdpId, uint256 indexed triggerId);

    event TriggerAdded(
        uint256 indexed triggerId,
        address indexed commandAddress,
        uint256 indexed cdpId,
        bytes triggerData
    );

    event TriggerExecuted(uint256 indexed triggerId, uint256 indexed cdpId, bytes executionData);
}

File 17 of 19 : McdUtils.sol
// SPDX-License-Identifier: AGPL-3.0-or-later

/// McdUtils.sol

// Copyright (C) 2021-2021 Oazo Apps Limited

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
pragma solidity ^0.8.0;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./external/DSMath.sol";
import "./interfaces/ManagerLike.sol";
import "./interfaces/ICommand.sol";
import "./interfaces/Mcd.sol";
import "./interfaces/BotLike.sol";

import "./ServiceRegistry.sol";

/// @title Getter contract for Vault info from Maker protocol
contract McdUtils is DSMath {
    address public immutable serviceRegistry;
    IERC20 private immutable DAI;
    address private immutable daiJoin;
    address public immutable jug;

    constructor(
        address _serviceRegistry,
        IERC20 _dai,
        address _daiJoin,
        address _jug
    ) {
        serviceRegistry = _serviceRegistry;
        DAI = _dai;
        daiJoin = _daiJoin;
        jug = _jug;
    }

    function toInt256(uint256 x) internal pure returns (int256 y) {
        y = int256(x);
        require(y >= 0, "int256-overflow");
    }

    function _getDrawDart(
        address vat,
        address urn,
        bytes32 ilk,
        uint256 wad
    ) internal returns (int256 dart) {
        // Updates stability fee rate
        uint256 rate = IJug(jug).drip(ilk);

        // Gets DAI balance of the urn in the vat
        uint256 dai = IVat(vat).dai(urn);

        // If there was already enough DAI in the vat balance, just exits it without adding more debt
        if (dai < mul(wad, RAY)) {
            // Calculates the needed dart so together with the existing dai in the vat is enough to exit wad amount of DAI tokens
            dart = toInt256(sub(mul(wad, RAY), dai) / rate);
            // This is neeeded due lack of precision. It might need to sum an extra dart wei (for the given DAI wad amount)
            dart = mul(uint256(dart), rate) < mul(wad, RAY) ? dart + 1 : dart;
        }
    }

    function drawDebt(
        uint256 borrowedDai,
        uint256 cdpId,
        ManagerLike manager,
        address sendTo
    ) external {
        address urn = manager.urns(cdpId);
        address vat = manager.vat();

        manager.frob(cdpId, 0, _getDrawDart(vat, urn, manager.ilks(cdpId), borrowedDai));
        manager.move(cdpId, address(this), mul(borrowedDai, RAY));

        if (IVat(vat).can(address(this), daiJoin) == 0) {
            IVat(vat).hope(daiJoin);
        }

        IJoin(daiJoin).exit(sendTo, borrowedDai);
    }
}

File 18 of 19 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

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

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

File 19 of 19 : Mcd.sol
//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

abstract contract IVat {
    struct Urn {
        uint256 ink; // Locked Collateral  [wad]
        uint256 art; // Normalised Debt    [wad]
    }

    struct Ilk {
        uint256 Art; // Total Normalised Debt     [wad]
        uint256 rate; // Accumulated Rates         [ray]
        uint256 spot; // Price with Safety Margin  [ray]
        uint256 line; // Debt Ceiling              [rad]
        uint256 dust; // Urn Debt Floor            [rad]
    }

    mapping(bytes32 => mapping(address => Urn)) public urns;
    mapping(bytes32 => Ilk) public ilks;
    mapping(bytes32 => mapping(address => uint256)) public gem; // [wad]

    function can(address, address) public view virtual returns (uint256);

    function dai(address) public view virtual returns (uint256);

    function frob(
        bytes32,
        address,
        address,
        address,
        int256,
        int256
    ) public virtual;

    function hope(address) public virtual;

    function move(
        address,
        address,
        uint256
    ) public virtual;

    function fork(
        bytes32,
        address,
        address,
        int256,
        int256
    ) public virtual;
}

abstract contract IGem {
    function dec() public virtual returns (uint256);

    function gem() public virtual returns (IGem);

    function join(address, uint256) public payable virtual;

    function exit(address, uint256) public virtual;

    function approve(address, uint256) public virtual;

    function transfer(address, uint256) public virtual returns (bool);

    function transferFrom(
        address,
        address,
        uint256
    ) public virtual returns (bool);

    function deposit() public payable virtual;

    function withdraw(uint256) public virtual;

    function allowance(address, address) public virtual returns (uint256);
}

abstract contract IJoin {
    bytes32 public ilk;

    function dec() public view virtual returns (uint256);

    function gem() public view virtual returns (IGem);

    function join(address, uint256) public payable virtual;

    function exit(address, uint256) public virtual;
}

abstract contract IDaiJoin {
    function vat() public virtual returns (IVat);

    function dai() public virtual returns (IGem);

    function join(address, uint256) public payable virtual;

    function exit(address, uint256) public virtual;
}

abstract contract IJug {
    struct Ilk {
        uint256 duty;
        uint256 rho;
    }

    mapping(bytes32 => Ilk) public ilks;

    function drip(bytes32) public virtual returns (uint256);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract ServiceRegistry","name":"_serviceRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CDP_MANAGER_KEY","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MCD_SPOT_KEY","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MCD_VAT_KEY","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MCD_VIEW_KEY","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_ALLOWED_DEVIATION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MPA_KEY","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxAcceptableBaseFeeInGwei","type":"uint256"}],"name":"baseFeeIsValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"decode","outputs":[{"components":[{"internalType":"uint256","name":"cdpId","type":"uint256"},{"internalType":"uint16","name":"triggerType","type":"uint16"},{"internalType":"uint256","name":"execCollRatio","type":"uint256"},{"internalType":"uint256","name":"targetCollRatio","type":"uint256"},{"internalType":"uint256","name":"maxBuyPrice","type":"uint256"},{"internalType":"bool","name":"continuous","type":"bool"},{"internalType":"uint64","name":"deviation","type":"uint64"},{"internalType":"uint32","name":"maxBaseFeeInGwei","type":"uint32"}],"internalType":"struct BasicBuyCommand.BasicBuyTriggerData","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"deviation","type":"uint256"}],"name":"deviationIsValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"executionData","type":"bytes"},{"internalType":"uint256","name":"cdpId","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cdpId","type":"uint256"}],"name":"getVaultAndMarketInfo","outputs":[{"internalType":"uint256","name":"collRatio","type":"uint256"},{"internalType":"uint256","name":"nextCollRatio","type":"uint256"},{"internalType":"uint256","name":"currPrice","type":"uint256"},{"internalType":"uint256","name":"nextPrice","type":"uint256"},{"internalType":"bytes32","name":"ilk","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cdpId","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"isExecutionCorrect","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"cdpId","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"isExecutionLegal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_cdpId","type":"uint256"},{"internalType":"bytes","name":"triggerData","type":"bytes"}],"name":"isTriggerDataValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"serviceRegistry","outputs":[{"internalType":"contract ServiceRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"expectedSelector","type":"bytes4"},{"internalType":"bytes","name":"executionData","type":"bytes"}],"name":"validateSelector","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint16","name":"triggerType","type":"uint16"},{"internalType":"uint16","name":"expectedTriggerType","type":"uint16"}],"name":"validateTriggerType","outputs":[],"stateMutability":"pure","type":"function"}]

60a060405234801561001057600080fd5b50604051611aaf380380611aaf83398101604081905261002f91610040565b6001600160a01b0316608052610070565b60006020828403121561005257600080fd5b81516001600160a01b038116811461006957600080fd5b9392505050565b6080516119ec6100c3600039600081816102e9015281816104f0015281816106550152818161090a01528181610a2b01528181610c1901528181610d6d0152818161108601526111c901526119ec6000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c80639306f6be116100b2578063c4b73fda11610081578063cbcf252a11610066578063cbcf252a146102e4578063d05e47fb14610323578063e5c5e9a31461035e57600080fd5b8063c4b73fda14610281578063c63fa8a4146102bd57600080fd5b80639306f6be146101f6578063938018771461020b5780639561557b1461021e578063a8438a581461024557600080fd5b80634f873e44116100ee5780634f873e44146101865780635b7f7ea81461019957806364ae63a5146101d05780637827a9b0146101e357600080fd5b80630441d02a1461012057806311449b61146101355780632fddf37e146101505780633c946ca314610173575b600080fd5b61013361012e3660046114ff565b6103e8565b005b61013d603281565b6040519081526020015b60405180910390f35b61016361015e36600461159d565b6104aa565b6040519015158152602001610147565b61016361018136600461159d565b61062b565b610133610194366004611615565b6107ec565b6101c36040518060400160405280600b81526020016a21a2282fa6a0a720a3a2a960a91b81525081565b60405161014791906116a7565b6101636101de3660046116ba565b6108a8565b6101636101f136600461159d565b6108c1565b6101636102043660046116ba565b6032111590565b6101336102193660046116e3565b610b8d565b6101c3604051806040016040528060088152602001674d43445f5649455760c01b81525081565b6101c36040518060400160405280600781526020017f4d43445f5641540000000000000000000000000000000000000000000000000081525081565b6101c36040518060400160405280601681526020017f4d554c5449504c595f50524f58595f414354494f4e530000000000000000000081525081565b6101c3604051806040016040528060088152602001671350d117d4d413d560c21b81525081565b61030b7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610147565b6103366103313660046116ba565b610c0e565b604080519586526020860194909452928401919091526060830152608082015260a001610147565b61037161036c36600461171c565b610fdf565b60405161014791906000610100820190508251825261ffff602084015116602083015260408301516040830152606083015160608301526080830151608083015260a0830151151560a083015267ffffffffffffffff60c08401511660c083015263ffffffff60e08401511660e083015292915050565b60006103f382610fdf565b905061040481602001516003610b8d565b61044b634a9b4e0c60e01b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107ec92505050565b61048a85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061103892505050565b8060a00151156104a3576104a38382602001518461117d565b5050505050565b6000806104b683610fdf565b60408051808201825260088152674d43445f5649455760c01b60208201529051630851f3bd60e01b81529192506000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691630851f3bd9161052491906004016116a7565b602060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610565919061176e565b604051632f792afb60e21b815260048101879052600160248201529091506000906001600160a01b0383169063bde4abec90604401602060405180830381865afa1580156105b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105db919061178b565b90506000806105fb8560c00151866060015161138d90919063ffffffff16565b91509150610608816113cd565b831115801561061f575061061b826113cd565b8310155b98975050505050505050565b60008061063783610fdf565b905060008060008061064888610c0e565b94509450945094505060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630851f3bd604051806040016040528060088152602001671350d117d4d413d560c21b8152506040518263ffffffff1660e01b81526004016106bf91906116a7565b602060405180830381865afa1580156106dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610700919061176e565b604051636cb1c69b60e11b8152600481018490529091506000906001600160a01b0383169063d9638d36906024016040805180830381865afa15801561074a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076e91906117a4565b91505061077e87604001516113cd565b8610158015610791575086608001518411155b80156107c457506107a1816113e7565b6107c2856107bc886107b68c606001516113cd565b90611407565b9061141a565b115b80156107de57506107de8760e0015163ffffffff166108a8565b9a9950505050505050505050565b60008180602001905181019061080291906117d2565b90507fffffffff00000000000000000000000000000000000000000000000000000000808216908416146108a35760405162461bcd60e51b815260206004820152602160248201527f626173652d6d70612d636f6d6d616e642f696e76616c69642d73656c6563746f60448201527f720000000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b60006108b882633b9aca00611805565b48111592915050565b6000806108cd83610fdf565b604080518082018252600b81526a21a2282fa6a0a720a3a2a960a91b60208201529051630851f3bd60e01b81529192506000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691630851f3bd9161093e91906004016116a7565b602060405180830381865afa15801561095b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097f919061176e565b8251604051632c2cb9fd60e01b815260048101919091529091506000906001600160a01b03831690632c2cb9fd90602401602060405180830381865afa1580156109cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f1919061178b565b60408051808201825260088152671350d117d4d413d560c21b60208201529051630851f3bd60e01b81529192506000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691630851f3bd91610a5f91906004016116a7565b602060405180830381865afa158015610a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa0919061176e565b604051636cb1c69b60e11b8152600481018490529091506000906001600160a01b0383169063d9638d36906024016040805180830381865afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0e91906117a4565b915050600080610b2f8760c00151886060015161138d90919063ffffffff16565b885191935091508a148015610b4c5750866020015161ffff166003145b8015610b5b5750808760400151115b8015610b6e575082610b6c83611426565b115b80156107de575060c087015167ffffffffffffffff16603211156107de565b8061ffff168261ffff1614610c0a5760405162461bcd60e51b815260206004820152602360248201527f626173652d6d70612d636f6d6d616e642f747970652d6e6f742d737570706f7260448201527f7465640000000000000000000000000000000000000000000000000000000000606482015260840161089a565b5050565b6000806000806000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316630851f3bd6040518060400160405280600b81526020016a21a2282fa6a0a720a3a2a960a91b8152506040518263ffffffff1660e01b8152600401610c8691906116a7565b602060405180830381865afa158015610ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc7919061176e565b604051632c2cb9fd60e01b8152600481018990529091506001600160a01b03821690632c2cb9fd90602401602060405180830381865afa158015610d0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d33919061178b565b60408051808201825260088152674d43445f5649455760c01b60208201529051630851f3bd60e01b81529193506000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691630851f3bd91610da191906004016116a7565b602060405180830381865afa158015610dbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de2919061176e565b604051632f792afb60e21b8152600481018a9052600060248201529091506001600160a01b0382169063bde4abec90604401602060405180830381865afa158015610e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e55919061178b565b604051632f792afb60e21b8152600481018a9052600160248201529097506001600160a01b0382169063bde4abec90604401602060405180830381865afa158015610ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec8919061178b565b6040517f31d98b3f000000000000000000000000000000000000000000000000000000008152600481018590529096506001600160a01b038216906331d98b3f90602401602060405180830381865afa158015610f29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4d919061178b565b6040517f0ee95ecf000000000000000000000000000000000000000000000000000000008152600481018590529095506001600160a01b03821690630ee95ecf90602401602060405180830381865afa158015610fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd2919061178b565b9350505091939590929450565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e0820152825190916110329184018101908401611865565b92915050565b604080518082018252601681527f4d554c5449504c595f50524f58595f414354494f4e530000000000000000000060208201529051630851f3bd60e01b815260009182916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691630851f3bd916110ba91906004016116a7565b602060405180830381865afa1580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fb919061176e565b6001600160a01b0316836040516111129190611913565b600060405180830381855af49150503d806000811461114d576040519150601f19603f3d011682016040523d82523d6000602084013e611152565b606091505b50915091508181906111775760405162461bcd60e51b815260040161089a91906116a7565b50505050565b604080518082018252600e81527f4155544f4d4154494f4e5f424f5400000000000000000000000000000000000060208201529051630851f3bd60e01b81526000916001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691630851f3bd916111fc916004016116a7565b602060405180830381865afa158015611219573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123d919061176e565b90506000816001600160a01b03166311386ede60e01b868660008760405160240161126b949392919061192f565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516112d69190611913565b600060405180830381855af49150503d8060008114611311576040519150601f19603f3d011682016040523d82523d6000602084013e611316565b606091505b50509050806104a35760405162461bcd60e51b815260206004820152602a60248201527f626173652d6d70612d636f6d6d616e642f747269676765722d7265637265617460448201527f696f6e2d6661696c656400000000000000000000000000000000000000000000606482015260840161089a565b600080806113ab6127106107bc8767ffffffffffffffff8816611407565b90506113b78582611444565b6113c18683611450565b92509250509250929050565b60006110326127106107bc84670de0b6b3a7640000611407565b60006110326b033b2e3c9fd0803ce80000006107bc84670de0b6b3a76400005b60006114138284611805565b9392505050565b60006114138284611965565b60006110326127106107bc846b033b2e3c9fd0803ce8000000611407565b60006114138284611987565b6000611413828461199e565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261148357600080fd5b813567ffffffffffffffff8082111561149e5761149e61145c565b604051601f8301601f19908116603f011681019082821181831017156114c6576114c661145c565b816040528381528660208588010111156114df57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806000806060858703121561151557600080fd5b843567ffffffffffffffff8082111561152d57600080fd5b818701915087601f83011261154157600080fd5b81358181111561155057600080fd5b88602082850101111561156257600080fd5b6020928301965094509086013592506040860135908082111561158457600080fd5b5061159187828801611472565b91505092959194509250565b600080604083850312156115b057600080fd5b82359150602083013567ffffffffffffffff8111156115ce57600080fd5b6115da85828601611472565b9150509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461161257600080fd5b50565b6000806040838503121561162857600080fd5b8235611633816115e4565b9150602083013567ffffffffffffffff8111156115ce57600080fd5b60005b8381101561166a578181015183820152602001611652565b838111156111775750506000910152565b6000815180845261169381602086016020860161164f565b601f01601f19169290920160200192915050565b602081526000611413602083018461167b565b6000602082840312156116cc57600080fd5b5035919050565b61ffff8116811461161257600080fd5b600080604083850312156116f657600080fd5b8235611701816116d3565b91506020830135611711816116d3565b809150509250929050565b60006020828403121561172e57600080fd5b813567ffffffffffffffff81111561174557600080fd5b61175184828501611472565b949350505050565b6001600160a01b038116811461161257600080fd5b60006020828403121561178057600080fd5b815161141381611759565b60006020828403121561179d57600080fd5b5051919050565b600080604083850312156117b757600080fd5b82516117c281611759565b6020939093015192949293505050565b6000602082840312156117e457600080fd5b8151611413816115e4565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561181f5761181f6117ef565b500290565b8051801515811461183457600080fd5b919050565b805167ffffffffffffffff8116811461183457600080fd5b805163ffffffff8116811461183457600080fd5b600061010080838503121561187957600080fd5b6040519081019067ffffffffffffffff8211818310171561189c5761189c61145c565b8160405283518152602084015191506118b4826116d3565b8160208201526040840151604082015260608401516060820152608084015160808201526118e460a08501611824565b60a08201526118f560c08501611839565b60c082015261190660e08501611851565b60e0820152949350505050565b6000825161192581846020870161164f565b9190910192915050565b84815261ffff8416602082015260ff8316604082015260806060820152600061195b608083018461167b565b9695505050505050565b60008261198257634e487b7160e01b600052601260045260246000fd5b500490565b600082821015611999576119996117ef565b500390565b600082198211156119b1576119b16117ef565b50019056fea2646970667358221220b74985902a46adce69c90992b2a1bc0779360e349de13c03f7c938713b9bb88064736f6c634300080d00330000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061011b5760003560e01c80639306f6be116100b2578063c4b73fda11610081578063cbcf252a11610066578063cbcf252a146102e4578063d05e47fb14610323578063e5c5e9a31461035e57600080fd5b8063c4b73fda14610281578063c63fa8a4146102bd57600080fd5b80639306f6be146101f6578063938018771461020b5780639561557b1461021e578063a8438a581461024557600080fd5b80634f873e44116100ee5780634f873e44146101865780635b7f7ea81461019957806364ae63a5146101d05780637827a9b0146101e357600080fd5b80630441d02a1461012057806311449b61146101355780632fddf37e146101505780633c946ca314610173575b600080fd5b61013361012e3660046114ff565b6103e8565b005b61013d603281565b6040519081526020015b60405180910390f35b61016361015e36600461159d565b6104aa565b6040519015158152602001610147565b61016361018136600461159d565b61062b565b610133610194366004611615565b6107ec565b6101c36040518060400160405280600b81526020016a21a2282fa6a0a720a3a2a960a91b81525081565b60405161014791906116a7565b6101636101de3660046116ba565b6108a8565b6101636101f136600461159d565b6108c1565b6101636102043660046116ba565b6032111590565b6101336102193660046116e3565b610b8d565b6101c3604051806040016040528060088152602001674d43445f5649455760c01b81525081565b6101c36040518060400160405280600781526020017f4d43445f5641540000000000000000000000000000000000000000000000000081525081565b6101c36040518060400160405280601681526020017f4d554c5449504c595f50524f58595f414354494f4e530000000000000000000081525081565b6101c3604051806040016040528060088152602001671350d117d4d413d560c21b81525081565b61030b7f0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada81565b6040516001600160a01b039091168152602001610147565b6103366103313660046116ba565b610c0e565b604080519586526020860194909452928401919091526060830152608082015260a001610147565b61037161036c36600461171c565b610fdf565b60405161014791906000610100820190508251825261ffff602084015116602083015260408301516040830152606083015160608301526080830151608083015260a0830151151560a083015267ffffffffffffffff60c08401511660c083015263ffffffff60e08401511660e083015292915050565b60006103f382610fdf565b905061040481602001516003610b8d565b61044b634a9b4e0c60e01b86868080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506107ec92505050565b61048a85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061103892505050565b8060a00151156104a3576104a38382602001518461117d565b5050505050565b6000806104b683610fdf565b60408051808201825260088152674d43445f5649455760c01b60208201529051630851f3bd60e01b81529192506000916001600160a01b037f0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada1691630851f3bd9161052491906004016116a7565b602060405180830381865afa158015610541573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610565919061176e565b604051632f792afb60e21b815260048101879052600160248201529091506000906001600160a01b0383169063bde4abec90604401602060405180830381865afa1580156105b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105db919061178b565b90506000806105fb8560c00151866060015161138d90919063ffffffff16565b91509150610608816113cd565b831115801561061f575061061b826113cd565b8310155b98975050505050505050565b60008061063783610fdf565b905060008060008061064888610c0e565b94509450945094505060007f0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada6001600160a01b0316630851f3bd604051806040016040528060088152602001671350d117d4d413d560c21b8152506040518263ffffffff1660e01b81526004016106bf91906116a7565b602060405180830381865afa1580156106dc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610700919061176e565b604051636cb1c69b60e11b8152600481018490529091506000906001600160a01b0383169063d9638d36906024016040805180830381865afa15801561074a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061076e91906117a4565b91505061077e87604001516113cd565b8610158015610791575086608001518411155b80156107c457506107a1816113e7565b6107c2856107bc886107b68c606001516113cd565b90611407565b9061141a565b115b80156107de57506107de8760e0015163ffffffff166108a8565b9a9950505050505050505050565b60008180602001905181019061080291906117d2565b90507fffffffff00000000000000000000000000000000000000000000000000000000808216908416146108a35760405162461bcd60e51b815260206004820152602160248201527f626173652d6d70612d636f6d6d616e642f696e76616c69642d73656c6563746f60448201527f720000000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b505050565b60006108b882633b9aca00611805565b48111592915050565b6000806108cd83610fdf565b604080518082018252600b81526a21a2282fa6a0a720a3a2a960a91b60208201529051630851f3bd60e01b81529192506000916001600160a01b037f0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada1691630851f3bd9161093e91906004016116a7565b602060405180830381865afa15801561095b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061097f919061176e565b8251604051632c2cb9fd60e01b815260048101919091529091506000906001600160a01b03831690632c2cb9fd90602401602060405180830381865afa1580156109cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f1919061178b565b60408051808201825260088152671350d117d4d413d560c21b60208201529051630851f3bd60e01b81529192506000916001600160a01b037f0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada1691630851f3bd91610a5f91906004016116a7565b602060405180830381865afa158015610a7c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa0919061176e565b604051636cb1c69b60e11b8152600481018490529091506000906001600160a01b0383169063d9638d36906024016040805180830381865afa158015610aea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b0e91906117a4565b915050600080610b2f8760c00151886060015161138d90919063ffffffff16565b885191935091508a148015610b4c5750866020015161ffff166003145b8015610b5b5750808760400151115b8015610b6e575082610b6c83611426565b115b80156107de575060c087015167ffffffffffffffff16603211156107de565b8061ffff168261ffff1614610c0a5760405162461bcd60e51b815260206004820152602360248201527f626173652d6d70612d636f6d6d616e642f747970652d6e6f742d737570706f7260448201527f7465640000000000000000000000000000000000000000000000000000000000606482015260840161089a565b5050565b6000806000806000807f0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada6001600160a01b0316630851f3bd6040518060400160405280600b81526020016a21a2282fa6a0a720a3a2a960a91b8152506040518263ffffffff1660e01b8152600401610c8691906116a7565b602060405180830381865afa158015610ca3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cc7919061176e565b604051632c2cb9fd60e01b8152600481018990529091506001600160a01b03821690632c2cb9fd90602401602060405180830381865afa158015610d0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d33919061178b565b60408051808201825260088152674d43445f5649455760c01b60208201529051630851f3bd60e01b81529193506000916001600160a01b037f0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada1691630851f3bd91610da191906004016116a7565b602060405180830381865afa158015610dbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610de2919061176e565b604051632f792afb60e21b8152600481018a9052600060248201529091506001600160a01b0382169063bde4abec90604401602060405180830381865afa158015610e31573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e55919061178b565b604051632f792afb60e21b8152600481018a9052600160248201529097506001600160a01b0382169063bde4abec90604401602060405180830381865afa158015610ea4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ec8919061178b565b6040517f31d98b3f000000000000000000000000000000000000000000000000000000008152600481018590529096506001600160a01b038216906331d98b3f90602401602060405180830381865afa158015610f29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f4d919061178b565b6040517f0ee95ecf000000000000000000000000000000000000000000000000000000008152600481018590529095506001600160a01b03821690630ee95ecf90602401602060405180830381865afa158015610fae573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fd2919061178b565b9350505091939590929450565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e0820152825190916110329184018101908401611865565b92915050565b604080518082018252601681527f4d554c5449504c595f50524f58595f414354494f4e530000000000000000000060208201529051630851f3bd60e01b815260009182916001600160a01b037f0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada1691630851f3bd916110ba91906004016116a7565b602060405180830381865afa1580156110d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110fb919061176e565b6001600160a01b0316836040516111129190611913565b600060405180830381855af49150503d806000811461114d576040519150601f19603f3d011682016040523d82523d6000602084013e611152565b606091505b50915091508181906111775760405162461bcd60e51b815260040161089a91906116a7565b50505050565b604080518082018252600e81527f4155544f4d4154494f4e5f424f5400000000000000000000000000000000000060208201529051630851f3bd60e01b81526000916001600160a01b037f0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada1691630851f3bd916111fc916004016116a7565b602060405180830381865afa158015611219573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123d919061176e565b90506000816001600160a01b03166311386ede60e01b868660008760405160240161126b949392919061192f565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009094169390931790925290516112d69190611913565b600060405180830381855af49150503d8060008114611311576040519150601f19603f3d011682016040523d82523d6000602084013e611316565b606091505b50509050806104a35760405162461bcd60e51b815260206004820152602a60248201527f626173652d6d70612d636f6d6d616e642f747269676765722d7265637265617460448201527f696f6e2d6661696c656400000000000000000000000000000000000000000000606482015260840161089a565b600080806113ab6127106107bc8767ffffffffffffffff8816611407565b90506113b78582611444565b6113c18683611450565b92509250509250929050565b60006110326127106107bc84670de0b6b3a7640000611407565b60006110326b033b2e3c9fd0803ce80000006107bc84670de0b6b3a76400005b60006114138284611805565b9392505050565b60006114138284611965565b60006110326127106107bc846b033b2e3c9fd0803ce8000000611407565b60006114138284611987565b6000611413828461199e565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261148357600080fd5b813567ffffffffffffffff8082111561149e5761149e61145c565b604051601f8301601f19908116603f011681019082821181831017156114c6576114c661145c565b816040528381528660208588010111156114df57600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806000806060858703121561151557600080fd5b843567ffffffffffffffff8082111561152d57600080fd5b818701915087601f83011261154157600080fd5b81358181111561155057600080fd5b88602082850101111561156257600080fd5b6020928301965094509086013592506040860135908082111561158457600080fd5b5061159187828801611472565b91505092959194509250565b600080604083850312156115b057600080fd5b82359150602083013567ffffffffffffffff8111156115ce57600080fd5b6115da85828601611472565b9150509250929050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461161257600080fd5b50565b6000806040838503121561162857600080fd5b8235611633816115e4565b9150602083013567ffffffffffffffff8111156115ce57600080fd5b60005b8381101561166a578181015183820152602001611652565b838111156111775750506000910152565b6000815180845261169381602086016020860161164f565b601f01601f19169290920160200192915050565b602081526000611413602083018461167b565b6000602082840312156116cc57600080fd5b5035919050565b61ffff8116811461161257600080fd5b600080604083850312156116f657600080fd5b8235611701816116d3565b91506020830135611711816116d3565b809150509250929050565b60006020828403121561172e57600080fd5b813567ffffffffffffffff81111561174557600080fd5b61175184828501611472565b949350505050565b6001600160a01b038116811461161257600080fd5b60006020828403121561178057600080fd5b815161141381611759565b60006020828403121561179d57600080fd5b5051919050565b600080604083850312156117b757600080fd5b82516117c281611759565b6020939093015192949293505050565b6000602082840312156117e457600080fd5b8151611413816115e4565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561181f5761181f6117ef565b500290565b8051801515811461183457600080fd5b919050565b805167ffffffffffffffff8116811461183457600080fd5b805163ffffffff8116811461183457600080fd5b600061010080838503121561187957600080fd5b6040519081019067ffffffffffffffff8211818310171561189c5761189c61145c565b8160405283518152602084015191506118b4826116d3565b8160208201526040840151604082015260608401516060820152608084015160808201526118e460a08501611824565b60a08201526118f560c08501611839565b60c082015261190660e08501611851565b60e0820152949350505050565b6000825161192581846020870161164f565b9190910192915050565b84815261ffff8416602082015260ff8316604082015260806060820152600061195b608083018461167b565b9695505050505050565b60008261198257634e487b7160e01b600052601260045260246000fd5b500490565b600082821015611999576119996117ef565b500390565b600082198211156119b1576119b16117ef565b50019056fea2646970667358221220b74985902a46adce69c90992b2a1bc0779360e349de13c03f7c938713b9bb88064736f6c634300080d0033

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

0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada

-----Decoded View---------------
Arg [0] : _serviceRegistry (address): 0x9b4Ae7b164d195df9C4Da5d08Be88b2848b2EaDA

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000009b4ae7b164d195df9c4da5d08be88b2848b2eada


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

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