Skip to content

Commit

Permalink
Fix force exits
Browse files Browse the repository at this point in the history
  • Loading branch information
tsudmi committed Dec 26, 2024
1 parent 8e95596 commit fa4d5c6
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 25 deletions.
16 changes: 10 additions & 6 deletions src/exit/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ def claim_exited_assets(
)
calls.append((leverage_strategy_contract.address, claim_call))
try:
tx = multicall_contract.functions.aggregate(calls).transact()
tx = multicall_contract.aggregate(calls).transact()
except Exception as e:
logger.info(
'Failed to claim exited assets for leverage positions: vault=%s, user=%s %s...',
logger.error(
'Failed to claim exited assets for leverage position: vault=%s, user=%s %s...',
vault,
user,
e,
Expand All @@ -83,8 +83,8 @@ def claim_exited_assets(
tx, timeout=EXECUTION_TRANSACTION_TIMEOUT
)
if not tx_receipt['status']:
logger.info(
'Failed to claim exited assets for leverage positions: vault=%s, user=%s...',
logger.error(
'Failed to confirm exited assets claim for leverage position: vault=%s, user=%s...',
vault,
user,
)
Expand Down Expand Up @@ -125,7 +125,11 @@ def force_enter_exit_queue(
tx, timeout=EXECUTION_TRANSACTION_TIMEOUT
)
if not tx_receipt['status']:
logger.error('Force enter exit queue transaction failed')
logger.error(
'Failed to confirm force enter exit queue: vault=%s, user=%s...',
vault,
user,
)
return None

return tx_hash
Expand Down
32 changes: 26 additions & 6 deletions src/exit/graph.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
from gql import gql
from sw_utils.networks import HOLESKY
from web3 import Web3
from web3.types import BlockNumber, ChecksumAddress

from src.common.graph import get_harvest_params
from src.common.typings import HarvestParams

from src.common.settings import NETWORK
from .clients import graph_client
from .typings import ExitRequest, LeveragePosition, OsTokenExitRequest

DISABLED_LIQ_THRESHOLD = 2**64 - 1
HOLESKY_UNCLAIMABLE_EXIT_REQUEST_IDS = [
'0x8a94e1d22d83990205843cda08376d16f150c9bb-210258902756807306422',
'0x8a94e1d22d83990205843cda08376d16f150c9bb-450147843736954431325',
'0x8a94e1d22d83990205843cda08376d16f150c9bb-458856763747647876703',
'0x8a94e1d22d83990205843cda08376d16f150c9bb-464067729736660634975',
'0x8a94e1d22d83990205843cda08376d16f150c9bb-465799992852070364982',
]


async def graph_get_leverage_positions(block_number: BlockNumber) -> list[LeveragePosition]:
query = gql(
Expand Down Expand Up @@ -77,6 +87,11 @@ async def graph_get_allocators(
skip: $skip
) {
address
vault {
osTokenConfig {
liqThresholdPercent
}
}
}
}
"""
Expand All @@ -89,14 +104,16 @@ async def graph_get_allocators(
response = await graph_client.fetch_pages(query, params=params)
result = []
for data in response:
result.append(
Web3.to_checksum_address(data['address']),
)
vault_liq_threshold = int(data['vault']['osTokenConfig']['liqThresholdPercent'])
if vault_liq_threshold != DISABLED_LIQ_THRESHOLD:
result.append(
Web3.to_checksum_address(data['address']),
)
return result


async def graph_ostoken_exit_requests(
ltv: int, block_number: BlockNumber
ltv: float, block_number: BlockNumber
) -> list[OsTokenExitRequest]:
query = gql(
"""
Expand Down Expand Up @@ -125,10 +142,13 @@ async def graph_ostoken_exit_requests(
exit_requests = await graph_get_exit_requests(
ids=[item['id'] for item in response], block_number=block_number
)
id_to_exit_request = {exit.id: exit for exit in exit_requests}
id_to_exit_request = {exit_req.id: exit_req for exit_req in exit_requests}

result = []
for data in response:
if NETWORK == HOLESKY and data['id'] in HOLESKY_UNCLAIMABLE_EXIT_REQUEST_IDS:
continue

result.append(
OsTokenExitRequest(
id=data['id'],
Expand Down
30 changes: 17 additions & 13 deletions src/exit/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,29 @@ async def handle_leverage_positions(block_number: BlockNumber) -> None:
borrow_ltv = strategy_registry_contract.get_borrow_ltv_percent(strategy_id) / WAD
vault_ltv = strategy_registry_contract.get_vault_ltv_percent(strategy_id) / WAD
all_leverage_positions = await graph_get_leverage_positions(block_number=block_number)
# Get positions by borrow ltv
borrow_ltv_positions = [pos for pos in all_leverage_positions if pos.borrow_ltv > borrow_ltv]
# Get vault position by vault ltv
# Get aave positions by borrow ltv
aave_positions = [pos for pos in all_leverage_positions if pos.borrow_ltv > borrow_ltv]
# Get vault positions by vault ltv
proxy_to_position = {position.proxy: position for position in all_leverage_positions}
allocators = await graph_get_allocators(
ltv=vault_ltv, addresses=list(proxy_to_position.keys()), block_number=block_number
)
leverage_positions_by_ltv = []
vault_positions = []
for allocator in allocators:
leverage_positions_by_ltv.append(proxy_to_position[allocator])
vault_positions.append(proxy_to_position[allocator])

# join positions
leverage_positions = []
leverage_positions.extend(borrow_ltv_positions)
borrow_ltv_positions_ids = [pos.id for pos in borrow_ltv_positions]
for position in leverage_positions_by_ltv:
leverage_positions.extend(aave_positions)
borrow_ltv_positions_ids = set(pos.id for pos in aave_positions)
for position in vault_positions:
if position.id not in borrow_ltv_positions_ids:
leverage_positions.append(position)

if not leverage_positions:
logger.info('No risky leverage positions found...')
return

logger.info('Checking %d leverage positions...', len(leverage_positions))

vault_to_harvest_params: dict[ChecksumAddress, HarvestParams | None] = {}
Expand All @@ -88,7 +92,7 @@ async def handle_ostoken_exit_requests(block_number: BlockNumber) -> None:
"""Process osTokenExitRequests from graph and claim exited assets."""
# force claim for exit positions
max_ltv_percent = ostoken_vault_escrow_contract.liq_threshold_percent()
max_ltv_percent = max_ltv_percent // WAD
max_ltv_percent = max_ltv_percent / WAD
exit_requests = await graph_ostoken_exit_requests(max_ltv_percent, block_number=block_number)
exit_requests = [
exit_request for exit_request in exit_requests if exit_request.exit_request.can_be_claimed
Expand Down Expand Up @@ -128,8 +132,8 @@ def handle_leverage_position(
position: LeveragePosition, harvest_params: HarvestParams | None, block_number: BlockNumber
) -> None:
"""
Submit force exit for leverage postion.
Also check for position active exit request and claim assets is possible.
Submit force exit for leverage position.
Also check for position active exit request and claim assets if possible.
"""
if not can_force_enter_exit_queue(
vault=position.vault,
Expand All @@ -138,7 +142,7 @@ def handle_leverage_position(
block_number=block_number,
):
logger.info(
'Skip leverage positions because it can\'t be forcefully closed: vault=%s, user=%s...',
'Skip leverage positions because it cannot be forcefully closed: vault=%s, user=%s...',
position.vault,
position.user,
)
Expand Down Expand Up @@ -180,7 +184,7 @@ def handle_leverage_position(
block_number=block_number,
):
logger.info(
'Skip leverage positions because it can\'t be forcefully closed: vault=%s, user=%s...',
'Skip leverage positions because it cannot be forcefully closed: vault=%s, user=%s...',
position.vault,
position.user,
)
Expand Down

0 comments on commit fa4d5c6

Please sign in to comment.