Skip to content

Commit

Permalink
Claim exited assets
Browse files Browse the repository at this point in the history
  • Loading branch information
cyc60 committed Dec 5, 2024
1 parent 3d64257 commit dd43535
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 7 deletions.
33 changes: 26 additions & 7 deletions src/exit/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from web3.types import BlockNumber, ChecksumAddress, Wei

from .clients import graph_client
from .typings import LeveragePosition, OsTokenExitRequest
from .typings import ExitRequest, LeveragePosition, OsTokenExitRequest


def graph_get_leverage_positions(
Expand All @@ -23,6 +23,14 @@ def graph_get_leverage_positions(
vault {
id
}
exitRequest {
positionTicket
timestamp
exitQueueIndex
isClaimable
exitedAssets
totalAssets
}
}
}
"""
Expand All @@ -31,13 +39,24 @@ def graph_get_leverage_positions(
response = graph_client.execute(query, params)
result = []
for data in response['leverageStrategyPositions']: # pylint: disable=unsubscriptable-object
result.append(
LeveragePosition(
vault=Web3.to_checksum_address(data['vault']['id']),
user=Web3.to_checksum_address(data['user']),
proxy=Web3.to_checksum_address(data['proxy']),
)
position = LeveragePosition(
vault=Web3.to_checksum_address(data['vault']['id']),
user=Web3.to_checksum_address(data['user']),
proxy=Web3.to_checksum_address(data['proxy']),
)
if data['exitRequest']:
request_data = data['exitRequest']
exit_request = ExitRequest(
position_ticket=request_data['positionTicket'],
timestamp=request_data['timestamp'],
exit_queue_index=request_data['exitQueueIndex'],
is_claimable=request_data['isClaimable'],
exited_assets=request_data['exitedAssets'],
total_assets=request_data['totalAssets'],
)
position.exit_request = exit_request

result.append(position)
return result


Expand Down
85 changes: 85 additions & 0 deletions src/exit/tasks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from typing import cast

from eth_typing import ChecksumAddress, HexStr
from web3 import Web3
Expand All @@ -23,6 +24,7 @@
graph_get_leverage_positions,
graph_ostoken_exit_requests,
)
from .typings import ExitRequest, LeveragePosition

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -67,6 +69,26 @@ def handle_leverage_postions(block_number: BlockNumber) -> None:
harvest_params=harvest_params,
block_number=block_number,
):
# claim active exit request
if position.exit_request and position.exit_request.can_be_claimed:
logger.info(
'Claiming exited assets for leverage positions: vault=%s, user=%s...',
position.vault,
position.user,
)
tx_hash = claim_exited_assets(
position=position,
harvest_params=harvest_params,
block_number=block_number,
)
if tx_hash:
logger.info(
'Successfully claimed exited assets for leverage positions: vault=%s, user=%s...',
position.vault,
position.user,
)
else:
continue
logger.info(
'Force exiting leverage positions: vault=%s, user=%s...',
position.vault,
Expand Down Expand Up @@ -104,6 +126,26 @@ def handle_leverage_postions(block_number: BlockNumber) -> None:
harvest_params=harvest_params,
block_number=block_number,
):
# claim active exit request
if position.exit_request and position.exit_request.can_be_claimed:
logger.info(
'Claiming exited assets for leverage positions: vault=%s, user=%s...',
position.vault,
position.user,
)
tx_hash = claim_exited_assets(
position=position,
harvest_params=harvest_params,
block_number=block_number,
)
if tx_hash:
logger.info(
'Successfully claimed exited assets for leverage positions: vault=%s, user=%s...',
position.vault,
position.user,
)
else:
continue
logger.info(
'Force exiting leverage positions: vault=%s, user=%s...',
position.vault,
Expand Down Expand Up @@ -189,6 +231,49 @@ def can_force_enter_exit_queue(
return bool(Web3.to_int(response.pop(0)))


def claim_exited_assets(
position: LeveragePosition,
harvest_params: HarvestParams | None,
block_number: BlockNumber,
) -> HexStr | None:
vault = position.vault
vault_contract = get_vault_contract(vault)
calls = []
if harvest_params and keeper_contract.can_harvest(vault, block_number):
update_state_call = (
vault,
_encode_update_state_call(vault_contract, harvest_params),
)
calls.append(update_state_call)

exit_request = position.exit_request
exit_request = cast(ExitRequest, exit_request)
claim_call = vault_contract.encode_abi(
fn_name='claimExitedAssets',
args=[exit_request.position_ticket, exit_request.timestamp, exit_request.exit_queue_index],
)
calls.append((vault_contract.address, claim_call))
try:
tx = multicall_contract.functions.aggregate(calls).transact()
except Exception as e:
logger.error(
'Failed to claim exited assets; vault=%s, user=%s %s: ', vault, position.user, e
)
logger.exception(e)
return None

tx_hash = Web3.to_hex(tx)
logger.info('Waiting for transaction %s confirmation', tx_hash)
tx_receipt = execution_client.eth.wait_for_transaction_receipt(
tx, timeout=EXECUTION_TRANSACTION_TIMEOUT
)
if not tx_receipt['status']:
logger.error('Exited assets claim transaction failed')
return None

return tx_hash


def _force_enter_exit_queue(vault: ChecksumAddress, user: ChecksumAddress) -> HexStr | None:
try:
tx = leverage_strategy_contract.force_enter_exit_queue(
Expand Down
15 changes: 15 additions & 0 deletions src/exit/typings.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,26 @@
from web3.types import ChecksumAddress, Wei


@dataclass
class ExitRequest:
position_ticket: int
timestamp: int
exit_queue_index: int
is_claimable: bool
exited_assets: Wei
total_assets: Wei

@property
def can_be_claimed(self) -> bool:
return self.is_claimable and self.exited_assets == self.total_assets


@dataclass
class LeveragePosition:
user: ChecksumAddress
vault: ChecksumAddress
proxy: ChecksumAddress
exit_request: ExitRequest | None = None


@dataclass
Expand Down

0 comments on commit dd43535

Please sign in to comment.