Пример #1
0
    def kick(self, tab, lot, usr, kpr, now):
        require(tab > Rad(0), "Clipper/zero-tab")
        require(lot > Wad(0), "Clipper/zero-lot")
        require(bool(usr), "Clipper/zero-usr")
        require(self.kicks < (1 << 31) - 1, "Clipper/overflow")

        self.kicks += 1
        sale_id = self.kicks
        self.active.append(sale_id)

        pip = self.spotter.ilks[self.ilk_id].pip
        val = pip.peek(now)

        self.sales[sale_id] = Sale(
            len(self.active) - 1,
            tab,
            lot,
            usr,
            now,
            Ray(val / Wad(self.spotter.par)) * self.buf,
            sale_id,
        )

        if self.tip > Rad(0) or self.chip > Wad(0):
            self.vat.suck(self.vow.ADDRESS, kpr,
                          self.tip + tab * Rad(self.chip))
Пример #2
0
 def track_stat(state, action, results):
     ilk = state["vat"].ilks[ilk_id]
     if action["key"] == "T_END":
         state["stats"]["num_unsafe_vaults"] = len([
             1 for urn in state["vat"].urns[ilk_id].values()
             if ilk.spot > Ray(0) and Rad(urn.ink * ilk.spot) < Rad(urn.art * ilk.rate)
         ])
Пример #3
0
    def frob(self, i, u, v, w, dink, dart):
        urn = self.urns[i].get(u, Urn(u, Wad(0), Wad(0)))
        ilk = self.ilks[i]

        urn.ink += dink
        urn.art += dart
        ilk.Art += dart

        dtab = Rad(ilk.rate * dart)
        tab = Rad(ilk.rate * urn.art)
        self.debt += dtab

        require(
            dart <= Wad(0) or
            (Rad(ilk.Art * ilk.rate) <= ilk.line and self.debt <= self.Line),
            "Vat/ceiling-exceeded",
        )
        require(dart <= Wad(0) <= dink or tab <= Rad(urn.ink * ilk.spot),
                "Vat/not-safe")
        require(urn.art == Wad(0) or tab >= ilk.dust, "Vat/dust")

        self.gem[i][v] -= dink
        w_dai = self.dai.get(w, Rad(0))
        w_dai += dtab
        self.dai[w] = w_dai

        self.urns[i][u] = urn
        self.ilks[i] = ilk
Пример #4
0
 def __init__(self, ilk_id):
     self.id = ilk_id
     self.Art = Wad(0)
     self.rate = Ray(0)
     self.spot = Ray(0)
     self.line = Rad(0)
     self.dust = Rad(0)
Пример #5
0
 def __init__(self, vat):
     self.ADDRESS = "cat"
     self.ilks = {}
     self.vat = vat
     self.box = Rad(0)
     self.litter = Rad(0)
     self.vow = None
Пример #6
0
    def __init__(self):
        self.ADDRESS = "vat"
        self.ilks = {}
        self.urns = {}
        self.gem = {}
        self.dai = {}
        self.sin = {}

        self.debt = Rad(0)
        self.vice = Rad(0)
        self.Line = Rad(0)
Пример #7
0
 def generate_actions_for_timestep(self, t):
     actions = []
     for ilk_id in self.ilks:
         ilk = self.vat.ilks[ilk_id]
         for urn in self.vat.urns[ilk_id].values():
             if Rad(urn.ink * ilk.spot) < Rad(urn.art * ilk.rate):
                 actions.append({
                     "key": "BITE",
                     "keeper": self,
                     "handler": self.cat.bite,
                     "args": [ilk_id, urn.ADDRESS, t],
                     "kwargs": {},
                 })
     return actions
Пример #8
0
    def take(self, sale_id, amt, max_price, who, data, now, sender):
        require(self.sales.get(sale_id), "Clipper/not-running-auction")
        usr = self.sales[sale_id].usr
        tic = self.sales[sale_id].tic

        (done, price) = self.status(tic, self.sales[sale_id].top, now)
        require(not done, "Clipper/needs-reset")

        require(max_price >= price, "Clipper/too-expensive")

        lot = self.sales[sale_id].lot
        tab = self.sales[sale_id].tab

        lot_slice = min(lot, amt)
        owe = Rad(price * lot_slice)

        if owe > tab:
            owe = tab
            lot_slice = Wad(owe / Rad(price))
        elif owe < tab and lot_slice < lot:
            dust = self.vat.ilks[self.ilk_id].dust
            if tab - owe < dust:
                require(tab > dust, "Clipper/no-partial-purchase")
                owe = tab - dust
                lot_slice = Wad(owe / Rad(price))

        tab = tab - owe
        lot = lot - lot_slice

        self.vat.flux(self.ilk_id, self.ADDRESS, who, lot_slice)

        if len(data
               ) > 0 and who != self.vat.ADDRESS and who != self.dog.ADDRESS:
            who.clipperCall(sender, owe, lot_slice, data)

        self.vat.move(sender, self.vow.ADDRESS, owe)

        self.dog.digs(self.ilk_id, owe)

        if lot == Wad(0):
            self._remove(sale_id)
        elif tab == Rad(0):
            self.vat.flux(self.ilk_id, self.ADDRESS, usr, lot)
            self._remove(sale_id)
        else:
            self.sales[sale_id].tab = tab
            self.sales[sale_id].lot = lot
        return [owe, self.vat.urns]
Пример #9
0
    def run_bidding_model(self, bid, ilk_id):
        curr_price = Wad(bid.bid) / bid.lot
        if (bid.guy == self.ADDRESS or bid.lot == Wad(0) or curr_price > Wad(
                self.vat.ilks[ilk_id].spot * self.spotter.ilks[ilk_id].mat)):
            return {"price": Wad(0)}

        if bid.bid == Rad(0):
            return {
                "price": Wad.from_number(0.05) * Wad(bid.tab / Rad(bid.lot))
            }

        return {
            "price":
            curr_price * (self.flippers[ilk_id].beg +
                          Wad.from_number(random.uniform(0, 0.15)))
        }
Пример #10
0
 def track_stat(state, action, results):
     if action["key"] == "T_START":
         state["stats"]["incentive_amount"] = Rad(0)
     elif action["key"] == "BARK":
         ilk_id = action["args"][0]
         clip = state["clippers"][ilk_id]
         tab = results[0]
         incentive = clip.tip + tab * Rad(clip.chip)
         state["stats"]["incentive_amount"] += incentive
     elif action["key"] == "REDO":
         sale_id = action["args"][0]
         ilk_id = action["extra"]["ilk_id"]
         clip = state["clippers"][ilk_id]
         sale = clip.sales[sale_id]
         incentive = clip.tip + sale.tab * Rad(clip.chip)
         state["stats"]["incentive_amount"] += incentive
Пример #11
0
 def suck(self, u, v, rad):
     self.sin[u] += rad
     if not self.dai.get(v):
         self.dai[v] = Rad(0)
     self.dai[v] += rad
     self.vice += rad
     self.debt += rad
Пример #12
0
 def fess(self, tab, now):
     # TODO: Remove `now` parameter if/when another solution for providing time / other
     # contextual info is implemented
     if not self.sin.get(now):
         self.sin[now] = Rad(0)
     self.sin[now] += tab
     self.Sin += tab
Пример #13
0
    def bark(self, ilk_id, urn_id, kpr, now):
        ink = self.vat.urns[ilk_id][urn_id].ink
        art = self.vat.urns[ilk_id][urn_id].art
        milk = self.ilks[ilk_id]

        rate = self.vat.ilks[ilk_id].rate
        spot = self.vat.ilks[ilk_id].spot
        dust = self.vat.ilks[ilk_id].dust
        require(spot > Ray(0) and spot * ink < rate * art, "Dog/not-unsafe")

        room = min(self.Hole - self.Dirt, milk.hole - milk.dirt)
        require(room > Rad(0) and room >= dust, "Dog/liquidation-limit-hit")

        dart = min(art, Wad(room / Rad(rate)) / milk.chop)

        if Rad(rate * (art - dart)) < dust:
            # Q: What if art > room?
            # Resetting dart = art here can push past liq limit
            dart = art

        dink = ink * dart / art

        require(dink > Wad(0), "Dog/null-auction")
        require(
            dart <= Wad.from_number(2**255)
            and dink <= Wad.from_number(2**255),
            "Dog/overflow",
        )

        self.vat.grab(
            ilk_id,
            urn_id,
            milk.clip.ADDRESS,
            self.vow.ADDRESS,
            Wad(0) - dink,
            Wad(0) - dart,
        )

        due = Rad(rate * dart)
        self.vow.fess(due, now)

        tab = due * Rad(milk.chop)
        self.Dirt += tab
        self.ilks[ilk_id].dirt = milk.dirt + tab

        milk.clip.kick(tab, dink, urn_id, kpr, now)
        return [tab]
Пример #14
0
    def grab(self, i, u, v, w, dink, dart):
        urn = self.urns[i][u]
        ilk = self.ilks[i]

        urn.ink += dink
        urn.art += dart
        ilk.Art += dart

        dtab = Rad(ilk.rate * dart)

        if not self.gem[i].get(v):
            self.gem[i][v] = Wad(0)
        self.gem[i][v] -= dink
        if not self.sin.get(w):
            self.sin[w] = Rad(0)
        self.sin[w] -= dtab
        self.vice -= dtab
Пример #15
0
    def __init__(self, vat, flapper, flopper):
        self.ADDRESS = "vow"

        self.vat = vat
        self.flapper = flapper
        self.flopper = flopper

        self.sin = {}
        self.Sin = Rad(0)
        self.Ash = Rad(0)

        self.wait = 0
        self.dump = Wad(0)
        self.sump = Rad(0)

        self.bump = Rad(0)
        self.hump = Rad(0)
Пример #16
0
 def open_max_vaults(self, actions):
     for ilk_id in self.ilks:
         vat_ilk = self.vat.ilks[ilk_id]
         if self.ilks[ilk_id].balanceOf(
                 self.ADDRESS) > 0 and vat_ilk.spot > Ray(0):
             dink = Wad.from_number(self.ilks[ilk_id].balanceOf(
                 self.ADDRESS))
             dart = self.spot_paddings[ilk_id] * vat_ilk.spot * dink
             if dart > Wad(vat_ilk.dust) and Rad(
                     dart * vat_ilk.rate) <= Rad(dink * vat_ilk.spot):
                 actions.append({
                     "key": "OPEN_VAULT",
                     "keeper": self,
                     "handler": self.open_vault,
                     "args": [ilk_id, dink, dart],
                     "kwargs": {},
                 })
Пример #17
0
    def run_bidding_model(self, bid, ilk_id):
        if bid.tic != 0:
            return {"price": Wad(0)}
        for keeper in self.other_keepers:
            if self.vat.dai.get(keeper.ADDRESS, Rad(0)) >= bid.tab:
                return {"price": Wad(0)}

        return super().run_bidding_model(bid, ilk_id)
Пример #18
0
    def place_bid(self, bid_id, price, ilk_id, now):
        if price > Wad(0):
            flipper = self.flippers[ilk_id]
            bid = flipper.bids[bid_id]

            if bid.bid == bid.tab:
                # Dent phase
                our_lot = Wad(bid.bid / Rad(price))
                if (our_lot * flipper.beg <= bid.lot and our_lot < bid.lot
                        and self.vat.dai.get(self.ADDRESS)
                        and self.vat.dai[self.ADDRESS] >= bid.bid):
                    return {
                        "key": "DENT",
                        "keeper": self,
                        "handler": flipper.dent,
                        "args": [bid_id, self.ADDRESS, our_lot, bid.bid, now],
                        "kwargs": {},
                    }

            else:
                # Tend phase
                our_bid = Rad.min(Rad(bid.lot) * price, bid.tab)
                if ((our_bid >= bid.bid * flipper.beg or our_bid == bid.tab)
                        and our_bid > bid.bid
                        and self.vat.dai.get(self.ADDRESS)
                        and self.vat.dai[self.ADDRESS] >=
                    (our_bid if self.ADDRESS != bid.guy else our_bid -
                     bid.bid)):
                    return {
                        "key": "TEND",
                        "keeper": self,
                        "handler": flipper.tend,
                        "args": [bid_id, self.ADDRESS, bid.lot, our_bid, now],
                        "kwargs": {},
                    }

        return None
Пример #19
0
 def get_slippage(self, pair_id, in_token, in_amt, t):
     self.tick(t)
     out_token = next(
         filter(lambda x: x != in_token, self.pairs[pair_id].keys()))
     in_reserve = Wad.from_number(float(self.pairs[pair_id][in_token]))
     out_reserve = Wad.from_number(float(self.pairs[pair_id][out_token]))
     initial_rate = out_reserve / in_reserve
     k = in_reserve * out_reserve
     new_in_reserve = in_reserve + in_amt
     new_out_reserve = k / new_in_reserve
     new_rate = new_out_reserve / new_in_reserve
     return (
         Rad(out_reserve - new_out_reserve),
         (new_rate - initial_rate) / initial_rate,
     )
Пример #20
0
    def redo(self, sale_id, kpr, now):
        usr = self.sales[sale_id].usr
        tic = self.sales[sale_id].tic
        top = self.sales[sale_id].top

        require(bool(usr), "Clipper/not-running-auction")

        (done, _) = self.status(tic, top, now)
        require(done, "Clipper/cannot-reset")

        tab = self.sales[sale_id].tab
        lot = self.sales[sale_id].lot
        self.sales[sale_id].tic = now

        pip = self.spotter.ilks[self.ilk_id].pip
        val = pip.peek(now)
        price = Ray(val / Wad(self.spotter.par))
        self.sales[sale_id].top = price * self.buf

        if self.tip > Rad(0) or self.chip > Wad(0):
            dust = self.vat.ilks[self.ilk_id].dust
            if tab >= dust and Rad(lot * price) >= dust:
                self.vat.suck(self.vow.ADDRESS, kpr,
                              self.tip + tab * Rad(self.chip))
Пример #21
0
    def __init__(self, vat, spotter, dog, ilk_id):
        self.ADDRESS = f"clipper-{ilk_id}"

        self.vat = vat
        self.spotter = spotter
        self.dog = dog
        self.ilk_id = ilk_id
        self.buf = Ray.from_number(1)

        self.vow = None
        self.calc = None
        self.tail = 0
        self.cusp = Ray(0)
        self.kicks = 0
        self.active = []
        self.sales = {}
        self.locked = 0
        self.stopped = 0
        self.chip = Wad(0)
        self.tip = Rad(0)
Пример #22
0
    def bite(self, ilk_id, urn, now):
        # TODO: Remove `now` once better timekeeping solution is implemented

        rate = self.vat.ilks[ilk_id].rate
        spot = self.vat.ilks[ilk_id].spot
        dust = self.vat.ilks[ilk_id].dust
        ink = self.vat.urns[ilk_id][urn].ink
        art = self.vat.urns[ilk_id][urn].art

        require(spot > Ray(0) and Rad(ink * spot) < Rad(art * rate),
                "Cat/not-unsafe")

        milk = self.ilks[ilk_id]

        room = self.box - self.litter
        require(self.litter < self.box and room >= dust,
                "Cat/liquidation-limit-hit")

        dart = Wad.min(art,
                       Wad(Rad.min(milk.dunk, room)) / Wad(rate) / milk.chop)
        dink = Wad.min(ink, ink * dart / art)

        require(dart > Wad(0) and dink > Wad(0), "Cat/null-auction")
        require(
            dart <= Wad.from_number(2**255)
            and dink <= Wad.from_number(2**255),
            "Cat/overflow",
        )

        self.vat.grab(ilk_id, urn, self.ADDRESS, self.vow.ADDRESS,
                      Wad(0) - dink,
                      Wad(0) - dart)
        self.vow.fess(Rad(dart * rate), now)

        tab = Rad(dart * rate * milk.chop)
        self.litter += tab

        milk.flip.kick(urn, self.vow.ADDRESS, tab, dink, Rad(0), now)
Пример #23
0
 def __init__(self, ilk_id):
     self.id = ilk_id
     self.chop = Wad(0)
     self.dunk = Rad(0)
Пример #24
0
    ]:
        timeframe_params = deepcopy(parameters)
        timeframe_params["Spotter"]["WETH"]["pip"] = PipLike(
            f"feeds/eth/{timeframe}.json")
        timeframe_params["GasOracle"][
            "price_feed_file"] = f"feeds/gas/{timeframe}.json"
        timeframe_params["Uniswap"]["pairs"][
            "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11"][
                "path"] = f"feeds/eth_dai_liquidity/{timeframe}.json"

        swept_params = sweep(
            {
                # "Clipper.WETH.chip": [Wad.from_number(0.001), Wad.from_number(0.01), Wad.from_number(0.1)],
                # "Clipper.WETH.tip": [Rad.from_number(100), Rad.from_number(500), Rad.from_number(1000)],
                "Clipper.WETH.chip": [Wad.from_number(0.001)],
                "Clipper.WETH.tip": [Rad.from_number(1000)],
            },
            timeframe_params,
        )

        DutchAuctionsSims = [
            DutchAuctionsExperiment(
                contracts,
                keepers,
                sort_actions,
                ilk_ids,
                Token,
                stat_trackers,
                params,
            ) for params in swept_params
        ]
Пример #25
0
 def exit(self, sender, usr, wad):
     self.vat.move(sender, self.ADDRESS, Rad(wad))
     self.dai.mint(usr, float(wad))
Пример #26
0
 def join(self, sender, usr, wad):
     self.vat.move(self.ADDRESS, usr, Rad(wad))
     self.dai.burn(sender, float(wad))
Пример #27
0
    "SpotterKeeper": SpotterKeeper,
    "BiteKeeper": BiteKeeper,
}
sort_actions = lambda _: random.random()
ilk_ids = ["WETH"]
stat_trackers = [
    ilk_price("WETH"),
    num_new_bites(),
    num_bids_placed(),
    keeper_gem_balances(),
    num_active_bids(),
    auction_debt(),
]
parameters = {
    "Cat": {
        "box": Rad(15000000000000000000000000000000000000000000000000000),
        "WETH": {
            "chop": Wad(1130000000000000000),
            "dunk": Rad(50000000000000000000000000000000000000000000000000),
        },
    },
    "Flipper": {
        "WETH": {
            "beg": Wad(1050000000000000000),
            "ttl": 18,
            "tau": 288,
        }
    },
    "Keepers": {
        "NaiveVaultKeeper": {
            "amount":
Пример #28
0
 def move(self, src, dst, rad):
     self.dai[src] -= rad
     dst_dai = self.dai.get(dst, Rad(0))
     dst_dai += rad
     self.dai[dst] = dst_dai
Пример #29
0
 def is_unsafe(urn, ilk):
     return ilk.spot > Ray(0) and Rad(urn.ink * ilk.spot) < Rad(urn.art * ilk.rate)
Пример #30
0
    auction_debt(),
    ilk_price("WETH"),
    gas_price_gwei(),
    avg_time_to_liquidation("WETH"),
]
parameters = {
    "Abacus": {
        "tau": 72
    },
    "Clipper": {
        "WETH": {
            "buf": Ray.from_number(1.05),
            "tail": 72,
            "cusp": Ray.from_number(0.5),
            "chip": Wad.from_number(0.08),
            "tip": Rad.from_number(1000),
        }
    },
    "Dog": {
        "Hole": Rad(15000000000000000000000000000000000000000000000000000),
        "WETH": {
            "chop": Wad.from_number(1.13),
            "hole": Rad(15000000000000000000000000000000000000000000000000000),
        },
    },
    "Keepers": {
        "NaiveVaultKeeper": {
            "amount":
            50,
            "get_params":
            lambda state: [