예제 #1
0
def from_dollars(badger, token_address, dollars):
    """
    Get the amount of a given coin required for a given dollar sum at current exchange rate
    """
    # Expected output in dollars

    # Price: Output <> USD
    # Price: Input <> Output
    exchange_rate = fetch_usd_price(token_address)
    tokens_amount = dollars / exchange_rate
    decimals = interface.IERC20(token_address).decimals()
    output = int(tokens_amount * (10**decimals))

    console.print({
        "exchange_rate": exchange_rate,
        "dollars": dollars,
        "token_amount_scaled": tokens_amount,
        "token_amount_unscaled": output,
        "decimals": decimals,
    })

    return output
예제 #2
0
def test_asset_tvl_usdc(v2VaultsTvlAdapter):
    assetsAddresses = v2VaultsTvlAdapter.assetsAddresses()
    # for address in assetsAddresses:
    #     tvl = v2VaultsTvlAdapter.assetTvlUsdc(address) / 10 ** 12
    #     assert tvl > 0

    # Print TVL per asset
    print("-------------")
    print("V2 Vaults TVL")
    print("-------------")
    totalTvl = 0
    tvlList = []
    for address in assetsAddresses:
        token = interface.IERC20(address)
        tvl = v2VaultsTvlAdapter.assetTvlUsdc(address) / 10**6
        totalTvl += tvl
        tvlList.append({"symbol": token.symbol(), "tvl": tvl})
    sortedTvlItems = sorted(tvlList, key=itemgetter("tvl"), reverse=True)
    for item in sortedTvlItems:
        print(item.get("symbol"), item.get("tvl"))

    calculatedTotalTvl = v2VaultsTvlAdapter.assetsTvlUsdc() / 10**6
    assert round(calculatedTotalTvl) == round(totalTvl)
    print("Total tvl", totalTvl)
예제 #3
0
dfd_amt = 100 * 10**18
dusd_amt = 10**18
lp_amt = 0
borrow_dfd_amt = 0
borrow_dusd_amt = 0

# calculate slippage control
total_dfd_amt = dfd_amt + borrow_dfd_amt
total_dusd_amt = dusd_amt + borrow_dusd_amt
dfd_weight = 0.58
dusd_weight = 0.42

ratio = (((prevARes + total_dfd_amt) / prevARes) ** dfd_weight) * \
    (((prevBRes + total_dusd_amt) / prevBRes) ** dusd_weight) - 1
lp_desired = lp_amt + int(interface.IERC20(lp).totalSupply() * ratio * 0.995)
print('lp desired', lp_desired)

tx = homora.execute(
    0,
    balancer_spell,
    balancer_spell.addLiquidityWStakingRewards.encode_input(
        lp,  # lp token
        [
            dfd_amt,  # supply DFD
            dusd_amt,  # supply DUSD
            lp_amt,  # supply LP
            borrow_dfd_amt,  # borrow DFD
            borrow_dusd_amt,  # borrow DUSD
            0,  # borrow LP tokens
            lp_desired
예제 #4
0
def test_main():
    badger = connect_badger("deploy-final.json")
    digg = connect_digg("deploy-final.json")

    distribute_from_whales(badger.keeper)

    manager = setup()
    deployer = badger.deployer
    keeper = badger.keeper

    badger.token.transfer(manager, Wei("1000 ether"), {"from": badger.keeper})
    digg.token.transfer(manager, Wei("100 gwei"), {"from": badger.keeper})

    before = badger.token.balanceOf(badger.devMultisig)
    wbtc = interface.IERC20(registry.tokens.wbtc)

    badger_swap_amount = Wei("100 ether")
    digg_swap_amount = Wei("10 gwei")
    badger_transfer_amount = Wei("10 ether")
    digg_transfer_amount = Wei("1 gwei")

    # with brownie.reverts("Initializable: contract is already initialized"):
    #     manager.initialize(
    #         badger.deployer,
    #         badger.keeper,
    #         badger.keeper,
    #         badger.guardian,
    #         badger.devMultisig,
    #         {"from": badger.keeper},
    #     ),

    testStrat = badger.getStrategy("native.badger")

    # # Can add strategy
    # manager.approveStrategy(testStrat, {"from": deployer})
    # assert manager.isApprovedStrategy(testStrat) == True

    # # Can revoke strategy
    # manager.revokeStrategy(testStrat, {"from": deployer})
    # assert manager.isApprovedStrategy(testStrat) == False

    # Get tokens
    before = wbtc.balanceOf(manager)
    manager.swapExactTokensForTokensUniswap(
        badger.token,
        badger_swap_amount,
        [badger.token, registry.tokens.wbtc],
        {"from": keeper},
    )
    after = wbtc.balanceOf(manager)

    console.print("token swap uni", {"before": before, "after": after})
    assert after > before

    manager.swapExactTokensForTokensSushiswap(
        badger.token,
        badger_swap_amount,
        [badger.token, registry.tokens.wbtc],
        {"from": keeper},
    )
    after2 = wbtc.balanceOf(manager)

    console.print("token swap sushi", {
        "before": before,
        "after": after,
        "after2": after2
    })

    assert after2 > after

    for key in strat_keys:
        console.print("[blue]=== Running for {} ===[/blue]".format(key))
        strat = badger.getStrategy(key)
        # manager.approveStrategy(strat, {"from": deployer})

        # ===== Convert And Transfer Assets
        want = interface.IERC20(strat.want())

        # Native Staking
        if key == "native.badger":
            before = snap_strategy_balance(strat, manager)
            manager.transferWant(strat.want(), strat, badger_transfer_amount,
                                 {"from": keeper})
            after = snap_strategy_balance(strat, manager)
            diff = diff_numbers_by_key(before, after)

            console.log("transfer only", key, before, after, diff)

        if key == "native.digg":
            before = snap_strategy_balance(strat, manager)
            manager.transferWant(strat.want(), strat, digg_transfer_amount,
                                 {"from": keeper})
            after = snap_strategy_balance(strat, manager)
            diff = diff_numbers_by_key(before, after)

            console.log("transfer only", key, before, after, diff)

        startToken = ""
        amount = 0
        if "Badger" in key:
            startToken = badger.token
            amount = badger_swap_amount
        elif "Digg" in key:
            startToken = digg.token
            amount = digg_swap_amount

        # LP Setts
        if "uni" in key:
            before = snap_strategy_balance(strat, manager)

            console.print("PreSwap", {
                "key": key,
                "startToken": startToken,
                "amount": amount
            })

            manager.swapExactTokensForTokensUniswap(startToken, amount,
                                                    [startToken, wbtc],
                                                    {"from": keeper})

            manager.addLiquidityUniswap(startToken, wbtc, {"from": keeper})

            after_swap = snap_strategy_balance(strat, manager)
            diff_swap = diff_numbers_by_key(before, after_swap)

            console.log("post swap", key, before, after_swap, diff_swap)

            manager.transferWant(strat.want(), strat, want.balanceOf(manager),
                                 {"from": keeper})
            after_transfer = snap_strategy_balance(strat, manager)
            diff_transfer = diff_numbers_by_key(after_swap, after_transfer)

            console.log("post transfer", key, after_swap, after_transfer,
                        diff_transfer)

        if "sushi" in key:
            before = snap_strategy_balance(strat, manager)
            manager.swapExactTokensForTokensSushiswap(startToken, amount,
                                                      [startToken, wbtc],
                                                      {"from": keeper})

            manager.addLiquiditySushiswap(startToken, wbtc, {"from": keeper})

            after_swap = snap_strategy_balance(strat, manager)
            diff_swap = diff_numbers_by_key(before, after_swap)

            console.log("post swap", key, before, after_swap, diff_swap)

            manager.transferWant(strat.want(), strat, want.balanceOf(manager),
                                 {"from": keeper})
            after_transfer = snap_strategy_balance(strat, manager)
            diff_transfer = diff_numbers_by_key(after_swap, after_transfer)

            console.log("post transfer", key, after_swap, after_transfer,
                        diff_transfer)

        tx = manager.deposit(strat, {"from": keeper})
        print("deposit events", tx.events)
        if strat.isTendable():
            tx = manager.tend(strat, {"from": keeper})
            print("tend events", tx.events)
        if key != "native.uniBadgerWbtc":
            tx = manager.harvest(strat, {"from": keeper})
            print("harvest events", tx.events)
예제 #5
0
    def printState(self, title):
        console.print(
            "\n[yellow]=== 🦡 Rewards Schedule: {} 🦡 ===[/yellow]".format(
                title))
        table = []

        rewardsEscrow = self.badger.rewardsEscrow
        for key, dist in self.distributions.items():
            if key == "native.digg":
                continue
            print(key, dist)
            geyser = self.badger.getGeyser(key)
            print(geyser)
            assert rewardsEscrow.isApproved(geyser)
            for asset, value in dist.toGeyser.items():
                """
                function signalTokenLock(
                    address geyser,
                    address token,
                    uint256 amount,
                    uint256 durationSec,
                    uint256 startTime
                )
                """

                encoded = rewardsEscrow.signalTokenLock.encode_input(
                    geyser, asset_to_address(asset), value, self.duration,
                    self.start)

                asset_contract = interface.IERC20(asset_to_address(asset))

                scaled = val(value, decimals=18)
                if asset == "digg":
                    scaled = val(shares_to_fragments(value), decimals=9)

                table.append([
                    key,
                    # geyser,
                    asset,
                    value,
                    scaled,
                    to_utc_date(self.start),
                    to_utc_date(self.end),
                    to_days(self.duration),
                    # geyser.address,
                    # encoded,
                ])

        print(
            tabulate(
                table,
                headers=[
                    "key",
                    # "geyser",
                    "token",
                    "total amount",
                    "scaled amount",
                    "start time",
                    "end time",
                    "duration",
                    # "rate per day",
                    # "destination",
                    # "encoded call",
                ],
                tablefmt="rst",
            ))
        print("total distributed for {}: ".format(asset),
              val(self.totals[asset]))
예제 #6
0
def getToken1(pair):
  return interface.IERC20(pair.token1())
예제 #7
0
def test_bridge_vault(vault):
    badger = connect_badger(badger_config.prod_json)
    bridge = connect_bridge(badger, badger_config.prod_json)
    swap = connect_swap(badger_config.prod_json)
    _upgrade_bridge(badger, bridge)
    _upgrade_swap(badger, swap)
    _deploy_bridge_mocks(badger, bridge)

    slippage = 0.03
    amount = 1 * 10**8

    v = vault["address"]
    if v == AddressZero:
        v = MockVault.deploy(vault["id"], vault["symbol"], vault["token"], {
            "from": badger.deployer
        }).address
        # Must approve mock vaults to mint/burn to/from.
        bridge.adapter.setVaultApproval(
            v,
            True,
            {"from": badger.devMultisig},
        )
    else:
        badger.sett_system.vaults[vault["id"]].approveContractAccess(
            bridge.adapter,
            {"from": badger.devMultisig},
        )

    # TODO: Can interleave these mints/burns.
    for accIdx in range(10, 12):
        account = accounts[accIdx]
        for i in range(0, 2):
            balanceBefore = interface.IERC20(v).balanceOf(account)

            bridge.adapter.mint(
                vault["inToken"],
                slippage * 10**4,
                account.address,
                v,
                amount,
                # Darknode args hash/sig optional since gateway is mocked.
                "",
                "",
                {"from": account},
            )
            balance = interface.IERC20(v).balanceOf(account)
            assert balance > balanceBefore

            interface.IERC20(v).approve(
                bridge.adapter.address,
                balance,
                {"from": account},
            )
            # Approve mock gateway for transfer of underlying token for "mock" burns.
            # NB: In the real world, burns don't require approvals as it's just
            # an internal update the the user's token balance.
            interface.IERC20(registry.tokens.renbtc).approve(
                bridge.mocks.BTC.gateway, balance, {"from": bridge.adapter})
            bridge.adapter.burn(
                vault["outToken"],
                v,
                slippage * 10**4,
                account.address,
                balance,
                {"from": account},
            )

            assert interface.IERC20(v).balanceOf(account) == 0
예제 #8
0
def swap_transfer(recipient, params):
    badger = connect_badger("deploy-final.json")

    badger.paymentsMultisig = connect_gnosis_safe(
        "0xD4868d98849a58F743787c77738D808376210292"
    )

    expectedMultisig = "0xB65cef03b9B89f99517643226d76e286ee999e77"
    assert badger.devMultisig == expectedMultisig
    multi = GnosisSafe(badger.paymentsMultisig)

    one_wei = Wei("1")

    end_token = interface.IERC20(params["path"][-1])

    console.print("Executing Swap:", style="yellow")
    console.print(params)

    # === Approve Uniswap Router on Rewards Escrow if not approved ===
    uniswap = UniswapSystem()

    # === Approve UNI Router for Badger ===

    # Note: The allowance must first be set to 0
    id = multi.addTx(
        MultisigTxMetadata(
            description="Approve UNI Router to send BADGER",
            operation="call",
        ),
        params={
            "to": badger.token.address,
            "data": badger.token.approve.encode_input(uniswap.router, 0),
        },
    )

    tx = multi.executeTx(id)

    # Set proper allowance
    id = multi.addTx(
        MultisigTxMetadata(
            description="Approve UNI Router to send BADGER",
            operation="call",
        ),
        params={
            "to": badger.token.address,
            "data": badger.token.approve.encode_input(
                uniswap.router, int(params["max_in"] * 1.5)
            ),
        },
    )

    tx = multi.executeTx(id)

    console.print(
        {
            "rewardsEscrowBalance": val(
                badger.token.balanceOf(badger.paymentsMultisig)
            ),
            "rewardsEscrowRouterAllowance": val(
                badger.token.allowance(badger.paymentsMultisig, uniswap.router)
            ),
            "max_in": val(params["max_in"]),
        }
    )

    assert badger.token.balanceOf(badger.paymentsMultisig) > params["max_in"]
    assert (
        badger.token.allowance(badger.paymentsMultisig, uniswap.router)
        >= params["max_in"]
    )

    # === Trade Badger ===
    before = end_token.balanceOf(badger.paymentsMultisig)
    beforeBadger = badger.token.balanceOf(badger.paymentsMultisig)

    console.print({"EAO": params["exact_amount_out"]})

    expiration = chain.time() + 8000

    id = multi.addTx(
        MultisigTxMetadata(
            description="Trade Badger for output token",
            operation="call",
            callInfo={},
        ),
        params={
            "to": uniswap.router.address,
            "data": uniswap.router.swapTokensForExactTokens.encode_input(
                params["exact_amount_out"],
                int(params["max_in"] * 1.5),
                params["path"],
                badger.paymentsMultisig,
                expiration,
            ),
        },
    )

    tx = multi.executeTx(id)
    print(tx.call_trace())
    print(tx.events)

    printUniTrade(
        method="swapTokensForExactTokens",
        params=(
            params["exact_amount_out"],
            int(params["max_in"] * 1.5),
            params["path"],
            badger.paymentsMultisig,
            expiration,
        ),
    )

    console.log("=== Post Trade ===")
    console.print(
        {
            "before_input_coin": val(beforeBadger),
            "after_input_coin": val(badger.token.balanceOf(badger.paymentsMultisig)),
            "change_input_coin": val(
                beforeBadger - badger.token.balanceOf(badger.paymentsMultisig)
            ),
            "before_output_coin": val(before, decimals=end_token.decimals()),
            "post_output_coin": val(
                end_token.balanceOf(badger.paymentsMultisig),
                decimals=end_token.decimals(),
            ),
            "end_token": end_token,
            "chain_time_before": chain.time(),
        }
    )

    assert end_token.balanceOf(badger.paymentsMultisig) >= params["exact_amount_out"]
    console.print("\n[green] ✅ Actions Complete [/green]")
예제 #9
0
from brownie import interface

UNISWAP_ROUTER = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D"
SUSHISWAP_ROUTER = "0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f"

ETH = interface.IERC20("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
BTC = interface.IERC20("0x2260fac5e5542a773aa44fbcfedf7c193bc2c599")
UNI = interface.IERC20("0x1f9840a85d5af5bf1d1762f925bdaddc4201f984")
SUSHI = interface.IERC20("0x6b3595068778dd592e39a122f4f5a5cf09c90fe2")
ONE_INCH = interface.IERC20("0x111111111117dc0aa78b770fa6a738034120c302")
YFI = interface.IERC20("0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e")
DAI = interface.IERC20("0x6b175474e89094c44da98b954eedeac495271d0f")
USDC = interface.IERC20("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")
USDT = interface.IERC20("0xdac17f958d2ee523a2206206994597c13d831ec7")
BUSD = interface.IERC20("0x4fabb145d64652a948d72533023f6e7a623c7c53")
UWL = interface.IERC20("0xdbdd6f355a37b94e6c7d32fef548e98a280b8df5")
COMP = interface.IERC20("0xc00e94cb662c3520282e6f5717214004a7f26888")
LRC = interface.IERC20("0xbbbbca6a901c926f240b89eacb641d8aec7aeafd")
AAVE = interface.IERC20("0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9")

UNI_USDT_ETH = interface.UniswapPair(
    "0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852")
UNI_DAI_ETH = interface.UniswapPair(
    "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11")
UNI_ALPHA_ETH = interface.UniswapPair(
    "0x411a9b902f364817a0f9c4261ce28b5566a42875")

SUSHI_ALPHA_ibETHv2 = interface.UniswapPair(
    "0xf79a07cd3488bbafb86df1bad09a6168d935c017")
SUSHI_ALCX = interface.IERC20("0xdbdb4d16eda451d0503b854cf79d55697f90c8df")
예제 #10
0
def WETH() -> interface.IERC20:
    return interface.IERC20(
        os.environ.get('WETH_ADDRESS',
                       "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"))
예제 #11
0
def DAI() -> interface.IERC20:
    return interface.IERC20(
        os.environ.get('DAI_ADDRESS',
                       "0x6b175474e89094c44da98b954eedeac495271d0f"))
예제 #12
0
def test_uniswap_add_two_tokens(
    a,
    chain,
    bank,
    werc20,
    ufactory,
    urouter,
    simple_oracle,
    oracle,
    usdc,
    usdt,
    UniswapV2SpellV1,
    UniswapLPOracle,
):
    spell = UniswapV2SpellV1.deploy(bank, werc20, urouter, {'from': a[0]})
    usdc.mint(a[0], 10000000 * 10**6, {'from': a[0]})
    usdt.mint(a[0], 10000000 * 10**6, {'from': a[0]})
    usdc.approve(urouter, 2**256 - 1, {'from': a[0]})
    usdt.approve(urouter, 2**256 - 1, {'from': a[0]})
    urouter.addLiquidity(
        usdc,
        usdt,
        1000000 * 10**6,
        1000000 * 10**6,
        0,
        0,
        a[0],
        chain.time() + 60,
        {'from': a[0]},
    )

    lp = ufactory.getPair(usdc, usdt)
    print('admin lp bal', interface.IERC20(lp).balanceOf(a[0]))
    uniswap_lp_oracle = UniswapLPOracle.deploy(simple_oracle, {'from': a[0]})

    print('usdt Px', simple_oracle.getETHPx(usdt))
    print('usdc Px', simple_oracle.getETHPx(usdc))

    print('lp Px', uniswap_lp_oracle.getETHPx(lp))
    oracle.setOracles(
        [usdc, usdt, lp],
        [
            [simple_oracle, 10000, 10000, 10000],
            [simple_oracle, 10000, 10000, 10000],
            [uniswap_lp_oracle, 10000, 10000, 10000],
        ],
        {'from': a[0]},
    )
    usdc.mint(a[1], 10000000 * 10**6, {'from': a[0]})
    usdt.mint(a[1], 10000000 * 10**6, {'from': a[0]})
    usdc.approve(bank, 2**256 - 1, {'from': a[1]})
    usdt.approve(bank, 2**256 - 1, {'from': a[1]})
    spell.getPair(usdc, usdt, {'from': a[0]})
    tx = bank.execute(
        0,
        spell,
        spell.addLiquidity.encode_input(
            usdt,  # token 0
            usdc,  # token 1
            [
                40000 * 10**6,  # 40000 USDT
                50000 * 10**6,  # 50000 USDC
                0,
                1000 * 10**6,  # 1000 USDT
                200 * 10**6,  # 200 USDC
                0,  # borrow LP tokens
                0,  # min USDT
                0,  # min USDC
            ],
        ),
        {'from': a[1]})

    position_id = tx.return_value
    print('tx gas used', tx.gas_used)
    print('bank collateral size', bank.getPositionInfo(position_id))
    print('bank collateral value', bank.getCollateralETHValue(position_id))
    print('bank borrow value', bank.getBorrowETHValue(position_id))

    print('bank usdt', bank.getBankInfo(usdt))
    print('bank usdc', bank.getBankInfo(usdc))

    print('usdt Px', simple_oracle.getETHPx(usdt))
    print('usdc Px', simple_oracle.getETHPx(usdc))

    print('lp Px', uniswap_lp_oracle.getETHPx(lp))
def main():
    admin = accounts[0]

    alice = accounts[1]
    bob = accounts[2]
    usdt = interface.IERC20Ex('0xdac17f958d2ee523a2206206994597c13d831ec7')
    weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')

    lp = interface.IERC20Ex('0x06da0fd433C1A5d7a4faa01111c044910A184553')
    crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157')

    sushi = interface.IERC20('0x6b3595068778dd592e39a122f4f5a5cf09c90fe2')

    # sushiswap router
    router = interface.IUniswapV2Router02(
        '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f')

    chef = accounts.at('0xc2edad668740f1aa35e4d8f227fb8e17dca888cd',
                       force=True)
    wchef = WMasterChef.deploy(chef, {'from': admin})

    werc20 = WERC20.deploy({'from': admin})

    simple_oracle = SimpleOracle.deploy({'from': admin})
    simple_oracle.setETHPx([usdt, weth], [2**112 // 700, 2**112])

    uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin})
    core_oracle = CoreOracle.deploy({'from': admin})
    oracle = ProxyOracle.deploy(core_oracle, {'from': admin})
    oracle.setWhitelistERC1155([werc20, wchef], True, {'from': admin})
    core_oracle.setRoute(
        [usdt, weth, lp],
        [simple_oracle, simple_oracle, uniswap_oracle],
        {'from': admin},
    )
    oracle.setOracles(
        [usdt, weth, lp],
        [
            [10000, 10000, 10000],
            [10000, 10000, 10000],
            [10000, 10000, 10000],
        ],
        {'from': admin},
    )

    homora = HomoraBank.deploy({'from': admin})
    homora.initialize(oracle, 1000, {'from': admin})  # 10% fee
    setup_bank_hack(homora)
    homora.addBank(usdt, crusdt, {'from': admin})

    # setup initial funds to alice
    mint_tokens(usdt, alice)
    mint_tokens(weth, alice)

    # check alice's funds
    print(f'Alice usdt balance {usdt.balanceOf(alice)}')
    print(f'Alice weth balance {weth.balanceOf(alice)}')

    # Steal some LP from the staking pool
    mint_tokens(lp, alice)
    mint_tokens(lp, bob)

    # set approval
    usdt.approve(homora, 2**256 - 1, {'from': alice})
    usdt.approve(crusdt, 2**256 - 1, {'from': alice})
    weth.approve(homora, 2**256 - 1, {'from': alice})
    lp.approve(homora, 2**256 - 1, {'from': alice})
    lp.approve(chef, 2**256 - 1, {'from': bob})

    sushiswap_spell = SushiswapSpellV1.deploy(homora, werc20, router, wchef,
                                              {'from': admin})
    # first time call to reduce gas
    sushiswap_spell.getPair(weth, usdt, {'from': admin})

    # whitelist spell in bank
    homora.setWhitelistSpells([sushiswap_spell], [True], {'from': admin})

    # whitelist lp in spell
    sushiswap_spell.setWhitelistLPTokens([lp], [True], {'from': admin})

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 1. add liquidity')

    prevABal = usdt.balanceOf(alice)
    prevBBal = weth.balanceOf(alice)
    prevLPBal = lp.balanceOf(alice)
    prevLPBal_bank = lp.balanceOf(homora)
    prevLPBal_wchef = lp.balanceOf(wchef)

    if interface.IUniswapV2Pair(lp).token0() == usdt:
        prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves()
    else:
        prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves()

    usdt_amt = 10 * 10**6
    weth_amt = 10**18
    lp_amt = 0
    borrow_usdt_amt = 0
    borrow_weth_amt = 0

    pid = 0

    tx = homora.execute(
        0,
        sushiswap_spell,
        sushiswap_spell.addLiquidityWMasterChef.encode_input(
            usdt,  # token 0
            weth,  # token 1
            [
                usdt_amt,  # supply USDT
                weth_amt,  # supply WETH
                lp_amt,  # supply LP
                borrow_usdt_amt,  # borrow USDT
                borrow_weth_amt,  # borrow WETH
                0,  # borrow LP tokens
                0,  # min USDT
                0
            ],  # min WETH
            pid,
        ),
        {'from': alice})

    curABal = usdt.balanceOf(alice)
    curBBal = weth.balanceOf(alice)
    curLPBal = lp.balanceOf(alice)
    curLPBal_bank = lp.balanceOf(homora)
    curLPBal_wchef = lp.balanceOf(wchef)

    if interface.IUniswapV2Pair(lp).token0() == usdt:
        curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves()
    else:
        curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves()

    print('spell lp balance', lp.balanceOf(sushiswap_spell))
    print('Alice delta A balance', curABal - prevABal)
    print('Alice delta B balance', curBBal - prevBBal)
    print('add liquidity gas', tx.gas_used)
    print('bank lp balance', curLPBal_bank)

    _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt)
    print('bank usdt totalDebt', totalDebt)
    print('bank usdt totalShare', totalShare)

    print('bank prev LP balance', prevLPBal_bank)
    print('bank cur LP balance', curLPBal_bank)

    print('wchef prev LP balance', prevLPBal_wchef)
    print('wchef cur LP balance', curLPBal_wchef)

    print('prev usdt res', prevARes)
    print('cur usdt res', curARes)

    print('prev weth res', prevBRes)
    print('cur weth res', curBRes)

    # alice
    assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt'
    assert almostEqual(curBBal - prevBBal, -weth_amt), 'incorrect WETH amt'
    assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt'

    # spell
    assert usdt.balanceOf(sushiswap_spell) == 0, 'non-zero spell USDT balance'
    assert weth.balanceOf(sushiswap_spell) == 0, 'non-zero spell WETH balance'
    assert lp.balanceOf(sushiswap_spell) == 0, 'non-zero spell LP balance'
    assert totalDebt == borrow_usdt_amt

    # check balance and pool reserves
    assert curABal - prevABal - borrow_usdt_amt == - \
        (curARes - prevARes), 'not all USDT tokens go to LP pool'
    assert almostEqual(
        curBBal - prevBBal - borrow_weth_amt,
        -(curBRes - prevBRes)), 'not all WETH tokens go to LP pool'

    # #####################################################################################

    print(
        '========================================================================='
    )
    print('Case 2. harvest first time')

    prevSushiBalance = sushi.balanceOf(alice)
    print('Alice SUSHI balance before harvest', prevSushiBalance)
    _, _, collId, collSize = homora.getPositionInfo(1)
    print('collSize', collSize)

    # staking directly
    prevSushi = sushi.balanceOf(bob)
    print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob))
    pid = 0
    tx = interface.IMasterChef(chef).deposit(pid, collSize, {'from': bob})

    chain.mine(100)

    tx = homora.execute(1, sushiswap_spell,
                        sushiswap_spell.harvestWMasterChef.encode_input(),
                        {'from': alice})

    print('tx gas used', tx.gas_used)

    curSushiBalance = sushi.balanceOf(alice)
    print('Alice SUSHI balance after harvest', curSushiBalance)
    receivedSushi = curSushiBalance - prevSushiBalance

    # check with staking directly
    pid = 0
    tx = interface.IMasterChef(chef).withdraw(pid, collSize, {'from': bob})
    receivedSushiFromStaking = sushi.balanceOf(bob) - prevSushi
    print('receivedSushiFromStaking', receivedSushiFromStaking)
    assert almostEqual(receivedSushi, receivedSushiFromStaking)

    # #####################################################################################

    print(
        '========================================================================='
    )
    print('Case 3. harvest second time')

    prevSushiBalance = sushi.balanceOf(alice)
    print('Alice SUSHI balance before harvest', prevSushiBalance)

    prevSushi = sushi.balanceOf(bob)
    print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob))

    # staking directly
    prevSushi = sushi.balanceOf(bob)
    print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob))
    pid = 0
    tx = interface.IMasterChef(chef).deposit(pid, collSize, {'from': bob})

    chain.mine(100)

    tx = homora.execute(1, sushiswap_spell,
                        sushiswap_spell.harvestWMasterChef.encode_input(),
                        {'from': alice})

    print('tx gas used', tx.gas_used)

    curSushiBalance = sushi.balanceOf(alice)
    print('Alice SUSHI balance after harvest', curSushiBalance)
    receivedSushi = curSushiBalance - prevSushiBalance

    # check with staking directly
    tx = interface.IMasterChef(chef).withdraw(pid, collSize, {'from': bob})
    receivedSushiFromStaking = sushi.balanceOf(bob) - prevSushi
    print('receivedSushiFromStaking', receivedSushiFromStaking)
    assert almostEqual(receivedSushi, receivedSushiFromStaking)
예제 #14
0
def main():
    badger = connect_badger("deploy-final.json")
    digg = badger.digg

    tx_data = {
        "to":
        "0x8D29bE29923b68abfDD21e541b9374737B49cdAD",
        "data":
        "0x8d80ff0a000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000009fe00b65cef03b9b89f99517643226d76e286ee999e7700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024694e80c300000000000000000000000000000000000000000000000000000000000000010019d099670a21bc0a8211a89b84cedf59abb4377f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064beabacc80000000000000000000000003472a5a71965499acd81997a54bba8d852c6e53d000000000000000000000000b65cef03b9b89f99517643226d76e286ee999e7700000000000000000000000000000000000000000000017c5d213c7a8f712f400019d099670a21bc0a8211a89b84cedf59abb4377f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064beabacc8000000000000000000000000798d1be841a82a273720ce31c822c61a67a601c3000000000000000000000000b65cef03b9b89f99517643226d76e286ee999e7700000000000000000000000000000000000000000000000000000001b69e2595003472a5a71965499acd81997a54bba8d852c6e53d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f000000000000000000000000000000000000000000000068bce40cf18444c28000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001244a25d94a000000000000000000000000000000000000000000000002b01ee2a20a8a2a90000000000000000000000000000000000000000000000068bce40cf18444c28000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000b65cef03b9b89f99517643226d76e286ee999e7700000000000000000000000000000000000000000000000000000000604be4d100000000000000000000000000000000000000000000000000000000000000030000000000000000000000003472a5a71965499acd81997a54bba8d852c6e53d0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2003472a5a71965499acd81997a54bba8d852c6e53d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b300000000000000000000000019d97d8fa813ee2f51ad4b4e04ea08baf4dffc28000000000000000000000000000000000000000000000113a03d2f890b2c6cc00019d97d8fa813ee2f51ad4b4e04ea08baf4dffc2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024b6b55f25000000000000000000000000000000000000000000000113a03d2f890b2c6cc000798d1be841a82a273720ce31c822c61a67a601c300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000007e7e112a68d8d2e221e11047a72ffc1065c38e1a00000000000000000000000000000000000000000000000000000001b69e2595007e7e112a68d8d2e221e11047a72ffc1065c38e1a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000246c361865000000000000000000000000b65cef03b9b89f99517643226d76e286ee999e77007e7e112a68d8d2e221e11047a72ffc1065c38e1a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024b6b55f2500000000000000000000000000000000000000000000000000000001b69e25950019d97d8fa813ee2f51ad4b4e04ea08baf4dffc2800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f0000000000000000000000000000000000000000000000e203f5dc3c00323a8000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f00000000000000000000000000000000000000000000000777723ca5ab7fcb9000000000000000000000000000000000000000000000000000000000000000c4f305d71900000000000000000000000019d97d8fa813ee2f51ad4b4e04ea08baf4dffc280000000000000000000000000000000000000000000000e203f5dc3c00323a800000000000000000000000000000000000000000000000e203f5dc3c00323a8000000000000000000000000000000000000000000000000777723ca5ab7fcb90000000000000000000000000b65cef03b9b89f99517643226d76e286ee999e7700000000000000000000000000000000000000000000000000000000604be4db007e7e112a68d8d2e221e11047a72ffc1065c38e1a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044095ea7b3000000000000000000000000d9e1ce17f2641f24ae83637ab66a2cca9c378b9f00000000000000000000000000000000000000000000000048ada1feff60844a00d9e1ce17f2641f24ae83637ab66a2cca9c378b9f00000000000000000000000000000000000000000000000777723ca5ab7fcb9000000000000000000000000000000000000000000000000000000000000000c4f305d7190000000000000000000000007e7e112a68d8d2e221e11047a72ffc1065c38e1a00000000000000000000000000000000000000000000000048ada1feff60844a00000000000000000000000000000000000000000000000048ada1feff60844a00000000000000000000000000000000000000000000000777723ca5ab7fcb90000000000000000000000000b65cef03b9b89f99517643226d76e286ee999e7700000000000000000000000000000000000000000000000000000000604be4dd0000",
    }

    sushiBbadgerPair = "0x0a54d4b378c8dbfc7bc93be50c85debafdb87439"
    sushiBDiggPair = "0xf9440fedc72a0b8030861dcdac39a75b544e7a3c"

    sushiswap = SushiswapSystem()

    pair = interface.IUniswapV2Pair(sushiBbadgerPair)
    console.print({
        "getReserves": pair.getReserves(),
        "token0": pair.token0(),
        "token1": pair.token1(),
        "price0CumulativeLast": pair.price0CumulativeLast(),
        "price1CumulativeLast": pair.price1CumulativeLast(),
    })

    pair = interface.IUniswapV2Pair(sushiBDiggPair)
    console.print({
        "getReserves": pair.getReserves(),
        "token0": pair.token0(),
        "token1": pair.token1(),
        "price0CumulativeLast": pair.price0CumulativeLast(),
        "price1CumulativeLast": pair.price1CumulativeLast(),
    })

    usd_amount = 500000

    weth = interface.IERC20(registry.tokens.weth)

    console.log("..Before Safe")

    safe = ApeSafe(badger.devMultisig.address)
    ops_safe = ApeSafe(badger.opsMultisig.address)

    console.log("..After Safe Setup")

    # multi = GnosisSafe(badger.devMultisig)

    # multi.execute(
    #     MultisigTxMetadata(description="Run TX"),
    #     {"to": tx_data["to"], "data": tx_data["data"], "operation": 1},
    # )

    after = get_token_balances(
        [
            badger.token,
            digg.token,
            interface.IERC20(registry.tokens.usdc),
            interface.IERC20(sushiBbadgerPair),
            interface.IERC20(sushiBDiggPair),
        ],
        [badger.devMultisig],
    )
    after.print()

    pair = interface.IUniswapV2Pair(sushiBbadgerPair)
    console.print({
        "getReserves": pair.getReserves(),
        "token0": pair.token0(),
        "token1": pair.token1(),
        "price0CumulativeLast": pair.price0CumulativeLast(),
        "price1CumulativeLast": pair.price1CumulativeLast(),
    })

    pair = interface.IUniswapV2Pair(sushiBDiggPair)
    console.print({
        "getReserves": pair.getReserves(),
        "token0": pair.token0(),
        "token1": pair.token1(),
        "price0CumulativeLast": pair.price0CumulativeLast(),
        "price1CumulativeLast": pair.price1CumulativeLast(),
    })

    router = safe.contract(sushiswap.router.address)
    rewardsEscrow = safe.contract(badger.rewardsEscrow.address)
    badgerToken = safe.contract(badger.token.address)
    diggToken = safe.contract(digg.token.address)

    digg_to_lp = Wei("8.4 gwei")

    usd_per_side = 250000

    # TODO: Use banteg's nice value calc script.

    badger_usd = fetch_usd_price(badger.token.address)
    digg_usd = fetch_usd_price(digg.token.address)
    eth_usd = fetch_usd_price_eth()

    console.log(eth_usd)

    badger_to_swap = Wei(str(95000 / badger_usd) + " ether")
    badger_to_lp = Wei(str(usd_per_side / badger_usd) + " ether")
    digg_to_lp = Wei(str(usd_per_side / digg_usd) + " gwei")
    eth_out = Wei(str(usd_per_side / eth_usd) + " ether")

    console.print({
        "badger_to_swap": badger_to_swap,
        "badger_to_lp": badger_to_lp,
        "digg_to_lp": digg_to_lp,
        "eth_out": eth_out,
        "badger_usd": badger_usd,
        "digg_usd": digg_usd,
        "eth_usd": eth_usd,
    })

    badger_to_get_from_escrow = badger_to_swap + badger_to_lp

    # Get 250k worth of bBadger + $90k Amount to swap to ETH
    rewardsEscrow.transfer(badger.token, badger.devMultisig,
                           badger_to_get_from_escrow)

    # Get 250k worth of bDigg
    rewardsEscrow.transfer(digg.token, badger.devMultisig, digg_to_lp)

    # Sell badger for 90k USD
    exact_eth = Wei(str(90000 / eth_usd) + " ether")

    console.print("exact_eth", exact_eth)

    assert badger.token.balanceOf(badger.devMultisig) >= badger_to_swap

    print("a")

    badgerToken.approve(sushiswap.router.address, badger_to_swap)

    print("b")

    assert (badger.token.allowance(badger.devMultisig,
                                   sushiswap.router.address) == badger_to_swap)

    router.swapTokensForExactETH(
        exact_eth,
        int(badger_to_swap * 1.02),
        [badger.token, registry.tokens.wbtc, registry.tokens.weth],
        badger.devMultisig,
        chain.time() + 200000,
    )

    print("d")

    after = get_token_balances([badger.token, digg.token],
                               [badger.devMultisig])
    after.print()

    # Deposit Badger for bBadger
    # Deposit DIGG for bDigg

    bBadger_address = badger.getSett("native.badger").address
    bDigg_address = badger.getSett("native.digg").address

    console.print(bBadger_address, bDigg_address)

    abi = Sett.abi

    bBadger = safe.contract_from_abi(bBadger_address, "Sett", abi)
    bDigg = safe.contract_from_abi(bDigg_address, "Sett", abi)

    badgerToken.approve(bBadger.address, badger_to_lp)

    print(bBadger)
    console.print(bBadger)
    bBadger.deposit(badger_to_lp)

    diggToken.approve(bDigg.address, digg_to_lp)
    bDigg.approveContractAccess(badger.devMultisig)

    tx = bDigg.deposit(digg_to_lp)
    console.print(tx.events)

    # tx = bDigg.withdraw(bDigg.balanceOf(badger.devMultisig))
    # console.print(tx.events)

    after = get_token_balances(
        [
            badger.token,
            digg.token,
            interface.IERC20(bDigg.address),
            interface.IERC20(bBadger.address),
        ],
        [badger.devMultisig],
    )
    after.print()

    # Seed pools: 250k worth of bToken, 250k worth of ETH

    tokenA = bBadger

    amountA = (badger_to_lp * 10**18) / bBadger.getPricePerFullShare()
    amountB = eth_out

    # TODO: Set the amount of ETH to what is required.

    after = get_token_balances(
        [
            badger.token,
            digg.token,
            interface.IERC20(bDigg.address),
            interface.IERC20(bBadger.address),
            interface.IERC20(sushiBbadgerPair),
            interface.IERC20(sushiBDiggPair),
        ],
        [badger.devMultisig],
    )
    after.print()

    safe_tx = safe.multisend_from_receipts()
    safe.preview(safe_tx)
    data = safe.print_transaction(safe_tx)
    safe.post_transaction(safe_tx)
    """
    How do we get exactly 250k worth of each asset?
    Calculate how much you need to get 250k

    ===== Normal Assets =====
    250k / USD price of asset 

    ===== For bTokens =====
    How much original token to get: 250k / USD price of underlying asset 
    bToken will handle itself
    """

    tokenA.approve(sushiswap.router, amountA)
    console.print(
        "addLiquidityETH",
        {
            "tokenA": tokenA.address,
            "amountA": amountA,
            "amountB": amountB,
            "badger ppfs": bBadger.getPricePerFullShare(),
            "original supply": Wei("4000 gwei"),
            "current supply": digg.token.totalSupply(),
        },
    )

    router.addLiquidityETH(
        tokenA.address,
        amountA,
        int(amountA * 0.95),
        int(eth_out * 0.95),
        badger.devMultisig,
        chain.time() + 200000,
        {"value": eth_out},
    )

    tokenA = bDigg

    amountA = ((digg_to_lp * 10**9) * 10**18) / bDigg.getPricePerFullShare()
    amountA = amountA * (Wei("4000 gwei")) / digg.token.totalSupply()

    print("expected bDigg", amountA)

    amountA = bDigg.balanceOf(badger.devMultisig)

    print("actual bDigg", amountA)

    tokenA.approve(sushiswap.router, amountA)
    console.print(
        "addLiquidityETH",
        {
            "tokenA": tokenA.address,
            "amountA": amountA,
            "amountB": amountB,
            "digg ppfs": bDigg.getPricePerFullShare(),
        },
    )

    router.addLiquidityETH(
        tokenA.address,
        amountA,
        int(amountA * 0.95),
        int(eth_out * 0.95),
        badger.devMultisig,
        chain.time() + 200000,
        {"value": eth_out},
    )

    after = get_token_balances(
        [
            badger.token,
            digg.token,
            interface.IERC20(bDigg.address),
            interface.IERC20(bBadger.address),
            interface.IERC20(sushiBbadgerPair),
            interface.IERC20(sushiBDiggPair),
        ],
        [badger.devMultisig],
    )
    after.print()

    safe_tx = safe.multisend_from_receipts()
    safe.preview(safe_tx)
    data = safe.print_transaction(safe_tx)
    safe.post_transaction(safe_tx)

    pair = interface.IUniswapV2Pair(sushiBbadgerPair)
    console.print({
        "getReserves": pair.getReserves(),
        "token0": pair.token0(),
        "token1": pair.token1(),
        "price0CumulativeLast": pair.price0CumulativeLast(),
        "price1CumulativeLast": pair.price1CumulativeLast(),
    })

    pair = interface.IUniswapV2Pair(sushiBDiggPair)
    console.print({
        "getReserves": pair.getReserves(),
        "token0": pair.token0(),
        "token1": pair.token1(),
        "price0CumulativeLast": pair.price0CumulativeLast(),
        "price1CumulativeLast": pair.price1CumulativeLast(),
    })

    safe.post_transaction(safe_tx)

    pair = interface.IUniswapV2Pair(sushiBbadgerPair)
    console.print({
        "getReserves": pair.getReserves(),
        "token0": pair.token0(),
        "token1": pair.token1(),
        "price0CumulativeLast": pair.price0CumulativeLast(),
        "price1CumulativeLast": pair.price1CumulativeLast(),
    })

    pair = interface.IUniswapV2Pair(sushiBDiggPair)
    console.print({
        "getReserves": pair.getReserves(),
        "token0": pair.token0(),
        "token1": pair.token1(),
        "price0CumulativeLast": pair.price0CumulativeLast(),
        "price1CumulativeLast": pair.price1CumulativeLast(),
    })
예제 #15
0
from brownie import interface
from functools import lru_cache

TRADERJOE_ROUTER = "0x60aE616a2155Ee3d9A68541Ba4544862310933d4"
PANGOLIN_ROUTER = "0xE54Ca86531e17Ef3616d22Ca28b0D458b6C89106"

ETH = interface.IERC20("0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB")
BTC = interface.IERC20("0x50b7545627a5162f82a992c33b87adc75187b218")
USDC = interface.IERC20("0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664")
USDT = interface.IERC20("0xc7198437980c041c805a1edcba50c1ce5db95118")
DAI = interface.IERC20("0xd586e7f844cea2f87f50152665bcbc2c279d8d70")
TIME = interface.IERC20("0xb54f16fb19478766a268f172c9480f8da1a7c9c3")
AVAX = interface.IERC20("0xb31f66aa3c1e785363f0875a1b74e27b85fd66c7")
crvUSDBTCETH = interface.CurveLPToken(
    "0x1daB6560494B04473A0BE3E7D83CF3Fdf3a51828")

tVaultUSDC = interface.yEarnVault("0x52cE2c4Bd817AdB765c476901cc09621DCACEc62")
tVaultDAI = interface.yEarnVault("0xdC808bADe323205f2c794198C1adDa8aEF215E29")
tVaultAVAX = interface.yEarnVault("0x83EA27549acc3CB64c3fCda8379d1eA229a02712")
tVault3crypto_V2 = interface.yEarnVault(
    "0x71712Ad47b2cBC4Fb2e814dBaC44A31749A5195e")


@lru_cache()
def TOKEN_PRICES():
    return {
        "TraderJoe": (TRADERJOE_ROUTER, [
            ("WETH.e", ETH),
            ("WBTC.e", BTC),
            ("USDC.e", USDC),
            ("USDT.e", USDT),
예제 #16
0
def main():
    admin = accounts[0]

    alice = accounts[1]
    bob = accounts[2]
    dfd = interface.IERC20Ex('0x20c36f062a31865bED8a5B1e512D9a1A20AA333A')
    dusd = interface.IERC20Ex('0x5BC25f649fc4e26069dDF4cF4010F9f706c23831')
    weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')
    dai = interface.IERC20Ex('0x6B175474E89094C44Da98b954EedeAC495271d0F')

    lp = interface.IERC20Ex('0xd8e9690eff99e21a2de25e0b148ffaf47f47c972')

    # pool is lp for balancer
    pool = interface.IBalancerPool(
        '0xd8e9690eff99e21a2de25e0b148ffaf47f47c972')
    lp_dai = interface.IERC20Ex('0x8b6e6e7b5b3801fed2cafd4b22b8a16c2f2db21a')
    pool_dai = interface.IBalancerPool(
        '0x8b6e6e7b5b3801fed2cafd4b22b8a16c2f2db21a')

    crdfd = MockCErc20.deploy(dfd, {'from': admin})
    crdusd = MockCErc20.deploy(dusd, {'from': admin})
    crdai = MockCErc20.deploy(dai, {'from': admin})
    crweth = MockCErc20.deploy(weth, {'from': admin})

    werc20 = WERC20.deploy({'from': admin})

    staking = accounts.at('0xf068236ecad5fabb9883bbb26a6445d6c7c9a924',
                          force=True)

    wstaking = WStakingRewards.deploy(staking, lp, dfd, {'from': admin})

    simple_oracle = SimpleOracle.deploy({'from': admin})
    simple_oracle.setETHPx([dfd, dusd],
                           [2**112 // 2 // 700, 2**112 * 2 // 700])

    balancer_oracle = BalancerPairOracle.deploy(simple_oracle, {'from': alice})

    core_oracle = CoreOracle.deploy({'from': admin})
    oracle = ProxyOracle.deploy(core_oracle, {'from': admin})
    oracle.setWhitelistERC1155([werc20, wstaking], True, {'from': admin})
    core_oracle.setRoute(
        [dfd, dusd, lp],
        [simple_oracle, simple_oracle, balancer_oracle],
        {'from': admin},
    )
    oracle.setOracles(
        [dfd, dusd, lp],
        [
            [10000, 10000, 10000],
            [10000, 10000, 10000],
            [10000, 10000, 10000],
        ],
        {'from': admin},
    )

    homora = HomoraBank.deploy({'from': admin})
    homora.initialize(oracle, 1000, {'from': admin})  # 10% fee
    setup_bank_hack(homora)
    homora.addBank(dfd, crdfd, {'from': admin})
    homora.addBank(dusd, crdusd, {'from': admin})

    # setup initial funds to alice
    mint_tokens(dfd, alice)
    mint_tokens(dusd, alice)

    mint_tokens(weth, alice)
    mint_tokens(dai, alice)

    mint_tokens(dfd, crdfd)

    # check alice's funds
    print(f'Alice dusd balance {dusd.balanceOf(alice)}')
    print(f'Alice dfd balance {dfd.balanceOf(alice)}')

    # Steal some LP from the staking pool
    mint_tokens(lp, alice)
    mint_tokens(lp, bob)

    # set approval
    dfd.approve(homora, 2**256 - 1, {'from': alice})
    dfd.approve(crdfd, 2**256 - 1, {'from': alice})
    dusd.approve(homora, 2**256 - 1, {'from': alice})
    dusd.approve(crdusd, 2**256 - 1, {'from': alice})
    dai.approve(homora, 2**256 - 1, {'from': alice})
    dai.approve(crdai, 2**256 - 1, {'from': alice})
    weth.approve(homora, 2**256 - 1, {'from': alice})
    weth.approve(crweth, 2**256 - 1, {'from': alice})

    lp.approve(homora, 2**256 - 1, {'from': alice})
    lp.approve(staking, 2**256 - 1, {'from': bob})

    balancer_spell = BalancerSpellV1.deploy(
        homora, werc20, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
        {'from': admin})
    # first time call to reduce gas
    balancer_spell.getPair(lp, {'from': admin})

    # whitelist spell in bank
    homora.setWhitelistSpells([balancer_spell], [True], {'from': admin})

    # whitelist token in bank
    homora.setWhitelistTokens([dfd], [True], {'from': admin})

    # whitelist lp in spell
    balancer_spell.setWhitelistLPTokens([lp, lp_dai], [True, True],
                                        {'from': admin})

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 1.')

    prevABal = dfd.balanceOf(alice)
    prevBBal = dusd.balanceOf(alice)
    prevLPBal = lp.balanceOf(alice)
    prevLPBal_bank = lp.balanceOf(homora)
    prevLPBal_staking = lp.balanceOf(staking)

    prevARes = interface.IBalancerPool(lp).getBalance(dfd)
    prevBRes = interface.IBalancerPool(lp).getBalance(dusd)

    dfd_amt = 100 * 10**18
    dusd_amt = 10**18
    lp_amt = 0
    borrow_dfd_amt = 10**18
    borrow_dusd_amt = 0

    # calculate slippage control
    total_dfd_amt = dfd_amt + borrow_dfd_amt
    total_dusd_amt = dusd_amt + borrow_dusd_amt
    dfd_weight = 0.58
    dusd_weight = 0.42

    ratio = (((prevARes + total_dfd_amt) / prevARes) ** dfd_weight) * \
        (((prevBRes + total_dusd_amt) / prevBRes) ** dusd_weight) - 1
    lp_desired = lp_amt + int(
        interface.IERC20(lp).totalSupply() * ratio * 0.995)
    print('lp desired', lp_desired)

    tx = homora.execute(
        0,
        balancer_spell,
        balancer_spell.addLiquidityWStakingRewards.encode_input(
            lp,  # lp token
            [
                dfd_amt,  # supply DFD
                dusd_amt,  # supply DUSD
                lp_amt,  # supply LP
                borrow_dfd_amt,  # borrow DFD
                borrow_dusd_amt,  # borrow DUSD
                0,  # borrow LP tokens
                lp_desired
            ],  # LP desired
            wstaking),
        {'from': alice})

    curABal = dfd.balanceOf(alice)
    curBBal = dusd.balanceOf(alice)
    curLPBal = lp.balanceOf(alice)
    curLPBal_bank = lp.balanceOf(homora)
    curLPBal_staking = lp.balanceOf(staking)

    curARes = interface.IBalancerPool(lp).getBalance(dfd)
    curBRes = interface.IBalancerPool(lp).getBalance(dusd)

    print('spell lp balance', lp.balanceOf(balancer_spell))
    print('Alice delta A balance', curABal - prevABal)
    print('Alice delta B balance', curBBal - prevBBal)
    print('add liquidity gas', tx.gas_used)
    print('bank lp balance', curLPBal_bank)

    _, _, _, dfdDebt, dfdShare = homora.getBankInfo(dfd)
    print('bank dfd dfdDebt', dfdDebt)
    print('bank dfd dfdShare', dfdShare)

    print('bank prev LP balance', prevLPBal_bank)
    print('bank cur LP balance', curLPBal_bank)

    print('staking prev LP balance', prevLPBal_staking)
    print('staking cur LP balance', curLPBal_staking)

    print('prev dfd res', prevARes)
    print('cur dfd res', curARes)

    print('prev dusd res', prevBRes)
    print('cur dusd res', curBRes)

    # alice
    assert almostEqual(curABal - prevABal, -dfd_amt), 'incorrect DFD amt'
    assert almostEqual(curBBal - prevBBal, -dusd_amt), 'incorrect DUSD amt'
    assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt'

    # spell
    assert dfd.balanceOf(balancer_spell) == 0, 'non-zero spell DFD balance'
    assert dusd.balanceOf(balancer_spell) == 0, 'non-zero spell DUSD balance'
    assert lp.balanceOf(balancer_spell) == 0, 'non-zero spell LP balance'
    assert dfdDebt == borrow_dfd_amt

    # check balance and pool reserves
    assert almostEqual(
        curABal - prevABal - borrow_dfd_amt,
        -(curARes - prevARes)), 'not all DFD tokens go to LP pool'
    assert almostEqual(
        curBBal - prevBBal - borrow_dusd_amt,
        -(curBRes - prevBRes)), 'not all DUSD tokens go to LP pool'

    _, _, collId, collSize = homora.getPositionInfo(1)
    print('collSize', collSize)

    # staking directly
    prevDfd = dfd.balanceOf(bob)
    print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob))
    tx = interface.IStakingRewards(staking).stake(collSize, {'from': bob})

    chain.sleep(20000)

    prevAliceDfdBalance = dfd.balanceOf(alice)
    print('Alice dfd balance', prevAliceDfdBalance)

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 2. add liquidity (failed tx desired)')

    weth_amt = 100 * 10**18
    dai_amt = 10**18
    lp_amt = 0
    borrow_weth_amt = 0
    borrow_dai_amt = 0

    # calculate slippage control
    total_weth_amt = weth_amt + borrow_weth_amt
    total_dai_amt = dai_amt + borrow_dai_amt
    dfd_weight = 0.8
    dusd_weight = 0.2

    ratio = (((prevARes + total_weth_amt) / prevARes) ** dfd_weight) * \
        (((prevBRes + total_dai_amt) / prevBRes) ** dusd_weight) - 1
    lp_desired = lp_amt + int(
        interface.IERC20(lp).totalSupply() * ratio * 0.995)
    lp_desired = 0
    print('lp desired', lp_desired)

    try:
        tx = homora.execute(
            1,
            balancer_spell,
            balancer_spell.addLiquidityWStakingRewards.encode_input(
                lp_dai,  # lp token
                [
                    weth_amt,  # supply DFD
                    dai_amt,  # supply DUSD
                    lp_amt,  # supply LP
                    borrow_weth_amt,  # borrow DFD
                    borrow_dai_amt,  # borrow DUSD
                    0,  # borrow LP tokens
                    lp_desired
                ],  # LP desired
                wstaking),
            {'from': alice})
        assert False, 'tx should fail'
    except VirtualMachineError:
        pass

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 3. remove liquidity (failed tx desired)')

    lp_take_amt = 2**256 - 1  # max
    lp_want = 0
    weth_repay = 2**256 - 1  # max
    dai_repay = 2**256 - 1  # max

    real_weth_repay = homora.borrowBalanceStored(1, dfd)
    _, _, _, real_lp_take_amt = homora.getPositionInfo(1)

    expected_withdraw_dfd = collSize * prevARes // interface.IBalancerPool(
        lp).totalSupply()
    print('expected withdraw DFD', expected_withdraw_dfd)

    try:
        tx = homora.execute(
            1,
            balancer_spell,
            balancer_spell.removeLiquidityWStakingRewards.encode_input(
                lp_dai,  # LP token
                [
                    lp_take_amt,  # take out LP tokens
                    lp_want,  # withdraw LP tokens to wallet
                    weth_repay,  # repay DFD
                    dai_repay,  # repay DUSD
                    0,  # repay LP
                    0,  # min DFD
                    0
                ],  # min DUSD
                wstaking),
            {'from': alice})
        assert False, 'tx should fail'
    except VirtualMachineError:
        pass

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 4. remove liquidity')

    # remove liquidity from the same position
    prevABal = dfd.balanceOf(alice)
    prevBBal = dusd.balanceOf(alice)
    prevETHBal = alice.balance()
    prevLPBal = lp.balanceOf(alice)
    prevLPBal_bank = lp.balanceOf(homora)
    prevLPBal_staking = lp.balanceOf(staking)
    prevETHBal = alice.balance()
    prevCrdfdBal = lp.balanceOf(crdfd)

    prevARes = interface.IBalancerPool(lp).getBalance(dfd)
    prevBRes = interface.IBalancerPool(lp).getBalance(dusd)

    lp_take_amt = 2**256 - 1  # max
    lp_want = 0
    dfd_repay = 2**256 - 1  # max
    dusd_repay = 0

    real_dfd_repay = homora.borrowBalanceStored(1, dfd)
    _, _, _, real_lp_take_amt = homora.getPositionInfo(1)

    expected_withdraw_dfd = collSize * prevARes // interface.IBalancerPool(
        lp).totalSupply()
    print('expected withdraw DFD', expected_withdraw_dfd)

    tx = homora.execute(
        1,
        balancer_spell,
        balancer_spell.removeLiquidityWStakingRewards.encode_input(
            lp,  # LP token
            [
                lp_take_amt,  # take out LP tokens
                lp_want,  # withdraw LP tokens to wallet
                dfd_repay,  # repay DFD
                dusd_repay,  # repay DUSD
                0,  # repay LP
                0,  # min DFD
                0
            ],  # min DUSD
            wstaking),
        {'from': alice})

    curABal = dfd.balanceOf(alice)
    curBBal = dusd.balanceOf(alice)
    curETHBal = alice.balance()
    curLPBal = lp.balanceOf(alice)
    curLPBal_bank = lp.balanceOf(homora)
    curLPBal_staking = lp.balanceOf(staking)
    curETHBal = alice.balance()
    curCrdfdBal = lp.balanceOf(crdfd)

    curARes = interface.IBalancerPool(lp).getBalance(dfd)
    curBRes = interface.IBalancerPool(lp).getBalance(dusd)

    print('spell lp balance', lp.balanceOf(balancer_spell))
    print('spell dfd balance', dfd.balanceOf(balancer_spell))
    print('spell dusd balance', dusd.balanceOf(balancer_spell))
    print('Alice delta A balance', curABal - prevABal)
    print('Alice delta B balance', curBBal - prevBBal)
    print('Alice delta ETH balance', curETHBal - prevETHBal)
    print('Alice delta LP balance', curLPBal - prevLPBal)
    print('remove liquidity gas', tx.gas_used)
    print('bank delta lp balance', curLPBal_bank - prevLPBal_bank)
    print('bank total lp balance', curLPBal_bank)

    _, _, _, dfdDebt, dfdShare = homora.getBankInfo(dfd)
    print('bank dfd totalDebt', dfdDebt)
    print('bank dfd totalShare', dfdShare)

    print('LP want', lp_want)

    print('bank delta LP amount', curLPBal_bank - prevLPBal_bank)
    print('LP take amount', lp_take_amt)

    print('prev staking LP balance', prevLPBal_staking)
    print('cur staking LP balance', curLPBal_staking)

    print('real dfd repay', real_dfd_repay)

    print('curCrdfdBal', curCrdfdBal)
    print('delta crdfd', curCrdfdBal - prevCrdfdBal)

    print('A res delta', prevARes - curARes)
    print('B res delta', prevBRes - curBRes)

    # alice
    assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt'

    # staking
    assert almostEqual(curLPBal_staking - prevLPBal_staking,
                       -real_lp_take_amt), 'incorrect staking LP amt'

    # spell
    assert dfd.balanceOf(balancer_spell) == 0, 'non-zero spell DFD balance'
    assert dusd.balanceOf(balancer_spell) == 0, 'non-zero spell DUSD balance'
    assert lp.balanceOf(balancer_spell) == 0, 'non-zero spell LP balance'

    # check balance and pool reserves
    assert almostEqual(curABal - prevABal + real_dfd_repay,
                       -(curARes - prevARes)), 'inconsistent DFD from withdraw'
    assert almostEqual(
        curBBal - prevBBal + dusd_repay,
        -(curBRes - prevBRes)), 'inconsistent DUSD from withdraw'

    curAliceDfdBalance = dfd.balanceOf(alice)
    print('Alice dfd balance', curAliceDfdBalance)
    receivedDfd = curAliceDfdBalance - prevAliceDfdBalance + real_dfd_repay - (
        prevARes - curARes)
    print('received dfd', receivedDfd)

    # check with staking directly
    tx = interface.IStakingRewards(staking).getReward({'from': bob})
    receivedDfdFromStaking = dfd.balanceOf(bob) - prevDfd
    print('receivedDfdFromStaking', receivedDfdFromStaking)
    assert almostEqual(receivedDfd, receivedDfdFromStaking)

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 5. add & remove all LP')

    lp_amt = 10 * 10**18

    prevLPBal = lp.balanceOf(alice)

    tx = homora.execute(
        0,
        balancer_spell,
        balancer_spell.addLiquidityWStakingRewards.encode_input(
            lp,  # lp token
            [
                0,  # supply DAI
                0,  # supply WETH
                lp_amt,  # supply LP
                0,  # borrow DAI
                0,  # borrow WETH
                0,  # borrow LP tokens
                0
            ],  # LP desired
            wstaking),
        {'from': alice})

    tx = homora.execute(
        2,
        balancer_spell,
        balancer_spell.removeLiquidityWStakingRewards.encode_input(
            lp,  # LP token
            [
                2**256 - 1,  # take out LP tokens
                lp_amt,  # withdraw LP tokens to wallet
                0,  # repay DAI
                0,  # repay WETH
                0,  # repay LP
                0,  # min DAI
                0
            ],  # min WETH
            wstaking),
        {'from': alice})

    curLPBal = lp.balanceOf(alice)

    assert prevLPBal == curLPBal, 'incorrect LP Balance'

    return tx
예제 #17
0
PANCAKE_SLME_BUSD = interface.UniswapPair(
    "0xfbd0b87f4132e5a14aa85c21476738c0c13fd06c")
PANCAKE_SLME_BNB = interface.UniswapPair(
    "0xcb645714520080ef4e65de3254d61356262f0818")

PANCAKESWAP_ROUTER = "0x05ff2b0db69458a0750badebc4f9e13add608c7f"

ICECREAM_USDT_BUSD = interface.UniswapPair(
    "0x57Bcf3Bb68f6E8DF00b9e6AD6aF8cE58fe7FC350")
ICECREAM_BUSD_BNB = interface.UniswapPair(
    "0x875DfffcBd97f6C7038E97A4959B0590C8714e1c")
ICECREAM_ETH_BNB = interface.UniswapPair(
    "0x68c277E93D9EB923E2EA9bfFC643307E731C044f")
ICECREAMSWAP_ROUTER = "0x6728f3c8241C44Cc741C9553Ff7824ba9E932A4A"

BSC_DAI = interface.IERC20("0x1af3f329e8be154074d8769d1ffa4ee058b1dbc3")
BSC_BUSD = interface.IERC20("0xe9e7cea3dedca5984780bafc599bd69add087d56")
BSC_USDT = interface.IERC20("0x55d398326f99059ff775485246999027b3197955")
BSC_USDC = interface.IERC20("0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d")
BSC_VAI = interface.IERC20("0x4bd17003473389a42daf6a0a729f6fdb328bbbd7")
BSC_ETH = interface.IERC20("0x2170ed0880ac9a755fd29b2688956bd959f933f8")
BSC_BTC = interface.IERC20("0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c")
BSC_BNB = interface.IERC20("0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c")

TOKEN_PRICES = {
    "PancakeSwap": (PANCAKESWAP_ROUTER, [
        ("ETH", BSC_ETH),
        ("BTC", BSC_BTC),
        ("BNB", BSC_BNB),
        ("DAI_BUSD", PANCAKE_DAI_BUSD),
        ("USDT_BUSD", PANCAKE_USDT_BUSD),
예제 #18
0
def USDT() -> interface.IERC20:
    return interface.IERC20(
        os.environ.get('USDT_ADDRESS',
                       "0xdac17f958d2ee523a2206206994597c13d831ec7"))
예제 #19
0
from brownie import interface
from functools import lru_cache

SUSHISWAP_ROUTER = "0x1b02dA8Cb0d097eB8D57A175b88c7D8b47997506"

ETH = interface.IERC20("0x82af49447d8a07e3bd95bd0d56f35241523fbab1")
BTC = interface.IERC20("0x2f2a2543b76a4166549f7aab2e75bef0aefc5b0f")
USDC = interface.IERC20("0xff970a61a04b1ca14834a43f5de4533ebddb5cc8")
USDT = interface.IERC20("0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9")
MIM = interface.IERC20("0xfea7a6a0b346362bf88a9e4a88416b77a57d6c2a")


@lru_cache()
def TOKEN_PRICES():
    SUSHI_USDC_ETH = interface.UniswapPair(
        "0x905dfcd5649217c42684f23958568e533c711aa3")
    SUSHI_USDT_ETH = interface.UniswapPair(
        "0xcb0e5bfa72bbb4d16ab5aa0c60601c438f04b4ad")
    SUSHI_MIM_ETH = interface.UniswapPair(
        "0xb6dd51d5425861c808fd60827ab6cfbffe604959")

    return {
        "Sushi-Arbitrum": (SUSHISWAP_ROUTER, [
            ("ETH", ETH),
            ("BTC", BTC),
            ("MIM", MIM),
            ("USDC_ETH", SUSHI_USDC_ETH),
            ("USDT_ETH", SUSHI_USDT_ETH),
            ("MIM_ETH", SUSHI_MIM_ETH),
        ]),
    }
예제 #20
0
def USDC() -> interface.IERC20:
    return interface.IERC20(
        os.environ.get('USDC_ADDRESS',
                       "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"))
예제 #21
0
def test_bridge_basic():
    renbtc = registry.tokens.renbtc
    wbtc = registry.tokens.wbtc

    badger = connect_badger(badger_config.prod_json)
    bridge = connect_bridge(badger, badger_config.prod_json)
    swap = connect_swap(badger_config.prod_json)
    _upgrade_bridge(badger, bridge)
    _upgrade_swap(badger, swap)
    _deploy_bridge_mocks(badger, bridge)

    router = swap.router
    # 3% slippage
    slippage = 0.03
    amount = 1 * 10**8
    # Test estimating slippage from a random account for wbtc <-> renbtc swaps.
    _assert_swap_slippage(
        router,
        renbtc,
        wbtc,
        amount,
        slippage,
    )
    _assert_swap_slippage(
        router,
        wbtc,
        renbtc,
        amount,
        slippage,
    )

    for accIdx in range(10, 12):
        account = accounts[accIdx]
        for i in range(0, 2):
            balanceBefore = interface.IERC20(wbtc).balanceOf(account)
            # Test mints
            bridge.adapter.mint(
                wbtc,
                slippage * 10**4,
                account.address,
                AddressZero,  # No vault.
                amount,
                # Darknode args hash/sig optional since gateway is mocked.
                "",
                "",
                {"from": account},
            )
            assert interface.IERC20(wbtc).balanceOf(account) > balanceBefore

            # Test burns
            balance = interface.IERC20(wbtc).balanceOf(account)
            interface.IERC20(wbtc).approve(bridge.adapter, balance,
                                           {"from": account})
            # Approve mock gateway for transfer of underlying token for "mock" burns.
            # NB: In the real world, burns don't require approvals as it's
            # just an internal update the the user's token balance.
            interface.IERC20(renbtc).approve(
                bridge.mocks.BTC.gateway,
                balance,
                {"from": bridge.adapter},
            )

            bridge.adapter.burn(
                wbtc,
                AddressZero,  # No vault.
                slippage * 10**4,
                account.address,
                balance,
                {"from": account},
            )
            assert interface.IERC20(wbtc).balanceOf(account) == 0
예제 #22
0
def getToken0(pair) -> interface.IERC20:
    return interface.IERC20(pair.token0())
예제 #23
0
from brownie import interface
from brownie.exceptions import ContractNotFound
from datetime import datetime, timedelta
from functools import lru_cache

DAI = interface.IERC20("0x6b175474e89094c44da98b954eedeac495271d0f")
WETH = interface.IERC20("0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")
USDT = interface.IERC20("0xdac17f958d2ee523a2206206994597c13d831ec7")
USDC = interface.IERC20("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")

@lru_cache
def getFactory(router):
  return interface.UniswapFactoryV2(router.factory())

@lru_cache
def getToken0(pair):
  return interface.IERC20(pair.token0())

@lru_cache
def getToken1(pair):
  return interface.IERC20(pair.token1())

@lru_cache
def getPair(factory, token0, token1):
  return interface.UniswapPair(factory.getPair(token0, token1))

def getReserves(token, otherToken, factory):
  try:
    pair = getPair(factory, token, otherToken)
  except ContractNotFound:
    return 0
예제 #24
0
from brownie import interface

QUICKSWAP_ROUTER = "0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff"

USDC_WETH_STAKING = interface.StakingRewards("0x9732E1cC876d8D0B61389385fC1FC756920404fd")
DAI_WETH_STAKING = interface.StakingRewards("0xDFc1b89b6184DfCC7371E3dd898377ECBFEf7058")
USDC_maUSDC_STAKING = interface.StakingRewards("0x68910d18332fFDc1D11caEA4fE93C94Ccd540732")
ETH_wBTC_STAKING = interface.StakingRewards("0x74aF83811468d7a51452128727AB14507B7DC57E")
maUSDC_maTUSD_STAKING = interface.StakingRewards("0x5AE1e3Af79270e600D0e86609bB56B6c6CE23Ee8")
maUSDC_maUSDT_STAKING = interface.StakingRewards("0x66aCCDc838F563D36D0695539c5A01E651eAAEC9")
maUSDC_maDAI_STAKING = interface.StakingRewards("0x0A8E11C2C9B89285e810A206D391CE480dbA7562")

MATIC_ETH = interface.IERC20("0x7ceb23fd6bc0add59e62ac25578270cff1b9f619")
MATIC_BTC = interface.IERC20("0x1bfd67037b42cf73acf2047067bd4f2c47d9bfd6")
MATIC_QUICK = interface.IERC20("0x831753dd7087cac61ab5644b308642cc1c33dc13")
MATIC_MATIC = interface.IERC20("0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270")

QUICK_ETH_USDC = interface.UniswapPair("0x853ee4b2a13f8a742d64c8f088be7ba2131f670d")
QUICK_ETH_DAI = interface.UniswapPair("0x4a35582a710e1f4b2030a3f826da20bfb6703c09")

TOKEN_PRICES = {
  "Quickswap": (
    QUICKSWAP_ROUTER,
    [
      ("ETH", MATIC_ETH),
      ("BTC", MATIC_BTC),
      ("QUICK", MATIC_QUICK),
      ("MATIC", MATIC_MATIC),
      ("ETH_USDC", QUICK_ETH_USDC),
      ("ETH_DAI", QUICK_ETH_DAI),
    ]
예제 #25
0
 def erc20_by_address(self, address):
     return interface.IERC20(address)
예제 #26
0
def main():
    admin = accounts[0]

    alice = accounts[1]
    bob = accounts[2]
    dfd = interface.IERC20Ex('0x20c36f062a31865bED8a5B1e512D9a1A20AA333A')
    dusd = interface.IERC20Ex('0x5BC25f649fc4e26069dDF4cF4010F9f706c23831')

    lp = interface.IERC20Ex('0xd8e9690eff99e21a2de25e0b148ffaf47f47c972')
    # pool is lp for balancer
    pool = interface.IBalancerPool(
        '0xd8e9690eff99e21a2de25e0b148ffaf47f47c972')

    crdfd = MockCErc20.deploy(dfd, {'from': admin})
    crdusd = MockCErc20.deploy(dusd, {'from': admin})

    werc20 = WERC20.deploy({'from': admin})

    staking = accounts.at('0xf068236ecad5fabb9883bbb26a6445d6c7c9a924',
                          force=True)

    wstaking = WStakingRewards.deploy(staking, lp, dfd, {'from': admin})

    simple_oracle = SimpleOracle.deploy({'from': admin})
    simple_oracle.setETHPx([dfd, dusd],
                           [2**112 // 2 // 700, 2**112 * 2 // 700])

    balancer_oracle = BalancerPairOracle.deploy(simple_oracle, {'from': alice})

    core_oracle = CoreOracle.deploy({'from': admin})
    oracle = ProxyOracle.deploy(core_oracle, {'from': admin})
    oracle.setWhitelistERC1155([werc20, wstaking], True, {'from': admin})
    core_oracle.setRoute(
        [dfd, dusd, lp],
        [simple_oracle, simple_oracle, balancer_oracle],
        {'from': admin},
    )
    oracle.setOracles(
        [dfd, dusd, lp],
        [
            [10000, 10000, 10000],
            [10000, 10000, 10000],
            [10000, 10000, 10000],
        ],
        {'from': admin},
    )

    homora = HomoraBank.deploy({'from': admin})
    homora.initialize(oracle, 1000, {'from': admin})  # 10% fee
    setup_bank_hack(homora)
    homora.addBank(dfd, crdfd, {'from': admin})
    homora.addBank(dusd, crdusd, {'from': admin})

    # setup initial funds to alice
    mint_tokens(dfd, alice)
    mint_tokens(dusd, alice)

    # check alice's funds
    print(f'Alice dusd balance {dusd.balanceOf(alice)}')
    print(f'Alice dfd balance {dfd.balanceOf(alice)}')

    # Steal some LP from the staking pool
    mint_tokens(lp, alice)
    mint_tokens(lp, bob)

    # set approval
    dfd.approve(homora, 2**256 - 1, {'from': alice})
    dfd.approve(crdfd, 2**256 - 1, {'from': alice})
    dusd.approve(homora, 2**256 - 1, {'from': alice})
    dusd.approve(crdusd, 2**256 - 1, {'from': alice})
    lp.approve(homora, 2**256 - 1, {'from': alice})
    lp.approve(staking, 2**256 - 1, {'from': bob})

    balancer_spell = BalancerSpellV1.deploy(
        homora, werc20, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
        {'from': admin})
    # first time call to reduce gas
    balancer_spell.getPair(lp, {'from': admin})

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 1.')

    prevABal = dfd.balanceOf(alice)
    prevBBal = dusd.balanceOf(alice)
    prevLPBal = lp.balanceOf(alice)
    prevLPBal_bank = lp.balanceOf(homora)
    prevLPBal_staking = lp.balanceOf(staking)

    prevARes = interface.IBalancerPool(lp).getBalance(dfd)
    prevBRes = interface.IBalancerPool(lp).getBalance(dusd)

    dfd_amt = 100 * 10**18
    dusd_amt = 10**18
    lp_amt = 0
    borrow_dfd_amt = 0
    borrow_dusd_amt = 0

    # calculate slippage control
    total_dfd_amt = dfd_amt + borrow_dfd_amt
    total_dusd_amt = dusd_amt + borrow_dusd_amt
    dfd_weight = 0.58
    dusd_weight = 0.42

    ratio = (((prevARes + total_dfd_amt) / prevARes) ** dfd_weight) * \
        (((prevBRes + total_dusd_amt) / prevBRes) ** dusd_weight) - 1
    lp_desired = lp_amt + int(
        interface.IERC20(lp).totalSupply() * ratio * 0.995)
    print('lp desired', lp_desired)

    tx = homora.execute(
        0,
        balancer_spell,
        balancer_spell.addLiquidityWStakingRewards.encode_input(
            lp,  # lp token
            [
                dfd_amt,  # supply DFD
                dusd_amt,  # supply DUSD
                lp_amt,  # supply LP
                borrow_dfd_amt,  # borrow DFD
                borrow_dusd_amt,  # borrow DUSD
                0,  # borrow LP tokens
                lp_desired
            ],  # LP desired
            wstaking),
        {'from': alice})

    curABal = dfd.balanceOf(alice)
    curBBal = dusd.balanceOf(alice)
    curLPBal = lp.balanceOf(alice)
    curLPBal_bank = lp.balanceOf(homora)
    curLPBal_staking = lp.balanceOf(staking)

    curARes = interface.IBalancerPool(lp).getBalance(dfd)
    curBRes = interface.IBalancerPool(lp).getBalance(dusd)

    print('spell lp balance', lp.balanceOf(balancer_spell))
    print('Alice delta A balance', curABal - prevABal)
    print('Alice delta B balance', curBBal - prevBBal)
    print('add liquidity gas', tx.gas_used)
    print('bank lp balance', curLPBal_bank)

    _, _, _, dfdDebt, dfdShare = homora.getBankInfo(dfd)
    print('bank dfd dfdDebt', dfdDebt)
    print('bank dfd dfdShare', dfdShare)

    print('bank prev LP balance', prevLPBal_bank)
    print('bank cur LP balance', curLPBal_bank)

    print('staking prev LP balance', prevLPBal_staking)
    print('staking cur LP balance', curLPBal_staking)

    print('prev dfd res', prevARes)
    print('cur dfd res', curARes)

    print('prev dusd res', prevBRes)
    print('cur dusd res', curBRes)

    # alice
    assert almostEqual(curABal - prevABal, -dfd_amt), 'incorrect DFD amt'
    assert almostEqual(curBBal - prevBBal, -dusd_amt), 'incorrect DUSD amt'
    assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt'

    # spell
    assert dfd.balanceOf(balancer_spell) == 0, 'non-zero spell DFD balance'
    assert dusd.balanceOf(balancer_spell) == 0, 'non-zero spell DUSD balance'
    assert lp.balanceOf(balancer_spell) == 0, 'non-zero spell LP balance'
    assert dfdDebt == borrow_dfd_amt

    # check balance and pool reserves
    assert almostEqual(
        curABal - prevABal - borrow_dfd_amt,
        -(curARes - prevARes)), 'not all DFD tokens go to LP pool'
    assert almostEqual(
        curBBal - prevBBal - borrow_dusd_amt,
        -(curBRes - prevBRes)), 'not all DUSD tokens go to LP pool'

    _, _, collId, collSize = homora.getPositionInfo(1)
    print('collSize', collSize)

    # staking directly
    prevDfd = dfd.balanceOf(bob)
    print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob))
    tx = interface.IStakingRewards(staking).stake(collSize, {'from': bob})

    chain.sleep(20000)

    prevAliceDfdBalance = dfd.balanceOf(alice)
    print('Alice dfd balance', prevAliceDfdBalance)

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 2. add liquidity the second time')

    prevABal = dfd.balanceOf(alice)
    prevBBal = dusd.balanceOf(alice)
    prevLPBal = lp.balanceOf(alice)
    prevLPBal_bank = lp.balanceOf(homora)
    prevLPBal_staking = lp.balanceOf(staking)

    prevARes = interface.IBalancerPool(lp).getBalance(dfd)
    prevBRes = interface.IBalancerPool(lp).getBalance(dusd)

    dfd_amt = 100 * 10**18
    dusd_amt = 10**18
    lp_amt = 0
    borrow_dfd_amt = 0
    borrow_dusd_amt = 0

    # calculate slippage control
    total_dfd_amt = dfd_amt + borrow_dfd_amt
    total_dusd_amt = dusd_amt + borrow_dusd_amt
    dfd_weight = 0.58
    dusd_weight = 0.42

    ratio = (((prevARes + total_dfd_amt) / prevARes) ** dfd_weight) * \
        (((prevBRes + total_dusd_amt) / prevBRes) ** dusd_weight) - 1
    lp_desired = lp_amt + int(
        interface.IERC20(lp).totalSupply() * ratio * 0.995)
    print('lp desired', lp_desired)

    tx = homora.execute(
        1,
        balancer_spell,
        balancer_spell.addLiquidityWStakingRewards.encode_input(
            lp,  # lp token
            [
                dfd_amt,  # supply DFD
                dusd_amt,  # supply DUSD
                lp_amt,  # supply LP
                borrow_dfd_amt,  # borrow DFD
                borrow_dusd_amt,  # borrow DUSD
                0,  # borrow LP tokens
                lp_desired
            ],  # LP desired
            wstaking),
        {'from': alice})

    curABal = dfd.balanceOf(alice)
    curBBal = dusd.balanceOf(alice)
    curLPBal = lp.balanceOf(alice)
    curLPBal_bank = lp.balanceOf(homora)
    curLPBal_staking = lp.balanceOf(staking)

    curARes = interface.IBalancerPool(lp).getBalance(dfd)
    curBRes = interface.IBalancerPool(lp).getBalance(dusd)

    print('spell lp balance', lp.balanceOf(balancer_spell))
    print('Alice delta A balance', curABal - prevABal)
    print('Alice delta B balance', curBBal - prevBBal)
    print('add liquidity gas', tx.gas_used)
    print('bank lp balance', curLPBal_bank)

    _, _, _, dfdDebt, dfdShare = homora.getBankInfo(dfd)
    print('bank dfd dfdDebt', dfdDebt)
    print('bank dfd dfdShare', dfdShare)

    print('bank prev LP balance', prevLPBal_bank)
    print('bank cur LP balance', curLPBal_bank)

    print('staking prev LP balance', prevLPBal_staking)
    print('staking cur LP balance', curLPBal_staking)

    print('prev dfd res', prevARes)
    print('cur dfd res', curARes)

    print('prev dusd res', prevBRes)
    print('cur dusd res', curBRes)

    # alice
    assert almostEqual(curABal - prevABal, -dfd_amt), 'incorrect DFD amt'
    assert almostEqual(curBBal - prevBBal, -dusd_amt), 'incorrect DUSD amt'
    assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt'

    # spell
    assert dfd.balanceOf(balancer_spell) == 0, 'non-zero spell DFD balance'
    assert dusd.balanceOf(balancer_spell) == 0, 'non-zero spell DUSD balance'
    assert lp.balanceOf(balancer_spell) == 0, 'non-zero spell LP balance'
    assert dfdDebt == borrow_dfd_amt

    # check balance and pool reserves
    assert almostEqual(
        curABal - prevABal - borrow_dfd_amt,
        -(curARes - prevARes)), 'not all DFD tokens go to LP pool'
    assert almostEqual(
        curBBal - prevBBal - borrow_dusd_amt,
        -(curBRes - prevBRes)), 'not all DUSD tokens go to LP pool'

    curAliceDfdBalance = dfd.balanceOf(alice)
    print('Alice dfd balance', curAliceDfdBalance)
    receivedDfd = curAliceDfdBalance - prevAliceDfdBalance + dfd_amt
    print('received dfd', receivedDfd)

    # check with staking directly
    tx = interface.IStakingRewards(staking).getReward({'from': bob})
    receivedDfdFromStaking = dfd.balanceOf(bob) - prevDfd
    print('receivedDfdFromStaking', receivedDfdFromStaking)
    assert almostEqual(receivedDfd, receivedDfdFromStaking)

    return tx
예제 #27
0
def swap_transfer(recipient, params):
    badger = connect_badger("deploy-final.json")

    expectedMultisig = "0xB65cef03b9B89f99517643226d76e286ee999e77"
    assert badger.devMultisig == expectedMultisig
    multi = GnosisSafe(badger.devMultisig)

    one_wei = Wei("1")

    end_token = interface.IERC20(params["path"][-1])

    console.print("Executing Swap:", style="yellow")
    console.print(params)

    # === Approve Uniswap Router on Rewards Escrow if not approved ===
    uniswap = UniswapSystem()
    assert badger.rewardsEscrow.isApproved(badger.token)
    assert badger.rewardsEscrow.isApproved(uniswap.router)

    # === Approve UNI Router for Badger ===

    # Note: The allowance must first be set to 0
    id = multi.addTx(
        MultisigTxMetadata(
            description="Approve UNI Router to send BADGER",
            operation="call",
            callInfo={
                'address': uniswap.router,
                'amount': params["max_in"] // 2
            },
        ),
        params={
            "to":
            badger.rewardsEscrow.address,
            "data":
            badger.rewardsEscrow.call.encode_input(
                badger.token,
                0,
                badger.token.approve.encode_input(uniswap.router, 0),
            ),
        },
    )

    tx = multi.executeTx(id)

    # Set proper allowance
    id = multi.addTx(
        MultisigTxMetadata(
            description="Approve UNI Router to send BADGER",
            operation="call",
            callInfo={
                'address': uniswap.router,
                'amount': params["max_in"] // 2
            },
        ),
        params={
            "to":
            badger.rewardsEscrow.address,
            "data":
            badger.rewardsEscrow.call.encode_input(
                badger.token,
                0,
                badger.token.approve.encode_input(uniswap.router,
                                                  params["max_in"]),
            ),
        },
    )

    tx = multi.executeTx(id)

    console.print({
        "rewardsEscrowBalance":
        val(badger.token.balanceOf(badger.rewardsEscrow)),
        "rewardsEscrowRouterAllowance":
        val(badger.token.allowance(badger.rewardsEscrow, uniswap.router)),
        "max_in":
        val(params["max_in"]),
    })

    assert badger.token.balanceOf(badger.rewardsEscrow) > params["max_in"]
    assert (badger.token.allowance(badger.rewardsEscrow, uniswap.router) >=
            params["max_in"])

    # === Trade Badger for USDC through WBTC ===
    before = end_token.balanceOf(badger.rewardsEscrow)
    beforeBadger = badger.token.balanceOf(badger.rewardsEscrow)

    console.print({"EAO": params["exact_amount_out"]})

    expiration = chain.time() + 8000

    id = multi.addTx(
        MultisigTxMetadata(
            description="Trade Badger for output token",
            operation="call",
            callInfo={},
        ),
        params={
            "to":
            badger.rewardsEscrow.address,
            "data":
            badger.rewardsEscrow.call.encode_input(
                uniswap.router,
                0,
                uniswap.router.swapTokensForExactTokens.encode_input(
                    params["exact_amount_out"],
                    MaxUint256,
                    params["path"],
                    badger.rewardsEscrow,
                    expiration,
                ),
            ),
        },
    )

    tx = multi.executeTx(id)
    print(tx.call_trace())
    print(tx.events)

    printUniTrade(
        method="swapTokensForExactTokens",
        params=(
            params["exact_amount_out"],
            params["max_in"],
            params['path'],
            badger.rewardsEscrow,
            expiration,
        ),
    )

    console.log("=== Post Trade ===")
    console.print({
        'before_input_coin':
        beforeBadger,
        'after_input_coin':
        badger.token.balanceOf(badger.rewardsEscrow),
        'before_output_coin':
        before,
        'post_output_coin':
        end_token.balanceOf(badger.rewardsEscrow),
        'end_token':
        end_token,
        'chain_time_before':
        chain.time()
    })

    assert end_token.balanceOf(
        badger.rewardsEscrow) >= params["exact_amount_out"]

    # === Approve Recipient if not approved ===
    if not badger.rewardsEscrow.isApproved(recipient):
        id = multi.addTx(
            MultisigTxMetadata(
                description="Approve the transfer recipient",
                operation="approveRecipient",
                callInfo={},
            ),
            params={
                "to":
                badger.rewardsEscrow.address,
                "data":
                badger.rewardsEscrow.approveRecipient.encode_input(recipient),
            },
        )

        multi.executeTx(id)

    assert badger.rewardsEscrow.isApproved(recipient)

    # === Test Payment to recipient ===
    before = end_token.balanceOf(recipient)

    id = multi.addTx(
        MultisigTxMetadata(
            description="Test payment to recipientt",
            operation="transfer",
            callInfo={
                "to": recipient,
                "amount": one_wei
            },
        ),
        params={
            "to":
            badger.rewardsEscrow.address,
            "data":
            badger.rewardsEscrow.transfer.encode_input(end_token, recipient,
                                                       one_wei),
        },
    )

    multi.executeTx(id)
    after = end_token.balanceOf(recipient)
    assert after == before + one_wei

    # === Full Payment to recipient ===
    rest = params["exact_amount_out"] - 1
    before = end_token.balanceOf(recipient)

    id = multi.addTx(
        MultisigTxMetadata(
            description="$12k payment to auditor, in USDC",
            operation="transfer",
            callInfo={
                "to": recipient,
                "amount": rest
            },
        ),
        params={
            "to":
            badger.rewardsEscrow.address,
            "data":
            badger.rewardsEscrow.transfer.encode_input(end_token, recipient,
                                                       rest),
        },
    )

    multi.executeTx(id)

    after = end_token.balanceOf(recipient)

    assert after == before + rest

    print(before, after, before + params["exact_amount_out"])

    console.print("\n[green] ✅ Actions Complete [/green]")
def main():
    admin = accounts[0]

    alice = accounts[1]
    bob = accounts[2]
    usdt = interface.IERC20Ex('0xdac17f958d2ee523a2206206994597c13d831ec7')
    weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')
    usdc = interface.IERC20Ex('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48')

    lp = interface.IERC20Ex('0x06da0fd433C1A5d7a4faa01111c044910A184553')
    lp_usdc = interface.IERC20Ex('0x3041cbd36888becc7bbcbc0045e3b1f144466f5f')
    crusdt = interface.ICErc20('0x797AAB1ce7c01eB727ab980762bA88e7133d2157')
    crusdc = interface.ICErc20('0x44fbebd2f576670a6c33f6fc0b00aa8c5753b322')

    sushi = interface.IERC20('0x6b3595068778dd592e39a122f4f5a5cf09c90fe2')

    # sushiswap router
    router = interface.IUniswapV2Router02(
        '0xd9e1ce17f2641f24ae83637ab66a2cca9c378b9f')

    chef = accounts.at('0xc2edad668740f1aa35e4d8f227fb8e17dca888cd',
                       force=True)
    wchef = WMasterChef.deploy(chef, {'from': admin})

    werc20 = WERC20.deploy({'from': admin})

    simple_oracle = SimpleOracle.deploy({'from': admin})
    simple_oracle.setETHPx([usdt, weth, usdc],
                           [2**112 // 700, 2**112, 2**112 // 700])

    uniswap_oracle = UniswapV2Oracle.deploy(simple_oracle, {'from': admin})
    core_oracle = CoreOracle.deploy({'from': admin})
    oracle = ProxyOracle.deploy(core_oracle, {'from': admin})
    oracle.setWhitelistERC1155([werc20, wchef], True, {'from': admin})
    core_oracle.setRoute(
        [usdt, weth, lp, usdc, lp_usdc],
        [
            simple_oracle, simple_oracle, uniswap_oracle, simple_oracle,
            uniswap_oracle
        ],
        {'from': admin},
    )
    oracle.setOracles(
        [usdt, weth, lp, usdc, lp_usdc],
        [
            [10000, 10000, 10000],
            [10000, 10000, 10000],
            [10000, 10000, 10000],
            [10000, 10000, 10000],
            [10000, 10000, 10000],
        ],
        {'from': admin},
    )

    homora = HomoraBank.deploy({'from': admin})
    homora.initialize(oracle, 1000, {'from': admin})  # 10% fee
    setup_bank_hack(homora)
    homora.addBank(usdt, crusdt, {'from': admin})
    homora.addBank(usdc, crusdc, {'from': admin})

    # setup initial funds to alice
    mint_tokens(usdt, alice)
    mint_tokens(weth, alice)
    mint_tokens(usdc, alice)

    # check alice's funds
    print(f'Alice usdt balance {usdt.balanceOf(alice)}')
    print(f'Alice weth balance {weth.balanceOf(alice)}')

    # Steal some LP from the staking pool
    mint_tokens(lp, alice)
    mint_tokens(lp, bob)

    # set approval
    usdt.approve(homora, 2**256 - 1, {'from': alice})
    usdt.approve(crusdt, 2**256 - 1, {'from': alice})
    usdc.approve(homora, 2**256 - 1, {'from': alice})
    usdc.approve(crusdc, 2**256 - 1, {'from': alice})
    weth.approve(homora, 2**256 - 1, {'from': alice})
    lp.approve(homora, 2**256 - 1, {'from': alice})
    lp.approve(chef, 2**256 - 1, {'from': bob})

    sushiswap_spell = SushiswapSpellV1.deploy(homora, werc20, router, wchef,
                                              {'from': admin})
    # first time call to reduce gas
    sushiswap_spell.getPair(weth, usdt, {'from': admin})

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 1. add liquidity first time')

    prevABal = usdt.balanceOf(alice)
    prevBBal = weth.balanceOf(alice)
    prevLPBal = lp.balanceOf(alice)
    prevLPBal_bank = lp.balanceOf(homora)
    prevLPBal_chef = lp.balanceOf(chef)

    if interface.IUniswapV2Pair(lp).token0() == usdt:
        prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves()
    else:
        prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves()

    usdt_amt = 10 * 10**6
    weth_amt = 10**18
    lp_amt = 0
    borrow_usdt_amt = 0
    borrow_weth_amt = 0

    pid = 0

    tx = homora.execute(
        0,
        sushiswap_spell,
        sushiswap_spell.addLiquidityWMasterChef.encode_input(
            usdt,  # token 0
            weth,  # token 1
            [
                usdt_amt,  # supply USDT
                weth_amt,  # supply WETH
                lp_amt,  # supply LP
                borrow_usdt_amt,  # borrow USDT
                borrow_weth_amt,  # borrow WETH
                0,  # borrow LP tokens
                0,  # min USDT
                0
            ],  # min WETH
            pid,
        ),
        {'from': alice})

    curABal = usdt.balanceOf(alice)
    curBBal = weth.balanceOf(alice)
    curLPBal = lp.balanceOf(alice)
    curLPBal_bank = lp.balanceOf(homora)
    curLPBal_chef = lp.balanceOf(chef)

    if interface.IUniswapV2Pair(lp).token0() == usdt:
        curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves()
    else:
        curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves()

    print('spell lp balance', lp.balanceOf(sushiswap_spell))
    print('Alice delta A balance', curABal - prevABal)
    print('Alice delta B balance', curBBal - prevBBal)
    print('add liquidity gas', tx.gas_used)
    print('bank lp balance', curLPBal_bank)

    _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt)
    print('bank usdt totalDebt', totalDebt)
    print('bank usdt totalShare', totalShare)

    print('bank prev LP balance', prevLPBal_bank)
    print('bank cur LP balance', curLPBal_bank)

    print('chef prev LP balance', prevLPBal_chef)
    print('chef cur LP balance', curLPBal_chef)

    print('prev usdt res', prevARes)
    print('cur usdt res', curARes)

    print('prev weth res', prevBRes)
    print('cur weth res', curBRes)

    # alice
    assert almostEqual(curABal - prevABal, -usdt_amt), 'incorrect USDT amt'
    assert almostEqual(curBBal - prevBBal, -weth_amt), 'incorrect WETH amt'
    assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt'

    # spell
    assert usdt.balanceOf(sushiswap_spell) == 0, 'non-zero spell USDT balance'
    assert weth.balanceOf(sushiswap_spell) == 0, 'non-zero spell WETH balance'
    assert lp.balanceOf(sushiswap_spell) == 0, 'non-zero spell LP balance'
    assert totalDebt == borrow_usdt_amt

    # check balance and pool reserves
    assert curABal - prevABal - borrow_usdt_amt == - \
        (curARes - prevARes), 'not all USDT tokens go to LP pool'
    assert almostEqual(
        curBBal - prevBBal - borrow_weth_amt,
        -(curBRes - prevBRes)), 'not all WETH tokens go to LP pool'

    _, _, collId, collSize = homora.getPositionInfo(1)
    print('collSize', collSize)

    # staking directly
    prevSushi = sushi.balanceOf(bob)
    pid = 0
    print('bob lp balance', interface.IERC20Ex(lp).balanceOf(bob))
    tx = interface.IMasterChef(chef).deposit(pid, collSize, {'from': bob})

    chain.sleep(20000)

    prevAliceSushiBalance = sushi.balanceOf(alice)
    print('Alice sushi balance', prevAliceSushiBalance)

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 2. add liquidity (failed tx desired)')

    usdc_amt = 10 * 10**6
    weth_amt = 10**18
    lp_amt = 0
    borrow_usdc_amt = 0
    borrow_weth_amt = 0

    pid = 0

    try:
        tx = homora.execute(
            1,
            sushiswap_spell,
            sushiswap_spell.addLiquidityWMasterChef.encode_input(
                usdc,  # token 0
                weth,  # token 1
                [
                    usdc_amt,  # supply USDC
                    weth_amt,  # supply WETH
                    lp_amt,  # supply LP
                    borrow_usdc_amt,  # borrow USDC
                    borrow_weth_amt,  # borrow WETH
                    0,  # borrow LP tokens
                    0,  # min USDC
                    0
                ],  # min WETH
                pid,
            ),
            {'from': alice})
        assert False, 'tx not fail'
    except VirtualMachineError:
        pass

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 3. remove liquidity (failed tx desired)')

    lp_take_amt = collSize
    lp_want = 0
    usdc_repay = 0
    weth_repay = 0

    try:
        tx = homora.execute(
            1,
            sushiswap_spell,
            sushiswap_spell.removeLiquidityWMasterChef.encode_input(
                usdc,  # token 0
                weth,  # token 1
                [
                    lp_take_amt,  # take out LP tokens
                    lp_want,  # withdraw LP tokens to wallet
                    usdc_repay,  # repay USDC
                    weth_repay,  # repay WETH
                    0,  # repay LP tokens
                    0,  # min USDC
                    0
                ],  # min WETH
            ),
            {'from': alice})
        assert False, 'tx not failed'
    except VirtualMachineError:
        pass

    #####################################################################################
    print(
        '========================================================================='
    )
    print('Case 4. remove liquidity')

    prevABal = usdt.balanceOf(alice)
    prevBBal = weth.balanceOf(alice)
    prevLPBal = lp.balanceOf(alice)
    prevLPBal_bank = lp.balanceOf(homora)
    prevLPBal_chef = lp.balanceOf(chef)
    prevETHBal = alice.balance()

    if interface.IUniswapV2Pair(lp).token0() == usdt:
        prevARes, prevBRes, _ = interface.IUniswapV2Pair(lp).getReserves()
    else:
        prevBRes, prevARes, _ = interface.IUniswapV2Pair(lp).getReserves()

    lp_take_amt = collSize
    lp_want = 0
    usdt_repay = 0
    weth_repay = 0

    pid = 0

    tx = homora.execute(
        1,
        sushiswap_spell,
        sushiswap_spell.removeLiquidityWMasterChef.encode_input(
            usdt,  # token 0
            weth,  # token 1
            [
                lp_take_amt,  # take out LP tokens
                lp_want,  # withdraw LP tokens to wallet
                usdt_repay,  # repay USDT
                weth_repay,  # repay WETH
                0,  # repay LP tokens
                0,  # min USDT
                0
            ],  # min WETH
        ),
        {'from': alice})

    curABal = usdt.balanceOf(alice)
    curBBal = weth.balanceOf(alice)
    curLPBal = lp.balanceOf(alice)
    curLPBal_bank = lp.balanceOf(homora)
    curLPBal_chef = lp.balanceOf(chef)
    curETHBal = alice.balance()

    if interface.IUniswapV2Pair(lp).token0() == usdt:
        curARes, curBRes, _ = interface.IUniswapV2Pair(lp).getReserves()
    else:
        curBRes, curARes, _ = interface.IUniswapV2Pair(lp).getReserves()

    print('spell lp balance', lp.balanceOf(sushiswap_spell))
    print('Alice delta A balance', curABal - prevABal)
    print('Alice delta B balance', curBBal - prevBBal)
    print('add liquidity gas', tx.gas_used)
    print('bank lp balance', curLPBal_bank)

    _, _, _, totalDebt, totalShare = homora.getBankInfo(usdt)
    print('bank usdt totalDebt', totalDebt)
    print('bank usdt totalShare', totalShare)

    print('bank prev LP balance', prevLPBal_bank)
    print('bank cur LP balance', curLPBal_bank)

    print('chef prev LP balance', prevLPBal_chef)
    print('chef cur LP balance', curLPBal_chef)

    print('prev usdt res', prevARes)
    print('cur usdt res', curARes)

    print('prev weth res', prevBRes)
    print('cur weth res', curBRes)

    # alice
    assert almostEqual(curBBal - prevBBal, 0), 'incorrect WETH amt'
    assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt'

    # chef
    assert almostEqual(curLPBal_chef - prevLPBal_chef,
                       -lp_take_amt), 'incorrect chef LP amt'

    # spell
    assert usdt.balanceOf(sushiswap_spell) == 0, 'non-zero spell USDT balance'
    assert weth.balanceOf(sushiswap_spell) == 0, 'non-zero spell WETH balance'
    assert lp.balanceOf(sushiswap_spell) == 0, 'non-zero spell LP balance'

    # check balance and pool reserves
    assert almostEqual(
        curABal - prevABal + usdt_repay,
        -(curARes - prevARes)), 'inconsistent USDT from withdraw'
    assert almostEqual(curBBal - prevBBal,
                       0), 'inconsistent WETH from withdraw'
    assert almostEqual(curETHBal - prevETHBal + weth_repay,
                       -(curBRes - prevBRes)), 'inconsistent ETH from withdraw'

    curAliceSushiBalance = sushi.balanceOf(alice)
    print('Alice sushi balance', curAliceSushiBalance)
    receivedSushi = curAliceSushiBalance - prevAliceSushiBalance
    print('received sushi', receivedSushi)

    # check with staking directly
    pid = 0
    tx = interface.IMasterChef(chef).withdraw(pid, collSize, {'from': bob})
    receivedSushiFromStaking = sushi.balanceOf(bob) - prevSushi
    print('receivedSushiFromStaking', receivedSushiFromStaking)
    assert almostEqual(receivedSushi, receivedSushiFromStaking)
예제 #29
0
def main():
    badger = connect_badger("deploy-final.json")

    test_user = accounts.at(decouple.config("TEST_ACCOUNT"), force=True)

    distribute_test_ether(test_user, Wei("20 ether"))
    distribute_from_whales(test_user, assets=["bBadger", "badger", "usdc"])

    rest = get_active_rewards_schedule(badger)
    usdc = interface.IERC20(registry.tokens.usdc)

    usdc_per_badger = 40.37 * 0.75
    usdc_total = 13386240

    multi = GnosisSafe(badger.devMultisig)

    badger_total_scaled = usdc_total / usdc_per_badger

    badger_total = Wei(str(badger_total_scaled) + " ether")

    bBadger = badger.getSett("native.badger")

    ppfs = bBadger.getPricePerFullShare()

    bBadger_total = int(badger_total / ppfs * 10**18)

    badger_total = Wei(str(badger_total_scaled) + " ether")

    console.print({
        "TRADE": "BASED",
        "usdc_per_badger": usdc_per_badger,
        "usdc_total": usdc_total,
        "badger_total_scaled": badger_total_scaled,
        "badger_total": badger_total,
        "ppfs": ppfs,
        "bBadger_total": str(bBadger_total),
    })

    params = {
        "beneficiary": "0x3159b46a7829a0dbfa856888af768fe7146e7418",
        "duration": days(182),
        "usdcAmount": usdc_total * 10**6,
        "bBadgerAmount": bBadger_total,
        # "usdcAmount": 0,
        # "bBadgerAmount": 0,
    }

    console.print(params)

    # # Oxb1 Test
    beneficiary = accounts.at(params["beneficiary"], force=True)

    escrow = OtcEscrow.at("0x7163fB2fA38Ea3BBc1F8525F3d8D0417C0c9d903")

    # bBadger.transfer(badger.devMultisig, Wei("100000 ether"), {"from": test_user})

    pre = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])
    pre.print()

    # assert usdc.balanceOf(params["beneficiary"]) >= params["usdcAmount"]

    # multi.execute(MultisigTxMetadata(description="Transfer to 0xb1"), {
    #     "to": bBadger.address,
    #     "data": bBadger.transfer.encode_input(escrow, bBadger_total + Wei("1000 ether"))
    # })

    # assert usdc.allowance(beneficiary, escrow) >= params["usdcAmount"]

    # usdc.approve(escrow, params["usdcAmount"], {"from": beneficiary})
    # tx = escrow.swap({"from": beneficiary})

    tx = multi.execute(MultisigTxMetadata(description="Swap"), {
        "to": escrow.address,
        "data": escrow.swap.encode_input()
    },
                       print_output=False)

    chain.mine()

    print(tx.call_trace())

    vesting = interface.ITokenTimelock(
        tx.events["VestingDeployed"][0]["vesting"])

    console.print({
        "token": vesting.token(),
        "beneficiary": vesting.beneficiary(),
        "releaseTime": to_utc_date(vesting.releaseTime()),
    })

    post = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])

    diff_token_balances(pre, post)
    try:
        vesting.release({"from": test_user})
    except:
        print("early vest failed!")

    chain.sleep(days(182))
    chain.mine()
    # End

    vesting.release({"from": test_user})

    post = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])

    diff_token_balances(pre, post)

    return

    escrow = OtcEscrow.deploy(
        params["beneficiary"],
        params["duration"],
        params["usdcAmount"],
        params["bBadgerAmount"],
        {"from": badger.deployer},
    )

    beneficiary = accounts.at(params["beneficiary"], force=True)
    usdc.transfer(beneficiary, params["usdcAmount"], {"from": test_user})
    usdc.transfer(beneficiary, 1500000000000, {"from": test_user})

    badger.token.transfer(badger.devMultisig, badger_total,
                          {"from": test_user})

    multi.execute(
        MultisigTxMetadata(description="Whitelist Multi"),
        {
            "to": bBadger.address,
            "data": bBadger.approveContractAccess.encode_input(
                badger.devMultisig),
        },
    )

    assert badger.token.balanceOf(badger.devMultisig) > Wei("100 ether")

    multi.execute(
        MultisigTxMetadata(description="Approve bBadger Contract"),
        {
            "to": badger.token.address,
            "data": badger.token.approve.encode_input(bBadger, badger_total),
        },
    )

    multi.execute(
        MultisigTxMetadata(description="Deposit"),
        {
            "to": bBadger.address,
            "data": bBadger.deposit.encode_input(badger_total)
        },
    )

    console.print(
        "bBadger.balanceOf(badger.devMultisig)",
        bBadger.balanceOf(badger.devMultisig), params["bBadgerAmount"],
        params["bBadgerAmount"] - bBadger.balanceOf(badger.devMultisig))
    assert bBadger.balanceOf(badger.devMultisig) >= params["bBadgerAmount"]

    chain.mine()
    chain.sleep(14)
    chain.mine()

    multi.execute(
        MultisigTxMetadata(description="Transfer"),
        {
            "to": bBadger.address,
            "data": bBadger.transfer.encode_input(escrow,
                                                  params["bBadgerAmount"]),
        },
    )

    assert bBadger.balanceOf(escrow) == params["bBadgerAmount"]

    multi.execute(
        MultisigTxMetadata(description="Revoke"),
        {
            "to": escrow.address,
            "data": escrow.revoke.encode_input()
        },
    )

    assert bBadger.balanceOf(escrow) == 0
    assert bBadger.balanceOf(badger.devMultisig) >= params["bBadgerAmount"]

    print(bBadger.balanceOf(badger.devMultisig))

    bBadger.transfer(escrow, params["bBadgerAmount"], {"from": test_user})

    pre = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])
    console.print(pre)

    assert usdc.balanceOf(beneficiary) >= params["usdcAmount"]
    assert bBadger.balanceOf(escrow) == params["bBadgerAmount"]

    usdc.approve(escrow, params["usdcAmount"], {"from": beneficiary})
    tx = escrow.swap({"from": beneficiary})

    post = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])

    console.print(tx.events)
    post.print()
    diff_token_balances(pre, post)

    vesting = interface.ITokenTimelock(
        tx.events["VestingDeployed"][0]["vesting"])

    console.print({
        "token": vesting.token(),
        "beneficiary": vesting.beneficiary(),
        "releaseTime": to_utc_date(vesting.releaseTime()),
    })

    chain.sleep(days(365))
    chain.mine()

    vesting.release({"from": test_user})
예제 #30
0
def main():
    admin = accounts[0]

    alice = accounts[1]
    dai = interface.IERC20Ex('0x6B175474E89094C44Da98b954EedeAC495271d0F')
    weth = interface.IERC20Ex('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2')

    lp = interface.IERC20Ex('0x8b6e6e7b5b3801fed2cafd4b22b8a16c2f2db21a')
    # pool is lp for balancer
    pool = interface.IBalancerPool('0x8b6e6e7b5b3801fed2cafd4b22b8a16c2f2db21a')

    crdai = interface.ICErc20('0x92b767185fb3b04f881e3ac8e5b0662a027a1d9f')

    werc20 = WERC20.deploy({'from': admin})

    simple_oracle = SimpleOracle.deploy({'from': admin})
    simple_oracle.setETHPx([weth, dai], [5192296858534827628530496329220096,
                                         8887571220661441971398610676149])

    balancer_oracle = BalancerPairOracle.deploy(simple_oracle, {'from': alice})

    core_oracle = CoreOracle.deploy({'from': admin})
    oracle = ProxyOracle.deploy(core_oracle, {'from': admin})
    oracle.setWhitelistERC1155([werc20], True, {'from': admin})
    core_oracle.setRoute(
        [weth, dai, lp],
        [simple_oracle, simple_oracle, balancer_oracle],
        {'from': admin},
    )
    oracle.setOracles(
        [weth, dai, lp],
        [
            [10000, 10000, 10000],
            [10000, 10000, 10000],
            [10000, 10000, 10000],
        ],
        {'from': admin},
    )

    homora = HomoraBank.deploy({'from': admin})
    homora.initialize(oracle, 1000, {'from': admin})  # 10% fee
    setup_bank_hack(homora)
    homora.addBank(dai, crdai, {'from': admin})

    # setup initial funds to alice
    mint_tokens(dai, alice)
    mint_tokens(weth, alice)

    # check alice's funds
    print(f'Alice weth balance {weth.balanceOf(alice)}')
    print(f'Alice dai balance {dai.balanceOf(alice)}')

    # Steal some LP from the staking pool
    mint_tokens(lp, alice)

    # set approval
    dai.approve(homora, 2**256-1, {'from': alice})
    dai.approve(crdai, 2**256-1, {'from': alice})
    weth.approve(homora, 2**256-1, {'from': alice})
    lp.approve(homora, 2**256-1, {'from': alice})

    balancer_spell = BalancerSpellV1.deploy(
        homora, werc20, '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', {'from': admin})
    # first time call to reduce gas
    balancer_spell.getPair(lp, {'from': admin})

    #####################################################################################
    print('=========================================================================')
    print('Case 1.')

    prevABal = dai.balanceOf(alice)
    prevBBal = weth.balanceOf(alice)
    prevLPBal = lp.balanceOf(alice)
    prevLPBal_bank = lp.balanceOf(homora)
    prevLPBal_werc20 = lp.balanceOf(werc20)

    prevARes = interface.IBalancerPool(lp).getBalance(dai)
    prevBRes = interface.IBalancerPool(lp).getBalance(weth)

    dai_amt = 40000 * 10**18
    weth_amt = 10 ** 18
    lp_amt = 1 * 10**16
    borrow_dai_amt = 0
    borrow_weth_amt = 0

    # calculate slippage control
    total_dai_amt = dai_amt + borrow_dai_amt
    total_weth_amt = weth_amt + borrow_weth_amt
    dai_weight = 0.2
    weth_weight = 0.8

    ratio = (((prevARes + total_dai_amt) / prevARes) ** dai_weight) * \
        (((prevBRes + total_weth_amt) / prevBRes) ** weth_weight) - 1
    lp_desired = lp_amt + int(interface.IERC20(lp).totalSupply() * ratio * 0.995)
    print('lp desired', lp_desired)

    tx = homora.execute(
        0,
        balancer_spell,
        balancer_spell.addLiquidityWERC20.encode_input(
            lp,  # lp token
            [dai_amt,  # supply DAI
             weth_amt,   # supply WETH
             lp_amt,  # supply LP
             borrow_dai_amt,  # borrow DAI
             borrow_weth_amt,  # borrow WETH
             0,  # borrow LP tokens
             lp_desired]  # LP desired
        ),
        {'from': alice}
    )

    curABal = dai.balanceOf(alice)
    curBBal = weth.balanceOf(alice)
    curLPBal = lp.balanceOf(alice)
    curLPBal_bank = lp.balanceOf(homora)
    curLPBal_werc20 = lp.balanceOf(werc20)

    curARes = interface.IBalancerPool(lp).getBalance(dai)
    curBRes = interface.IBalancerPool(lp).getBalance(weth)

    print('spell lp balance', lp.balanceOf(balancer_spell))
    print('Alice delta A balance', curABal - prevABal)
    print('Alice delta B balance', curBBal - prevBBal)
    print('add liquidity gas', tx.gas_used)
    print('bank lp balance', curLPBal_bank)

    _, _, _, daiDebt, daiShare = homora.getBankInfo(dai)
    print('bank dai daiDebt', daiDebt)
    print('bank dai daiShare', daiShare)

    print('bank prev LP balance', prevLPBal_bank)
    print('bank cur LP balance', curLPBal_bank)

    print('werc20 prev LP balance', prevLPBal_werc20)
    print('werc20 cur LP balance', curLPBal_werc20)

    print('prev dai res', prevARes)
    print('cur dai res', curARes)

    print('prev weth res', prevBRes)
    print('cur weth res', curBRes)

    # alice
    assert almostEqual(curABal - prevABal, -dai_amt), 'incorrect DAI amt'
    assert almostEqual(curBBal - prevBBal, -weth_amt), 'incorrect WETH amt'
    assert curLPBal - prevLPBal == -lp_amt, 'incorrect LP amt'

    # spell
    assert dai.balanceOf(balancer_spell) == 0, 'non-zero spell DAI balance'
    assert weth.balanceOf(balancer_spell) == 0, 'non-zero spell WETH balance'
    assert lp.balanceOf(balancer_spell) == 0, 'non-zero spell LP balance'
    assert daiDebt == borrow_dai_amt

    # check balance and pool reserves
    assert almostEqual(curABal - prevABal - borrow_dai_amt, -
                       (curARes - prevARes)), 'not all DAI tokens go to LP pool'
    assert almostEqual(curBBal - prevBBal - borrow_weth_amt, -
                       (curBRes - prevBRes)), 'not all WETH tokens go to LP pool'

    #####################################################################################
    print('=========================================================================')
    print('Case 2.')

    # remove liquidity from the same position
    prevABal = dai.balanceOf(alice)
    prevBBal = weth.balanceOf(alice)
    prevETHBal = alice.balance()
    prevLPBal = lp.balanceOf(alice)
    prevLPBal_bank = lp.balanceOf(homora)
    prevLPBal_werc20 = lp.balanceOf(werc20)
    prevETHBal = alice.balance()

    prevARes = interface.IBalancerPool(lp).getBalance(dai)
    prevBRes = interface.IBalancerPool(lp).getBalance(weth)

    lp_take_amt = 2**256-1  # max
    lp_want = 1 * 10**15
    dai_repay = 2**256-1  # max
    weth_repay = 0

    real_dai_repay = homora.borrowBalanceStored(1, dai)
    _, _, _, real_lp_take_amt = homora.getPositionInfo(1)

    tx = homora.execute(
        1,
        balancer_spell,
        balancer_spell.removeLiquidityWERC20.encode_input(
            lp,  # LP token
            [lp_take_amt,  # take out LP tokens
             lp_want,   # withdraw LP tokens to wallet
             dai_repay,  # repay DAI
             weth_repay,   # repay WETH
             0,   # repay LP
             0,   # min DAI
             0],  # min WETH
        ),
        {'from': alice}
    )
    # return tx

    curABal = dai.balanceOf(alice)
    curBBal = weth.balanceOf(alice)
    curETHBal = alice.balance()
    curLPBal = lp.balanceOf(alice)
    curLPBal_bank = lp.balanceOf(homora)
    curLPBal_werc20 = lp.balanceOf(werc20)
    curETHBal = alice.balance()

    curARes = interface.IBalancerPool(lp).getBalance(dai)
    curBRes = interface.IBalancerPool(lp).getBalance(weth)

    print('spell lp balance', lp.balanceOf(balancer_spell))
    print('spell dai balance', dai.balanceOf(balancer_spell))
    print('spell weth balance', weth.balanceOf(balancer_spell))
    print('Alice delta A balance', curABal - prevABal)
    print('Alice delta B balance', curBBal - prevBBal)
    print('Alice delta ETH balance', curETHBal - prevETHBal)
    print('Alice delta LP balance', curLPBal - prevLPBal)
    print('remove liquidity gas', tx.gas_used)
    print('bank delta lp balance', curLPBal_bank - prevLPBal_bank)
    print('bank total lp balance', curLPBal_bank)

    _, _, _, daiDebt, daiShare = homora.getBankInfo(dai)
    print('bank dai totalDebt', daiDebt)
    print('bank dai totalShare', daiShare)

    print('LP want', lp_want)

    print('bank delta LP amount', curLPBal_bank - prevLPBal_bank)
    print('LP take amount', lp_take_amt)

    print('prev werc20 LP balance', prevLPBal_werc20)
    print('cur werc20 LP balance', curLPBal_werc20)

    print('real dai repay', real_dai_repay)

    # alice
    assert almostEqual(curBBal - prevBBal, 0), 'incorrect WETH amt'
    assert almostEqual(curLPBal - prevLPBal, lp_want), 'incorrect LP amt'

    # werc20
    assert almostEqual(curLPBal_werc20 - prevLPBal_werc20, -
                       real_lp_take_amt), 'incorrect werc20 LP amt'

    # spell
    assert dai.balanceOf(balancer_spell) == 0, 'non-zero spell DAI balance'
    assert weth.balanceOf(balancer_spell) == 0, 'non-zero spell WETH balance'
    assert lp.balanceOf(balancer_spell) == 0, 'non-zero spell LP balance'

    # check balance and pool reserves
    assert almostEqual(curABal - prevABal + real_dai_repay, -
                       (curARes - prevARes)), 'inconsistent DAI from withdraw'
    assert almostEqual(curBBal - prevBBal,
                       0), 'inconsistent WETH from withdraw'
    assert almostEqual(curETHBal - prevETHBal + weth_repay, -
                       (curBRes - prevBRes)), 'inconsistent ETH from withdraw'

    return tx