예제 #1
0
 def test_multiply_by_wad(self):
     assert Ray.from_number(2) * Wad.from_number(3) == Ray.from_number(6)
     assert Ray.from_number(2) * Wad(3) == Ray(6000000000)
     assert Ray(2) * Wad(3) == Ray(0)
     assert Ray(2) * Wad(999999999999999999) == Ray(1)
     assert Ray(2) * Wad(1000000000000000000) == Ray(2)
예제 #2
0
 def test_multiply_by_int(self):
     assert Ray.from_number(2) * 3 == Ray.from_number(6)
     assert Ray.from_number(2) * 1 == Ray.from_number(2)
예제 #3
0
 def test_should_have_nice_printable_representation(self):
     for ray in [Ray(1), Ray(100), Ray.from_number(2.5), Ray(-1)]:
         assert repr(ray) == f"Ray({ray.value})"
예제 #4
0
 def test_multiply(self):
     assert Ray.from_number(2) * Ray.from_number(3) == Ray.from_number(6)
     assert Ray.from_number(2) * Ray(3) == Ray(6)
     assert Ray.from_number(2.5) * Ray(3) == Ray(7)
     assert Ray.from_number(2.99999) * Ray(3) == Ray(8)
예제 #5
0
    def deploy(web3: Web3, debt_ceiling: Wad):
        assert isinstance(web3, Web3)

        vat = Vat.deploy(web3=web3)

        pit = Pit.deploy(web3=web3, vat=vat.address)
        assert pit.file_global_line(debt_ceiling).transact()  # Global debt Ceiling
        assert vat.rely(pit.address).transact()

        dai = DSToken.deploy(web3=web3, symbol='DAI')
        dai_adapter = DaiAdapter.deploy(web3=web3, vat=vat.address, dai=dai.address)
        dai_move = DaiVat.deploy(web3=web3, vat=vat.address)
        assert vat.rely(dai_adapter.address).transact()
        assert vat.rely(dai_move.address).transact()

        mkr = DSToken.deploy(web3=web3, symbol='MKR')

        # TODO: use a DSProxy
        mom = DSGuard.deploy(web3)
        assert mom.permit(DSGuard.ANY, DSGuard.ANY, DSGuard.ANY).transact()
        assert dai.set_authority(mom.address).transact()
        assert mkr.set_authority(mom.address).transact()

        vow = Vow.deploy(web3=web3)
        drip = Drip.deploy(web3=web3, vat=vat.address)
        flap = Flapper.deploy(web3=web3, dai=dai_move.address, gem=mkr.address)

        assert vow.file_vat(vat).transact()
        assert vow.file_flap(flap).transact()
        assert vow.file_bump(Wad.from_number(1000)).transact()
        assert vow.file_sump(Wad.from_number(10)).transact()
        assert drip.file_vow(vow).transact()

        assert vat.rely(vow.address).transact()
        assert vat.rely(drip.address).transact()
        assert vat.rely(flap.address).transact()

        cat = Cat.deploy(web3=web3, vat=vat.address)
        assert cat.file_vow(vow).transact()
        assert cat.file_pit(pit).transact()

        flop = Flopper.deploy(web3=web3, dai=dai_move.address, gem=mkr.address)

        assert vow.file_flop(flop).transact()

        assert vat.rely(cat.address).transact()
        assert vat.rely(flop.address).transact()
        assert vow.rely(cat.address).transact()
        assert flop.rely(vow.address).transact()

        config = DssDeployment.Config(mom, vat, vow, drip, pit, cat, flap, flop, dai, dai_adapter, dai_move, mkr)
        deployment = DssDeployment(web3, config)

        collateral = Collateral.deploy(web3=web3, name='WETH', vat=vat)
        deployment.deploy_collateral(collateral,
                                     debt_ceiling=Wad.from_number(100000),
                                     penalty=Ray.from_number(1),
                                     flop_lot=Wad.from_number(10000),
                                     ratio=Ray.from_number(1.5),
                                     initial_price=Wad.from_number(219))

        return deployment
예제 #6
0
    def __init__(self):
        web3 = Web3(HTTPProvider("http://localhost:8555"))
        web3.eth.defaultAccount = web3.eth.accounts[0]
        our_address = Address(web3.eth.defaultAccount)
        sai = DSToken.deploy(web3, 'DAI')
        sin = DSToken.deploy(web3, 'SIN')
        skr = DSToken.deploy(web3, 'PETH')
        gem = DSToken.deploy(web3, 'WETH')
        gov = DSToken.deploy(web3, 'MKR')
        pip = DSValue.deploy(web3)
        pep = DSValue.deploy(web3)
        pit = DSVault.deploy(web3)

        vox = Vox.deploy(web3, per=Ray.from_number(1))
        tub = Tub.deploy(web3, sai=sai.address, sin=sin.address, skr=skr.address, gem=gem.address, gov=gov.address,
                         pip=pip.address, pep=pep.address, vox=vox.address, pit=pit.address)
        tap = Tap.deploy(web3, tub.address)
        top = Top.deploy(web3, tub.address, tap.address)

        tub._contract.transact().turn(tap.address.address)

        otc = MatchingMarket.deploy(web3, 2600000000)
        etherdelta = EtherDelta.deploy(web3,
                                       admin=Address('0x1111100000999998888877777666665555544444'),
                                       fee_account=Address('0x8888877777666665555544444111110000099999'),
                                       account_levels_addr=Address('0x0000000000000000000000000000000000000000'),
                                       fee_make=Wad.from_number(0.01),
                                       fee_take=Wad.from_number(0.02),
                                       fee_rebate=Wad.from_number(0.03))

        # set permissions
        dad = DSGuard.deploy(web3)
        dad.permit(DSGuard.ANY, DSGuard.ANY, DSGuard.ANY).transact()
        tub.set_authority(dad.address).transact()
        for auth in [sai, sin, skr, gem, gov, pit, tap, top]:
            auth.set_authority(dad.address).transact()

        # whitelist pairs
        otc.add_token_pair_whitelist(sai.address, gem.address).transact()

        # approve
        tub.approve(directly())
        tap.approve(directly())

        # mint some GEMs
        gem.mint(Wad.from_number(1000000)).transact()

        self.snapshot_id = web3.manager.request_blocking("evm_snapshot", [])

        self.web3 = web3
        self.our_address = our_address
        self.sai = sai
        self.sin = sin
        self.skr = skr
        self.gem = gem
        self.gov = gov
        self.vox = vox
        self.tub = tub
        self.tap = tap
        self.top = top
        self.otc = otc
        self.etherdelta = etherdelta
예제 #7
0
    def test_should_identify_arbitrage_against_oasis_and_bust(
            self, deployment: Deployment):
        # given
        keeper = ArbitrageKeeper(args=args(
            f"--eth-from {deployment.our_address.address}"
            f" --tub-address {deployment.tub.address}"
            f" --tap-address {deployment.tap.address}"
            f" --oasis-address {deployment.otc.address}"
            f" --base-token {deployment.sai.address}"
            f" --min-profit 950.0 --max-engagement 14250.0"),
                                 web3=deployment.web3)

        # and
        # [we generate some bad debt available for `bust`]
        DSValue(web3=deployment.web3,
                address=deployment.tub.pip()).poke_with_int(
                    Wad.from_number(500).value).transact()
        deployment.tub.mold_cap(Wad.from_number(1000000)).transact()
        deployment.tub.mold_mat(Ray.from_number(2.0)).transact()
        deployment.tub.mold_axe(Ray.from_number(2.0)).transact()
        deployment.gem.mint(Wad.from_number(100)).transact()
        deployment.tub.join(Wad.from_number(100)).transact()
        deployment.tub.open().transact()
        deployment.tub.lock(1, Wad.from_number(100)).transact()
        deployment.tub.draw(1, Wad.from_number(25000)).transact()
        DSValue(web3=deployment.web3,
                address=deployment.tub.pip()).poke_with_int(
                    Wad.from_number(400).value).transact()
        deployment.tub.bite(1).transact()
        DSValue(web3=deployment.web3,
                address=deployment.tub.pip()).poke_with_int(
                    Wad.from_number(500).value).transact()
        assert deployment.tap.woe() == Wad.from_number(25000)
        assert deployment.tap.fog() == Wad.from_number(100)

        # and
        # [we add a boom/bust spread to make calculations a bit more difficult]
        deployment.tap.mold_gap(Wad.from_number(0.95)).transact()
        assert deployment.tap.ask(Wad.from_number(1)) == Wad.from_number(475.0)
        assert deployment.tap.bid(Wad.from_number(1)) == Wad.from_number(525.0)

        # and
        # [we have some SKR to cover rounding errors]
        deployment.skr.mint(Wad.from_number(0.000000000000000001)).transact()

        # and
        # [we should now have 30 SKR available for 14250 SAI on `bust`]
        # [now lets pretend somebody else placed an order on OASIS offering 15250 SAI for these 30 SKR]
        # [this will be an arbitrage opportunity which can make the bot earn 1000 SAI]
        deployment.sai.mint(Wad.from_number(15250)).transact()
        deployment.otc.approve([deployment.sai, deployment.skr], directly())
        deployment.otc.add_token_pair_whitelist(
            deployment.skr.address, deployment.sai.address).transact()
        deployment.otc.make(deployment.sai.address,
                            Wad.from_number(15250), deployment.skr.address,
                            Wad.from_number(30)).transact()
        assert len(deployment.otc.get_orders()) == 1

        # when
        keeper.approve()
        keeper.process_block()

        # then
        # [the order on Oasis has been taken by the keeper]
        assert len(deployment.otc.get_orders()) == 0

        # and
        # [the amount of bad debt has decreased, so we know the keeper did call bust('14250.0')]
        # [the inequality below is to cater for rounding errors]
        assert deployment.tap.woe() < Wad.from_number(10800.0)
예제 #8
0
 def test_beg(self):
     assert self.flipper.beg() == Ray.from_number(1.05)
예제 #9
0
파일: test_sai.py 프로젝트: w1r2p1/pymaker
 def test_default_par(self, deployment: Deployment):
     # expect
     assert deployment.vox.par() == Ray.from_number(1)
예제 #10
0
파일: test_sai.py 프로젝트: w1r2p1/pymaker
 def test_default_fix(self, deployment: Deployment):
     # expect
     assert deployment.top.fix() == Ray.from_number(0)
예제 #11
0
파일: test_sai.py 프로젝트: w1r2p1/pymaker
    def test_tag(self, deployment: Deployment):
        # when
        DSValue(web3=deployment.web3, address=deployment.tub.pip()).poke_with_int(Wad.from_number(250.45).value).transact()

        # then
        assert deployment.tub.tag() == Ray.from_number(250.45)
예제 #12
0
파일: test_sai.py 프로젝트: w1r2p1/pymaker
 def test_per(self, deployment: Deployment):
     assert deployment.tub.per() == Ray.from_number(1.0)
예제 #13
0
    def test_scenario(self, web3, mcd, collateral, clipper, our_address, other_address, deployment_address):
        dirt_before = mcd.dog.dog_dirt()
        vice_before = mcd.vat.vice()
        sin_before = mcd.vow.sin()

        # Create a vault
        ilk = collateral.ilk
        ink = Wad.from_number(1)
        wrap_eth(mcd, deployment_address, ink)
        collateral.approve(deployment_address)
        assert collateral.adapter.join(deployment_address, ink).transact(
            from_address=deployment_address)
        frob(mcd, collateral, deployment_address, dink=ink, dart=Wad(0))
        dart = max_dart(mcd, collateral, deployment_address) - Wad(1)
        frob(mcd, collateral, deployment_address, dink=Wad(0), dart=dart)

        # Mint and withdraw all the Dai
        mcd.approve_dai(deployment_address)
        assert mcd.dai_adapter.exit(deployment_address, dart).transact(from_address=deployment_address)

        # Undercollateralize the vault
        to_price = Wad(Web3.toInt(collateral.pip.read())) / Wad.from_number(2)
        set_collateral_price(mcd, collateral, to_price)
        urn = mcd.vat.urn(collateral.ilk, deployment_address)
        ilk = mcd.vat.ilk(ilk.name)
        safe = Ray(urn.art) * mcd.vat.ilk(ilk.name).rate <= Ray(urn.ink) * ilk.spot
        assert not safe
        assert clipper.active_count() == 0

        # Bark the vault, which moves debt to the vow and kicks the clipper
        dai_before_bark: Rad = mcd.vat.dai(our_address)
        urn = mcd.vat.urn(collateral.ilk, deployment_address)
        assert urn.ink > Wad(0)
        tab = urn.art * ilk.rate  # Wad
        assert tab == dart
        assert mcd.dog.bark(ilk, urn).transact()
        barks = mcd.dog.past_barks(1)
        assert len(barks) == 1
        last_bite = barks[0]
        assert last_bite.due > Rad(0)
        assert clipper.active_count() == 1
        kick = clipper.kicks()
        assert kick == 1
        assert len(clipper.active_auctions()) == 1
        assert clipper.active_auctions()[0].id == 1
        assert mcd.active_auctions()['clips']['ETH-B'][0].id == 1
        urn = mcd.vat.urn(collateral.ilk, deployment_address)
        (needs_redo, price, lot, tab) = clipper.status(kick)
        assert not needs_redo
        assert price == Ray.from_number(172.5)
        assert lot == ink
        assert float(tab) == 105.0
        # Check vat, vow, and dog
        assert urn.ink == Wad(0)
        assert vice_before < mcd.vat.vice()
        assert sin_before < mcd.vow.sin()
        assert dirt_before < mcd.dog.dog_dirt()
        # Check the clipper
        current_sale = clipper.sales(kick)
        assert isinstance(current_sale, Clipper.Sale)
        assert current_sale.pos == 0
        assert float(current_sale.tab) == 105.0
        assert current_sale.lot == ink
        assert current_sale.usr == deployment_address
        assert current_sale.tic > 0
        assert round(current_sale.top, 1) == price
        coin = Rad(clipper.tip() + (current_sale.tab * clipper.chip()))
        # Confirm we received our liquidation reward
        dai_after_bark: Rad = mcd.vat.dai(our_address)
        assert dai_after_bark == dai_before_bark + coin
        kick_log = self.last_log(clipper)
        assert isinstance(kick_log, Clipper.KickLog)
        assert kick_log.id == kick
        assert kick_log.top == current_sale.top
        assert kick_log.tab == current_sale.tab
        assert kick_log.lot == current_sale.lot
        assert kick_log.usr == deployment_address
        assert kick_log.kpr == our_address
        assert kick_log.coin == coin

        # Wrap some eth and handle approvals before bidding
        eth_required = Wad(current_sale.tab / Rad(ilk.spot)) * Wad.from_number(1.1)
        wrap_eth(mcd, our_address, eth_required)
        collateral.approve(our_address)
        assert collateral.adapter.join(our_address, eth_required).transact(from_address=our_address)
        clipper.approve(mcd.vat.address, approval_function=hope_directly(from_address=our_address))

        # Ensure we cannot take collateral below the current price
        (needs_redo, price, lot, tab) = clipper.status(kick)
        with pytest.raises(AssertionError):
            clipper.validate_take(kick, ink, price - Ray.from_number(1))
        assert not clipper.take(kick, ink, Ray.from_number(140)).transact(from_address=our_address)

        # Take some collateral with max above the top price
        clipper.validate_take(kick, Wad.from_number(0.07), Ray.from_number(180))
        assert web3.eth.defaultAccount == our_address.address
        assert clipper.take(kick, Wad.from_number(0.07), Ray.from_number(180)).transact(from_address=our_address)
        (needs_redo, price, lot, tab) = clipper.status(kick)
        assert not needs_redo
        current_sale = clipper.sales(kick)
        assert current_sale.lot > Wad(0)
        assert current_sale.top > price
        assert Rad(0) < current_sale.tab < kick_log.tab
        first_take_log = self.last_log(clipper)
        assert first_take_log.id == 1
        assert first_take_log.max == Ray.from_number(180)
        assert first_take_log.price == price
        assert first_take_log.lot == current_sale.lot
        assert first_take_log.usr == deployment_address
        assert first_take_log.sender == our_address
        assert round(first_take_log.owe, 18) == round(Rad.from_number(0.07) * Rad(price), 18)

        # Allow the auction to expire, and then resurrect it
        # TODO: If abaci contract is ever wrapped, read tau from it
        time_travel_by(web3, 24)
        (needs_redo, price, lot, tab) = clipper.status(kick)
        assert needs_redo
        assert len(clipper.active_auctions()) == clipper.active_count()
        assert clipper.redo(kick, our_address).transact()
        (needs_redo, price, lot, tab) = clipper.status(kick)
        assert not needs_redo
        current_sale = clipper.sales(kick)
        assert current_sale.lot > Wad(0)
        redo_log = self.last_log(clipper)
        assert isinstance(redo_log, Clipper.RedoLog)
        assert redo_log.id == kick
        assert redo_log.top == current_sale.top
        assert redo_log.tab == current_sale.tab
        assert redo_log.lot == current_sale.lot
        assert redo_log.usr == deployment_address
        assert redo_log.kpr == our_address
        coin = Rad(clipper.tip() + (current_sale.tab * clipper.chip()))
        assert round(float(redo_log.coin), 18) == round(float(coin), 18)

        # Sleep until price has gone down enough to bid with remaining Dai
        dai = mcd.vat.dai(our_address)
        last_price = price
        print(f"Bid cost={float(price * Ray(current_sale.lot))}, Dai balance={float(dai)}")
        while price * Ray(current_sale.lot) > Ray(dai):
            print(f"Bid cost {price * Ray(current_sale.lot)} exceeds Dai balance {dai}")
            time_travel_by(web3, 2)
            (needs_redo, price, lot, tab) = clipper.status(kick)
            assert price < last_price
            assert not needs_redo
            last_price = price
        clipper.validate_take(kick, current_sale.lot, price)
        assert clipper.take(kick, current_sale.lot, price).transact(from_address=our_address)
        current_sale = clipper.sales(kick)
        assert current_sale.lot == Wad(0)
        assert current_sale.tab == Rad(0)
        assert clipper.active_count() == 0
        assert len(clipper.active_auctions()) == 0

        # Ensure we can retrieve our collateral
        collateral_before = collateral.gem.balance_of(our_address)
        assert collateral.adapter.exit(our_address, ink).transact(from_address=our_address)
        collateral_after = collateral.gem.balance_of(our_address)
        assert collateral_before < collateral_after

        # Cleanup
        set_collateral_price(mcd, collateral, Wad.from_number(230))
        cleanup_urn(mcd, collateral, our_address)