ETH Price: $2,716.58 (+0.57%)

Contract

0xb00AA15F78A278Be2FCb2aa7de899F3F863780f8
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

Transaction Hash
Method
Block
From
To
Report To Vault182307772023-09-28 0:49:23506 days ago1695862163IN
0xb00AA15F...F863780f8
0 ETH0.001081927.36979805
Report To Vault181239362023-09-13 0:52:23521 days ago1694566343IN
0xb00AA15F...F863780f8
0 ETH0.001228978.37146435
Report To Vault180167402023-08-29 0:33:23536 days ago1693269203IN
0xb00AA15F...F863780f8
0 ETH0.0022684720.14543434
Report To Vault179095382023-08-14 0:33:23551 days ago1691973203IN
0xb00AA15F...F863780f8
0 ETH0.0014037112.46585708
Report To Vault178022972023-07-30 0:33:23566 days ago1690677203IN
0xb00AA15F...F863780f8
0 ETH0.0024425616.63814815
Repay Vault176953082023-07-15 0:39:47581 days ago1689381587IN
0xb00AA15F...F863780f8
0 ETH0.0012628213.52801421
Report To Vault176952762023-07-15 0:33:23581 days ago1689381203IN
0xb00AA15F...F863780f8
0 ETH0.001907812.99553676
Report To Vault175885522023-06-30 0:33:23596 days ago1688085203IN
0xb00AA15F...F863780f8
0 ETH0.0027268824.21634557
Report To Vault174817832023-06-15 0:38:47611 days ago1686789527IN
0xb00AA15F...F863780f8
0 ETH0.0016230114.41334306
Report To Vault173753292023-05-31 0:33:23626 days ago1685493203IN
0xb00AA15F...F863780f8
0 ETH0.0034270830.43458922
Repay Vault172289722023-05-10 8:59:35646 days ago1683709175IN
0xb00AA15F...F863780f8
0 ETH0.0063004767.49371063
Report To Vault172289392023-05-10 8:52:59646 days ago1683708779IN
0xb00AA15F...F863780f8
0 ETH0.0088300760.14832714
Report To Vault169649872023-04-03 0:34:59684 days ago1680482099IN
0xb00AA15F...F863780f8
0 ETH0.001923217.08071594
Report To Vault169436452023-03-31 0:33:23687 days ago1680222803IN
0xb00AA15F...F863780f8
0 ETH0.0026584923.61112207
Repay Vault169223452023-03-28 0:42:11690 days ago1679964131IN
0xb00AA15F...F863780f8
0 ETH0.0018943820.29359439
Report To Vault169223082023-03-28 0:34:47690 days ago1679963687IN
0xb00AA15F...F863780f8
0 ETH0.0031130221.20660641
Report To Vault169009582023-03-25 0:36:35693 days ago1679704595IN
0xb00AA15F...F863780f8
0 ETH0.0017651415.67691898
Repay Vault168796332023-03-22 0:42:11696 days ago1679445731IN
0xb00AA15F...F863780f8
0 ETH0.0014662515.70729115
Report To Vault168796022023-03-22 0:35:47696 days ago1679445347IN
0xb00AA15F...F863780f8
0 ETH0.0021455514.61602464
Report To Vault168583602023-03-19 0:59:11699 days ago1679187551IN
0xb00AA15F...F863780f8
0 ETH0.0016912515.02067639
Repay Vault168369142023-03-16 0:40:59702 days ago1678927259IN
0xb00AA15F...F863780f8
0 ETH0.001830319.60207327
Report To Vault168368812023-03-16 0:34:23702 days ago1678926863IN
0xb00AA15F...F863780f8
0 ETH0.002913519.84744068
Repay Vault168156362023-03-13 0:55:35705 days ago1678668935IN
0xb00AA15F...F863780f8
0 ETH0.0030584432.7635311
Report To Vault168155292023-03-13 0:33:35705 days ago1678667615IN
0xb00AA15F...F863780f8
0 ETH0.0035519231.54936983
Report To Vault167942262023-03-10 0:33:23708 days ago1678408403IN
0xb00AA15F...F863780f8
0 ETH0.0035567331.58876148
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:
default evmVersion, 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.