ETH Price: $3,116.58 (+5.79%)
Gas: 4 Gwei

Contract

0xc1176ea7074EDdd71530ac517af66E73E6FC0b78
 

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Open Cdp With Et...198843482024-05-16 18:33:1133 hrs ago1715884391IN
0xc1176ea7...3E6FC0b78
2.21 ETH0.003724775.05180186
Add Coll With Et...198804502024-05-16 5:28:1146 hrs ago1715837291IN
0xc1176ea7...3E6FC0b78
0.06 ETH0.001942893.56648675
Open Cdp With Wr...198620642024-05-13 15:42:594 days ago1715614979IN
0xc1176ea7...3E6FC0b78
0 ETH0.0196082629
Open Cdp With Et...198338422024-05-09 17:00:358 days ago1715274035IN
0xc1176ea7...3E6FC0b78
2.21 ETH0.006240558.04750084
Open Cdp With Et...198178762024-05-07 11:25:2310 days ago1715081123IN
0xc1176ea7...3E6FC0b78
140 ETH0.003019684.99635197
Open Cdp With Et...198173912024-05-07 9:47:4710 days ago1715075267IN
0xc1176ea7...3E6FC0b78
50 ETH0.003850665.89898211
Add Coll With Et...197805892024-05-02 6:15:4715 days ago1714630547IN
0xc1176ea7...3E6FC0b78
10 ETH0.002774534.90815555
Open Cdp With Et...197784142024-05-01 22:57:3516 days ago1714604255IN
0xc1176ea7...3E6FC0b78
140 ETH0.002624474.08395326
Open Cdp With Et...197476142024-04-27 15:39:1120 days ago1714232351IN
0xc1176ea7...3E6FC0b78
34.79 ETH0.005355948.02074469
Open Cdp With Et...197198412024-04-23 18:20:1124 days ago1713896411IN
0xc1176ea7...3E6FC0b78
500 ETH0.0103551215.12
Open Cdp With Et...197133572024-04-22 20:35:2325 days ago1713818123IN
0xc1176ea7...3E6FC0b78
3 ETH0.0075723811.02302928
Open Cdp With Et...197123672024-04-22 17:16:2325 days ago1713806183IN
0xc1176ea7...3E6FC0b78
2.21 ETH0.0102799413.99551073
Open Cdp With Wr...196888102024-04-19 10:12:4728 days ago1713521567IN
0xc1176ea7...3E6FC0b78
0 ETH0.0081788213
Open Cdp With Et...196856632024-04-18 23:36:5929 days ago1713483419IN
0xc1176ea7...3E6FC0b78
14 ETH0.006014767.97447941
Add Coll With Et...196163562024-04-09 6:39:1138 days ago1712644751IN
0xc1176ea7...3E6FC0b78
1 ETH0.0122007922.71458426
Open Cdp With Et...196146402024-04-09 0:53:1139 days ago1712623991IN
0xc1176ea7...3E6FC0b78
23 ETH0.0146148719.44457988
Open Cdp With Et...195957312024-04-06 9:16:1141 days ago1712394971IN
0xc1176ea7...3E6FC0b78
9 ETH0.0083603312.60494679
Open Cdp With Et...195955632024-04-06 8:42:2341 days ago1712392943IN
0xc1176ea7...3E6FC0b78
17 ETH0.0079600411.92071594
Open Cdp With Et...195809512024-04-04 7:36:1143 days ago1712216171IN
0xc1176ea7...3E6FC0b78
10 ETH0.011873617.88861533
Open Cdp With Ws...195744432024-04-03 9:46:1144 days ago1712137571IN
0xc1176ea7...3E6FC0b78
0 ETH0.0223625622.87659841
Open Cdp With Et...195728482024-04-03 4:24:5944 days ago1712118299IN
0xc1176ea7...3E6FC0b78
2.215 ETH0.0148698523.1394948
Open Cdp With Et...195687502024-04-02 14:38:1145 days ago1712068691IN
0xc1176ea7...3E6FC0b78
100 ETH0.0446124167
Open Cdp With Et...195635262024-04-01 21:02:3546 days ago1712005355IN
0xc1176ea7...3E6FC0b78
24 ETH0.0160386723.41922508
Open Cdp With Ws...195532192024-03-31 10:14:3547 days ago1711880075IN
0xc1176ea7...3E6FC0b78
0 ETH0.0143929618.07721372
Open Cdp With Ws...195439932024-03-30 3:06:1149 days ago1711767971IN
0xc1176ea7...3E6FC0b78
0 ETH0.0132540920.93639475
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To Value
198843482024-05-16 18:33:1133 hrs ago1715884391
0xc1176ea7...3E6FC0b78
2.21 ETH
198804502024-05-16 5:28:1146 hrs ago1715837291
0xc1176ea7...3E6FC0b78
0.06 ETH
198620642024-05-13 15:42:594 days ago1715614979
0xc1176ea7...3E6FC0b78
50 ETH
198620642024-05-13 15:42:594 days ago1715614979
0xc1176ea7...3E6FC0b78
50 ETH
198338422024-05-09 17:00:358 days ago1715274035
0xc1176ea7...3E6FC0b78
2.21 ETH
198178762024-05-07 11:25:2310 days ago1715081123
0xc1176ea7...3E6FC0b78
140 ETH
198173912024-05-07 9:47:4710 days ago1715075267
0xc1176ea7...3E6FC0b78
50 ETH
197805892024-05-02 6:15:4715 days ago1714630547
0xc1176ea7...3E6FC0b78
10 ETH
197784142024-05-01 22:57:3516 days ago1714604255
0xc1176ea7...3E6FC0b78
140 ETH
197476142024-04-27 15:39:1120 days ago1714232351
0xc1176ea7...3E6FC0b78
34.79 ETH
197198412024-04-23 18:20:1124 days ago1713896411
0xc1176ea7...3E6FC0b78
500 ETH
197133572024-04-22 20:35:2325 days ago1713818123
0xc1176ea7...3E6FC0b78
3 ETH
197123672024-04-22 17:16:2325 days ago1713806183
0xc1176ea7...3E6FC0b78
2.21 ETH
196888102024-04-19 10:12:4728 days ago1713521567
0xc1176ea7...3E6FC0b78
137.04356435 ETH
196888102024-04-19 10:12:4728 days ago1713521567
0xc1176ea7...3E6FC0b78
137.04356435 ETH
196856632024-04-18 23:36:5929 days ago1713483419
0xc1176ea7...3E6FC0b78
14 ETH
196163562024-04-09 6:39:1138 days ago1712644751
0xc1176ea7...3E6FC0b78
1 ETH
196146402024-04-09 0:53:1139 days ago1712623991
0xc1176ea7...3E6FC0b78
23 ETH
195957312024-04-06 9:16:1141 days ago1712394971
0xc1176ea7...3E6FC0b78
9 ETH
195955632024-04-06 8:42:2341 days ago1712392943
0xc1176ea7...3E6FC0b78
17 ETH
195809512024-04-04 7:36:1143 days ago1712216171
0xc1176ea7...3E6FC0b78
10 ETH
195728482024-04-03 4:24:5944 days ago1712118299
0xc1176ea7...3E6FC0b78
2.215 ETH
195687502024-04-02 14:38:1145 days ago1712068691
0xc1176ea7...3E6FC0b78
100 ETH
195635262024-04-01 21:02:3546 days ago1712005355
0xc1176ea7...3E6FC0b78
24 ETH
195429442024-03-29 23:33:5949 days ago1711755239
0xc1176ea7...3E6FC0b78
20 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EbtcZapRouter

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion
File 1 of 25 : EbtcZapRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import {ICdpManagerData} from "@ebtc/contracts/interfaces/ICdpManagerData.sol";
import {ICdpManager} from "@ebtc/contracts/interfaces/ICdpManager.sol";
import {IBorrowerOperations} from "@ebtc/contracts/interfaces/IBorrowerOperations.sol";
import {IPositionManagers} from "@ebtc/contracts/interfaces/IPositionManagers.sol";
import {IERC20} from "@ebtc/contracts/Dependencies/IERC20.sol";
import {SafeERC20} from "@ebtc/contracts/Dependencies/SafeERC20.sol";
import {IStETH} from "./interface/IStETH.sol";
import {IWrappedETH} from "./interface/IWrappedETH.sol";
import {IEbtcZapRouter} from "./interface/IEbtcZapRouter.sol";
import {IWstETH} from "./interface/IWstETH.sol";

interface IMinChangeGetter {
    function MIN_CHANGE() external view returns (uint256);
}

contract EbtcZapRouter is IEbtcZapRouter {
    using SafeERC20 for IERC20;

    address public constant NATIVE_ETH_ADDRESS =
        0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
    uint256 public constant LIQUIDATOR_REWARD = 2e17;
    uint256 public constant MIN_NET_STETH_BALANCE = 2e18;

    IStETH public immutable stEth;
    IERC20 public immutable ebtc;
    IERC20 public immutable wrappedEth;
    IERC20 public immutable wstEth;
    IBorrowerOperations public immutable borrowerOperations;
    ICdpManager public immutable cdpManager;
    address public immutable owner;
    uint256 public immutable MIN_CHANGE;

    constructor(
        IERC20 _wstEth,
        IERC20 _wEth,
        IStETH _stEth,
        IERC20 _ebtc,
        IBorrowerOperations _borrowerOperations,
        ICdpManager _cdpManager,
        address _owner
    ) {
        wstEth = _wstEth;
        wrappedEth = _wEth;
        stEth = _stEth;
        ebtc = _ebtc;
        borrowerOperations = _borrowerOperations;
        cdpManager = _cdpManager;
        owner = _owner;

        // Infinite Approvals @TODO: do these stay at max for each token?
        stEth.approve(address(borrowerOperations), type(uint256).max);
        wrappedEth.approve(address(wrappedEth), type(uint256).max);
        wstEth.approve(address(wstEth), type(uint256).max);
        stEth.approve(address(wstEth), type(uint256).max);

        MIN_CHANGE = IMinChangeGetter(address(borrowerOperations)).MIN_CHANGE();
    }

    /// @dev This is to allow wrapped ETH related Zap
    receive() external payable {
        require(
            msg.sender == address(wrappedEth),
            "EbtcZapRouter: only allow Wrapped ETH to send Ether!"
        );
    }

    /// @dev Open a CDP with stEth
    function openCdp(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalance,
        PositionManagerPermit calldata _positionManagerPermit
    ) external returns (bytes32 cdpId) {
        uint256 _collVal = _transferInitialStETHFromCaller(_stEthBalance);

        cdpId = _openCdpWithPermit(
            _debt,
            _upperHint,
            _lowerHint,
            _collVal,
            _positionManagerPermit
        );

        emit ZapOperationEthVariant(
            cdpId, 
            EthVariantZapOperationType.OpenCdp, 
            true, 
            address(stEth), 
            _stEthBalance, 
            _collVal,
            msg.sender
        );
    }

    /// @dev Open a CDP with raw native Ether
    /// @param _debt The total expected debt for new CDP
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    /// @param _ethBalance The total stETH collateral (converted from raw Ether) amount deposited (added) for the specified Cdp
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function openCdpWithEth(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _ethBalance,
        PositionManagerPermit calldata _positionManagerPermit
    ) external payable returns (bytes32 cdpId) {
        uint256 _collVal = _convertRawEthToStETH(_ethBalance);

        cdpId = _openCdpWithPermit(
            _debt,
            _upperHint,
            _lowerHint,
            _collVal,
            _positionManagerPermit
        );

        emit ZapOperationEthVariant(
            cdpId, 
            EthVariantZapOperationType.OpenCdp, 
            true, 
            NATIVE_ETH_ADDRESS, 
            _ethBalance, 
            _collVal,
            msg.sender
        );
    }

    /// @dev Open a CDP with Wrapped Ether
    /// @param _debt The total expected debt for new CDP
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    /// @param _wethBalance The total stETH collateral (converted from wrapped Ether) amount deposited (added) for the specified Cdp
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function openCdpWithWrappedEth(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _wethBalance,
        PositionManagerPermit calldata _positionManagerPermit
    ) external returns (bytes32 cdpId) {
        uint256 _collVal = _convertWrappedEthToStETH(_wethBalance);

        cdpId = _openCdpWithPermit(
            _debt,
            _upperHint,
            _lowerHint,
            _collVal,
            _positionManagerPermit
        );
        
        emit ZapOperationEthVariant(
            cdpId, 
            EthVariantZapOperationType.OpenCdp, 
            true, 
            address(wrappedEth), 
            _wethBalance, 
            _collVal,
            msg.sender
        );
    }

    /// @dev Open a CDP with Wrapped StETH
    /// @param _debt The total expected debt for new CDP
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    /// @param _wstEthBalance The total stETH collateral (converted from wrapped stETH) amount deposited (added) for the specified Cdp
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function openCdpWithWstEth(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _wstEthBalance,
        PositionManagerPermit calldata _positionManagerPermit
    ) external returns (bytes32 cdpId) {
        uint256 _collVal = _convertWstEthToStETH(_wstEthBalance);

        cdpId = _openCdpWithPermit(
            _debt,
            _upperHint,
            _lowerHint,
            _collVal,
            _positionManagerPermit
        );

        emit ZapOperationEthVariant(
            cdpId, 
            EthVariantZapOperationType.OpenCdp, 
            true, 
            address(wstEth), 
            _wstEthBalance, 
            _collVal,
            msg.sender
        );
    }

    /// @dev Close a CDP with original collateral(stETH) returned to CDP owner
    /// @dev Note plain collateral(stETH) is returned no matter whatever asset is zapped in
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function closeCdp(
        bytes32 _cdpId,
        PositionManagerPermit calldata _positionManagerPermit
    ) external {
        _closeCdpWithPermit(_cdpId, false, _positionManagerPermit);
    }

    /// @dev Close a CDP with wrapped version of collateral(WstETH) returned to CDP owner
    /// @dev Note plain collateral(stETH) is returned no matter whatever asset is zapped in
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function closeCdpForWstETH(
        bytes32 _cdpId,
        PositionManagerPermit calldata _positionManagerPermit
    ) external {
        _closeCdpWithPermit(_cdpId, true, _positionManagerPermit);
    }

    /// @notice Function that allows various operations which might change both collateral (increase collateral with raw native Ether) and debt of a Cdp
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _collBalanceDecrease The total stETH collateral amount withdrawn from the specified Cdp
    /// @param _debtChange The total eBTC debt amount withdrawn or repaid for the specified Cdp
    /// @param _isDebtIncrease The flag (true or false) to indicate whether this is a eBTC token withdrawal (debt increase) or a repayment (debt reduce)
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    /// @param _ethBalanceIncrease The total stETH collateral (converted from raw native Ether) amount deposited (added) for the specified Cdp
    /// @param _useWstETHForDecrease Indicator whether withdrawn collateral is original(stETH) or wrapped version(WstETH)
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function adjustCdpWithEth(
        bytes32 _cdpId,
        uint256 _collBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _ethBalanceIncrease,
        bool _useWstETHForDecrease,
        PositionManagerPermit calldata _positionManagerPermit
    ) external payable {
        _adjustCdpWithEth(
            _cdpId,
            _collBalanceDecrease,
            _debtChange,
            _isDebtIncrease,
            _upperHint,
            _lowerHint,
            _ethBalanceIncrease,
            _useWstETHForDecrease,
            _positionManagerPermit
        );
    }

    function _adjustCdpWithEth(
        bytes32 _cdpId,
        uint256 _collBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _ethBalanceIncrease,
        bool _useWstETHForDecrease,
        PositionManagerPermit calldata _positionManagerPermit
    ) internal {
        uint256 _collBalanceIncrease = _ethBalanceIncrease;
        if (_ethBalanceIncrease > 0) {
            _collBalanceIncrease = _convertRawEthToStETH(_ethBalanceIncrease);
            emit ZapOperationEthVariant(
                _cdpId, 
                EthVariantZapOperationType.AdjustCdp, 
                true, 
                NATIVE_ETH_ADDRESS, 
                _ethBalanceIncrease, 
                _collBalanceIncrease,
                msg.sender
            );
        }

        _adjustCdpWithPermit(
            _cdpId,
            _collBalanceDecrease,
            _debtChange,
            _isDebtIncrease,
            _upperHint,
            _lowerHint,
            _collBalanceIncrease,
            _useWstETHForDecrease,
            _positionManagerPermit
        );
    }

    /// @notice Function that allows various operations which might change both collateral (increase collateral with wrapped Ether) and debt of a Cdp
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _collBalanceDecrease The total stETH collateral amount withdrawn from the specified Cdp
    /// @param _debtChange The total eBTC debt amount withdrawn or repaid for the specified Cdp
    /// @param _isDebtIncrease The flag (true or false) to indicate whether this is a eBTC token withdrawal (debt increase) or a repayment (debt reduce)
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    /// @param _wethBalanceIncrease The total stETH collateral (converted from wrapped Ether) amount deposited (added) for the specified Cdp
    /// @param _useWstETHForDecrease Indicator whether withdrawn collateral is original(stETH) or wrapped version(WstETH)
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function adjustCdpWithWrappedEth(
        bytes32 _cdpId,
        uint256 _collBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _wethBalanceIncrease,
        bool _useWstETHForDecrease,
        PositionManagerPermit calldata _positionManagerPermit
    ) external {
        uint256 _collBalanceIncrease = _wethBalanceIncrease;
        if (_wethBalanceIncrease > 0) {
            _collBalanceIncrease = _convertWrappedEthToStETH(
                _wethBalanceIncrease
            );
            emit ZapOperationEthVariant(
                _cdpId, 
                EthVariantZapOperationType.AdjustCdp, 
                true, 
                address(wrappedEth), 
                _wethBalanceIncrease, 
                _collBalanceIncrease,
                msg.sender
            );
        }

        _adjustCdpWithPermit(
            _cdpId,
            _collBalanceDecrease,
            _debtChange,
            _isDebtIncrease,
            _upperHint,
            _lowerHint,
            _collBalanceIncrease,
            _useWstETHForDecrease,
            _positionManagerPermit
        );
    }

    /// @notice Function that allows various operations which might change both collateral (increase collateral with wrapped Ether) and debt of a Cdp
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _collBalanceDecrease The total stETH collateral amount withdrawn from the specified Cdp
    /// @param _debtChange The total eBTC debt amount withdrawn or repaid for the specified Cdp
    /// @param _isDebtIncrease The flag (true or false) to indicate whether this is a eBTC token withdrawal (debt increase) or a repayment (debt reduce)
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    /// @param _wstEthBalanceIncrease The total stETH collateral (converted from wrapped stETH) amount deposited (added) for the specified Cdp
    /// @param _useWstETHForDecrease Indicator whether withdrawn collateral is original(stETH) or wrapped version(WstETH)
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function adjustCdpWithWstEth(
        bytes32 _cdpId,
        uint256 _collBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _wstEthBalanceIncrease,
        bool _useWstETHForDecrease,
        PositionManagerPermit calldata _positionManagerPermit
    ) external {
        uint256 _collBalanceIncrease = _wstEthBalanceIncrease;

        // wstETH In
        if (_wstEthBalanceIncrease > 0) {
            _collBalanceIncrease = _convertWstEthToStETH(
                _wstEthBalanceIncrease
            );
            emit ZapOperationEthVariant(
                _cdpId, 
                EthVariantZapOperationType.AdjustCdp, 
                true, 
                address(wstEth), 
                _wstEthBalanceIncrease, 
                _collBalanceIncrease,
                msg.sender
            );
        } 

        _adjustCdpWithPermit(
            _cdpId,
            _collBalanceDecrease,
            _debtChange,
            _isDebtIncrease,
            _upperHint,
            _lowerHint,
            _collBalanceIncrease,
            _useWstETHForDecrease,
            _positionManagerPermit
        );
    }

    /// @notice Function that allows various operations which might change both collateral and debt of a Cdp
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _collBalanceDecrease The total stETH collateral amount withdrawn from the specified Cdp
    /// @param _debtChange The total eBTC debt amount withdrawn or repaid for the specified Cdp
    /// @param _isDebtIncrease The flag (true or false) to indicate whether this is a eBTC token withdrawal (debt increase) or a repayment (debt reduce)
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    /// @param _collBalanceIncrease The total stETH collateral amount deposited (added) for the specified Cdp
    /// @param _useWstETHForDecrease Indicator whether withdrawn collateral is original(stETH) or wrapped version(WstETH)
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function adjustCdp(
        bytes32 _cdpId,
        uint256 _collBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _collBalanceIncrease,
        bool _useWstETHForDecrease,
        PositionManagerPermit calldata _positionManagerPermit
    ) external {
        if (_collBalanceIncrease > 0) {
            uint256 _collVal = _transferInitialStETHFromCaller(_collBalanceIncrease);
            emit ZapOperationEthVariant(
                _cdpId, 
                EthVariantZapOperationType.AdjustCdp, 
                true, 
                address(stEth), 
                _collBalanceIncrease, 
                _collVal,
                msg.sender
            );
        }
        _adjustCdpWithPermit(
            _cdpId,
            _collBalanceDecrease,
            _debtChange,
            _isDebtIncrease,
            _upperHint,
            _lowerHint,
            _collBalanceIncrease,
            _useWstETHForDecrease,
            _positionManagerPermit
        );
    }

    /// @dev Increase the collateral for given CDP with raw native Ether
    /// @param _cdpId The CdpId on which this operation is operated
    /// @param _upperHint The expected CdpId of neighboring higher ICR within SortedCdps, could be simply bytes32(0)
    /// @param _lowerHint The expected CdpId of neighboring lower ICR within SortedCdps, could be simply bytes32(0)
    /// @param _ethBalanceIncrease The total stETH collateral (converted from raw Ether) amount deposited (added) for the specified Cdp
    /// @param _positionManagerPermit PositionPermit required for Zap approved by calling user
    function addCollWithEth(
        bytes32 _cdpId,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _ethBalanceIncrease,
        PositionManagerPermit calldata _positionManagerPermit
    ) external payable {        
        _adjustCdpWithEth(
            _cdpId,
            0,
            0,
            false,
            _upperHint,
            _lowerHint,
            _ethBalanceIncrease,
            false,
            _positionManagerPermit
        );
    }

    /// @notice Transfer an arbitrary token back to you
    function sweepToken(address token, uint256 amount) public {
        require(owner == msg.sender, "Must be owner");

        if (amount > 0) {
            IERC20(token).safeTransfer(msg.sender, amount);
        }
    }

    function _openCdpWithPermit(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalance,
        PositionManagerPermit calldata _positionManagerPermit
    ) internal returns (bytes32 cdpId) {
        // Check token balances of Zap before operation
        require(
            stEth.balanceOf(address(this)) >= _stEthBalance,
            "EbtcZapRouter: not enough collateral for open!"
        );

        _requireZeroOrMinAdjustment(_debt);
        _requireAtLeastMinNetStEthBalance(_stEthBalance - LIQUIDATOR_REWARD);

        _permitPositionManagerApproval(_positionManagerPermit);

        cdpId = borrowerOperations.openCdpFor(
            _debt,
            _upperHint,
            _lowerHint,
            _stEthBalance,
            msg.sender
        );

        ebtc.transfer(msg.sender, _debt);

        // Token balances should not have changed after operation
        // Created CDP should be owned by borrower
    }

    function _closeCdpWithPermit(
        bytes32 _cdpId,
        bool _useWstETH,
        PositionManagerPermit calldata _positionManagerPermit
    ) internal {
        require(
            msg.sender == _getOwnerAddress(_cdpId),
            "EbtcZapRouter: not owner for close!"
        );

        // for debt repayment
        uint256 _debt = ICdpManagerData(address(cdpManager)).getSyncedCdpDebt(
            _cdpId
        );
        ebtc.transferFrom(msg.sender, address(this), _debt);

        _permitPositionManagerApproval(_positionManagerPermit);

        uint256 _zapStEthBalanceBefore = stEth.balanceOf(address(this));
        borrowerOperations.closeCdp(_cdpId);
        uint256 _zapStEthBalanceAfter = stEth.balanceOf(address(this));
        uint256 _stETHDiff = _zapStEthBalanceAfter - _zapStEthBalanceBefore;

        _transferStEthToCaller(_cdpId, EthVariantZapOperationType.CloseCdp, _useWstETH, _stETHDiff);
    }

    function _transferStEthToCaller(
        bytes32 _cdpId,
        EthVariantZapOperationType _operationType,
        bool _useWstETH,
        uint256 _stEthVal
    ) internal {
        if (_useWstETH) {
            // return wrapped version(WstETH)
            uint256 _wstETHVal = IWstETH(address(wstEth)).wrap(_stEthVal);
            emit ZapOperationEthVariant(
                _cdpId, 
                _operationType, 
                false, 
                address(wstEth), 
                _wstETHVal, 
                _stEthVal,
                msg.sender
            );

            wstEth.transfer(msg.sender, _wstETHVal);
        } else {
            // return original collateral(stETH)
            emit ZapOperationEthVariant(
                _cdpId, 
                _operationType, 
                false, 
                address(stEth), 
                _stEthVal, 
                _stEthVal,
                msg.sender
            );
            stEth.transfer(msg.sender, _stEthVal);
        }
    }

    function _adjustCdpWithPermit(
        bytes32 _cdpId,
        uint256 _collBalanceDecrease,
        uint256 _debtChange,
        bool isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _collBalanceIncrease,
        bool _useWstETH,
        PositionManagerPermit calldata _positionManagerPermit
    ) internal {
        require(
            msg.sender == _getOwnerAddress(_cdpId),
            "EbtcZapRouter: not owner for adjust!"
        );
        require(
            (_collBalanceDecrease > 0 && _collBalanceIncrease == 0) ||
                (_collBalanceIncrease > 0 && _collBalanceDecrease == 0) ||
                (_collBalanceIncrease == 0 && _collBalanceDecrease == 0),
            "EbtcZapRouter: can't add and remove collateral at the same time!"
        );

        _requireNonZeroAdjustment(_collBalanceIncrease, _collBalanceDecrease, _debtChange);
        _requireZeroOrMinAdjustment(_debtChange);
        _requireZeroOrMinAdjustment(_collBalanceIncrease);
        _requireZeroOrMinAdjustment(_collBalanceDecrease);

        _permitPositionManagerApproval(_positionManagerPermit);

        // for debt decrease
        if (!isDebtIncrease && _debtChange > 0) {
            ebtc.transferFrom(msg.sender, address(this), _debtChange);
        }

        uint256 _zapStEthBalanceBefore = stEth.balanceOf(address(this));
        borrowerOperations.adjustCdpWithColl(
            _cdpId,
            _collBalanceDecrease,
            _debtChange,
            isDebtIncrease,
            _upperHint,
            _lowerHint,
            _collBalanceIncrease
        );
        uint256 _zapStEthBalanceAfter = stEth.balanceOf(address(this));

        // Send any withdrawn debt back to borrower
        if (isDebtIncrease && _debtChange > 0) {
            ebtc.transfer(msg.sender, _debtChange);
        }

        // Send any withdrawn collateral to back to borrower
        if (_collBalanceDecrease > 0) {
            _transferStEthToCaller(
                _cdpId,
                EthVariantZapOperationType.AdjustCdp,
                _useWstETH,
                _zapStEthBalanceAfter - _zapStEthBalanceBefore
            );
        }
    }

    function _transferInitialStETHFromCaller(
        uint256 _initialStETH
    ) internal returns (uint256) {
        // check before-after balances for 1-wei corner case
        uint256 _balBefore = stEth.balanceOf(address(this));
        stEth.transferFrom(msg.sender, address(this), _initialStETH);
        uint256 _deposit = stEth.balanceOf(address(this)) - _balBefore;
        return _deposit;
    }

    function _convertRawEthToStETH(
        uint256 _initialETH
    ) internal returns (uint256) {
        require(
            msg.value == _initialETH,
            "EbtcZapRouter: Incorrect ETH amount"
        );
        return _depositRawEthIntoLido(_initialETH);
    }

    function _depositRawEthIntoLido(
        uint256 _initialETH
    ) internal returns (uint256) {
        // check before-after balances for 1-wei corner case
        uint256 _balBefore = stEth.balanceOf(address(this));
        // TODO call submit() with a referral?
        payable(address(stEth)).call{value: _initialETH}("");
        uint256 _deposit = stEth.balanceOf(address(this)) - _balBefore;
        return _deposit;
    }

    function _convertWrappedEthToStETH(
        uint256 _initialWETH
    ) internal returns (uint256) {
        uint256 _wETHBalBefore = wrappedEth.balanceOf(address(this));
        wrappedEth.transferFrom(msg.sender, address(this), _initialWETH);
        uint256 _wETHReiceived = wrappedEth.balanceOf(address(this)) -
            _wETHBalBefore;

        uint256 _rawETHBalBefore = address(this).balance;
        IWrappedETH(address(wrappedEth)).withdraw(_wETHReiceived);
        uint256 _rawETHConverted = address(this).balance - _rawETHBalBefore;
        return _depositRawEthIntoLido(_rawETHConverted);
    }

    function _convertWstEthToStETH(
        uint256 _initialWstETH
    ) internal returns (uint256) {
        require(
            wstEth.transferFrom(msg.sender, address(this), _initialWstETH),
            "EbtcZapRouter: transfer wstETH failure!"
        );

        uint256 _stETHBalBefore = stEth.balanceOf(address(this));
        IWstETH(address(wstEth)).unwrap(_initialWstETH);
        uint256 _stETHReiceived = stEth.balanceOf(address(this)) -
            _stETHBalBefore;

        return _stETHReiceived;
    }

    function _permitPositionManagerApproval(
        PositionManagerPermit calldata _positionManagerPermit
    ) internal {
        try
            borrowerOperations.permitPositionManagerApproval(
                msg.sender,
                address(this),
                IPositionManagers.PositionManagerApproval.OneTime,
                _positionManagerPermit.deadline,
                _positionManagerPermit.v,
                _positionManagerPermit.r,
                _positionManagerPermit.s
            )
        {} catch {
            /// @notice adding try...catch around to mitigate potential permit front-running
            /// see: https://www.trust-security.xyz/post/permission-denied
        }
    }

    function _getOwnerAddress(bytes32 cdpId) internal pure returns (address) {
        uint256 _tmp = uint256(cdpId) >> 96;
        return address(uint160(_tmp));
    }

    function _requireZeroOrMinAdjustment(uint256 _change) internal view {
        require(
            _change == 0 || _change >= MIN_CHANGE,
            "EbtcZapRouter: Debt or collateral change must be zero or above min"
        );
    }

    function _requireAtLeastMinNetStEthBalance(uint256 _stEthBalance) internal pure {
        require(
            _stEthBalance >= MIN_NET_STETH_BALANCE,
            "EbtcZapRouter: Cdp's net stEth balance must not fall below minimum"
        );
    }

    function _requireNonZeroAdjustment(
        uint256 _stEthBalanceIncrease,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange
    ) internal pure {
        require(
            _stEthBalanceIncrease > 0 || _stEthBalanceDecrease > 0 || _debtChange > 0,
            "EbtcZapRouter: There must be either a collateral or debt change"
        );
    }
}

File 3 of 25 : ICdpManagerData.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "./ICollSurplusPool.sol";
import "./IEBTCToken.sol";
import "./ISortedCdps.sol";
import "./IActivePool.sol";
import "./IRecoveryModeGracePeriod.sol";
import "../Dependencies/ICollateralTokenOracle.sol";

// Common interface for the Cdp Manager.
interface ICdpManagerData is IRecoveryModeGracePeriod {
    // --- Events ---

    event StakingRewardSplitSet(uint256 _stakingRewardSplit);
    event RedemptionFeeFloorSet(uint256 _redemptionFeeFloor);
    event MinuteDecayFactorSet(uint256 _minuteDecayFactor);
    event BetaSet(uint256 _beta);
    event RedemptionsPaused(bool _paused);

    event Liquidation(uint256 _liquidatedDebt, uint256 _liquidatedColl, uint256 _liqReward);
    event Redemption(
        uint256 _debtToRedeemExpected,
        uint256 _debtToRedeemActual,
        uint256 _collSharesSent,
        uint256 _feeCollShares,
        address indexed _redeemer
    );
    event CdpUpdated(
        bytes32 indexed _cdpId,
        address indexed _borrower,
        address indexed _executor,
        uint256 _oldDebt,
        uint256 _oldCollShares,
        uint256 _debt,
        uint256 _collShares,
        uint256 _stake,
        CdpOperation _operation
    );
    event CdpLiquidated(
        bytes32 indexed _cdpId,
        address indexed _borrower,
        uint _debt,
        uint _collShares,
        CdpOperation _operation,
        address indexed _liquidator,
        uint _premiumToLiquidator
    );
    event CdpPartiallyLiquidated(
        bytes32 indexed _cdpId,
        address indexed _borrower,
        uint256 _debt,
        uint256 _collShares,
        CdpOperation operation,
        address indexed _liquidator,
        uint _premiumToLiquidator
    );
    event BaseRateUpdated(uint256 _baseRate);
    event LastRedemptionTimestampUpdated(uint256 _lastFeeOpTime);
    event TotalStakesUpdated(uint256 _newTotalStakes);
    event SystemSnapshotsUpdated(uint256 _totalStakesSnapshot, uint256 _totalCollateralSnapshot);
    event SystemDebtRedistributionIndexUpdated(uint256 _systemDebtRedistributionIndex);
    event CdpDebtRedistributionIndexUpdated(bytes32 _cdpId, uint256 _cdpDebtRedistributionIndex);
    event CdpArrayIndexUpdated(bytes32 _cdpId, uint256 _newIndex);
    event StEthIndexUpdated(uint256 _oldIndex, uint256 _newIndex, uint256 _updTimestamp);
    event CollateralFeePerUnitUpdated(uint256 _oldPerUnit, uint256 _newPerUnit, uint256 _feeTaken);
    event CdpFeeSplitApplied(
        bytes32 _cdpId,
        uint256 _oldPerUnitCdp,
        uint256 _newPerUnitCdp,
        uint256 _collReduced,
        uint256 _collLeft
    );

    enum CdpOperation {
        openCdp,
        closeCdp,
        adjustCdp,
        syncAccounting,
        liquidateInNormalMode,
        liquidateInRecoveryMode,
        redeemCollateral,
        partiallyLiquidate,
        failedPartialRedemption
    }

    enum Status {
        nonExistent,
        active,
        closedByOwner,
        closedByLiquidation,
        closedByRedemption
    }

    // Store the necessary data for a cdp
    struct Cdp {
        uint256 debt;
        uint256 coll;
        uint256 stake;
        uint128 liquidatorRewardShares;
        Status status;
    }

    /*
     * --- Variable container structs for liquidations ---
     *
     * These structs are used to hold, return and assign variables inside the liquidation functions,
     * in order to avoid the error: "CompilerError: Stack too deep".
     **/

    struct CdpDebtAndCollShares {
        uint256 debt;
        uint256 collShares;
    }

    struct LiquidationLocals {
        bytes32 cdpId;
        uint256 partialAmount; // used only for partial liquidation, default 0 means full liquidation
        uint256 price;
        uint256 ICR;
        bytes32 upperPartialHint;
        bytes32 lowerPartialHint;
        bool recoveryModeAtStart;
        uint256 TCR;
        uint256 totalSurplusCollShares;
        uint256 totalCollSharesToSend;
        uint256 totalDebtToBurn;
        uint256 totalDebtToRedistribute;
        uint256 totalLiquidatorRewardCollShares;
    }

    struct LiquidationRecoveryModeLocals {
        uint256 entireSystemDebt;
        uint256 entireSystemColl;
        uint256 totalDebtToBurn;
        uint256 totalCollSharesToSend;
        uint256 totalSurplusCollShares;
        bytes32 cdpId;
        uint256 price;
        uint256 ICR;
        uint256 totalDebtToRedistribute;
        uint256 totalLiquidatorRewardCollShares;
    }

    struct LocalVariables_OuterLiquidationFunction {
        uint256 price;
        bool recoveryModeAtStart;
        uint256 liquidatedDebt;
        uint256 liquidatedColl;
    }

    struct LocalVariables_LiquidationSequence {
        uint256 i;
        uint256 ICR;
        bytes32 cdpId;
        bool backToNormalMode;
        uint256 entireSystemDebt;
        uint256 entireSystemColl;
        uint256 price;
        uint256 TCR;
    }

    struct SingleRedemptionInputs {
        bytes32 cdpId;
        uint256 maxEBTCamount;
        uint256 price;
        bytes32 upperPartialRedemptionHint;
        bytes32 lowerPartialRedemptionHint;
        uint256 partialRedemptionHintNICR;
    }

    struct LiquidationValues {
        uint256 entireCdpDebt;
        uint256 debtToBurn;
        uint256 totalCollToSendToLiquidator;
        uint256 debtToRedistribute;
        uint256 collSurplus;
        uint256 liquidatorCollSharesReward;
    }

    struct LiquidationTotals {
        uint256 totalDebtInSequence;
        uint256 totalDebtToBurn;
        uint256 totalCollToSendToLiquidator;
        uint256 totalDebtToRedistribute;
        uint256 totalCollSurplus;
        uint256 totalCollReward;
    }

    // --- Variable container structs for redemptions ---

    struct RedemptionTotals {
        uint256 remainingDebtToRedeem;
        uint256 debtToRedeem;
        uint256 collSharesDrawn;
        uint256 totalCollSharesSurplus;
        uint256 feeCollShares;
        uint256 collSharesToRedeemer;
        uint256 decayedBaseRate;
        uint256 price;
        uint256 systemDebtAtStart;
        uint256 twapSystemDebtAtStart;
        uint256 systemCollSharesAtStart;
        uint256 tcrAtStart;
    }

    struct SingleRedemptionValues {
        uint256 debtToRedeem;
        uint256 collSharesDrawn;
        uint256 collSurplus;
        uint256 liquidatorRewardShares;
        bool cancelledPartial;
        bool fullRedemption;
        uint256 newPartialNICR;
    }

    function getActiveCdpsCount() external view returns (uint256);

    function totalStakes() external view returns (uint256);

    function ebtcToken() external view returns (IEBTCToken);

    function systemStEthFeePerUnitIndex() external view returns (uint256);

    function systemStEthFeePerUnitIndexError() external view returns (uint256);

    function stEthIndex() external view returns (uint256);

    function calcFeeUponStakingReward(
        uint256 _newIndex,
        uint256 _prevIndex
    ) external view returns (uint256, uint256, uint256);

    function syncGlobalAccounting() external; // Accrues StEthFeeSplit without influencing Grace Period

    function syncGlobalAccountingAndGracePeriod() external; // Accrues StEthFeeSplit and influences Grace Period

    function getAccumulatedFeeSplitApplied(
        bytes32 _cdpId,
        uint256 _systemStEthFeePerUnitIndex
    ) external view returns (uint256, uint256);

    function getCachedNominalICR(bytes32 _cdpId) external view returns (uint256);

    function getCachedICR(bytes32 _cdpId, uint256 _price) external view returns (uint256);

    function getSyncedCdpDebt(bytes32 _cdpId) external view returns (uint256);

    function getSyncedCdpCollShares(bytes32 _cdpId) external view returns (uint256);

    function getSyncedICR(bytes32 _cdpId, uint256 _price) external view returns (uint256);

    function getSyncedTCR(uint256 _price) external view returns (uint256);

    function getSyncedSystemCollShares() external view returns (uint256);

    function getSyncedNominalICR(bytes32 _cdpId) external view returns (uint256);

    function getPendingRedistributedDebt(bytes32 _cdpId) external view returns (uint256);

    function hasPendingRedistributedDebt(bytes32 _cdpId) external view returns (bool);

    function getSyncedDebtAndCollShares(
        bytes32 _cdpId
    ) external view returns (uint256 debt, uint256 collShares);

    function canLiquidateRecoveryMode(uint256 icr, uint256 tcr) external view returns (bool);

    function totalCollateralSnapshot() external view returns (uint256);

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

File 4 of 25 : ICdpManager.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "./IEbtcBase.sol";
import "./ICdpManagerData.sol";

// Common interface for the Cdp Manager.
interface ICdpManager is IEbtcBase, ICdpManagerData {
    // --- Functions ---
    function liquidate(bytes32 _cdpId) external;

    function partiallyLiquidate(
        bytes32 _cdpId,
        uint256 _partialAmount,
        bytes32 _upperPartialHint,
        bytes32 _lowerPartialHint
    ) external;

    function batchLiquidateCdps(bytes32[] calldata _cdpArray) external;

    function redeemCollateral(
        uint256 _EBTCAmount,
        bytes32 _firstRedemptionHint,
        bytes32 _upperPartialRedemptionHint,
        bytes32 _lowerPartialRedemptionHint,
        uint256 _partialRedemptionHintNICR,
        uint256 _maxIterations,
        uint256 _maxFee
    ) external;

    function updateStakeAndTotalStakes(bytes32 _cdpId) external returns (uint256);

    function syncAccounting(bytes32 _cdpId) external;

    function closeCdp(bytes32 _cdpId, address _borrower, uint256 _debt, uint256 _coll) external;

    function getRedemptionRate() external view returns (uint256);

    function getRedemptionRateWithDecay() external view returns (uint256);

    function getRedemptionFeeWithDecay(uint256 _stETHToRedeem) external view returns (uint256);

    function getCdpStatus(bytes32 _cdpId) external view returns (uint256);

    function getCdpStake(bytes32 _cdpId) external view returns (uint256);

    function getCdpDebt(bytes32 _cdpId) external view returns (uint256);

    function getCdpCollShares(bytes32 _cdpId) external view returns (uint256);

    function getCdpLiquidatorRewardShares(bytes32 _cdpId) external view returns (uint);

    function initializeCdp(
        bytes32 _cdpId,
        uint256 _debt,
        uint256 _coll,
        uint256 _liquidatorRewardShares,
        address _borrower
    ) external;

    function updateCdp(
        bytes32 _cdpId,
        address _borrower,
        uint256 _coll,
        uint256 _debt,
        uint256 _newColl,
        uint256 _newDebt
    ) external;

    function getCachedTCR(uint256 _price) external view returns (uint256);

    function checkRecoveryMode(uint256 _price) external view returns (bool);
}

File 5 of 25 : IBorrowerOperations.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;
import "./IPositionManagers.sol";

// Common interface for the Cdp Manager.
interface IBorrowerOperations is IPositionManagers {
    // --- Events ---

    event FeeRecipientAddressChanged(address indexed _feeRecipientAddress);
    event FlashLoanSuccess(
        address indexed _receiver,
        address indexed _token,
        uint256 _amount,
        uint256 _fee
    );

    // --- Functions ---

    function openCdp(
        uint256 _EBTCAmount,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalance
    ) external returns (bytes32);

    function openCdpFor(
        uint _EBTCAmount,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint _collAmount,
        address _borrower
    ) external returns (bytes32);

    function addColl(
        bytes32 _cdpId,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalanceIncrease
    ) external;

    function withdrawColl(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function withdrawDebt(
        bytes32 _cdpId,
        uint256 _amount,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function repayDebt(
        bytes32 _cdpId,
        uint256 _amount,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function closeCdp(bytes32 _cdpId) external;

    function adjustCdp(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint
    ) external;

    function adjustCdpWithColl(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalanceIncrease
    ) external;

    function claimSurplusCollShares() external;

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

File 6 of 25 : IPositionManagers.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IPositionManagers {
    enum PositionManagerApproval {
        None,
        OneTime,
        Persistent
    }

    event PositionManagerApprovalSet(
        address indexed _borrower,
        address indexed _positionManager,
        PositionManagerApproval _approval
    );

    function getPositionManagerApproval(
        address _borrower,
        address _positionManager
    ) external view returns (PositionManagerApproval);

    function setPositionManagerApproval(
        address _positionManager,
        PositionManagerApproval _approval
    ) external;

    function revokePositionManagerApproval(address _positionManager) external;

    function renouncePositionManagerApproval(address _borrower) external;

    function permitPositionManagerApproval(
        address _borrower,
        address _positionManager,
        PositionManagerApproval _approval,
        uint _deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

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

    function permitTypeHash() external view returns (bytes32);

    function domainSeparator() external view returns (bytes32);
}

File 7 of 25 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/**
 * Based on the OpenZeppelin IER20 interface:
 * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol
 *
 * @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 `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);

    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);

    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);

    /**
     * @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);

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

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

    function decimals() external view returns (uint8);

    /**
     * @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 8 of 25 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity 0.8.17;

import "./IERC20.sol";
import "./Address.sol";

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

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

    /// @dev Calls approve while checking bool return value, handles no-return tokens
    function safeApprove(IERC20 token, address spender, uint256 amount) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, amount));
    }

    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(
            token,
            abi.encodeWithSelector(token.transferFrom.selector, from, to, value)
        );
    }

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

        bytes memory returndata = address(token).functionCall(
            data,
            "SafeERC20: low-level call failed"
        );
        require(
            returndata.length == 0 || abi.decode(returndata, (bool)),
            "SafeERC20: ERC20 operation did not succeed"
        );
    }
}

File 9 of 25 : IStETH.sol
// SPDX-FileCopyrightText: 2020 Lido <[email protected]>

// SPDX-License-Identifier: GPL-3.0

/* See contracts/COMPILERS.md */
pragma solidity 0.8.17;

import "@ebtc/contracts/Dependencies/ICollateralToken.sol";

/// @notice Add submit functionality to eBTC stETH interface
interface IStETH is ICollateralToken {
    function submit(address _referral) external payable returns (uint256);
}

File 10 of 25 : IWrappedETH.sol
// SPDX-License-Identifier: GPL-3.0

/* See contracts/COMPILERS.md */
pragma solidity 0.8.17;

/// @notice Wrapped ETH (version 9)
/// @dev check https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code
interface IWrappedETH {
    function withdraw(uint wad) external;
}

File 11 of 25 : IEbtcZapRouter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IEbtcZapRouter {
    struct PositionManagerPermit {
        uint256 deadline;
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    enum EthVariantZapOperationType {
        OpenCdp,
        AdjustCdp,
        CloseCdp
    }

    event ZapOperationEthVariant(
        bytes32 indexed cdpId,
        EthVariantZapOperationType indexed operation,
        bool isCollateralIncrease,
        address indexed collateralToken,
        uint256 collateralTokenDelta,
        uint256 stEthDelta,
        address cdpOwner
    );

    function openCdp(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalance,
        PositionManagerPermit memory _positionManagerPermit
    ) external returns (bytes32 cdpId);

    function openCdpWithEth(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _ethBalance,
        PositionManagerPermit memory _positionManagerPermit
    ) external payable returns (bytes32 cdpId);

    function openCdpWithWrappedEth(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _wethBalance,
        PositionManagerPermit memory _positionManagerPermit
    ) external returns (bytes32 cdpId);

    function openCdpWithWstEth(
        uint256 _debt,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _wstEthBalance,
        PositionManagerPermit memory _positionManagerPermit
    ) external returns (bytes32 cdpId);

    function adjustCdp(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _stEthBalanceIncrease,
        bool _useWstETHForDecrease,
        PositionManagerPermit memory _positionManagerPermit
    ) external;

    function adjustCdpWithEth(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _ethBalanceIncrease,
        bool _useWstETHForDecrease,
        PositionManagerPermit memory _positionManagerPermit
    ) external payable;

    function adjustCdpWithWrappedEth(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _wethBalanceIncrease,
        bool _useWstETHForDecrease,
        PositionManagerPermit memory _positionManagerPermit
    ) external;

    function adjustCdpWithWstEth(
        bytes32 _cdpId,
        uint256 _stEthBalanceDecrease,
        uint256 _debtChange,
        bool _isDebtIncrease,
        bytes32 _upperHint,
        bytes32 _lowerHint,
        uint256 _wstEthBalanceIncrease,
        bool _useWstETHForDecrease,
        PositionManagerPermit memory _positionManagerPermit
    ) external;

    function closeCdp(
        bytes32 _cdpId,
        PositionManagerPermit memory _positionManagerPermit
    ) external;

    function closeCdpForWstETH(
        bytes32 _cdpId,
        PositionManagerPermit memory _positionManagerPermit
    ) external;
}

File 12 of 25 : IWstETH.sol
// SPDX-FileCopyrightText: 2020 Lido <[email protected]>

// SPDX-License-Identifier: GPL-3.0

/* See contracts/COMPILERS.md */
pragma solidity 0.8.17;

/// @notice Check https://etherscan.io/token/0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0#code
interface IWstETH {
    /// @notice Exchanges wstETH to stETH
    function unwrap(uint256 _wstETHAmount) external returns (uint256);

    /// @notice Exchanges stETH to wstETH
    function wrap(uint256 _stETHAmount) external returns (uint256);

    /// @notice Get amount of wstETH for a given amount of stETH
    function getWstETHByStETH(
        uint256 _stETHAmount
    ) external view returns (uint256);

    /// @notice Get amount of stETH for a given amount of wstETH
    function getStETHByWstETH(
        uint256 _stETHAmount
    ) external view returns (uint256);
}

File 13 of 25 : ICollSurplusPool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface ICollSurplusPool {
    // --- Events ---

    event SurplusCollSharesAdded(
        bytes32 indexed _cdpId,
        address indexed _account,
        uint256 _claimableSurplusCollShares,
        uint256 _surplusCollSharesAddedFromCollateral,
        uint256 _surplusCollSharesAddedFromLiquidatorReward
    );
    event CollSharesTransferred(address indexed _to, uint256 _amount);

    event SweepTokenSuccess(address indexed _token, uint256 _amount, address indexed _recipient);

    // --- Contract setters ---

    function getTotalSurplusCollShares() external view returns (uint256);

    function getSurplusCollShares(address _account) external view returns (uint256);

    function increaseSurplusCollShares(
        bytes32 _cdpId,
        address _account,
        uint256 _collateralShares,
        uint256 _liquidatorRewardShares
    ) external;

    function claimSurplusCollShares(address _account) external;

    function increaseTotalSurplusCollShares(uint256 _value) external;
}

File 14 of 25 : IEBTCToken.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "../Dependencies/IERC20.sol";
import "../Dependencies/IERC2612.sol";

interface IEBTCToken is IERC20, IERC2612 {
    // --- Functions ---

    function mint(address _account, uint256 _amount) external;

    function burn(address _account, uint256 _amount) external;
}

File 15 of 25 : ISortedCdps.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

// Common interface for the SortedCdps Doubly Linked List.
interface ISortedCdps {
    // --- Events ---

    event NodeAdded(bytes32 _id, uint _NICR);
    event NodeRemoved(bytes32 _id);

    // --- Functions ---

    function remove(bytes32 _id) external;

    function batchRemove(bytes32[] memory _ids) external;

    function reInsert(bytes32 _id, uint256 _newICR, bytes32 _prevId, bytes32 _nextId) external;

    function contains(bytes32 _id) external view returns (bool);

    function isFull() external view returns (bool);

    function isEmpty() external view returns (bool);

    function getSize() external view returns (uint256);

    function getMaxSize() external view returns (uint256);

    function getFirst() external view returns (bytes32);

    function getLast() external view returns (bytes32);

    function getNext(bytes32 _id) external view returns (bytes32);

    function getPrev(bytes32 _id) external view returns (bytes32);

    function validInsertPosition(
        uint256 _ICR,
        bytes32 _prevId,
        bytes32 _nextId
    ) external view returns (bool);

    function findInsertPosition(
        uint256 _ICR,
        bytes32 _prevId,
        bytes32 _nextId
    ) external view returns (bytes32, bytes32);

    function insert(
        address owner,
        uint256 _ICR,
        bytes32 _prevId,
        bytes32 _nextId
    ) external returns (bytes32);

    function getOwnerAddress(bytes32 _id) external pure returns (address);

    function nonExistId() external view returns (bytes32);

    function cdpCountOf(address owner) external view returns (uint256);

    function getCdpCountOf(
        address owner,
        bytes32 startNodeId,
        uint maxNodes
    ) external view returns (uint256, bytes32);

    function getCdpsOf(address owner) external view returns (bytes32[] memory);

    function getAllCdpsOf(
        address owner,
        bytes32 startNodeId,
        uint maxNodes
    ) external view returns (bytes32[] memory, uint256, bytes32);

    function cdpOfOwnerByIndex(address owner, uint256 index) external view returns (bytes32);

    function cdpOfOwnerByIdx(
        address owner,
        uint256 index,
        bytes32 startNodeId,
        uint maxNodes
    ) external view returns (bytes32, bool);

    function toCdpId(
        address owner,
        uint256 blockHeight,
        uint256 nonce
    ) external pure returns (bytes32);

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

File 16 of 25 : IActivePool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "./IPool.sol";
import "./ITwapWeightedObserver.sol";

interface IActivePool is IPool, ITwapWeightedObserver {
    // --- Events ---
    event ActivePoolEBTCDebtUpdated(uint256 _EBTCDebt);
    event SystemCollSharesUpdated(uint256 _coll);
    event FeeRecipientClaimableCollSharesIncreased(uint256 _coll, uint256 _fee);
    event FeeRecipientClaimableCollSharesDecreased(uint256 _coll, uint256 _fee);
    event FlashLoanSuccess(
        address indexed _receiver,
        address indexed _token,
        uint256 _amount,
        uint256 _fee
    );
    event SweepTokenSuccess(address indexed _token, uint256 _amount, address indexed _recipient);

    // --- Functions ---
    function transferSystemCollShares(address _account, uint256 _amount) external;

    function increaseSystemCollShares(uint256 _value) external;

    function transferSystemCollSharesAndLiquidatorReward(
        address _account,
        uint256 _shares,
        uint256 _liquidatorRewardShares
    ) external;

    function allocateSystemCollSharesToFeeRecipient(uint256 _shares) external;

    function claimFeeRecipientCollShares(uint256 _shares) external;

    function feeRecipientAddress() external view returns (address);

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

File 17 of 25 : IRecoveryModeGracePeriod.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

// Interface for State Updates that can trigger RM Liquidations
interface IRecoveryModeGracePeriod {
    event TCRNotified(uint256 TCR); /// NOTE: Mostly for debugging to ensure synch

    // NOTE: Ts is implicit in events (it's added by GETH)
    event GracePeriodStart();
    event GracePeriodEnd();
    event GracePeriodDurationSet(uint256 _recoveryModeGracePeriodDuration);

    function notifyStartGracePeriod(uint256 tcr) external;

    function notifyEndGracePeriod(uint256 tcr) external;
}

File 18 of 25 : ICollateralTokenOracle.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

/**
 * Based on the stETH:
 *  -   https://docs.lido.fi/contracts/lido#
 */
interface ICollateralTokenOracle {
    // Return beacon specification data.
    function getBeaconSpec()
        external
        view
        returns (
            uint64 epochsPerFrame,
            uint64 slotsPerEpoch,
            uint64 secondsPerSlot,
            uint64 genesisTime
        );
}

File 19 of 25 : IEbtcBase.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "./IPriceFeed.sol";

interface IEbtcBase {
    function priceFeed() external view returns (IPriceFeed);
}

File 20 of 25 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity 0.8.17;

/**
 * @dev Collection of functions related to the address type
 */
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
     *
     * Furthermore, `isContract` will also return true if the target contract within
     * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
     * which only has an effect at the end of a transaction.
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev 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-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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

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

File 21 of 25 : ICollateralToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import "./IERC20.sol";

/**
 * Based on the stETH:
 *  -   https://docs.lido.fi/contracts/lido#
 */
interface ICollateralToken is IERC20 {
    // Returns the amount of shares that corresponds to _ethAmount protocol-controlled Ether
    function getSharesByPooledEth(uint256 _ethAmount) external view returns (uint256);

    // Returns the amount of Ether that corresponds to _sharesAmount token shares
    function getPooledEthByShares(uint256 _sharesAmount) external view returns (uint256);

    // Moves `_sharesAmount` token shares from the caller's account to the `_recipient` account.
    function transferShares(address _recipient, uint256 _sharesAmount) external returns (uint256);

    // Returns the amount of shares owned by _account
    function sharesOf(address _account) external view returns (uint256);

    // Returns authorized oracle address
    function getOracle() external view returns (address);
}

File 22 of 25 : IERC2612.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

/**
 * @dev Interface of the ERC2612 standard as defined in the EIP.
 *
 * Adds the {permit} method, which can be used to change one's
 * {IERC20-allowance} without having to send a transaction, by signing a
 * message. This allows users to spend tokens without having to hold Ether.
 *
 * See https://eips.ethereum.org/EIPS/eip-2612.
 *
 * Code adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237/
 */
interface IERC2612 {
    /**
     * @dev Sets `amount` as the allowance of `spender` over `owner`'s tokens,
     * given `owner`'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current ERC2612 nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases `owner`'s nonce by one. This
     * prevents a signature from being used multiple times.
     *
     * `owner` can limit the time a Permit is valid for by setting `deadline` to
     * a value in the near future. The deadline argument can be set to uint256(-1) to
     * create Permits that effectively never expire.
     */
    function nonces(address owner) external view returns (uint256);

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

    function permitTypeHash() external view returns (bytes32);

    function domainSeparator() external view returns (bytes32);
}

File 23 of 25 : IPool.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

// Common interface for the Pools.
interface IPool {
    // --- Events ---

    event ETHBalanceUpdated(uint256 _newBalance);
    event EBTCBalanceUpdated(uint256 _newBalance);
    event CollSharesTransferred(address indexed _to, uint256 _amount);

    // --- Functions ---

    function getSystemCollShares() external view returns (uint256);

    function getSystemDebt() external view returns (uint256);

    function increaseSystemDebt(uint256 _amount) external;

    function decreaseSystemDebt(uint256 _amount) external;
}

File 24 of 25 : ITwapWeightedObserver.sol
// SPDX-License Identifier: MIT
pragma solidity 0.8.17;
import {IBaseTwapWeightedObserver} from "./IBaseTwapWeightedObserver.sol";

interface ITwapWeightedObserver is IBaseTwapWeightedObserver {
    event TwapDisabled();

    function PERIOD() external view returns (uint256);

    function valueToTrack() external view returns (uint128);

    function timeToAccrue() external view returns (uint64);

    function getLatestAccumulator() external view returns (uint128);

    function observe() external returns (uint256);

    function update() external;

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

File 25 of 25 : IPriceFeed.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

interface IPriceFeed {
    // --- Events ---
    event LastGoodPriceUpdated(uint256 _lastGoodPrice);
    event PriceFeedStatusChanged(Status newStatus);
    event FallbackCallerChanged(
        address indexed _oldFallbackCaller,
        address indexed _newFallbackCaller
    );
    event UnhealthyFallbackCaller(address indexed _fallbackCaller, uint256 timestamp);
    event CollateralFeedSourceUpdated(address indexed stEthFeed);

    // --- Structs ---

    struct ChainlinkResponse {
        uint80 roundEthBtcId;
        uint80 roundStEthEthId;
        uint256 answer;
        uint256 timestampEthBtc;
        uint256 timestampStEthEth;
        bool success;
    }

    struct FallbackResponse {
        uint256 answer;
        uint256 timestamp;
        bool success;
    }

    // --- Enum ---

    enum Status {
        chainlinkWorking,
        usingFallbackChainlinkUntrusted,
        bothOraclesUntrusted,
        usingFallbackChainlinkFrozen,
        usingChainlinkFallbackUntrusted
    }

    // --- Function ---
    function fetchPrice() external returns (uint256);
}

File 26 of 25 : IBaseTwapWeightedObserver.sol
// SPDX-License Identifier: MIT
pragma solidity 0.8.17;

interface IBaseTwapWeightedObserver {
    // NOTE: Packing manually is cheaper, but this is simpler to understand and follow
    struct PackedData {
        // Slot 0
        // Seconds in a year: 3.154e+7
        /// @dev Accumulator value recorded for TWAP Observer until last update
        uint128 observerCumuVal; // 3.154e+7 * 80 * 100e27 = 2.5232e+38 | log_2(100e27 * 3.154e+7 * 80) = 127.568522171
        /// @dev Accumulator for TWAP globally
        uint128 accumulator; // 3.154e+7 * 80 * 100e27 = 2.5232e+38 | log_2(100e27 * 3.154e+7 * 80) = 127.568522171
        // NOTE: We can further compress this slot but we will not be able to use only one (see u72 impl)
        /// So what's the point of making the code more complex?

        // Slot 1
        /// @dev last update timestamp for TWAP Observer
        uint64 lastObserved; // Thousands of Years, if we use relative time we can use u32 | Relative to deploy time (as immutable)
        /// @dev last update timestamp for TWAP global track(spot) value
        uint64 lastAccrued; // Thousands of years
        // Expect eBTC debt to never surpass 100e27, which is 100 BILLION eBTC
        // log_2(100e27) = 96.3359147517 | log_2(100e27 / 1e18) = 36.5412090438
        // We could use a u64
        /// @dev average value since last observe
        uint128 lastObservedAverage;
    }
}

Settings
{
  "remappings": [
    "@ebtc/=lib/ebtc/packages/contracts/",
    "@crytic/=lib/",
    "ERC4626/=lib/properties/lib/ERC4626/contracts/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "ebtc/=lib/ebtc/",
    "erc4626-tests/=lib/properties/lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/properties/lib/openzeppelin-contracts/",
    "properties/=lib/properties/contracts/",
    "solmate/=lib/properties/lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"contract IERC20","name":"_wstEth","type":"address"},{"internalType":"contract IERC20","name":"_wEth","type":"address"},{"internalType":"contract IStETH","name":"_stEth","type":"address"},{"internalType":"contract IERC20","name":"_ebtc","type":"address"},{"internalType":"contract IBorrowerOperations","name":"_borrowerOperations","type":"address"},{"internalType":"contract ICdpManager","name":"_cdpManager","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"cdpId","type":"bytes32"},{"indexed":true,"internalType":"enum IEbtcZapRouter.EthVariantZapOperationType","name":"operation","type":"uint8"},{"indexed":false,"internalType":"bool","name":"isCollateralIncrease","type":"bool"},{"indexed":true,"internalType":"address","name":"collateralToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"collateralTokenDelta","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"stEthDelta","type":"uint256"},{"indexed":false,"internalType":"address","name":"cdpOwner","type":"address"}],"name":"ZapOperationEthVariant","type":"event"},{"inputs":[],"name":"LIQUIDATOR_REWARD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_CHANGE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_NET_STETH_BALANCE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NATIVE_ETH_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_cdpId","type":"bytes32"},{"internalType":"bytes32","name":"_upperHint","type":"bytes32"},{"internalType":"bytes32","name":"_lowerHint","type":"bytes32"},{"internalType":"uint256","name":"_ethBalanceIncrease","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"addCollWithEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_cdpId","type":"bytes32"},{"internalType":"uint256","name":"_collBalanceDecrease","type":"uint256"},{"internalType":"uint256","name":"_debtChange","type":"uint256"},{"internalType":"bool","name":"_isDebtIncrease","type":"bool"},{"internalType":"bytes32","name":"_upperHint","type":"bytes32"},{"internalType":"bytes32","name":"_lowerHint","type":"bytes32"},{"internalType":"uint256","name":"_collBalanceIncrease","type":"uint256"},{"internalType":"bool","name":"_useWstETHForDecrease","type":"bool"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"adjustCdp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_cdpId","type":"bytes32"},{"internalType":"uint256","name":"_collBalanceDecrease","type":"uint256"},{"internalType":"uint256","name":"_debtChange","type":"uint256"},{"internalType":"bool","name":"_isDebtIncrease","type":"bool"},{"internalType":"bytes32","name":"_upperHint","type":"bytes32"},{"internalType":"bytes32","name":"_lowerHint","type":"bytes32"},{"internalType":"uint256","name":"_ethBalanceIncrease","type":"uint256"},{"internalType":"bool","name":"_useWstETHForDecrease","type":"bool"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"adjustCdpWithEth","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_cdpId","type":"bytes32"},{"internalType":"uint256","name":"_collBalanceDecrease","type":"uint256"},{"internalType":"uint256","name":"_debtChange","type":"uint256"},{"internalType":"bool","name":"_isDebtIncrease","type":"bool"},{"internalType":"bytes32","name":"_upperHint","type":"bytes32"},{"internalType":"bytes32","name":"_lowerHint","type":"bytes32"},{"internalType":"uint256","name":"_wethBalanceIncrease","type":"uint256"},{"internalType":"bool","name":"_useWstETHForDecrease","type":"bool"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"adjustCdpWithWrappedEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_cdpId","type":"bytes32"},{"internalType":"uint256","name":"_collBalanceDecrease","type":"uint256"},{"internalType":"uint256","name":"_debtChange","type":"uint256"},{"internalType":"bool","name":"_isDebtIncrease","type":"bool"},{"internalType":"bytes32","name":"_upperHint","type":"bytes32"},{"internalType":"bytes32","name":"_lowerHint","type":"bytes32"},{"internalType":"uint256","name":"_wstEthBalanceIncrease","type":"uint256"},{"internalType":"bool","name":"_useWstETHForDecrease","type":"bool"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"adjustCdpWithWstEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"borrowerOperations","outputs":[{"internalType":"contract IBorrowerOperations","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cdpManager","outputs":[{"internalType":"contract ICdpManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_cdpId","type":"bytes32"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"closeCdp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_cdpId","type":"bytes32"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"closeCdpForWstETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ebtc","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debt","type":"uint256"},{"internalType":"bytes32","name":"_upperHint","type":"bytes32"},{"internalType":"bytes32","name":"_lowerHint","type":"bytes32"},{"internalType":"uint256","name":"_stEthBalance","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"openCdp","outputs":[{"internalType":"bytes32","name":"cdpId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debt","type":"uint256"},{"internalType":"bytes32","name":"_upperHint","type":"bytes32"},{"internalType":"bytes32","name":"_lowerHint","type":"bytes32"},{"internalType":"uint256","name":"_ethBalance","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"openCdpWithEth","outputs":[{"internalType":"bytes32","name":"cdpId","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debt","type":"uint256"},{"internalType":"bytes32","name":"_upperHint","type":"bytes32"},{"internalType":"bytes32","name":"_lowerHint","type":"bytes32"},{"internalType":"uint256","name":"_wethBalance","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"openCdpWithWrappedEth","outputs":[{"internalType":"bytes32","name":"cdpId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_debt","type":"uint256"},{"internalType":"bytes32","name":"_upperHint","type":"bytes32"},{"internalType":"bytes32","name":"_lowerHint","type":"bytes32"},{"internalType":"uint256","name":"_wstEthBalance","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IEbtcZapRouter.PositionManagerPermit","name":"_positionManagerPermit","type":"tuple"}],"name":"openCdpWithWstEth","outputs":[{"internalType":"bytes32","name":"cdpId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stEth","outputs":[{"internalType":"contract IStETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"sweepToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wrappedEth","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wstEth","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101806040523480156200001257600080fd5b5060405162002b4738038062002b478339810160408190526200003591620002e3565b6001600160a01b0387811660e05286811660c052858116608081905285821660a052848216610100819052848316610120529183166101405260405163095ea7b360e01b8152600481019290925260001960248301529063095ea7b3906044016020604051808303816000875af1158015620000b5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000db91906200038e565b5060c05160405163095ea7b360e01b81526001600160a01b039091166004820181905260001960248301529063095ea7b3906044016020604051808303816000875af115801562000130573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200015691906200038e565b5060e05160405163095ea7b360e01b81526001600160a01b039091166004820181905260001960248301529063095ea7b3906044016020604051808303816000875af1158015620001ab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001d191906200038e565b5060805160e05160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af115801562000229573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200024f91906200038e565b50610100516001600160a01b031663d9901b946040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000292573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002b89190620003b9565b6101605250620003d395505050505050565b6001600160a01b0381168114620002e057600080fd5b50565b600080600080600080600060e0888a031215620002ff57600080fd5b87516200030c81620002ca565b60208901519097506200031f81620002ca565b60408901519096506200033281620002ca565b60608901519095506200034581620002ca565b60808901519094506200035881620002ca565b60a08901519093506200036b81620002ca565b60c08901519092506200037e81620002ca565b8091505092959891949750929550565b600060208284031215620003a157600080fd5b81518015158114620003b257600080fd5b9392505050565b600060208284031215620003cc57600080fd5b5051919050565b60805160a05160c05160e051610100516101205161014051610160516125ef62000558600039600081816104ec0152611a4c0152600081816103bc01526107980152600081816104780152610dc801526000818161032501528181610bf801528181610f7f015281816115cf0152611b820152600081816103f00152818161065d015281816108be015281816110ae0152818161122a01528181611c3b01528181611cb40152611d37015260008181610154015281816102b50152818161076301528181610834015281816117b001528181611835015281816118d4015261196401526000818161038801528181610c8c01528181610e550152818161148201526116ee01526000818161044401528181610595015281816106da015281816109070152818161098c01528181610a2b01528181610acb01528181610ef301528181610ffa0152818161119e015281816115180152818161164a01528181611db501528181611e3801528181611ed501528181611f440152611fd701526125ef6000f3fe6080604052600436106101445760003560e01c80638c5888ca116100b6578063c4e4d3ac1161006f578063c4e4d3ac1461049a578063cc900ea6146104ba578063d9901b94146104da578063e90a182f1461050e578063eea081371461052e578063fb073d611461054e57600080fd5b80638c5888ca146103765780638da5cb5b146103aa57806391815a98146103de578063949868d11461041257806399940ece14610432578063bb038e151461046657600080fd5b806368ca883a1161010857806368ca883a146102a35780636ee4c8cf146102d75780637630f44d146102f357806377553ad4146103135780637f3020c11461034757806380e44cb81461036357600080fd5b80630318ab99146101ea578063284d9a8a1461021d5780632b4324f71461025d5780634163523b1461027057806367da7be51461028357600080fd5b366101e557336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101e35760405162461bcd60e51b815260206004820152603460248201527f456274635a6170526f757465723a206f6e6c7920616c6c6f7720577261707065604482015273642045544820746f2073656e642045746865722160601b60648201526084015b60405180910390fd5b005b600080fd5b3480156101f657600080fd5b5061020a6102053660046122a2565b61056e565b6040519081526020015b60405180910390f35b34801561022957600080fd5b5061024573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b039091168152602001610214565b6101e361026b3660046122fb565b6105ef565b6101e361027e3660046122a2565b61060b565b34801561028f57600080fd5b506101e361029e36600461237e565b610626565b3480156102af57600080fd5b506102457f000000000000000000000000000000000000000000000000000000000000000081565b3480156102e357600080fd5b5061020a671bc16d674ec8000081565b3480156102ff57600080fd5b5061020a61030e3660046122a2565b610636565b34801561031f57600080fd5b506102457f000000000000000000000000000000000000000000000000000000000000000081565b34801561035357600080fd5b5061020a6702c68af0bb14000081565b61020a6103713660046122a2565b610684565b34801561038257600080fd5b506102457f000000000000000000000000000000000000000000000000000000000000000081565b3480156103b657600080fd5b506102457f000000000000000000000000000000000000000000000000000000000000000081565b3480156103ea57600080fd5b506102457f000000000000000000000000000000000000000000000000000000000000000081565b34801561041e57600080fd5b506101e361042d3660046122fb565b6106bd565b34801561043e57600080fd5b506102457f000000000000000000000000000000000000000000000000000000000000000081565b34801561047257600080fd5b506102457f000000000000000000000000000000000000000000000000000000000000000081565b3480156104a657600080fd5b5061020a6104b53660046122a2565b61073c565b3480156104c657600080fd5b506101e36104d536600461237e565b61078a565b3480156104e657600080fd5b5061020a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561051a57600080fd5b506101e36105293660046123ab565b610796565b34801561053a57600080fd5b506101e36105493660046122fb565b610818565b34801561055a57600080fd5b506101e36105693660046122fb565b6108a2565b60008061057a846108e5565b90506105898787878487610aa9565b91506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660005b8360008051602061259a83398151915260018886336040516105dd94939291906123f9565b60405180910390a45095945050505050565b610600898989898989898989610d0b565b505050505050505050565b61061f856000806000888888600089610d0b565b5050505050565b61063282600083610d39565b5050565b60008061064284611094565b90506106518787878487610aa9565b91506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660006105b8565b6000806106908461129f565b905061069f8787878487610aa9565b915073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60006105b8565b821561072b5760006106ce846108e5565b90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660018b60008051602061259a833981519152600188863360405161072194939291906123f9565b60405180910390a4505b61060089898989898989898961130b565b6000806107488461178e565b90506107578787878487610aa9565b91506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660006105b8565b61063282600183610d39565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633146107fe5760405162461bcd60e51b815260206004820152600d60248201526c26bab9ba1031329037bbb732b960991b60448201526064016101da565b8015610632576106326001600160a01b03831633836119eb565b828015610885576108288461178e565b90506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660015b8b60008051602061259a833981519152600188863360405161087c94939291906123f9565b60405180910390a45b6108968a8a8a8a8a8a878a8a61130b565b50505050505050505050565b828015610885576108b284611094565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166001610857565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561094e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610972919061241f565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906109c590339030908890600401612438565b6020604051808303816000875af11580156109e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a08919061245c565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a08231906024015b602060405180830381865afa158015610a73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a97919061241f565b610aa19190612480565b949350505050565b6040516370a0823160e01b815230600482015260009083906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015610b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b36919061241f565b1015610b9b5760405162461bcd60e51b815260206004820152602e60248201527f456274635a6170526f757465723a206e6f7420656e6f75676820636f6c6c617460448201526d6572616c20666f72206f70656e2160901b60648201526084016101da565b610ba486611a42565b610bbe610bb96702c68af0bb14000085612480565b611aef565b610bc782611b78565b6040516338d0b1cb60e21b8152600481018790526024810186905260448101859052606481018490523360848201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063e342c72c9060a4016020604051808303816000875af1158015610c49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6d919061241f565b60405163a9059cbb60e01b8152336004820152602481018890529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610cdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d01919061245c565b5095945050505050565b82801561088557610d1b8461129f565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001610857565b610d438360601c90565b6001600160a01b0316336001600160a01b031614610daf5760405162461bcd60e51b815260206004820152602360248201527f456274635a6170526f757465723a206e6f74206f776e657220666f7220636c6f60448201526273652160e81b60648201526084016101da565b6040516318cc429f60e11b8152600481018490526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690633198853e90602401602060405180830381865afa158015610e17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3b919061241f565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90610e8e90339030908690600401612438565b6020604051808303816000875af1158015610ead573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed1919061245c565b50610edb82611b78565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f66919061241f565b6040516314e67a0360e01b8152600481018790529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906314e67a0390602401600060405180830381600087803b158015610fcb57600080fd5b505af1158015610fdf573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691506370a0823190602401602060405180830381865afa15801561104a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106e919061241f565b9050600061107c8383612480565b905061108b8760028884611c1c565b50505050505050565b6040516323b872dd60e01b81526000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906110e790339030908790600401612438565b6020604051808303816000875af1158015611106573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112a919061245c565b6111865760405162461bcd60e51b815260206004820152602760248201527f456274635a6170526f757465723a207472616e7366657220777374455448206660448201526661696c7572652160c81b60648201526084016101da565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156111ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611211919061241f565b604051636f074d1f60e11b8152600481018590529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063de0e9a3e906024016020604051808303816000875af115801561127b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a08919061241f565b60008134146112fc5760405162461bcd60e51b815260206004820152602360248201527f456274635a6170526f757465723a20496e636f72726563742045544820616d6f6044820152621d5b9d60ea1b60648201526084016101da565b61130582611eb3565b92915050565b6113158960601c90565b6001600160a01b0316336001600160a01b0316146113815760405162461bcd60e51b8152602060048201526024808201527f456274635a6170526f757465723a206e6f74206f776e657220666f722061646a6044820152637573742160e01b60648201526084016101da565b60008811801561138f575082155b806113a357506000831180156113a3575087155b806113b55750821580156113b5575087155b611429576040805162461bcd60e51b81526020600482015260248101919091527f456274635a6170526f757465723a2063616e27742061646420616e642072656d60448201527f6f766520636f6c6c61746572616c206174207468652073616d652074696d652160648201526084016101da565b611434838989612006565b61143d87611a42565b61144683611a42565b61144f88611a42565b61145881611b78565b851580156114665750600087115b15611500576040516323b872dd60e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906114bb90339030908c90600401612438565b6020604051808303816000875af11580156114da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fe919061245c565b505b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158b919061241f565b604051639d938e8560e01b8152600481018c9052602481018b9052604481018a905288151560648201526084810188905260a4810187905260c481018690529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690639d938e859060e401600060405180830381600087803b15801561161b57600080fd5b505af115801561162f573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691506370a0823190602401602060405180830381865afa15801561169a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116be919061241f565b90508780156116cd5750600089115b156117655760405163a9059cbb60e01b8152336004820152602481018a90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af115801561173f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611763919061245c565b505b8915611781576117818b60018661177c8686612480565b611c1c565b5050505050505050505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b919061241f565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd9061186e90339030908890600401612438565b6020604051808303816000875af115801561188d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b1919061245c565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561191b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193f919061241f565b6119499190612480565b604051632e1a7d4d60e01b81526004810182905290915047907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156119b057600080fd5b505af11580156119c4573d6000803e3d6000fd5b50505050600081476119d69190612480565b90506119e181611eb3565b9695505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611a3d908490612092565b505050565b801580611a6f57507f00000000000000000000000000000000000000000000000000000000000000008110155b611aec5760405162461bcd60e51b815260206004820152604260248201527f456274635a6170526f757465723a2044656274206f7220636f6c6c617465726160448201527f6c206368616e6765206d757374206265207a65726f206f722061626f7665206d60648201526134b760f11b608482015260a4016101da565b50565b671bc16d674ec80000811015611aec5760405162461bcd60e51b815260206004820152604260248201527f456274635a6170526f757465723a204364702773206e6574207374457468206260448201527f616c616e6365206d757374206e6f742066616c6c2062656c6f77206d696e696d606482015261756d60f01b608482015260a4016101da565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663ca542f89333060018535611bbd60408801602089016124a1565b876040013588606001356040518863ffffffff1660e01b8152600401611be997969594939291906124c4565b600060405180830381600087803b158015611c0357600080fd5b505af1925050508015611c14575060015b15611aec5750565b8115611db357604051630ea598cb60e41b8152600481018290526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ea598cb0906024016020604051808303816000875af1158015611c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb0919061241f565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846002811115611cee57611cee6123e3565b8660008051602061259a8339815191526000858733604051611d1394939291906123f9565b60405180910390a460405163a9059cbb60e01b8152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611d88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dac919061245c565b5050611ead565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836002811115611def57611def6123e3565b8560008051602061259a8339815191526000858633604051611e1494939291906123f9565b60405180910390a460405163a9059cbb60e01b8152336004820152602481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611e89573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061f919061245c565b50505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f40919061241f565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168360405160006040518083038185875af1925050503d8060008114611fad576040519150601f19603f3d011682016040523d82523d6000602084013e611fb2565b606091505b50506040516370a0823160e01b81523060048201526000915082906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401610a56565b60008311806120155750600082115b806120205750600081115b611a3d5760405162461bcd60e51b815260206004820152603f60248201527f456274635a6170526f757465723a205468657265206d7573742062652065697460448201527f686572206120636f6c6c61746572616c206f722064656274206368616e67650060648201526084016101da565b60006120e7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166121679092919063ffffffff16565b9050805160001480612108575080806020019051810190612108919061245c565b611a3d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016101da565b6060610aa1848460008585600080866001600160a01b0316858760405161218e919061254a565b60006040518083038185875af1925050503d80600081146121cb576040519150601f19603f3d011682016040523d82523d6000602084013e6121d0565b606091505b50915091506121e1878383876121ec565b979650505050505050565b6060831561225b578251600003612254576001600160a01b0385163b6122545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101da565b5081610aa1565b610aa183838151156122705781518083602001fd5b8060405162461bcd60e51b81526004016101da9190612566565b60006080828403121561229c57600080fd5b50919050565b600080600080600061010086880312156122bb57600080fd5b853594506020860135935060408601359250606086013591506122e1876080880161228a565b90509295509295909350565b8015158114611aec57600080fd5b60008060008060008060008060006101808a8c03121561231a57600080fd5b8935985060208a0135975060408a0135965060608a013561233a816122ed565b955060808a0135945060a08a0135935060c08a0135925060e08a013561235f816122ed565b915061236f8b6101008c0161228a565b90509295985092959850929598565b60008060a0838503121561239157600080fd5b823591506123a2846020850161228a565b90509250929050565b600080604083850312156123be57600080fd5b82356001600160a01b03811681146123d557600080fd5b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b9315158452602084019290925260408301526001600160a01b0316606082015260800190565b60006020828403121561243157600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60006020828403121561246e57600080fd5b8151612479816122ed565b9392505050565b8181038181111561130557634e487b7160e01b600052601160045260246000fd5b6000602082840312156124b357600080fd5b813560ff8116811461247957600080fd5b6001600160a01b0388811682528716602082015260e08101600387106124fa57634e487b7160e01b600052602160045260246000fd5b6040820196909652606081019490945260ff92909216608084015260a083015260c09091015292915050565b60005b83811015612541578181015183820152602001612529565b50506000910152565b6000825161255c818460208701612526565b9190910192915050565b6020815260008251806020840152612585816040850160208701612526565b601f01601f1916919091016040019291505056fef415a19a6ef014ac40c05386c2befca0cdf7415e3de0fee79d4ad7645db88bbea264697066735822122027326678788a06d1aea381f44bd00080cec3f8a20e0f89e4c70cb2ae1e0a8bcf64736f6c634300081100330000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000661c70333aa1850ccdbae82776bb436a0fcfeefb000000000000000000000000d366e016ae0677cdce93472e603b75051e022ad0000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c375711774000000000000000000000000690c74af48be029e763e61b4adeb10e06119d3ba

Deployed Bytecode

0x6080604052600436106101445760003560e01c80638c5888ca116100b6578063c4e4d3ac1161006f578063c4e4d3ac1461049a578063cc900ea6146104ba578063d9901b94146104da578063e90a182f1461050e578063eea081371461052e578063fb073d611461054e57600080fd5b80638c5888ca146103765780638da5cb5b146103aa57806391815a98146103de578063949868d11461041257806399940ece14610432578063bb038e151461046657600080fd5b806368ca883a1161010857806368ca883a146102a35780636ee4c8cf146102d75780637630f44d146102f357806377553ad4146103135780637f3020c11461034757806380e44cb81461036357600080fd5b80630318ab99146101ea578063284d9a8a1461021d5780632b4324f71461025d5780634163523b1461027057806367da7be51461028357600080fd5b366101e557336001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216146101e35760405162461bcd60e51b815260206004820152603460248201527f456274635a6170526f757465723a206f6e6c7920616c6c6f7720577261707065604482015273642045544820746f2073656e642045746865722160601b60648201526084015b60405180910390fd5b005b600080fd5b3480156101f657600080fd5b5061020a6102053660046122a2565b61056e565b6040519081526020015b60405180910390f35b34801561022957600080fd5b5061024573eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee81565b6040516001600160a01b039091168152602001610214565b6101e361026b3660046122fb565b6105ef565b6101e361027e3660046122a2565b61060b565b34801561028f57600080fd5b506101e361029e36600461237e565b610626565b3480156102af57600080fd5b506102457f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b3480156102e357600080fd5b5061020a671bc16d674ec8000081565b3480156102ff57600080fd5b5061020a61030e3660046122a2565b610636565b34801561031f57600080fd5b506102457f000000000000000000000000d366e016ae0677cdce93472e603b75051e022ad081565b34801561035357600080fd5b5061020a6702c68af0bb14000081565b61020a6103713660046122a2565b610684565b34801561038257600080fd5b506102457f000000000000000000000000661c70333aa1850ccdbae82776bb436a0fcfeefb81565b3480156103b657600080fd5b506102457f000000000000000000000000690c74af48be029e763e61b4adeb10e06119d3ba81565b3480156103ea57600080fd5b506102457f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca081565b34801561041e57600080fd5b506101e361042d3660046122fb565b6106bd565b34801561043e57600080fd5b506102457f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8481565b34801561047257600080fd5b506102457f000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c37571177481565b3480156104a657600080fd5b5061020a6104b53660046122a2565b61073c565b3480156104c657600080fd5b506101e36104d536600461237e565b61078a565b3480156104e657600080fd5b5061020a7f00000000000000000000000000000000000000000000000000000000000003e881565b34801561051a57600080fd5b506101e36105293660046123ab565b610796565b34801561053a57600080fd5b506101e36105493660046122fb565b610818565b34801561055a57600080fd5b506101e36105693660046122fb565b6108a2565b60008061057a846108e5565b90506105898787878487610aa9565b91506001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe841660005b8360008051602061259a83398151915260018886336040516105dd94939291906123f9565b60405180910390a45095945050505050565b610600898989898989898989610d0b565b505050505050505050565b61061f856000806000888888600089610d0b565b5050505050565b61063282600083610d39565b5050565b60008061064284611094565b90506106518787878487610aa9565b91506001600160a01b037f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca01660006105b8565b6000806106908461129f565b905061069f8787878487610aa9565b915073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60006105b8565b821561072b5760006106ce846108e5565b90506001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe841660018b60008051602061259a833981519152600188863360405161072194939291906123f9565b60405180910390a4505b61060089898989898989898961130b565b6000806107488461178e565b90506107578787878487610aa9565b91506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21660006105b8565b61063282600183610d39565b7f000000000000000000000000690c74af48be029e763e61b4adeb10e06119d3ba6001600160a01b031633146107fe5760405162461bcd60e51b815260206004820152600d60248201526c26bab9ba1031329037bbb732b960991b60448201526064016101da565b8015610632576106326001600160a01b03831633836119eb565b828015610885576108288461178e565b90506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc21660015b8b60008051602061259a833981519152600188863360405161087c94939291906123f9565b60405180910390a45b6108968a8a8a8a8a8a878a8a61130b565b50505050505050505050565b828015610885576108b284611094565b90506001600160a01b037f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0166001610857565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8416906370a0823190602401602060405180830381865afa15801561094e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610972919061241f565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8416906323b872dd906109c590339030908890600401612438565b6020604051808303816000875af11580156109e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a08919061245c565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8416906370a08231906024015b602060405180830381865afa158015610a73573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a97919061241f565b610aa19190612480565b949350505050565b6040516370a0823160e01b815230600482015260009083906001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8416906370a0823190602401602060405180830381865afa158015610b12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b36919061241f565b1015610b9b5760405162461bcd60e51b815260206004820152602e60248201527f456274635a6170526f757465723a206e6f7420656e6f75676820636f6c6c617460448201526d6572616c20666f72206f70656e2160901b60648201526084016101da565b610ba486611a42565b610bbe610bb96702c68af0bb14000085612480565b611aef565b610bc782611b78565b6040516338d0b1cb60e21b8152600481018790526024810186905260448101859052606481018490523360848201527f000000000000000000000000d366e016ae0677cdce93472e603b75051e022ad06001600160a01b03169063e342c72c9060a4016020604051808303816000875af1158015610c49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c6d919061241f565b60405163a9059cbb60e01b8152336004820152602481018890529091507f000000000000000000000000661c70333aa1850ccdbae82776bb436a0fcfeefb6001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015610cdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d01919061245c565b5095945050505050565b82801561088557610d1b8461129f565b905073eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6001610857565b610d438360601c90565b6001600160a01b0316336001600160a01b031614610daf5760405162461bcd60e51b815260206004820152602360248201527f456274635a6170526f757465723a206e6f74206f776e657220666f7220636c6f60448201526273652160e81b60648201526084016101da565b6040516318cc429f60e11b8152600481018490526000907f000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c3757117746001600160a01b031690633198853e90602401602060405180830381865afa158015610e17573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e3b919061241f565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000661c70333aa1850ccdbae82776bb436a0fcfeefb16906323b872dd90610e8e90339030908690600401612438565b6020604051808303816000875af1158015610ead573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ed1919061245c565b50610edb82611b78565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b0316906370a0823190602401602060405180830381865afa158015610f42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f66919061241f565b6040516314e67a0360e01b8152600481018790529091507f000000000000000000000000d366e016ae0677cdce93472e603b75051e022ad06001600160a01b0316906314e67a0390602401600060405180830381600087803b158015610fcb57600080fd5b505af1158015610fdf573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092507f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b031691506370a0823190602401602060405180830381865afa15801561104a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106e919061241f565b9050600061107c8383612480565b905061108b8760028884611c1c565b50505050505050565b6040516323b872dd60e01b81526000906001600160a01b037f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca016906323b872dd906110e790339030908790600401612438565b6020604051808303816000875af1158015611106573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112a919061245c565b6111865760405162461bcd60e51b815260206004820152602760248201527f456274635a6170526f757465723a207472616e7366657220777374455448206660448201526661696c7572652160c81b60648201526084016101da565b6040516370a0823160e01b81523060048201526000907f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b0316906370a0823190602401602060405180830381865afa1580156111ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611211919061241f565b604051636f074d1f60e11b8152600481018590529091507f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b03169063de0e9a3e906024016020604051808303816000875af115801561127b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a08919061241f565b60008134146112fc5760405162461bcd60e51b815260206004820152602360248201527f456274635a6170526f757465723a20496e636f72726563742045544820616d6f6044820152621d5b9d60ea1b60648201526084016101da565b61130582611eb3565b92915050565b6113158960601c90565b6001600160a01b0316336001600160a01b0316146113815760405162461bcd60e51b8152602060048201526024808201527f456274635a6170526f757465723a206e6f74206f776e657220666f722061646a6044820152637573742160e01b60648201526084016101da565b60008811801561138f575082155b806113a357506000831180156113a3575087155b806113b55750821580156113b5575087155b611429576040805162461bcd60e51b81526020600482015260248101919091527f456274635a6170526f757465723a2063616e27742061646420616e642072656d60448201527f6f766520636f6c6c61746572616c206174207468652073616d652074696d652160648201526084016101da565b611434838989612006565b61143d87611a42565b61144683611a42565b61144f88611a42565b61145881611b78565b851580156114665750600087115b15611500576040516323b872dd60e01b81526001600160a01b037f000000000000000000000000661c70333aa1850ccdbae82776bb436a0fcfeefb16906323b872dd906114bb90339030908c90600401612438565b6020604051808303816000875af11580156114da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114fe919061245c565b505b6040516370a0823160e01b81523060048201526000907f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b0316906370a0823190602401602060405180830381865afa158015611567573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061158b919061241f565b604051639d938e8560e01b8152600481018c9052602481018b9052604481018a905288151560648201526084810188905260a4810187905260c481018690529091507f000000000000000000000000d366e016ae0677cdce93472e603b75051e022ad06001600160a01b031690639d938e859060e401600060405180830381600087803b15801561161b57600080fd5b505af115801561162f573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092507f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b031691506370a0823190602401602060405180830381865afa15801561169a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116be919061241f565b90508780156116cd5750600089115b156117655760405163a9059cbb60e01b8152336004820152602481018a90527f000000000000000000000000661c70333aa1850ccdbae82776bb436a0fcfeefb6001600160a01b03169063a9059cbb906044016020604051808303816000875af115801561173f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611763919061245c565b505b8915611781576117818b60018661177c8686612480565b611c1c565b5050505050505050505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190602401602060405180830381865afa1580156117f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061181b919061241f565b6040516323b872dd60e01b81529091506001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906323b872dd9061186e90339030908890600401612438565b6020604051808303816000875af115801561188d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118b1919061245c565b506040516370a0823160e01b815230600482015260009082906001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc216906370a0823190602401602060405180830381865afa15801561191b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193f919061241f565b6119499190612480565b604051632e1a7d4d60e01b81526004810182905290915047907f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031690632e1a7d4d90602401600060405180830381600087803b1580156119b057600080fd5b505af11580156119c4573d6000803e3d6000fd5b50505050600081476119d69190612480565b90506119e181611eb3565b9695505050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611a3d908490612092565b505050565b801580611a6f57507f00000000000000000000000000000000000000000000000000000000000003e88110155b611aec5760405162461bcd60e51b815260206004820152604260248201527f456274635a6170526f757465723a2044656274206f7220636f6c6c617465726160448201527f6c206368616e6765206d757374206265207a65726f206f722061626f7665206d60648201526134b760f11b608482015260a4016101da565b50565b671bc16d674ec80000811015611aec5760405162461bcd60e51b815260206004820152604260248201527f456274635a6170526f757465723a204364702773206e6574207374457468206260448201527f616c616e6365206d757374206e6f742066616c6c2062656c6f77206d696e696d606482015261756d60f01b608482015260a4016101da565b6001600160a01b037f000000000000000000000000d366e016ae0677cdce93472e603b75051e022ad01663ca542f89333060018535611bbd60408801602089016124a1565b876040013588606001356040518863ffffffff1660e01b8152600401611be997969594939291906124c4565b600060405180830381600087803b158015611c0357600080fd5b505af1925050508015611c14575060015b15611aec5750565b8115611db357604051630ea598cb60e41b8152600481018290526000907f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b03169063ea598cb0906024016020604051808303816000875af1158015611c8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cb0919061241f565b90507f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b0316846002811115611cee57611cee6123e3565b8660008051602061259a8339815191526000858733604051611d1394939291906123f9565b60405180910390a460405163a9059cbb60e01b8152336004820152602481018290527f0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca06001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611d88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611dac919061245c565b5050611ead565b7f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b0316836002811115611def57611def6123e3565b8560008051602061259a8339815191526000858633604051611e1494939291906123f9565b60405180910390a460405163a9059cbb60e01b8152336004820152602481018290527f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b03169063a9059cbb906044016020604051808303816000875af1158015611e89573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061f919061245c565b50505050565b6040516370a0823160e01b815230600482015260009081906001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8416906370a0823190602401602060405180830381865afa158015611f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f40919061241f565b90507f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe846001600160a01b03168360405160006040518083038185875af1925050503d8060008114611fad576040519150601f19603f3d011682016040523d82523d6000602084013e611fb2565b606091505b50506040516370a0823160e01b81523060048201526000915082906001600160a01b037f000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe8416906370a0823190602401610a56565b60008311806120155750600082115b806120205750600081115b611a3d5760405162461bcd60e51b815260206004820152603f60248201527f456274635a6170526f757465723a205468657265206d7573742062652065697460448201527f686572206120636f6c6c61746572616c206f722064656274206368616e67650060648201526084016101da565b60006120e7826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166121679092919063ffffffff16565b9050805160001480612108575080806020019051810190612108919061245c565b611a3d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016101da565b6060610aa1848460008585600080866001600160a01b0316858760405161218e919061254a565b60006040518083038185875af1925050503d80600081146121cb576040519150601f19603f3d011682016040523d82523d6000602084013e6121d0565b606091505b50915091506121e1878383876121ec565b979650505050505050565b6060831561225b578251600003612254576001600160a01b0385163b6122545760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016101da565b5081610aa1565b610aa183838151156122705781518083602001fd5b8060405162461bcd60e51b81526004016101da9190612566565b60006080828403121561229c57600080fd5b50919050565b600080600080600061010086880312156122bb57600080fd5b853594506020860135935060408601359250606086013591506122e1876080880161228a565b90509295509295909350565b8015158114611aec57600080fd5b60008060008060008060008060006101808a8c03121561231a57600080fd5b8935985060208a0135975060408a0135965060608a013561233a816122ed565b955060808a0135945060a08a0135935060c08a0135925060e08a013561235f816122ed565b915061236f8b6101008c0161228a565b90509295985092959850929598565b60008060a0838503121561239157600080fd5b823591506123a2846020850161228a565b90509250929050565b600080604083850312156123be57600080fd5b82356001600160a01b03811681146123d557600080fd5b946020939093013593505050565b634e487b7160e01b600052602160045260246000fd5b9315158452602084019290925260408301526001600160a01b0316606082015260800190565b60006020828403121561243157600080fd5b5051919050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b60006020828403121561246e57600080fd5b8151612479816122ed565b9392505050565b8181038181111561130557634e487b7160e01b600052601160045260246000fd5b6000602082840312156124b357600080fd5b813560ff8116811461247957600080fd5b6001600160a01b0388811682528716602082015260e08101600387106124fa57634e487b7160e01b600052602160045260246000fd5b6040820196909652606081019490945260ff92909216608084015260a083015260c09091015292915050565b60005b83811015612541578181015183820152602001612529565b50506000910152565b6000825161255c818460208701612526565b9190910192915050565b6020815260008251806020840152612585816040850160208701612526565b601f01601f1916919091016040019291505056fef415a19a6ef014ac40c05386c2befca0cdf7415e3de0fee79d4ad7645db88bbea264697066735822122027326678788a06d1aea381f44bd00080cec3f8a20e0f89e4c70cb2ae1e0a8bcf64736f6c63430008110033

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

0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84000000000000000000000000661c70333aa1850ccdbae82776bb436a0fcfeefb000000000000000000000000d366e016ae0677cdce93472e603b75051e022ad0000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c375711774000000000000000000000000690c74af48be029e763e61b4adeb10e06119d3ba

-----Decoded View---------------
Arg [0] : _wstEth (address): 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0
Arg [1] : _wEth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : _stEth (address): 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84
Arg [3] : _ebtc (address): 0x661c70333AA1850CcDBAe82776Bb436A0fCfeEfB
Arg [4] : _borrowerOperations (address): 0xd366e016Ae0677CdCE93472e603b75051E022AD0
Arg [5] : _cdpManager (address): 0xc4cbaE499bb4Ca41E78f52F07f5d98c375711774
Arg [6] : _owner (address): 0x690C74AF48BE029e763E61b4aDeB10E06119D3ba

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84
Arg [3] : 000000000000000000000000661c70333aa1850ccdbae82776bb436a0fcfeefb
Arg [4] : 000000000000000000000000d366e016ae0677cdce93472e603b75051e022ad0
Arg [5] : 000000000000000000000000c4cbae499bb4ca41e78f52f07f5d98c375711774
Arg [6] : 000000000000000000000000690c74af48be029e763e61b4adeb10e06119d3ba


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  ]
[ 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.