collateral = geb.collaterals['ETH-A'] collateral_type = geb.safe_engine.collateral_type( collateral.collateral_type.name) liq_price = collateral_type.liquidation_price safe = geb.safe_engine.safe(collateral_type, Address(safe_addr)) print(f"SAFE {safe_addr}") print( "-----------------------------------------------------------------------------" ) print( f"collateral_type {str(safe.collateral_type.name)}" ) print( f"locked_collateral {str(safe.locked_collateral)}" ) print( f"generated_debt {str(safe.generated_debt)}") if safe.generated_debt != Wad(0): is_critical = (Ray(safe.locked_collateral) * collateral_type.liquidation_price) < Ray( safe.generated_debt) * collateral_type.accumulated_rate coll_ratio = (safe.locked_collateral * collateral_type.liquidation_price * geb.oracle_relayer.liquidation_c_ratio(collateral_type)) / ( safe.generated_debt * collateral_type.accumulated_rate) * 100 print(f"coll_ratio {coll_ratio}") print(f"is_critical {is_critical}")
def test_balance_of(self): assert self.token.balance_of(self.our_address) == Wad(1000000) assert self.token.balance_of(self.second_address) == Wad(0)
def __init__(self, receipt): self.raw_receipt = receipt self.transaction_hash = receipt['transactionHash'] self.gas_used = receipt['gasUsed'] self.transfers = [] self.result = None if int(str(receipt['status']), 16) == 1: self.successful = True elif int(str(receipt['status']), 16) == 0: self.successful = False else: raise ValueError('unknown tx receipt status %s' % receipt) receipt_logs = receipt['logs'] for receipt_log in receipt_logs: if len(receipt_log['topics']) > 0: # $ seth keccak $(seth --from-ascii "Transfer(address,address,uint256)") # 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef if receipt_log['topics'][0] == HexBytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef' ): from pyflex.token import ERC20Token transfer_abi = [ abi for abi in ERC20Token.abi if abi.get('name') == 'Transfer' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, transfer_abi, receipt_log) self.transfers.append( Transfer(token_address=Address(event_data['address']), from_address=Address( event_data['args']['from']), to_address=Address(event_data['args']['to']), value=Wad(event_data['args']['value']))) # $ seth keccak $(seth --from-ascii "Mint(address,uint256)") # 0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885 if receipt_log['topics'][0] == HexBytes( '0x0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885' ): from pyflex.token import DSToken transfer_abi = [ abi for abi in DSToken.abi if abi.get('name') == 'Mint' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, transfer_abi, receipt_log) self.transfers.append( Transfer( token_address=Address(event_data['address']), from_address=Address( '0x0000000000000000000000000000000000000000'), to_address=Address(event_data['args']['guy']), value=Wad(event_data['args']['wad']))) # $ seth keccak $(seth --from-ascii "Burn(address,uint256)") # 0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5 if receipt_log['topics'][0] == HexBytes( '0xcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5' ): from pyflex.token import DSToken transfer_abi = [ abi for abi in DSToken.abi if abi.get('name') == 'Burn' ][0] codec = ABICodec(default_registry) event_data = get_event_data(codec, transfer_abi, receipt_log) self.transfers.append( Transfer( token_address=Address(event_data['address']), from_address=Address(event_data['args']['guy']), to_address=Address( '0x0000000000000000000000000000000000000000'), value=Wad(event_data['args']['wad'])))
def test_should_be_comparable(self): # given order1 = Order( exchange=None, sender=Address("0x0000000000000000000000000000000000000000"), maker=Address("0x9e56625509c2f60af937f23b7b532600390e8c8b"), taker=Address("0x0000000000000000000000000000000000000000"), maker_fee=Wad.from_number(123), taker_fee=Wad.from_number(456), pay_asset=ERC20Asset( Address("0x323b5d4c32345ced77393b3530b1eed0f346429d")), pay_amount=Wad(10000000000000000), buy_asset=ERC20Asset( Address("0xef7fff64389b814a946f3e92105513705ca6b990")), buy_amount=Wad(20000000000000000), salt= 67006738228878699843088602623665307406148487219438534730168799356281242528500, fee_recipient=Address( '0x6666666666666666666666666666666666666666'), expiration=42, exchange_contract_address=Address( "0x12459c951127e0c374ff9105dda097662a027093"), signature= "0x1bf9f6a3b67b52d40c16387df2cd6283bbdbfc174577743645dd6f4bd828c7dbc315baf69f6c3cc8ac0f62c89264d73accf1ae165cce5d6e2a0b6325c6e4bab96403" ) order2 = Order( exchange=None, sender=Address("0x0000000000000000000000000000000000000000"), maker=Address("0x9e56625509c2f60af937f23b7b532600390e8c8b"), taker=Address("0x0000000000000000000000000000000000000000"), maker_fee=Wad.from_number(123), taker_fee=Wad.from_number(456), pay_asset=ERC20Asset( Address("0x323b5d4c32345ced77393b3530b1eed0f346429d")), pay_amount=Wad(10000000000000000), buy_asset=ERC20Asset( Address("0xef7fff64389b814a946f3e92105513705ca6b990")), buy_amount=Wad(20000000000000000), salt= 67006738228878699843088602623665307406148487219438534730168799356281242528500, fee_recipient=Address( '0x6666666666666666666666666666666666666666'), expiration=42, exchange_contract_address=Address( "0x12459c951127e0c374ff9105dda097662a027093"), signature= "0x1bf9f6a3b67b52d40c16387df2cd6283bbdbfc174577743645dd6f4bd828c7dbc315baf69f6c3cc8ac0f62c89264d73accf1ae165cce5d6e2a0b6325c6e4bab96403" ) # expect assert order1 == order2 # when order2.maker_fee = Wad.from_number(124) # then assert order1 != order2 # when order1.maker_fee = Wad.from_number(124) # then assert order1 == order2
def test_total_supply(self): assert self.token.total_supply() == Wad(1000000)
def test_should_fail_to_divide_by_ints(self): with pytest.raises(ArithmeticError): Wad(4) / 2
def test_should_compare_wads_with_each_other(self): assert Wad(1000) == Wad(1000) assert Wad(1000) != Wad(999) assert Wad(1000) > Wad(999) assert Wad(999) < Wad(1000) assert Wad(999) <= Wad(1000) assert Wad(1000) <= Wad(1000) assert Wad(1000) >= Wad(1000) assert Wad(1000) >= Wad(999)
def amount_sold_increase(self) -> Wad: """Returns the amount_to_sell increase applied after an auction has been `restartAuction`ed.""" return Wad(self._contract.functions.amountSoldIncrease().call())
def test_allowance_of(self): assert self.token.allowance_of(self.our_address, self.second_address) == Wad(0)
auction_state = json.loads(auction_input) # If we are already the high bidder, do nothing if auction_state['high_bidder'] == os.environ['KEEPER_ADDRESS']: continue # Ensure our custom bid increase is at least the minimum allowed MY_BID_DECREASE = max(Wad.from_number(MY_BID_DECREASE), Wad.from_number(auction_state['bid_decrease'])) # Add slight amount to account for possible redemption price change between the time of model output and bid placement MY_BID_DECREASE += Wad.from_number(1e-4) # Bid price using `MY_BID_INCREASE` my_bid_amount = Wad.from_number(auction_state['amount_to_sell']) / MY_BID_DECREASE # Round up from Rad to Wad my_bid_price = Wad(Rad.from_number(auction_state['bid_amount']) * redemption_price / Rad(my_bid_amount)) + Wad(1) # Bid price using minimum bid increase allowed min_bid_amount = Wad.from_number(auction_state['amount_to_sell']) / Wad.from_number(auction_state['bid_decrease']) # Round up from Rad to Wad min_bid_price = Wad(Rad.from_number(auction_state['bid_amount']) * redemption_price / Rad(min_bid_amount)) + Wad(1) # Try our bid increase first # If price is too low, then try minimum bid increase if my_bid_price <= Wad.from_number(MAXIMUM_FLX_MULTIPLIER * current_flx_usd_price): bid = {'price': str(my_bid_price)} print(json.dumps(bid), flush=True) elif min_bid_price <= Wad.from_number(MAXIMUM_FLX_MULTIPLIER * current_flx_usd_price): bid = {'price': str(min_bid_price)} print(json.dumps(bid), flush=True)
def create_collateral_auction(geb: GfDeployment, deployment_address: Address, our_address: Address): assert isinstance(geb, GfDeployment) assert isinstance(our_address, Address) assert isinstance(deployment_address, Address) # Create a SAFE collateral = geb.collaterals['ETH-A'] collateral_type = collateral.collateral_type wrap_eth(geb, deployment_address, Wad.from_number(1)) collateral.approve(deployment_address) assert collateral.adapter.join( deployment_address, Wad.from_number(1)).transact(from_address=deployment_address) wrap_modify_safe_collateralization(geb, collateral, deployment_address, delta_collateral=Wad.from_number(1), delta_debt=Wad(0)) delta_debt = max_delta_debt(geb, collateral, deployment_address) - Wad(1) wrap_modify_safe_collateralization(geb, collateral, deployment_address, delta_collateral=Wad(0), delta_debt=delta_debt) # Undercollateralize and bite the SAFE to_price = Wad(geb.web3.toInt(collateral.osm.read())) / Wad.from_number(2) set_collateral_price(geb, collateral, to_price) safe = geb.safe_engine.safe(collateral.collateral_type, deployment_address) collateral_type = geb.safe_engine.collateral_type(collateral_type.name) safe = Ray(safe.generated_debt) * geb.safe_engine.collateral_type( collateral_type.name).accumulated_rate <= Ray( safe.locked_collateral) * collateral_type.safety_price assert not safe assert geb.liquidation_engine.can_liquidate(collateral.collateral_type, SAFE(deployment_address)) assert geb.liquidation_engine.liquidate_safe( collateral.collateral_type, SAFE(deployment_address)).transact() auction_id = collateral.collateral_auction_house.auctions_started() # Generate some system coin, bid on the collateral auction without covering all the debt wrap_eth(geb, our_address, Wad.from_number(10)) collateral.approve(our_address) assert collateral.adapter.join( our_address, Wad.from_number(10)).transact(from_address=our_address) geb.web3.eth.defaultAccount = our_address.address wrap_modify_safe_collateralization(geb, collateral, our_address, delta_collateral=Wad.from_number(10), delta_debt=Wad.from_number(50)) collateral.collateral_auction_house.approve( geb.safe_engine.address, approval_function=approve_safe_modification_directly()) current_bid = collateral.collateral_auction_house.bids(auction_id) safe = geb.safe_engine.safe(collateral.collateral_type, our_address) assert Rad(safe.generated_debt) > current_bid.amount_to_raise bid_amount = Rad.from_number(6) if isinstance(collateral.collateral_auction_house, EnglishCollateralAuctionHouse): increase_bid_size(collateral.collateral_auction_house, auction_id, our_address, current_bid.amount_to_sell, bid_amount) elif isinstance(collateral.collateral_auction_house, FixedDiscountCollateralAuctionHouse): assert collateral.collateral_auction_house.get_collateral_bought( auction_id, Wad(bid_amount)).transact(from_address=our_address) assert collateral.collateral_auction_house.buy_collateral( auction_id, Wad(bid_amount)).transact(from_address=our_address)
def create_almost_risky_safe(geb: GfDeployment, c: Collateral, collateral_amount: Wad, auction_income_recipient_address: Address, draw_system_coin=True) -> SAFE: assert isinstance(geb, GfDeployment) assert isinstance(c, Collateral) assert isinstance(auction_income_recipient_address, Address) logging.debug("Creating almost risky safe") print("create_almost_risky") print( f"Liquidation price {geb.safe_engine.collateral_type(c.collateral_type.name).safety_price}" ) print( f"Safety price {geb.safe_engine.collateral_type(c.collateral_type.name).liquidation_price}" ) # Ensure vault isn't already unsafe (if so, this shouldn't be called) safe = geb.safe_engine.safe(c.collateral_type, auction_income_recipient_address) assert is_safe_safe( geb.safe_engine.collateral_type(c.collateral_type.name), safe) # Add collateral to auction_income_recipient vault if necessary c.approve(auction_income_recipient_address) token = Token(c.collateral_type.name, c.collateral.address, c.adapter.decimals()) print( f"collateral_amount={collateral_amount} locked_collateral={safe.locked_collateral}" ) delta_collateral = collateral_amount - safe.locked_collateral if delta_collateral > Wad(0): safe_engine_balance = geb.safe_engine.token_collateral( c.collateral_type, auction_income_recipient_address) balance = token.normalize_amount( c.collateral.balance_of(auction_income_recipient_address)) print( f"before join: delta_collateral={delta_collateral} safe_engine_balance={safe_engine_balance} balance={balance} safe_engine_gap={delta_collateral - safe_engine_balance}" ) if safe_engine_balance < delta_collateral: safe_engine_gap = delta_collateral - safe_engine_balance if balance < safe_engine_gap: if c.collateral_type.name.startswith("ETH"): wrap_eth(geb, auction_income_recipient_address, safe_engine_gap) else: raise RuntimeError("Insufficient collateral balance") amount_to_join = token.unnormalize_amount(safe_engine_gap) if amount_to_join == Wad( 0): # handle dusty balances with non-18-decimal tokens amount_to_join += token.unnormalize_amount(token.min_amount) assert c.adapter.join( auction_income_recipient_address, amount_to_join).transact( from_address=auction_income_recipient_address) safe_engine_balance = geb.safe_engine.token_collateral( c.collateral_type, auction_income_recipient_address) print( f"after join: delta_collateral={delta_collateral} safe_engine_balance={safe_engine_balance} balance={balance} safe_engine_gap={delta_collateral - safe_engine_balance}" ) assert safe_engine_balance >= delta_collateral assert geb.safe_engine.modify_safe_collateralization( c.collateral_type, auction_income_recipient_address, delta_collateral, Wad(0)).transact(from_address=auction_income_recipient_address) # Put auction_income_recipient SAFE at max possible debt delta_debt = max_delta_debt(geb, c, auction_income_recipient_address) - Wad(1) if delta_debt > Wad(0): print( f"Attempting to modify safe collateralization with delta_debt={delta_debt}" ) assert geb.safe_engine.modify_safe_collateralization( c.collateral_type, auction_income_recipient_address, Wad(0), delta_debt).transact(from_address=auction_income_recipient_address) # Draw our Dai, simulating the usual behavior safe = geb.safe_engine.safe(c.collateral_type, auction_income_recipient_address) if draw_system_coin and safe.generated_debt > Wad(0): geb.approve_system_coin(auction_income_recipient_address) assert geb.system_coin_adapter.exit( auction_income_recipient_address, safe.generated_debt).transact( from_address=auction_income_recipient_address) print(f"Exited {safe.generated_debt} System coin from safe") logging.debug("Almost risky safe created")
def get_collateral_price(collateral: Collateral): assert isinstance(collateral, Collateral) return Wad(Web3.toInt(collateral.osm.read()))
def test_flash_settle_auction(self, web3, geb, collateral, keeper_flash_proxy, fixed_collateral_auction_house, our_address, other_address, deployment_address): if not isinstance(keeper_flash_proxy, GebETHKeeperFlashProxy): return #collateral = geb.collaterals['ETH-A'] auctions_started_before = fixed_collateral_auction_house.auctions_started( ) collateral_type = collateral.collateral_type # Generate eth and join wrap_eth(geb, deployment_address, Wad.from_number(1)) collateral.approve(deployment_address) assert collateral.adapter.join( deployment_address, Wad.from_number(1)).transact(from_address=deployment_address) # generate the maximum debt possible wrap_modify_safe_collateralization(geb, collateral, deployment_address, delta_collateral=Wad.from_number(1), delta_debt=Wad(0)) delta_debt = max_delta_debt(geb, collateral, deployment_address) - Wad(1) debt_before = geb.safe_engine.safe(collateral_type, deployment_address).generated_debt wrap_modify_safe_collateralization(geb, collateral, deployment_address, delta_collateral=Wad(0), delta_debt=delta_debt) # Mint and withdraw all the system coin ''' geb.approve_system_coin(deployment_address) assert geb.system_coin_adapter.exit(deployment_address, delta_debt).transact(from_address=deployment_address) assert geb.system_coin.balance_of(deployment_address) == delta_debt assert geb.safe_engine.coin_balance(deployment_address) == Rad(0) ''' # Undercollateralize the SAFE to_price = Wad(Web3.toInt(collateral.osm.read())) / Wad.from_number(2) set_collateral_price(geb, collateral, to_price) safe = geb.safe_engine.safe(collateral.collateral_type, deployment_address) collateral_type = geb.safe_engine.collateral_type(collateral_type.name) # Make sure the SAFE is not safe assert collateral_type.accumulated_rate is not None assert collateral_type.safety_price is not None safe = Ray(safe.generated_debt) * geb.safe_engine.collateral_type(collateral_type.name).accumulated_rate <= \ Ray(safe.locked_collateral) * collateral_type.safety_price assert not safe assert len(fixed_collateral_auction_house.active_auctions()) == 0 on_auction_before = geb.liquidation_engine.current_on_auction_system_coins( ) # Ensure there is no saviour saviour = geb.liquidation_engine.safe_saviours( collateral.collateral_type, deployment_address) assert saviour == Address('0x0000000000000000000000000000000000000000') # Liquidate the SAFE safe = geb.safe_engine.safe(collateral.collateral_type, deployment_address) ''' assert safe.locked_collateral > Wad(0) generated_debt = min(safe.generated_debt, Wad(geb.liquidation_engine.liquidation_quantity(collateral_type))) # Wad amount_to_raise = generated_debt * collateral_type.accumulated_rate # Wad assert amount_to_raise == delta_debt ''' # Ensure safe can be liquidated assert geb.liquidation_engine.can_liquidate(collateral_type, safe) assert geb.liquidation_engine.liquidate_safe(collateral_type, safe).transact() liquidated_id = collateral.collateral_auction_house.auctions_started() assert liquidated_id == auctions_started_before + 1 eth_before = web3.eth.getBalance(our_address.address) # liquidate and settle #assert collateral.keeper_flash_proxy.liquidate_and_settle_safe(safe).transact(gas=800000, from_address=our_address) assert collateral.keeper_flash_proxy.settle_auction( liquidated_id).transact(from_address=our_address) eth_after = web3.eth.getBalance(our_address.address) print(f"Ether profit {(eth_after - eth_before)/1000000000000000000}") assert eth_after > eth_before # Ensure auction was started auction_id = fixed_collateral_auction_house.auctions_started() assert auction_id == auctions_started_before + 1 assert len(fixed_collateral_auction_house.active_auctions()) == 0 # Check safe_engine, accounting_engine, and liquidation_engine liquidations = geb.liquidation_engine.past_liquidations(1) assert len(liquidations) == 1 last_liquidation = liquidations[0] assert last_liquidation.amount_to_raise > Rad(0) # Check the fixed_collateral_auction_house current_bid = fixed_collateral_auction_house.bids(auction_id) assert isinstance(current_bid, FixedDiscountCollateralAuctionHouse.Bid) assert current_bid.amount_to_sell == Wad(0) assert current_bid.amount_to_raise == Rad(0) assert current_bid.raised_amount == Rad(0) assert current_bid.sold_amount == Wad(0) # Ensure auction has ended assert len(fixed_collateral_auction_house.active_auctions()) == 0 # Cleanup set_collateral_price(geb, collateral, Wad.from_number(230)) cleanup_safe(geb, collateral, other_address)
def remaining_buy_amount(self) -> Wad: return Wad.max( self.buy_amount - self._exchange.get_unavailable_buy_amount(self), Wad(0))
def test_mint(self): # when self.dstoken.mint(Wad(100000)).transact() # then assert self.dstoken.balance_of(self.our_address) == Wad(100000)
def test_should_fail_to_multiply_by_float(self): with pytest.raises(ArithmeticError): Wad(2) * 3.0
def test_mint_to_other_address(self): # when self.dstoken.mint_to(self.second_address, Wad(100000)).transact() # then assert self.dstoken.balance_of(self.second_address) == Wad(100000)
def test_should_support_abs(self): assert abs(Wad(1000)) == Wad(1000) assert abs(Wad(0)) == Wad(0) assert abs(Wad(-1000)) == Wad(1000)
def test_deposit(self): # when self.dsethtoken.deposit(Wad(100000)).transact() # then assert self.dsethtoken.balance_of(self.our_address) == Wad(100000)
def test_should_be_hashable(self): assert is_hashable(Wad(123))
def test_should_replace_pending_transactions_if_model_raises_bid_and_increases_gas_price(self, auction_id): # given (model, model_factory) = models(self.keeper, auction_id) amount_to_sell = self.surplus_auction_house.bids(auction_id).amount_to_sell # when simulate_model_output(model=model, price=Wad.from_number(9.0), gas_price=10) # and self.start_ignoring_transactions() # and self.keeper.check_all_auctions() self.keeper.check_for_bids() # and self.end_ignoring_transactions() # and simulate_model_output(model=model, price=Wad.from_number(8.0), gas_price=15) # and self.keeper.check_for_bids() wait_for_other_threads() # then assert round(self.surplus_auction_house.bids(auction_id).bid_amount, 2) == round(Wad(amount_to_sell / Rad.from_number(8.0)), 2) assert self.web3.eth.getBlock('latest', full_transactions=True).transactions[0].gasPrice == 15 # cleanup time_travel_by(self.web3, self.surplus_auction_house.bid_duration() + 1) assert self.surplus_auction_house.settle_auction(auction_id).transact()