ETH Price: $2,908.26 (+1.21%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Pause144977522022-04-01 2:41:23952 days ago1648780883IN
0xdF60b2CC...F39939f4C
0 ETH0.0031235460.86892698
Repay Vault144846202022-03-30 1:27:56954 days ago1648603676IN
0xdF60b2CC...F39939f4C
0 ETH0.0032461537.73982662
Report To Vault144845932022-03-30 1:21:44954 days ago1648603304IN
0xdF60b2CC...F39939f4C
0 ETH0.0035408933.73819359
Repay Vault144652652022-03-27 1:22:05957 days ago1648344125IN
0xdF60b2CC...F39939f4C
0 ETH0.0026961431.34540118
Report To Vault144652312022-03-27 1:13:49957 days ago1648343629IN
0xdF60b2CC...F39939f4C
0 ETH0.0027882426.5668715
Report To Vault144460362022-03-24 1:21:31960 days ago1648084891IN
0xdF60b2CC...F39939f4C
0 ETH0.0056166953.51681241
Repay Vault144269792022-03-21 2:11:01963 days ago1647828661IN
0xdF60b2CC...F39939f4C
0 ETH0.0025124729.21012695
Report To Vault144268842022-03-21 1:48:38963 days ago1647827318IN
0xdF60b2CC...F39939f4C
0 ETH0.0023979922.84851624
Borrow From Vaul...144075912022-03-18 2:02:56966 days ago1647568976IN
0xdF60b2CC...F39939f4C
0 ETH0.007382364.02470919
Report To Vault144075772022-03-18 1:59:32966 days ago1647568772IN
0xdF60b2CC...F39939f4C
0 ETH0.0050831248.4328673
Repay Vault143882382022-03-15 1:23:43969 days ago1647307423IN
0xdF60b2CC...F39939f4C
0 ETH0.0034797440.4555105
Report To Vault143882142022-03-15 1:16:51969 days ago1647307011IN
0xdF60b2CC...F39939f4C
0 ETH0.0034280432.66296459
Borrow From Vaul...143690432022-03-12 1:40:38972 days ago1647049238IN
0xdF60b2CC...F39939f4C
0 ETH0.0022664919.65669229
Report To Vault143690242022-03-12 1:37:29972 days ago1647049049IN
0xdF60b2CC...F39939f4C
0 ETH0.0029292727.90425378
Repay Vault143497142022-03-09 1:41:04975 days ago1646790064IN
0xdF60b2CC...F39939f4C
0 ETH0.0021838625.39673655
Report To Vault143496692022-03-09 1:34:37975 days ago1646789677IN
0xdF60b2CC...F39939f4C
0 ETH0.0046026443.84478333
Borrow From Vaul...143305272022-03-06 2:00:49978 days ago1646532049IN
0xdF60b2CC...F39939f4C
0 ETH0.0029649325.71408278
Borrow From Vaul...143303422022-03-06 1:21:02978 days ago1646529662IN
0xdF60b2CC...F39939f4C
0 ETH0.0044833438.88285593
Report To Vault143303252022-03-06 1:16:32978 days ago1646529392IN
0xdF60b2CC...F39939f4C
0 ETH0.0034136332.51821646
Repay Vault143111892022-03-03 1:59:04981 days ago1646272744IN
0xdF60b2CC...F39939f4C
0 ETH0.0056579565.79777234
Report To Vault143110982022-03-03 1:39:36981 days ago1646271576IN
0xdF60b2CC...F39939f4C
0 ETH0.0055683953.04443136
Borrow From Vaul...143026762022-03-01 18:15:23982 days ago1646158523IN
0xdF60b2CC...F39939f4C
0 ETH0.0112740299.74096185
Borrow From Vaul...142916262022-02-28 1:11:41984 days ago1646010701IN
0xdF60b2CC...F39939f4C
0 ETH0.0057492149.86134174
Report To Vault142916082022-02-28 1:08:07984 days ago1646010487IN
0xdF60b2CC...F39939f4C
0 ETH0.0066594963.43830276
Borrow From Vaul...142723612022-02-25 1:38:27987 days ago1645753107IN
0xdF60b2CC...F39939f4C
0 ETH0.0052587145.6074094
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0x7C765C47...09071cba7
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
Vyper_contract

Compiler Version
vyper:0.2.12

Optimization Enabled:
N/A

Other Settings:
GNU AGPLv3 license

Contract Source Code (Vyper language format)

# @version 0.2.12

"""
@title Unagii FundManager 0.1.1
@author stakewith.us
@license AGPL-3.0-or-later
"""

from vyper.interfaces import ERC20


interface Vault:
    def token() -> address: view
    def debt() -> uint256: view
    def borrow(amount: uint256) -> uint256: nonpayable
    def repay(amount: uint256) -> uint256: nonpayable
    def report(gain: uint256, loss: uint256): nonpayable


interface IStrategy:
    def fundManager() -> address: view
    def token() -> address: view
    def withdraw(amount: uint256) -> uint256: nonpayable
    def migrate(newVersion: address): nonpayable


# interface to new version of FundManager used for migration
interface FundManager:
    def token() -> address: view
    def vault() -> address: view
    def totalDebt() -> uint256: view
    def totalDebtRatio() -> uint256: view
    def queue(i: uint256) -> address: view
    def strategies(
        addr: address,
    ) -> (bool, bool, bool, uint256, uint256, uint256, uint256): view
    def initialize(): nonpayable


# maximum number of active strategies
MAX_QUEUE: constant(uint256) = 20


struct Strategy:
    approved: bool
    active: bool
    activated: bool  # sent to True once after strategy is active
    debtRatio: uint256  # ratio of total assets this strategy can borrow
    debt: uint256  # current amount borrowed
    minBorrow: uint256  # minimum amount to borrow per call to borrow()
    maxBorrow: uint256  # maximum amount to borrow per call to borrow()


event SetNextTimeLock:
    nextTimeLock: address


event AcceptTimeLock:
    timeLock: address


event SetAdmin:
    admin: address


event SetGuardian:
    guardian: address


event SetWorker:
    worker: address


event SetPause:
    paused: bool


event SetVault:
    vault: address


event ApproveStrategy:
    strategy: indexed(address)


event RevokeStrategy:
    strategy: indexed(address)


event AddStrategyToQueue:
    strategy: indexed(address)


event RemoveStrategyFromQueue:
    strategy: indexed(address)


event SetQueue:
    queue: address[MAX_QUEUE]


event SetDebtRatios:
    debtRatios: uint256[MAX_QUEUE]


event SetMinMaxBorrow:
    strategy: indexed(address)
    minBorrow: uint256
    maxBorrow: uint256


event BorrowFromVault:
    vault: indexed(address)
    amount: uint256
    borrowed: uint256


event RepayVault:
    vault: indexed(address)
    amount: uint256
    repaid: uint256


event ReportToVault:
    vault: indexed(address)
    total: uint256
    debt: uint256
    gain: uint256
    loss: uint256


event Withdraw:
    vault: indexed(address)
    amount: uint256
    actual: uint256
    loss: uint256


event WithdrawStrategy:
    strategy: indexed(address)
    debt: uint256
    need: uint256
    loss: uint256
    diff: uint256


event Borrow:
    strategy: indexed(address)
    amount: uint256
    borrowed: uint256


event Repay:
    strategy: indexed(address)
    amount: uint256
    repaid: uint256


event Report:
    strategy: indexed(address)
    gain: uint256
    loss: uint256
    debt: uint256


event MigrateStrategy:
    oldStrategy: indexed(address)
    newStrategy: indexed(address)


event Migrate:
    fundManager: address
    bal: uint256
    totalDebt: uint256


paused: public(bool)
initialized: public(bool)

vault: public(Vault)
token: public(ERC20)
# privileges - time lock >= admin >= guardian, worker
timeLock: public(address)
nextTimeLock: public(address)
admin: public(address)
guardian: public(address)
worker: public(address)

totalDebt: public(uint256)  # sum of all debts of strategies
MAX_TOTAL_DEBT_RATIO: constant(uint256) = 10000
totalDebtRatio: public(uint256)  # sum of all debtRatios of strategies
strategies: public(HashMap[address, Strategy])  # all strategies
queue: public(address[MAX_QUEUE])  # list of active strategies

# migration
OLD_MAX_QUEUE: constant(uint256) = 20  # must be <= MAX_QUEUE
oldFundManager: public(FundManager)


@external
def __init__(
    token: address, guardian: address, worker: address, oldFundManager: address
):
    self.token = ERC20(token)
    self.timeLock = msg.sender
    self.admin = msg.sender
    self.guardian = guardian
    self.worker = worker

    if oldFundManager != ZERO_ADDRESS:
        self.oldFundManager = FundManager(oldFundManager)
        assert self.oldFundManager.token() == token, "old fund manager token != token"


@internal
def _safeApprove(token: address, spender: address, amount: uint256):
    res: Bytes[32] = raw_call(
        token,
        concat(
            method_id("approve(address,uint256)"),
            convert(spender, bytes32),
            convert(amount, bytes32),
        ),
        max_outsize=32,
    )
    if len(res) > 0:
        assert convert(res, bool), "approve failed"


@internal
def _safeTransfer(token: address, receiver: address, amount: uint256):
    res: Bytes[32] = raw_call(
        token,
        concat(
            method_id("transfer(address,uint256)"),
            convert(receiver, bytes32),
            convert(amount, bytes32),
        ),
        max_outsize=32,
    )
    if len(res) > 0:
        assert convert(res, bool), "transfer failed"


@internal
def _safeTransferFrom(
    token: address, owner: address, receiver: address, amount: uint256
):
    res: Bytes[32] = raw_call(
        token,
        concat(
            method_id("transferFrom(address,address,uint256)"),
            convert(owner, bytes32),
            convert(receiver, bytes32),
            convert(amount, bytes32),
        ),
        max_outsize=32,
    )
    if len(res) > 0:
        assert convert(res, bool), "transferFrom failed"


@external
def initialize():
    """
    @notice Initialize fund manager. Transfer tokens and copy states if
            old fund manager is set.
    """
    assert not self.initialized, "initialized"

    if self.oldFundManager.address == ZERO_ADDRESS:
        assert msg.sender in [self.timeLock, self.admin], "!auth"
    else:
        assert msg.sender == self.oldFundManager.address, "!old fund manager"

        assert (
            self.vault.address == self.oldFundManager.vault()
        ), "old fund manager vault != vault"

        bal: uint256 = self.token.balanceOf(self.oldFundManager.address)
        self._safeTransferFrom(
            self.token.address, self.oldFundManager.address, self, bal
        )

        self.totalDebt = self.oldFundManager.totalDebt()
        self.totalDebtRatio = self.oldFundManager.totalDebtRatio()

        for i in range(OLD_MAX_QUEUE):
            addr: address = self.oldFundManager.queue(i)
            if addr == ZERO_ADDRESS:
                break

            assert (
                IStrategy(addr).fundManager() == self
            ), "strategy fund manager != self"

            approved: bool = False
            active: bool = False
            activated: bool = False
            debtRatio: uint256 = 0
            debt: uint256 = 0
            minBorrow: uint256 = 0
            maxBorrow: uint256 = 0
            (
                approved,
                active,
                activated,
                debtRatio,
                debt,
                minBorrow,
                maxBorrow,
            ) = self.oldFundManager.strategies(addr)
            assert approved, "!approved"
            assert active, "!active"
            assert activated, "!activated"

            self.queue[i] = addr
            self.strategies[addr] = Strategy(
                {
                    approved: True,
                    active: True,
                    activated: True,
                    debtRatio: debtRatio,
                    debt: debt,
                    minBorrow: minBorrow,
                    maxBorrow: maxBorrow,
                }
            )

    self.initialized = True


# Migration steps to new fund manager
#
# t = token
# v = vault
# f1 = fund manager 1
# f2 = fund manager 2
# strats = active strategies of f1
#
# action                         | caller
# ----------------------------------------
# 1. f2.setVault(v)              | time lock
# 2. f1.setPause(true)           | admin
# 3. for s in strats             |
#      s.setFundManager(f2)      | time lock
# 4. t.approve(f2, bal)          | f1
# 5. t.transferFrom(f1, f2, bal) | f2
# 6. f2 copy states from f1      | f2
#    - totalDebt                 |
#    - totalDebtRatio            |
#    - queue                     |
#    - active strategy params    |
# 7. f1 reset state              | f1
#    - totalDebt                 |
#    - active strategy debt      |
# 8. v.setFundManager(f2)        | time lock


@external
def migrate(fundManager: address):
    """
    @notice Migrate to new fund manager
    @param fundManager Address of new fund manager
    """
    assert msg.sender == self.timeLock, "!time lock"
    assert self.initialized, "!initialized"
    assert self.paused, "!paused"

    assert (
        FundManager(fundManager).token() == self.token.address
    ), "new fund manager token != token"
    assert (
        FundManager(fundManager).vault() == self.vault.address
    ), "new fund manager vault != vault"

    for strat in self.queue:
        if strat == ZERO_ADDRESS:
            break
        assert (
            IStrategy(strat).fundManager() == fundManager
        ), "strategy fund manager != new fund manager"

    bal: uint256 = self.token.balanceOf(self)
    self._safeApprove(self.token.address, fundManager, bal)
    FundManager(fundManager).initialize()

    assert self.token.balanceOf(self) == 0, "bal != 0"

    log Migrate(fundManager, bal, self.totalDebt)

    self.totalDebt = 0

    for strat in self.queue:
        if strat == ZERO_ADDRESS:
            break
        self.strategies[strat].debt = 0


@external
def setNextTimeLock(nextTimeLock: address):
    """
    @notice Set next time lock
    @param nextTimeLock Address of next time lock
    """
    assert msg.sender == self.timeLock, "!time lock"
    self.nextTimeLock = nextTimeLock
    log SetNextTimeLock(nextTimeLock)


@external
def acceptTimeLock():
    """
    @notice Accept time lock
    @dev Only `nextTimeLock` can claim time lock
    """
    assert msg.sender == self.nextTimeLock, "!next time lock"
    self.timeLock = msg.sender
    self.nextTimeLock = ZERO_ADDRESS
    log AcceptTimeLock(msg.sender)


@external
def setAdmin(admin: address):
    assert msg.sender in [self.timeLock, self.admin], "!auth"
    self.admin = admin
    log SetAdmin(admin)


@external
def setGuardian(guardian: address):
    assert msg.sender in [self.timeLock, self.admin], "!auth"
    self.guardian = guardian
    log SetGuardian(guardian)


@external
def setWorker(worker: address):
    assert msg.sender in [self.timeLock, self.admin], "!auth"
    self.worker = worker
    log SetWorker(worker)


@external
def setPause(paused: bool):
    assert msg.sender in [self.timeLock, self.admin, self.guardian], "!auth"
    self.paused = paused
    log SetPause(paused)


@external
def setVault(vault: address):
    """
    @notice Set vault
    @param vault Address of vault
    """
    assert msg.sender == self.timeLock, "!time lock"
    assert Vault(vault).token() == self.token.address, "vault token != token"

    if self.vault.address != ZERO_ADDRESS:
        self._safeApprove(self.token.address, self.vault.address, 0)

    self.vault = Vault(vault)
    self._safeApprove(self.token.address, self.vault.address, MAX_UINT256)

    log SetVault(vault)


@internal
@view
def _totalAssets() -> uint256:
    """
    @notice Total amount of token in this fund manager + total amount borrowed
            by strategies
    @dev Returns total amount of token managed by this contract
    """
    return self.token.balanceOf(self) + self.totalDebt


@external
@view
def totalAssets() -> uint256:
    return self._totalAssets()


# array functions tested in test/Array.vy
@internal
def _pack():
    arr: address[MAX_QUEUE] = empty(address[MAX_QUEUE])
    i: uint256 = 0
    for strat in self.queue:
        if strat != ZERO_ADDRESS:
            arr[i] = strat
            i += 1
    self.queue = arr


@internal
def _append(strategy: address):
    assert self.queue[MAX_QUEUE - 1] == ZERO_ADDRESS, "queue > max"
    self.queue[MAX_QUEUE - 1] = strategy
    self._pack()


@internal
def _remove(i: uint256):
    assert i < MAX_QUEUE, "i >= max"
    assert self.queue[i] != ZERO_ADDRESS, "!zero address"
    self.queue[i] = ZERO_ADDRESS
    self._pack()


@internal
@view
def _find(strategy: address) -> uint256:
    for i in range(MAX_QUEUE):
        if self.queue[i] == strategy:
            return i
    raise "not found"


@external
def approveStrategy(strategy: address):
    """
    @notice Approve strategy
    @param strategy Address of strategy
    """
    assert msg.sender == self.timeLock, "!time lock"

    assert not self.strategies[strategy].approved, "approved"
    assert IStrategy(strategy).fundManager() == self, "strategy fund manager != this"
    assert IStrategy(strategy).token() == self.token.address, "strategy token != token"

    self.strategies[strategy] = Strategy(
        {
            approved: True,
            active: False,
            activated: False,
            debtRatio: 0,
            debt: 0,
            minBorrow: 0,
            maxBorrow: 0,
        }
    )

    log ApproveStrategy(strategy)


@external
def revokeStrategy(strategy: address):
    """
    @notice Disapprove strategy
    @param strategy Address of strategy
    """
    assert msg.sender in [self.timeLock, self.admin], "!auth"
    assert self.strategies[strategy].approved, "!approved"
    assert not self.strategies[strategy].active, "active"

    self.strategies[strategy].approved = False
    log RevokeStrategy(strategy)


@external
def addStrategyToQueue(
    strategy: address, debtRatio: uint256, minBorrow: uint256, maxBorrow: uint256
):
    """
    @notice Activate strategy
    @param strategy Address of strategy
    @param debtRatio Ratio of total assets this strategy can borrow
    @param minBorrow Minimum amount to borrow per call to borrow()
    @param maxBorrow Maximum amount to borrow per call to borrow()
    """
    assert msg.sender in [self.timeLock, self.admin], "!auth"
    assert self.strategies[strategy].approved, "!approved"
    assert not self.strategies[strategy].active, "active"
    assert self.totalDebtRatio + debtRatio <= MAX_TOTAL_DEBT_RATIO, "ratio > max"
    assert minBorrow <= maxBorrow, "min borrow > max borrow"

    self._append(strategy)
    self.strategies[strategy].active = True
    self.strategies[strategy].activated = True
    self.strategies[strategy].debtRatio = debtRatio
    self.strategies[strategy].minBorrow = minBorrow
    self.strategies[strategy].maxBorrow = maxBorrow
    self.totalDebtRatio += debtRatio

    log AddStrategyToQueue(strategy)


@external
def removeStrategyFromQueue(strategy: address):
    """
    @notice Deactivate strategy
    @param strategy Addres of strategy
    """
    assert msg.sender in [self.timeLock, self.admin, self.guardian], "!auth"
    assert self.strategies[strategy].active, "!active"

    self._remove(self._find(strategy))
    self.strategies[strategy].active = False
    self.totalDebtRatio -= self.strategies[strategy].debtRatio
    self.strategies[strategy].debtRatio = 0

    log RemoveStrategyFromQueue(strategy)


@external
def setQueue(queue: address[MAX_QUEUE]):
    """
    @notice Reorder queue
    @param queue Array of active strategies
    """
    assert msg.sender in [self.timeLock, self.admin], "!auth"

    # check no gaps in new queue
    zero: bool = False
    for i in range(MAX_QUEUE):
        strat: address = queue[i]
        if strat == ZERO_ADDRESS:
            if not zero:
                zero = True
        else:
            assert not zero, "gap"

    # Check old and new queue counts of non zero strategies are equal
    for i in range(MAX_QUEUE):
        oldStrat: address = self.queue[i]
        newStrat: address = queue[i]
        if oldStrat == ZERO_ADDRESS:
            assert newStrat == ZERO_ADDRESS, "new != 0"
        else:
            assert newStrat != ZERO_ADDRESS, "new = 0"

    # Check new strategy is active and no duplicate
    for i in range(MAX_QUEUE):
        strat: address = queue[i]
        if strat == ZERO_ADDRESS:
            break
        # code below will fail if duplicate strategy in new queue
        assert self.strategies[strat].active, "!active"
        self.strategies[strat].active = False

    # update queue
    for i in range(MAX_QUEUE):
        strat: address = queue[i]
        if strat == ZERO_ADDRESS:
            break
        self.strategies[strat].active = True
        self.queue[i] = strat

    log SetQueue(queue)


@external
def setDebtRatios(debtRatios: uint256[MAX_QUEUE]):
    """
    @notice Update debt ratios of active strategies
    @param debtRatios Array of debt ratios
    """
    assert msg.sender in [self.timeLock, self.admin], "!auth"

    # check that we're only setting debt ratio on active strategy
    for i in range(MAX_QUEUE):
        if self.queue[i] == ZERO_ADDRESS:
            assert debtRatios[i] == 0, "debt ratio != 0"

    # use memory to save gas
    totalDebtRatio: uint256 = 0
    for i in range(MAX_QUEUE):
        addr: address = self.queue[i]
        if addr == ZERO_ADDRESS:
            break

        debtRatio: uint256 = debtRatios[i]
        self.strategies[addr].debtRatio = debtRatio
        totalDebtRatio += debtRatio

    self.totalDebtRatio = totalDebtRatio

    assert self.totalDebtRatio <= MAX_TOTAL_DEBT_RATIO, "total > max"

    log SetDebtRatios(debtRatios)


@external
def setMinMaxBorrow(strategy: address, minBorrow: uint256, maxBorrow: uint256):
    """
    @notice Update `minBorrow` and `maxBorrow` of approved strategy
    @param minBorrow Minimum amount to borrow per call to borrow()
    @param maxBorrow Maximum amount to borrow per call to borrow()
    """
    assert msg.sender in [self.timeLock, self.admin], "!auth"
    assert self.strategies[strategy].approved, "!approved"
    assert minBorrow <= maxBorrow, "min borrow > max borrow"

    self.strategies[strategy].minBorrow = minBorrow
    self.strategies[strategy].maxBorrow = maxBorrow

    log SetMinMaxBorrow(strategy, minBorrow, maxBorrow)


# functions between Vault and this contract #
@external
def borrowFromVault(amount: uint256, _min: uint256):
    """
    @notice Borrow `token` from vault
    @param amount Amount of token to borrow
    @param _min Minimum amount to borrow
    """
    assert self.initialized, "!initialized"
    assert msg.sender in [self.timeLock, self.admin, self.worker], "!auth"
    # fails if vault not set
    borrowed: uint256 = self.vault.borrow(amount)
    assert borrowed >= _min, "borrowed < min"

    log BorrowFromVault(self.vault.address, amount, borrowed)


@external
def repayVault(amount: uint256, _min: uint256):
    """
    @notice Repay `token` to vault
    @param amount Amount to repay
    @param _min Minimum amount to repay
    """
    assert self.initialized, "!initialized"
    assert msg.sender in [self.timeLock, self.admin, self.worker], "!auth"
    # fails if vault not set
    # infinite approved in setVault()
    repaid: uint256 = self.vault.repay(amount)
    assert repaid >= _min, "repaid < min"

    log RepayVault(self.vault.address, amount, repaid)


@external
def reportToVault(_minTotal: uint256, _maxTotal: uint256):
    """
    @notice Report gain and loss to vault
    @param _minTotal Minumum of total assets
    @param _maxTotal Maximum of total assets
    @dev `_minTotal` and `_maxTotal` is used to check that totalAssets is
         within a reasonable range before this function is called
    """
    assert self.initialized, "!initialized"
    assert msg.sender in [self.timeLock, self.admin, self.worker], "!auth"

    total: uint256 = self._totalAssets()
    assert total >= _minTotal and total <= _maxTotal, "total not in range"

    debt: uint256 = self.vault.debt()
    gain: uint256 = 0
    loss: uint256 = 0

    if total > debt:
        # token.balanceOf(self) = total - self.totalDebt
        gain = min(total - debt, total - self.totalDebt)
    else:
        loss = debt - total

    if gain > 0 or loss > 0:
        self.vault.report(gain, loss)

    log ReportToVault(self.vault.address, total, debt, gain, loss)


# functions between vault -> this contract -> strategies #
@internal
def _withdraw(amount: uint256) -> uint256:
    """
    @notice Withdraw `token` from active strategies
    @param amount Amount of `token` to withdraw
    @dev Returns sum of losses from active strategies that were withdrawn.
    """
    _amount: uint256 = amount
    totalLoss: uint256 = 0
    for strategy in self.queue:
        if strategy == ZERO_ADDRESS:
            break

        bal: uint256 = self.token.balanceOf(self)
        if bal >= _amount:
            break

        debt: uint256 = self.strategies[strategy].debt
        need: uint256 = min(_amount - bal, debt)
        if need == 0:
            continue

        # loss must be <= debt
        loss: uint256 = IStrategy(strategy).withdraw(need)
        diff: uint256 = self.token.balanceOf(self) - bal

        if loss > 0:
            _amount -= loss
            totalLoss += loss
            self.strategies[strategy].debt -= loss
            self.totalDebt -= loss

        self.strategies[strategy].debt -= diff
        self.totalDebt -= diff

        log WithdrawStrategy(strategy, debt, need, loss, diff)

    return totalLoss


@external
def withdraw(amount: uint256) -> uint256:
    """
    @notice Withdraw `token` from fund manager back to vault
    @param amount Amount of `token` to withdraw
    @dev Returns sum of losses from active strategies that were withdrawn.
    """
    assert self.initialized, "!initialized"
    assert msg.sender == self.vault.address, "!vault"

    total: uint256 = self._totalAssets()
    _amount: uint256 = min(amount, total)
    assert _amount > 0, "withdraw = 0"

    debt: uint256 = self.vault.debt()
    loss: uint256 = 0
    if debt > total:
        # debt > total can occur when strategies reported losses to this contract
        # but this contract has not reported losses back to vault
        loss = debt - total

    bal: uint256 = self.token.balanceOf(self)
    if _amount > bal:
        # try to withdraw until balance of fund manager >= _amount
        loss += self._withdraw(_amount)
        _amount = min(_amount, self.token.balanceOf(self))

    if _amount > 0:
        self._safeTransfer(self.token.address, msg.sender, _amount)

    log Withdraw(msg.sender, amount, _amount, loss)

    return loss


# functions between this contract and strategies #
@internal
@view
def _calcMaxBorrow(strategy: address) -> uint256:
    """
    @notice Calculate how much `token` strategy can borrow
    @param strategy Address of strategy
    @dev Returns amount of `token` that `strategy` can borrow
    """
    if (not self.initialized) or self.paused or self.totalDebtRatio == 0:
        return 0

    # strategy debtRatio > 0 only if strategy is active
    limit: uint256 = (
        self.strategies[strategy].debtRatio * self._totalAssets() / self.totalDebtRatio
    )
    debt: uint256 = self.strategies[strategy].debt

    if debt >= limit:
        return 0

    available: uint256 = min(limit - debt, self.token.balanceOf(self))

    if available < self.strategies[strategy].minBorrow:
        return 0
    else:
        return min(available, self.strategies[strategy].maxBorrow)


@external
@view
def calcMaxBorrow(strategy: address) -> uint256:
    return self._calcMaxBorrow(strategy)


@internal
@view
def _calcOutstandingDebt(strategy: address) -> uint256:
    """
    @notice Calculate amount of `token` that `strategy` should pay back to fund manager
    @param strategy Address of strategy
    @dev Returns minimum amount of `token` strategy should repay
    """
    if not self.initialized:
        return 0

    if self.totalDebtRatio == 0:
        return self.strategies[strategy].debt

    limit: uint256 = (
        self.strategies[strategy].debtRatio * self.totalDebt / self.totalDebtRatio
    )
    debt: uint256 = self.strategies[strategy].debt

    if self.paused:
        return debt
    elif debt <= limit:
        return 0
    else:
        return debt - limit


@external
@view
def calcOutstandingDebt(strategy: address) -> uint256:
    return self._calcOutstandingDebt(strategy)


@external
@view
def getDebt(strategy: address) -> uint256:
    """
    @notice Return debt of strategy
    @param strategy Address of strategy
    @dev Returns current debt of strategy
    """
    return self.strategies[strategy].debt


@external
@nonreentrant("lock")
def borrow(amount: uint256) -> uint256:
    """
    @notice Borrow `token` from fund manager
    @param amount Amount of `token` to borrow
    @dev Returns actual amount sent
    @dev Only active strategy can borrow
    """
    assert self.initialized, "!initialized"
    assert not self.paused, "paused"
    assert self.strategies[msg.sender].active, "!active"

    _amount: uint256 = min(amount, self._calcMaxBorrow(msg.sender))
    assert _amount > 0, "borrow = 0"

    self._safeTransfer(self.token.address, msg.sender, _amount)

    # include any fee on transfer to debt
    self.strategies[msg.sender].debt += _amount
    self.totalDebt += _amount

    log Borrow(msg.sender, amount, _amount)

    return _amount


@external
def repay(amount: uint256) -> uint256:
    """
    @notice Repay debt to fund manager
    @param amount Amount of `token` to repay
    @dev Returns actual amount repaid
    @dev Only approved strategy can repay
    """
    assert self.initialized, "!initialized"
    assert self.strategies[msg.sender].approved, "!approved"

    _amount: uint256 = min(amount, self.strategies[msg.sender].debt)
    assert _amount > 0, "repay = 0"

    diff: uint256 = self.token.balanceOf(self)
    self._safeTransferFrom(self.token.address, msg.sender, self, _amount)
    diff = self.token.balanceOf(self) - diff

    # exclude fee on transfer from debt payment
    self.strategies[msg.sender].debt -= diff
    self.totalDebt -= diff

    log Repay(msg.sender, amount, diff)

    return diff


@external
def report(gain: uint256, loss: uint256):
    """
    @notice Report gain and loss from strategy
    @param gain Amount of profit
    @param loss Amount of loss
    """
    assert self.initialized, "!initialized"
    assert self.strategies[msg.sender].active, "!active"
    # can't have both gain and loss > 0
    assert (gain >= 0 and loss == 0) or (gain == 0 and loss >= 0), "gain and loss > 0"

    if gain > 0:
        self._safeTransferFrom(self.token.address, msg.sender, self, gain)
    elif loss > 0:
        self.strategies[msg.sender].debt -= loss
        self.totalDebt -= loss

    log Report(msg.sender, gain, loss, self.strategies[msg.sender].debt)


@external
def migrateStrategy(oldStrat: address, newStrat: address):
    """
    @notice Migrate strategy
    @param oldStrat Address of current strategy
    @param newStrat Address of strategy to migrate to
    """
    assert self.initialized, "!initialized"
    assert msg.sender in [self.timeLock, self.admin], "!auth"
    assert self.strategies[oldStrat].active, "old !active"
    assert self.strategies[newStrat].approved, "new !approved"
    assert not self.strategies[newStrat].activated, "activated"

    strat: Strategy = self.strategies[oldStrat]

    self.strategies[newStrat] = Strategy(
        {
            approved: True,
            active: True,
            activated: True,
            debtRatio: strat.debtRatio,
            debt: strat.debt,
            minBorrow: strat.minBorrow,
            maxBorrow: strat.maxBorrow,
        }
    )

    self.strategies[oldStrat].active = False
    self.strategies[oldStrat].debtRatio = 0
    self.strategies[oldStrat].debt = 0
    self.strategies[oldStrat].minBorrow = 0
    self.strategies[oldStrat].maxBorrow = 0

    # find and replace strategy
    i: uint256 = self._find(oldStrat)
    self.queue[i] = newStrat

    IStrategy(oldStrat).migrate(newStrat)
    log MigrateStrategy(oldStrat, newStrat)


@external
def sweep(token: address):
    """
    @notice Transfer any token (except `token`) accidentally sent to this contract
            to admin or time lock
    @dev Cannot transfer `token`
    """
    assert msg.sender in [self.timeLock, self.admin], "!auth"
    assert token != self.token.address, "protected"
    self._safeTransfer(token, msg.sender, ERC20(token).balanceOf(self))

Contract Security Audit

Contract ABI

[{"name":"SetNextTimeLock","inputs":[{"name":"nextTimeLock","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"AcceptTimeLock","inputs":[{"name":"timeLock","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetAdmin","inputs":[{"name":"admin","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetGuardian","inputs":[{"name":"guardian","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetWorker","inputs":[{"name":"worker","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetPause","inputs":[{"name":"paused","type":"bool","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetVault","inputs":[{"name":"vault","type":"address","indexed":false}],"anonymous":false,"type":"event"},{"name":"ApproveStrategy","inputs":[{"name":"strategy","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"RevokeStrategy","inputs":[{"name":"strategy","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"AddStrategyToQueue","inputs":[{"name":"strategy","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"RemoveStrategyFromQueue","inputs":[{"name":"strategy","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"SetQueue","inputs":[{"name":"queue","type":"address[20]","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetDebtRatios","inputs":[{"name":"debtRatios","type":"uint256[20]","indexed":false}],"anonymous":false,"type":"event"},{"name":"SetMinMaxBorrow","inputs":[{"name":"strategy","type":"address","indexed":true},{"name":"minBorrow","type":"uint256","indexed":false},{"name":"maxBorrow","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"BorrowFromVault","inputs":[{"name":"vault","type":"address","indexed":true},{"name":"amount","type":"uint256","indexed":false},{"name":"borrowed","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"RepayVault","inputs":[{"name":"vault","type":"address","indexed":true},{"name":"amount","type":"uint256","indexed":false},{"name":"repaid","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"ReportToVault","inputs":[{"name":"vault","type":"address","indexed":true},{"name":"total","type":"uint256","indexed":false},{"name":"debt","type":"uint256","indexed":false},{"name":"gain","type":"uint256","indexed":false},{"name":"loss","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Withdraw","inputs":[{"name":"vault","type":"address","indexed":true},{"name":"amount","type":"uint256","indexed":false},{"name":"actual","type":"uint256","indexed":false},{"name":"loss","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"WithdrawStrategy","inputs":[{"name":"strategy","type":"address","indexed":true},{"name":"debt","type":"uint256","indexed":false},{"name":"need","type":"uint256","indexed":false},{"name":"loss","type":"uint256","indexed":false},{"name":"diff","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Borrow","inputs":[{"name":"strategy","type":"address","indexed":true},{"name":"amount","type":"uint256","indexed":false},{"name":"borrowed","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Repay","inputs":[{"name":"strategy","type":"address","indexed":true},{"name":"amount","type":"uint256","indexed":false},{"name":"repaid","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"Report","inputs":[{"name":"strategy","type":"address","indexed":true},{"name":"gain","type":"uint256","indexed":false},{"name":"loss","type":"uint256","indexed":false},{"name":"debt","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"name":"MigrateStrategy","inputs":[{"name":"oldStrategy","type":"address","indexed":true},{"name":"newStrategy","type":"address","indexed":true}],"anonymous":false,"type":"event"},{"name":"Migrate","inputs":[{"name":"fundManager","type":"address","indexed":false},{"name":"bal","type":"uint256","indexed":false},{"name":"totalDebt","type":"uint256","indexed":false}],"anonymous":false,"type":"event"},{"stateMutability":"nonpayable","type":"constructor","inputs":[{"name":"token","type":"address"},{"name":"guardian","type":"address"},{"name":"worker","type":"address"},{"name":"oldFundManager","type":"address"}],"outputs":[]},{"stateMutability":"nonpayable","type":"function","name":"initialize","inputs":[],"outputs":[],"gas":6015090},{"stateMutability":"nonpayable","type":"function","name":"migrate","inputs":[{"name":"fundManager","type":"address"}],"outputs":[],"gas":614975},{"stateMutability":"nonpayable","type":"function","name":"setNextTimeLock","inputs":[{"name":"nextTimeLock","type":"address"}],"outputs":[],"gas":38981},{"stateMutability":"nonpayable","type":"function","name":"acceptTimeLock","inputs":[],"outputs":[],"gas":58909},{"stateMutability":"nonpayable","type":"function","name":"setAdmin","inputs":[{"name":"admin","type":"address"}],"outputs":[],"gas":41562},{"stateMutability":"nonpayable","type":"function","name":"setGuardian","inputs":[{"name":"guardian","type":"address"}],"outputs":[],"gas":41592},{"stateMutability":"nonpayable","type":"function","name":"setWorker","inputs":[{"name":"worker","type":"address"}],"outputs":[],"gas":41622},{"stateMutability":"nonpayable","type":"function","name":"setPause","inputs":[{"name":"paused","type":"bool"}],"outputs":[],"gas":43920},{"stateMutability":"nonpayable","type":"function","name":"setVault","inputs":[{"name":"vault","type":"address"}],"outputs":[],"gas":74660},{"stateMutability":"view","type":"function","name":"totalAssets","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":7978},{"stateMutability":"nonpayable","type":"function","name":"approveStrategy","inputs":[{"name":"strategy","type":"address"}],"outputs":[],"gas":168784},{"stateMutability":"nonpayable","type":"function","name":"revokeStrategy","inputs":[{"name":"strategy","type":"address"}],"outputs":[],"gas":31536},{"stateMutability":"nonpayable","type":"function","name":"addStrategyToQueue","inputs":[{"name":"strategy","type":"address"},{"name":"debtRatio","type":"uint256"},{"name":"minBorrow","type":"uint256"},{"name":"maxBorrow","type":"uint256"}],"outputs":[],"gas":1773661},{"stateMutability":"nonpayable","type":"function","name":"removeStrategyFromQueue","inputs":[{"name":"strategy","type":"address"}],"outputs":[],"gas":1672791},{"stateMutability":"nonpayable","type":"function","name":"setQueue","inputs":[{"name":"queue","type":"address[20]"}],"outputs":[],"gas":1941136},{"stateMutability":"nonpayable","type":"function","name":"setDebtRatios","inputs":[{"name":"debtRatios","type":"uint256[20]"}],"outputs":[],"gas":861988},{"stateMutability":"nonpayable","type":"function","name":"setMinMaxBorrow","inputs":[{"name":"strategy","type":"address"},{"name":"minBorrow","type":"uint256"},{"name":"maxBorrow","type":"uint256"}],"outputs":[],"gas":80796},{"stateMutability":"nonpayable","type":"function","name":"borrowFromVault","inputs":[{"name":"amount","type":"uint256"},{"name":"_min","type":"uint256"}],"outputs":[],"gas":18996},{"stateMutability":"nonpayable","type":"function","name":"repayVault","inputs":[{"name":"amount","type":"uint256"},{"name":"_min","type":"uint256"}],"outputs":[],"gas":19026},{"stateMutability":"nonpayable","type":"function","name":"reportToVault","inputs":[{"name":"_minTotal","type":"uint256"},{"name":"_maxTotal","type":"uint256"}],"outputs":[],"gas":39513},{"stateMutability":"nonpayable","type":"function","name":"withdraw","inputs":[{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":3452159},{"stateMutability":"view","type":"function","name":"calcMaxBorrow","inputs":[{"name":"strategy","type":"address"}],"outputs":[{"name":"","type":"uint256"}],"gas":40029},{"stateMutability":"view","type":"function","name":"calcOutstandingDebt","inputs":[{"name":"strategy","type":"address"}],"outputs":[{"name":"","type":"uint256"}],"gas":20463},{"stateMutability":"view","type":"function","name":"getDebt","inputs":[{"name":"strategy","type":"address"}],"outputs":[{"name":"","type":"uint256"}],"gas":3371},{"stateMutability":"nonpayable","type":"function","name":"borrow","inputs":[{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":213592},{"stateMutability":"nonpayable","type":"function","name":"repay","inputs":[{"name":"amount","type":"uint256"}],"outputs":[{"name":"","type":"uint256"}],"gas":106756},{"stateMutability":"nonpayable","type":"function","name":"report","inputs":[{"name":"gain","type":"uint256"},{"name":"loss","type":"uint256"}],"outputs":[],"gas":85897},{"stateMutability":"nonpayable","type":"function","name":"migrateStrategy","inputs":[{"name":"oldStrat","type":"address"},{"name":"newStrat","type":"address"}],"outputs":[],"gas":468697},{"stateMutability":"nonpayable","type":"function","name":"sweep","inputs":[{"name":"token","type":"address"}],"outputs":[],"gas":20791},{"stateMutability":"view","type":"function","name":"paused","inputs":[],"outputs":[{"name":"","type":"bool"}],"gas":3258},{"stateMutability":"view","type":"function","name":"initialized","inputs":[],"outputs":[{"name":"","type":"bool"}],"gas":3288},{"stateMutability":"view","type":"function","name":"vault","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3318},{"stateMutability":"view","type":"function","name":"token","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3348},{"stateMutability":"view","type":"function","name":"timeLock","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3378},{"stateMutability":"view","type":"function","name":"nextTimeLock","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3408},{"stateMutability":"view","type":"function","name":"admin","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3438},{"stateMutability":"view","type":"function","name":"guardian","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3468},{"stateMutability":"view","type":"function","name":"worker","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3498},{"stateMutability":"view","type":"function","name":"totalDebt","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3528},{"stateMutability":"view","type":"function","name":"totalDebtRatio","inputs":[],"outputs":[{"name":"","type":"uint256"}],"gas":3558},{"stateMutability":"view","type":"function","name":"strategies","inputs":[{"name":"arg0","type":"address"}],"outputs":[{"name":"approved","type":"bool"},{"name":"active","type":"bool"},{"name":"activated","type":"bool"},{"name":"debtRatio","type":"uint256"},{"name":"debt","type":"uint256"},{"name":"minBorrow","type":"uint256"},{"name":"maxBorrow","type":"uint256"}],"gas":17747},{"stateMutability":"view","type":"function","name":"queue","inputs":[{"name":"arg0","type":"uint256"}],"outputs":[{"name":"","type":"address"}],"gas":3727},{"stateMutability":"view","type":"function","name":"oldFundManager","inputs":[],"outputs":[{"name":"","type":"address"}],"gas":3648}]

Deployed Bytecode

0x600436101561000d57613fde565b600035601c52600051341561002157600080fd5b638129fc1c8114156106365760015415151561007c576308c379a061014052602061016052600b610180527f696e697469616c697a65640000000000000000000000000000000000000000006101a05261018050606461015cfd5b600d54151561012b57600454610160526006546101805260006101405261014061012060006002818352015b6101205160200261016001513314156100c457600183526100d4565b81516001018083528114156100a8575b505050610140511515610126576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b61062f565b600d543314151561017b576308c379a0610140526020610160526011610180527f216f6c642066756e64206d616e616765720000000000000000000000000000006101a05261018050606461015cfd5b60206101a0600463fbfa77cf6101405261015c600d545afa61019c57600080fd5b601f3d116101a957600080fd5b6000506101a0516002541415156101ff576308c379a06101c05260206101e052601f610200527f6f6c642066756e64206d616e61676572207661756c7420213d207661756c7400610220526102005060646101dcfd5b60206101e060246370a0823161016052600d546101805261017c6003545afa61022757600080fd5b601f3d1161023457600080fd5b6000506101e051610140526101405160035461016052600d5461018052306101a052610140516101c0526101c0516101a051610180516101605160065801614318565b6101405260005060206101c0600463fc7b9c186101605261017c600d545afa61029f57600080fd5b601f3d116102ac57600080fd5b6000506101c05160095560206101c06004632df9eab96101605261017c600d545afa6102d757600080fd5b601f3d116102e457600080fd5b6000506101c051600a5561016060006014818352015b6020610220602463ddf0b0096101a052610160516101c0526101bc600d545afa61032357600080fd5b601f3d1161033057600080fd5b600050610220516101805261018051151561034a5761062c565b3060206102006004636209ec2d6101a0526101bc610180515afa61036d57600080fd5b601f3d1161037a57600080fd5b600050610200511415156103cd576308c379a061022052602061024052601d610260527f73747261746567792066756e64206d616e6167657220213d2073656c660000006102805261026050606461023cfd5b60e0366101a03760e061030060246339ebf82361028052610180516102a05261029c600d545afa6103fd57600080fd5b60df3d1161040a57600080fd5b61030080808080516103e05250506020810190508080805161040052505060208101905080808051610420525050602081019050808080516104405250506020810190508080805161046052505060208101905080808051610480525050602081019050808080516104a052505050506000506103e080516101a05280602001516101c05280604001516101e0528060600151610200528060800151610220528060a00151610240528060c0015161026052506101a051151561050c576308c379a06102805260206102a05260096102c0527f21617070726f76656400000000000000000000000000000000000000000000006102e0526102c050606461029cfd5b6101c051151561055b576308c379a06102805260206102a05260076102c0527f21616374697665000000000000000000000000000000000000000000000000006102e0526102c050606461029cfd5b6101e05115156105aa576308c379a06102805260206102a052600a6102c0527f21616374697661746564000000000000000000000000000000000000000000006102e0526102c050606461029cfd5b6101805161016051601481106105bf57600080fd5b600c60c052602060c0200155600b6101805160e05260c052604060c02060c052602060c020600181556001600182015560016002820155610200516003820155610220516004820155610240516005820155610260516006820155505b81516001018083528114156102fa575b50505b6001600155005b63ce5494bb811415610aff5760043560a01c1561065257600080fd5b600454331415156106a2576308c379a061014052602061016052600a610180527f2174696d65206c6f636b000000000000000000000000000000000000000000006101a05261018050606461015cfd5b60015415156106f0576308c379a061014052602061016052600c610180527f21696e697469616c697a656400000000000000000000000000000000000000006101a05261018050606461015cfd5b600054151561073e576308c379a0610140526020610160526007610180527f21706175736564000000000000000000000000000000000000000000000000006101a05261018050606461015cfd5b60035460206101a0600463fc0c546a6101405261015c6004355afa61076257600080fd5b601f3d1161076f57600080fd5b6000506101a0511415156107c2576308c379a06101c05260206101e052601f610200527f6e65772066756e64206d616e6167657220746f6b656e20213d20746f6b656e00610220526102005060646101dcfd5b60025460206101a0600463fbfa77cf6101405261015c6004355afa6107e657600080fd5b601f3d116107f357600080fd5b6000506101a051141515610846576308c379a06101c05260206101e052601f610200527f6e65772066756e64206d616e61676572207661756c7420213d207661756c7400610220526102005060646101dcfd5b61016060006014818352015b61016051600c60c052602060c0200154610140526101405115156108755761092f565b60043560206101e06004636209ec2d6101805261019c610140515afa61089a57600080fd5b601f3d116108a757600080fd5b6000506101e05114151561091f576308c379a0610200526020610220526029610240527f73747261746567792066756e64206d616e6167657220213d206e65772066756e610260527f64206d616e6167657200000000000000000000000000000000000000000000006102805261024050608461021cfd5b8151600101808352811415610852575b505060206101e060246370a0823161016052306101805261017c6003545afa61095757600080fd5b601f3d1161096457600080fd5b6000506101e05161014052610140516003546101605260043561018052610140516101a0526101a051610180516101605160065801613fe4565b610140526000506004353b6109b257600080fd5b600060006004638129fc1c6101605261017c60006004355af16109d457600080fd5b60206101e060246370a0823161016052306101805261017c6003545afa6109fa57600080fd5b601f3d11610a0757600080fd5b6000506101e051151515610a5a576308c379a0610200526020610220526008610240527f62616c20213d20300000000000000000000000000000000000000000000000006102605261024050606461021cfd5b6004356101605261014051610180526009546101a0527fd44a6dd2bfac4f6bc02d116d96aa12c24e8580626b95cb6a2f543f18cb61bd4c6060610160a1600060095561018060006014818352015b61018051600c60c052602060c020015461016052610160511515610acb57610afb565b60006004600b6101605160e05260c052604060c02060c052602060c02001555b8151600101808352811415610aa8575b5050005b6347a02a44811415610ba15760043560a01c15610b1b57600080fd5b60045433141515610b6b576308c379a061014052602061016052600a610180527f2174696d65206c6f636b000000000000000000000000000000000000000000006101a05261018050606461015cfd5b600435600555600435610140527f5c06d5a6f95a574bb95a214c88933831c63fcd6f6c5d1d61a21efb92be19bc2c6020610140a1005b631e39831e811415610c345760055433141515610bfd576308c379a061014052602061016052600f610180527f216e6578742074696d65206c6f636b00000000000000000000000000000000006101a05261018050606461015cfd5b33600455600060055533610140527f77b69635186d51fb2d031f67a7995795c8384acb800219c7d30861125d154f026020610140a1005b63704b6c02811415610d275760043560a01c15610c5057600080fd5b600454610160526006546101805260006101405261014061012060006002818352015b610120516020026101600151331415610c8f5760018352610c9f565b8151600101808352811415610c73575b505050610140511515610cf1576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b600435600655600435610140527f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a16020610140a1005b638a0dac4a811415610e1a5760043560a01c15610d4357600080fd5b600454610160526006546101805260006101405261014061012060006002818352015b610120516020026101600151331415610d825760018352610d92565b8151600101808352811415610d66575b505050610140511515610de4576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b600435600755600435610140527f31845eceb9cde510c7e8b37f76301c688feb70bc9653aa4c28a3734999840fd86020610140a1005b63c26f6d44811415610f0d5760043560a01c15610e3657600080fd5b600454610160526006546101805260006101405261014061012060006002818352015b610120516020026101600151331415610e755760018352610e85565b8151600101808352811415610e59575b505050610140511515610ed7576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b600435600855600435610140527fcabc8521621c89fc973d8f1e8455da2ce64a666915af33e0ebaa69cd5215083b6020610140a1005b63bedb86fb8114156110075760043560011c15610f2957600080fd5b60045461016052600654610180526007546101a05260006101405261014061012060006003818352015b610120516020026101600151331415610f6f5760018352610f7f565b8151600101808352811415610f53575b505050610140511515610fd1576308c379a06101c05260206101e0526005610200527f2161757468000000000000000000000000000000000000000000000000000000610220526102005060646101dcfd5b600435600055600435610140527f140eb9f8b591138e129e4caf389c92df4f0545b902523eee9e63153ecdb2026e6020610140a1005b636817031b8114156111b05760043560a01c1561102357600080fd5b60045433141515611073576308c379a061014052602061016052600a610180527f2174696d65206c6f636b000000000000000000000000000000000000000000006101a05261018050606461015cfd5b60035460206101a0600463fc0c546a6101405261015c6004355afa61109757600080fd5b601f3d116110a457600080fd5b6000506101a0511415156110f7576308c379a06101c05260206101e0526014610200527f7661756c7420746f6b656e20213d20746f6b656e000000000000000000000000610220526102005060646101dcfd5b6000600254181561112f57600354610140526002546101605260006101805261018051610160516101405160065801613fe4565b6000505b60043560025560035461014052600254610160527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6101805261018051610160516101405160065801613fe4565b600050600435610140527fd459c7242e23d490831b5676a611c4342d899d28f342d89ae80793e56a930f306020610140a1005b6301e1d1148114156111d657600658016144c9565b610140526101405160005260206000f35b633b8ae39781141561141f5760043560a01c156111f257600080fd5b60045433141515611242576308c379a061014052602061016052600a610180527f2174696d65206c6f636b000000000000000000000000000000000000000000006101a05261018050606461015cfd5b600b60043560e05260c052604060c02060c052602060c020541515156112a7576308c379a0610140526020610160526008610180527f617070726f7665640000000000000000000000000000000000000000000000006101a05261018050606461015cfd5b3060206101a06004636209ec2d6101405261015c6004355afa6112c957600080fd5b601f3d116112d657600080fd5b6000506101a051141515611329576308c379a06101c05260206101e052601d610200527f73747261746567792066756e64206d616e6167657220213d2074686973000000610220526102005060646101dcfd5b60035460206101a0600463fc0c546a6101405261015c6004355afa61134d57600080fd5b601f3d1161135a57600080fd5b6000506101a0511415156113ad576308c379a06101c05260206101e0526017610200527f737472617465677920746f6b656e20213d20746f6b656e000000000000000000610220526102005060646101dcfd5b600b60043560e05260c052604060c02060c052602060c02060018155600060018201556000600282015560006003820155600060048201556000600582015560006006820155506004357f4c6d0fbb89373829bc56000a87d561331bca06f725fd8861d055215ed90f209b60006000a2005b63bb994d488114156115ee5760043560a01c1561143b57600080fd5b600454610160526006546101805260006101405261014061012060006002818352015b61012051602002610160015133141561147a576001835261148a565b815160010180835281141561145e575b5050506101405115156114dc576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b600b60043560e05260c052604060c02060c052602060c020541515611540576308c379a0610140526020610160526009610180527f21617070726f76656400000000000000000000000000000000000000000000006101a05261018050606461015cfd5b6001600b60043560e05260c052604060c02060c052602060c02001541515156115a8576308c379a0610140526020610160526006610180527f61637469766500000000000000000000000000000000000000000000000000006101a05261018050606461015cfd5b6000600b60043560e05260c052604060c02060c052602060c020556004357f7d3e35e217272b8400fec8397b08eb8c60c4db9ae834af14ac0fc9c0bb914a8f60006000a2005b635f1ac3108114156119315760043560a01c1561160a57600080fd5b600454610160526006546101805260006101405261014061012060006002818352015b6101205160200261016001513314156116495760018352611659565b815160010180835281141561162d575b5050506101405115156116ab576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b600b60043560e05260c052604060c02060c052602060c02054151561170f576308c379a0610140526020610160526009610180527f21617070726f76656400000000000000000000000000000000000000000000006101a05261018050606461015cfd5b6001600b60043560e05260c052604060c02060c052602060c0200154151515611777576308c379a0610140526020610160526006610180527f61637469766500000000000000000000000000000000000000000000000000006101a05261018050606461015cfd5b612710600a5460243581818301101561178f57600080fd5b80820190509050111515156117e3576308c379a061014052602061016052600b610180527f726174696f203e206d61780000000000000000000000000000000000000000006101a05261018050606461015cfd5b60643560443511151515611836576308c379a0610140526020610160526017610180527f6d696e20626f72726f77203e206d617820626f72726f770000000000000000006101a05261018050606461015cfd5b600435610140526101405160065801614676565b60005060016001600b60043560e05260c052604060c02060c052602060c020015560016002600b60043560e05260c052604060c02060c052602060c02001556024356003600b60043560e05260c052604060c02060c052602060c02001556044356005600b60043560e05260c052604060c02060c052602060c02001556064356006600b60043560e05260c052604060c02060c052602060c0200155600a80546024358181830110156118fc57600080fd5b808201905090508155506004357fa3cbd67e6583e6c7ef034e5f87b7b40b0a0e87182a8377dfb42e59aa414c6cd560006000a2005b63b22439f5811415611b5a5760043560a01c1561194d57600080fd5b60045461016052600654610180526007546101a05260006101405261014061012060006003818352015b61012051602002610160015133141561199357600183526119a3565b8151600101808352811415611977575b5050506101405115156119f5576308c379a06101c05260206101e0526005610200527f2161757468000000000000000000000000000000000000000000000000000000610220526102005060646101dcfd5b6001600b60043560e05260c052604060c02060c052602060c02001541515611a5c576308c379a0610140526020610160526007610180527f21616374697665000000000000000000000000000000000000000000000000006101a05261018050606461015cfd5b600435610140526101405160065801614813565b6101a0526101a0516101c0526101405161016051610180516101a0516101c0516101c0516101e0526101e0516006580161470c565b6101c0526101a05261018052610160526101405260005060006001600b60043560e05260c052604060c02060c052602060c0200155600a80546003600b60043560e05260c052604060c02060c052602060c020015480821015611b0757600080fd5b8082039050905081555060006003600b60043560e05260c052604060c02060c052602060c02001556004357fff2f97c1f3529c6b02543b63f7efae22cdc885048adf65c679a1c5c4ea3b2fa860006000a2005b63c5cde90b81141561201a576000610120525b610120516004013560a01c15611b8257600080fd5b6020610120510161012052610280610120511015611b9f57611b6d565b600454610160526006546101805260006101405261014061012060006002818352015b610120516020026101600151331415611bde5760018352611bee565b8151600101808352811415611bc2575b505050610140511515611c40576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b60006101405261016060006014818352015b60046101605160148110611c6557600080fd5b602002013561018052610180511515611c8e57610140511515611c89576001610140525b611cde565b61014051151515611cde576308c379a06101a05260206101c05260036101e0527f6761700000000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b8151600101808352811415611c52575b505061016060006014818352015b6101605160148110611d0d57600080fd5b600c60c052602060c02001546101805260046101605160148110611d3057600080fd5b60200201356101a052610180511515611d98576101a051151515611d93576308c379a06101c05260206101e0526008610200527f6e657720213d2030000000000000000000000000000000000000000000000000610220526102005060646101dcfd5b611deb565b60006101a05114151515611deb576308c379a06101c05260206101e0526007610200527f6e6577203d203000000000000000000000000000000000000000000000000000610220526102005060646101dcfd5b8151600101808352811415611cfc575b505061016060006014818352015b60046101605160148110611e1c57600080fd5b602002013561018052610180511515611e3457611ecc565b6001600b6101805160e05260c052604060c02060c052602060c02001541515611e9c576308c379a06101a05260206101c05260076101e0527f2161637469766500000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b60006001600b6101805160e05260c052604060c02060c052602060c02001555b8151600101808352811415611e09575b505061016060006014818352015b60046101605160148110611eed57600080fd5b602002013561018052610180511515611f0557611f56565b60016001600b6101805160e05260c052604060c02060c052602060c0200155610180516101605160148110611f3957600080fd5b600c60c052602060c02001555b8151600101808352811415611eda575b505060043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205260e4356102405261010435610260526101243561028052610144356102a052610164356102c052610184356102e0526101a435610300526101c435610320526101e4356103405261020435610360526102243561038052610244356103a052610264356103c0527fa03ab32749bdff946d914bdbc7fadedf2bdeb6a83f2b56effa25a0eae1012675610280610160a1005b63260829c081141561233c57600454610160526006546101805260006101405261014061012060006002818352015b6101205160200261016001513314156120655760018352612075565b8151600101808352811415612049575b5050506101405115156120c7576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b61014060006014818352015b61014051601481106120e457600080fd5b600c60c052602060c0200154151561215a576004610140516014811061210957600080fd5b602002013515151561215a576308c379a061016052602061018052600f6101a0527f6465627420726174696f20213d203000000000000000000000000000000000006101c0526101a050606461017cfd5b81516001018083528114156120d3575b505060006101405261016060006014818352015b610160516014811061218f57600080fd5b600c60c052602060c0200154610180526101805115156121ae5761221e565b600461016051601481106121c157600080fd5b60200201356101a0526101a0516003600b6101805160e05260c052604060c02060c052602060c020015561014080516101a05181818301101561220357600080fd5b808201905090508152505b815160010180835281141561217e575b505061014051600a55612710600a541115151561227a576308c379a061016052602061018052600b6101a0527f746f74616c203e206d61780000000000000000000000000000000000000000006101c0526101a050606461017cfd5b60043561016052602435610180526044356101a0526064356101c0526084356101e05260a4356102005260c4356102205260e4356102405261010435610260526101243561028052610144356102a052610164356102c052610184356102e0526101a435610300526101c435610320526101e4356103405261020435610360526102243561038052610244356103a052610264356103c0527f8edb07c0d6dfa3d8e47f8faaeffa94a7c21b80ebb98ccf264581f64c8270a906610280610160a1005b63da1714318114156125285760043560a01c1561235857600080fd5b600454610160526006546101805260006101405261014061012060006002818352015b61012051602002610160015133141561239757600183526123a7565b815160010180835281141561237b575b5050506101405115156123f9576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b600b60043560e05260c052604060c02060c052602060c02054151561245d576308c379a0610140526020610160526009610180527f21617070726f76656400000000000000000000000000000000000000000000006101a05261018050606461015cfd5b604435602435111515156124b0576308c379a0610140526020610160526017610180527f6d696e20626f72726f77203e206d617820626f72726f770000000000000000006101a05261018050606461015cfd5b6024356005600b60043560e05260c052604060c02060c052602060c02001556044356006600b60043560e05260c052604060c02060c052602060c020015560243561014052604435610160526004357ffedf8d30e937b57e4e95271e9f17cfab1a1315ac6d612ef72912405e9524f7d56040610140a2005b63505b6a768114156126fb576001541515612582576308c379a061014052602061016052600c610180527f21696e697469616c697a656400000000000000000000000000000000000000006101a05261018050606461015cfd5b60045461016052600654610180526008546101a05260006101405261014061012060006003818352015b6101205160200261016001513314156125c857600183526125d8565b81516001018083528114156125ac575b50505061014051151561262a576308c379a06101c05260206101e0526005610200527f2161757468000000000000000000000000000000000000000000000000000000610220526102005060646101dcfd5b60206101e0602463c5ebeaec610160526004356101805261017c60006002545af161265457600080fd5b601f3d1161266157600080fd5b6000506101e0516101405260243561014051101515156126c0576308c379a061016052602061018052600e6101a0527f626f72726f776564203c206d696e0000000000000000000000000000000000006101c0526101a050606461017cfd5b6004356101605261014051610180526002547fb87de9931230544a0b3a00e753f5ab70f79a54e84e47bcad4239e1c1c97588d36040610160a2005b6348b8a1f98114156128ce576001541515612755576308c379a061014052602061016052600c610180527f21696e697469616c697a656400000000000000000000000000000000000000006101a05261018050606461015cfd5b60045461016052600654610180526008546101a05260006101405261014061012060006003818352015b61012051602002610160015133141561279b57600183526127ab565b815160010180835281141561277f575b5050506101405115156127fd576308c379a06101c05260206101e0526005610200527f2161757468000000000000000000000000000000000000000000000000000000610220526102005060646101dcfd5b60206101e0602463371fd8e6610160526004356101805261017c60006002545af161282757600080fd5b601f3d1161283457600080fd5b6000506101e051610140526024356101405110151515612893576308c379a061016052602061018052600c6101a0527f726570616964203c206d696e00000000000000000000000000000000000000006101c0526101a050606461017cfd5b6004356101605261014051610180526002547f447949f39e7c140dbba1469e2e065abd8a278ac561449a4fcd1c51f5aadc91d86040610160a2005b63d5b6e219811415612bc5576001541515612928576308c379a061014052602061016052600c610180527f21696e697469616c697a656400000000000000000000000000000000000000006101a05261018050606461015cfd5b60045461016052600654610180526008546101a05260006101405261014061012060006003818352015b61012051602002610160015133141561296e576001835261297e565b8151600101808352811415612952575b5050506101405115156129d0576308c379a06101c05260206101e0526005610200527f2161757468000000000000000000000000000000000000000000000000000000610220526102005060646101dcfd5b61014051600658016144c9565b6101605261014052610160516101405260043561014051101515612a0957602435610140511115612a0c565b60005b1515612a57576308c379a06101605260206101805260126101a0527f746f74616c206e6f7420696e2072616e676500000000000000000000000000006101c0526101a050606461017cfd5b60206101e06004630dca59c16101805261019c6002545afa612a7857600080fd5b601f3d11612a8557600080fd5b6000506101e051610160526040366101803761016051610140511115612af957610140516101605180821015612aba57600080fd5b808203905090506101405160095480821015612ad557600080fd5b8082039050905080821115612aea5780612aec565b815b9050905061018052612b1a565b610160516101405180821015612b0e57600080fd5b808203905090506101a0525b6000610180511115612b2d576001612b35565b60006101a051115b15612b79576002543b612b4757600080fd5b60006000604463753c09856101c052610180516101e0526101a051610200526101dc60006002545af1612b7957600080fd5b610140516101c052610160516101e05261018051610200526101a051610220526002547fd94ac81cdb49ea558800854e3bfd1aedf2a0a02abc471047c34e382fd5137cbd60806101c0a2005b632e1a7d4d811415612f1e576001541515612c1f576308c379a061014052602061016052600c610180527f21696e697469616c697a656400000000000000000000000000000000000000006101a05261018050606461015cfd5b60025433141515612c6f576308c379a0610140526020610160526006610180527f217661756c7400000000000000000000000000000000000000000000000000006101a05261018050606461015cfd5b61014051600658016144c9565b610160526101405261016051610140526004356101405180821115612ca15780612ca3565b815b9050905061016052600061016051111515612cfd576308c379a06101805260206101a052600c6101c0527f7769746864726177203d203000000000000000000000000000000000000000006101e0526101c050606461019cfd5b60206102006004630dca59c16101a0526101bc6002545afa612d1e57600080fd5b601f3d11612d2b57600080fd5b600050610200516101805260006101a05261014051610180511115612d6b57610180516101405180821015612d5f57600080fd5b808203905090506101a0525b602061026060246370a082316101e05230610200526101fc6003545afa612d9157600080fd5b601f3d11612d9e57600080fd5b600050610260516101c0526101c051610160511115612e71576101a080516101405161016051610180516101a0516101c051610160516101e0526101e051600658016148b7565b610240526101c0526101a05261018052610160526101405261024051818183011015612e1057600080fd5b8082019050905081525061016051602061026060246370a082316101e05230610200526101fc6003545afa612e4457600080fd5b601f3d11612e5157600080fd5b6000506102605180821115612e665780612e68565b815b90509050610160525b6000610160511115612ed2576101405161016051610180516101a0516101c0516003546101e0523361020052610160516102205261022051610200516101e0516006580161417e565b6101c0526101a0526101805261016052610140526000505b6004356101e05261016051610200526101a05161022052337f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca9460606101e0a26101a05160005260206000f35b63f19f0542811415612f5f5760043560a01c15612f3a57600080fd5b600435610140526101405160065801614bbd565b6101a0526101a05160005260206000f35b63c6f2be58811415612fa05760043560a01c15612f7b57600080fd5b600435610140526101405160065801614d9d565b6101a0526101a05160005260206000f35b639a78e72e811415612fe15760043560a01c15612fbc57600080fd5b6004600b60043560e05260c052604060c02060c052602060c020015460005260206000f35b63c5ebeaec81141561326657600e5415612ffa57600080fd5b6001600e55600154151561304d576308c379a061014052602061016052600c610180527f21696e697469616c697a656400000000000000000000000000000000000000006101a05261018050606461015cfd5b60005415151561309c576308c379a0610140526020610160526006610180527f70617573656400000000000000000000000000000000000000000000000000006101a05261018050606461015cfd5b6001600b3360e05260c052604060c02060c052602060c02001541515613101576308c379a0610140526020610160526007610180527f21616374697665000000000000000000000000000000000000000000000000006101a05261018050606461015cfd5b6004356101405133610160526101605160065801614bbd565b6101c052610140526101c051808211156131345780613136565b815b9050905061014052600061014051111515613190576308c379a061016052602061018052600a6101a0527f626f72726f77203d2030000000000000000000000000000000000000000000006101c0526101a050606461017cfd5b61014051600354610160523361018052610140516101a0526101a05161018051610160516006580161417e565b610140526000506004600b3360e05260c052604060c02060c052602060c020018054610140518181830110156131f257600080fd5b80820190509050815550600980546101405181818301101561321357600080fd5b80820190509050815550600435610160526101405161018052337fe1979fe4c35e0cef342fef5668e2c8e7a7e9f5d5d1ca8fee0ac6c427fa4153af6040610160a2610140516000526000600e5560206000f35b63371fd8e681141561351b5760015415156132c0576308c379a061014052602061016052600c610180527f21696e697469616c697a656400000000000000000000000000000000000000006101a05261018050606461015cfd5b600b3360e05260c052604060c02060c052602060c020541515613322576308c379a0610140526020610160526009610180527f21617070726f76656400000000000000000000000000000000000000000000006101a05261018050606461015cfd5b6004356004600b3360e05260c052604060c02060c052602060c02001548082111561334d578061334f565b815b90509050610140526000610140511115156133a9576308c379a06101605260206101805260096101a0527f7265706179203d203000000000000000000000000000000000000000000000006101c0526101a050606461017cfd5b602061020060246370a0823161018052306101a05261019c6003545afa6133cf57600080fd5b601f3d116133dc57600080fd5b6000506102005161016052610140516101605160035461018052336101a052306101c052610140516101e0526101e0516101c0516101a0516101805160065801614318565b6101605261014052600050602061020060246370a0823161018052306101a05261019c6003545afa61345257600080fd5b601f3d1161345f57600080fd5b60005061020051610160518082101561347757600080fd5b80820390509050610160526004600b3360e05260c052604060c02060c052602060c02001805461016051808210156134ae57600080fd5b808203905090508155506009805461016051808210156134cd57600080fd5b8082039050905081555060043561018052610160516101a052337f77c6871227e5d2dec8dadd5354f78453203e22e669cd0ec4c19d9a8c5edb31d06040610180a26101605160005260206000f35b63753c0985811415613754576001541515613575576308c379a061014052602061016052600c610180527f21696e697469616c697a656400000000000000000000000000000000000000006101a05261018050606461015cfd5b6001600b3360e05260c052604060c02060c052602060c020015415156135da576308c379a0610140526020610160526007610180527f21616374697665000000000000000000000000000000000000000000000000006101a05261018050606461015cfd5b60006004351015156135ef57602435156135f2565b60005b156135fe576001613616565b60043515156136135760006024351015613616565b60005b1515613661576308c379a0610140526020610160526011610180527f6761696e20616e64206c6f7373203e20300000000000000000000000000000006101a05261018050606461015cfd5b600060043511156136a55760035461014052336101605230610180526004356101a0526101a05161018051610160516101405160065801614318565b600050613704565b60006024351115613704576004600b3360e05260c052604060c02060c052602060c020018054602435808210156136db57600080fd5b8082039050905081555060098054602435808210156136f957600080fd5b808203905090508155505b60406004610140376004600b3360e05260c052604060c02060c052602060c020015461018052337f36d8646df39e8831ab3926651692b6a0ea874e6cc807ea1c428fcf2ba32859f86060610140a2005b636cb56d19811415613bf85760043560a01c1561377057600080fd5b60243560a01c1561378057600080fd5b60015415156137ce576308c379a061014052602061016052600c610180527f21696e697469616c697a656400000000000000000000000000000000000000006101a05261018050606461015cfd5b600454610160526006546101805260006101405261014061012060006002818352015b61012051602002610160015133141561380d576001835261381d565b81516001018083528114156137f1575b50505061014051151561386f576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b6001600b60043560e05260c052604060c02060c052602060c020015415156138d6576308c379a061014052602061016052600b610180527f6f6c6420216163746976650000000000000000000000000000000000000000006101a05261018050606461015cfd5b600b60243560e05260c052604060c02060c052602060c02054151561393a576308c379a061014052602061016052600d610180527f6e65772021617070726f766564000000000000000000000000000000000000006101a05261018050606461015cfd5b6002600b60243560e05260c052604060c02060c052602060c02001541515156139a2576308c379a0610140526020610160526009610180527f61637469766174656400000000000000000000000000000000000000000000006101a05261018050606461015cfd5b610140600b60043560e05260c052604060c0208060c052602060c02054825260018160c052602060c0200154826020015260028160c052602060c0200154826040015260038160c052602060c0200154826060015260048160c052602060c0200154826080015260058160c052602060c02001548260a0015260068160c052602060c02001548260c001525050600b60243560e05260c052604060c02060c052602060c0206001815560016001820155600160028201556101a05160038201556101c05160048201556101e05160058201556102005160068201555060006001600b60043560e05260c052604060c02060c052602060c020015560006003600b60043560e05260c052604060c02060c052602060c020015560006004600b60043560e05260c052604060c02060c052602060c020015560006005600b60043560e05260c052604060c02060c052602060c020015560006006600b60043560e05260c052604060c02060c052602060c02001556101405161016051610180516101a0516101c0516101e0516102005161022051600435610240526102405160065801614813565b6102a05261022052610200526101e0526101c0526101a0526101805261016052610140526102a051610220526024356102205160148110613b8857600080fd5b600c60c052602060c02001556004353b613ba157600080fd5b60006000602463ce5494bb610240526024356102605261025c60006004355af1613bca57600080fd5b6024356004357f9249d6a64288c19c5be5f4f1bb9b763ad4afac803128f1ef65b88acb13df9aa460006000a3005b6301681a62811415613da45760043560a01c15613c1457600080fd5b600454610160526006546101805260006101405261014061012060006002818352015b610120516020026101600151331415613c535760018352613c63565b8151600101808352811415613c37575b505050610140511515613cb5576308c379a06101a05260206101c05260056101e0527f2161757468000000000000000000000000000000000000000000000000000000610200526101e05060646101bcfd5b60035460043514151515613d08576308c379a0610140526020610160526009610180527f70726f74656374656400000000000000000000000000000000000000000000006101a05261018050606461015cfd5b60206101c060246370a0823161014052306101605261015c6004355afa613d2e57600080fd5b601f3d11613d3b57600080fd5b6000506101c0516101e0526101405161016051610180516101a0516101c0516101e0516004356102005233610220526101e051610240526102405161022051610200516006580161417e565b6101e0526101c0526101a052610180526101605261014052600050005b635c975abb811415613dbc5760005460005260206000f35b63158ef93e811415613dd45760015460005260206000f35b63fbfa77cf811415613dec5760025460005260206000f35b63fc0c546a811415613e045760035460005260206000f35b63d085835a811415613e1c5760045460005260206000f35b63b127df87811415613e345760055460005260206000f35b63f851a440811415613e4c5760065460005260206000f35b63452a9320811415613e645760075460005260206000f35b634d547ada811415613e7c5760085460005260206000f35b63fc7b9c18811415613e945760095460005260206000f35b632df9eab9811415613eac57600a5460005260206000f35b6339ebf823811415613f935760043560a01c15613ec857600080fd5b600b60043560e05260c052604060c0206101408080808460c052602060c0205481525050602081019050808060018560c052602060c020015481525050602081019050808060028560c052602060c020015481525050602081019050808060038560c052602060c020015481525050602081019050808060048560c052602060c020015481525050602081019050808060058560c052602060c020015481525050602081019050808060068560c052602060c02001548152505060e09050905060c05260c051610140f35b63ddf0b009811415613fc45760043560148110613faf57600080fd5b600c60c052602060c020015460005260206000f35b63a598adff811415613fdc57600d5460005260206000f35b505b60006000fd5b6101a05261014052610160526101805260006004610220527f095ea7b3000000000000000000000000000000000000000000000000000000006102405261022060048060208461028001018260208501600060045af15050805182019150506101605160208261028001015260208101905061018051602082610280010152602081019050806102805261028090508051602001806103208284600060045af161408d57600080fd5b505060206103e0610320516103406000610140515af16140ac57600080fd5b60203d808211156140bd57806140bf565b815b905090506103c0526103c08051602001806101c08284600060045af16140e457600080fd5b505060006101c0511115614178576101c080602001516000825180602090131561410d57600080fd5b809190121561411b57600080fd5b806020036101000a820490509050905015151515614178576308c379a061022052602061024052600e610260527f617070726f7665206661696c65640000000000000000000000000000000000006102805261026050606461023cfd5b6101a051565b6101a05261014052610160526101805260006004610220527fa9059cbb000000000000000000000000000000000000000000000000000000006102405261022060048060208461028001018260208501600060045af15050805182019150506101605160208261028001015260208101905061018051602082610280010152602081019050806102805261028090508051602001806103208284600060045af161422757600080fd5b505060206103e0610320516103406000610140515af161424657600080fd5b60203d808211156142575780614259565b815b905090506103c0526103c08051602001806101c08284600060045af161427e57600080fd5b505060006101c0511115614312576101c08060200151600082518060209013156142a757600080fd5b80919012156142b557600080fd5b806020036101000a820490509050905015151515614312576308c379a061022052602061024052600f610260527f7472616e73666572206661696c656400000000000000000000000000000000006102805261026050606461023cfd5b6101a051565b6101c0526101405261016052610180526101a05260006004610240527f23b872dd00000000000000000000000000000000000000000000000000000000610260526102406004806020846102a001018260208501600060045af1505080518201915050610160516020826102a0010152602081019050610180516020826102a00101526020810190506101a0516020826102a0010152602081019050806102a0526102a090508051602001806103608284600060045af16143d857600080fd5b50506020610440610360516103806000610140515af16143f757600080fd5b60203d80821115614408578061440a565b815b90509050610420526104208051602001806101e08284600060045af161442f57600080fd5b505060006101e05111156144c3576101e080602001516000825180602090131561445857600080fd5b809190121561446657600080fd5b806020036101000a8204905090509050151515156144c3576308c379a0610240526020610260526013610280527f7472616e7366657246726f6d206661696c6564000000000000000000000000006102a05261028050606461025cfd5b6101c051565b6101405260206101e060246370a0823161016052306101805261017c6003545afa6144f357600080fd5b601f3d1161450057600080fd5b6000506101e05160095481818301101561451957600080fd5b8082019050905060005260005161014051565b610140526102a0366101603761042060006014818352015b61042051600c60c052602060c02001546104005260006104005118156145a257610400516101606103e0516014811061457c57600080fd5b60200201526103e08051600181818301101561459757600080fd5b808201905090508152505b8151600101808352811415614544575b5050600c60c052602060c0206101605181556101805160018201556101a05160028201556101c05160038201556101e05160048201556102005160058201556102205160068201556102405160078201556102605160088201556102805160098201556102a051600a8201556102c051600b8201556102e051600c82015561030051600d82015561032051600e82015561034051600f8201556103605160108201556103805160118201556103a05160128201556103c05160138201555061014051565b61016052610140526013600c60c052602060c02001541515156146d8576308c379a06101805260206101a052600b6101c0527f7175657565203e206d61780000000000000000000000000000000000000000006101e0526101c050606461019cfd5b610140516013600c60c052602060c020015561014051610160516006580161452c565b610160526101405260005061016051565b6101605261014052601461014051101515614766576308c379a06101805260206101a05260086101c0527f69203e3d206d61780000000000000000000000000000000000000000000000006101e0526101c050606461019cfd5b6000610140516014811061477957600080fd5b600c60c052602060c0200154141515156147d2576308c379a06101805260206101a052600d6101c0527f217a65726f2061646472657373000000000000000000000000000000000000006101e0526101c050606461019cfd5b600061014051601481106147e557600080fd5b600c60c052602060c020015561014051610160516006580161452c565b610160526101405260005061016051565b610160526101405261018060006014818352015b61014051610180516014811061483c57600080fd5b600c60c052602060c020015414156148605761018051600052505060005161016051565b8151600101808352811415614827575b50506308c379a06101805260206101a05260096101c0527f6e6f7420666f756e6400000000000000000000000000000000000000000000006101e0526101c050606461019cfd5b6101605261014052610140516101805260006101a0526101e060006014818352015b6101e051600c60c052602060c02001546101c0526101c05115156148fc57614bab565b60206102a060246370a0823161022052306102405261023c6003545afa61492257600080fd5b601f3d1161492f57600080fd5b6000506102a05161020052610180516102005110151561494e57614bab565b6004600b6101c05160e05260c052604060c02060c052602060c02001546102205261018051610200518082101561498457600080fd5b80820390509050610220518082111561499d578061499f565b815b90509050610240526102405115156149b657614b9b565b60206103006024632e1a7d4d61028052610240516102a05261029c60006101c0515af16149e257600080fd5b601f3d116149ef57600080fd5b6000506103005161026052602061032060246370a082316102a052306102c0526102bc6003545afa614a2057600080fd5b601f3d11614a2d57600080fd5b600050610320516102005180821015614a4557600080fd5b80820390509050610280526000610260511115614af75761018080516102605180821015614a7257600080fd5b808203905090508152506101a0805161026051818183011015614a9457600080fd5b808201905090508152506004600b6101c05160e05260c052604060c02060c052602060c0200180546102605180821015614acd57600080fd5b80820390509050815550600980546102605180821015614aec57600080fd5b808203905090508155505b6004600b6101c05160e05260c052604060c02060c052602060c0200180546102805180821015614b2657600080fd5b80820390509050815550600980546102805180821015614b4557600080fd5b80820390509050815550610220516102a052610240516102c052610260516102e05261028051610300526101c0517fa1db2d4488a8004dde12ff73253859b508b0458878ea4086047bab6672f9f1d760806102a0a25b81516001018083528114156148d9575b50506101a05160005260005161016051565b61016052610140526001541515614bd5576001614be9565b60005415614be4576001614be9565b600a54155b15614bfc57600060005260005161016051565b6003600b6101405160e05260c052604060c02060c052602060c0200154610140516101605161018051600658016144c9565b6101a0526101805261016052610140526101a0518082028215828483041417614c5657600080fd5b80905090509050600a548080614c6b57600080fd5b820490509050610180526004600b6101405160e05260c052604060c02060c052602060c02001546101a052610180516101a051101515614cb357600060005260005161016051565b610180516101a05180821015614cc857600080fd5b80820390509050602061026060246370a082316101e05230610200526101fc6003545afa614cf557600080fd5b601f3d11614d0257600080fd5b6000506102605180821115614d175780614d19565b815b905090506101c0526005600b6101405160e05260c052604060c02060c052602060c02001546101c0511015614d5a5760006000526000516101605156614d9b565b6101c0516006600b6101405160e05260c052604060c02060c052602060c020015480821115614d895780614d8b565b815b9050905060005260005161016051565b005b61016052610140526001541515614dbc57600060005260005161016051565b600a541515614dee576004600b6101405160e05260c052604060c02060c052602060c020015460005260005161016051565b6003600b6101405160e05260c052604060c02060c052602060c02001546009548082028215828483041417614e2257600080fd5b80905090509050600a548080614e3757600080fd5b820490509050610180526004600b6101405160e05260c052604060c02060c052602060c02001546101a05260005415614e7e576101a0516000526000516101605156614ec7565b610180516101a051111515614e9f5760006000526000516101605156614ec7565b6101a0516101805180821015614eb457600080fd5b8082039050905060005260005161016051565b00

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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