Skip to content

Commit

Permalink
Merge pull request #339 from djeck1432/feat/is-opened-position
Browse files Browse the repository at this point in the history
Feat/is opened position
  • Loading branch information
djeck1432 authored Dec 10, 2024
2 parents b929e28 + 0e43356 commit e4feca3
Show file tree
Hide file tree
Showing 29 changed files with 157 additions and 991 deletions.
2 changes: 1 addition & 1 deletion frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const CONTRACT_ADDRESS = '0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf';
export const CLASS_HASH = '0x031ae5768dced8a123907259d946edec39afa08073277abb3e55be8daa8fe49d';
export const CLASS_HASH = '0x035ae0fe6ca00fcc8020a6c64503f38bfaf3481ae9a6c8b7daec2f899df735fa';
export const UNIQUE = '0x0';
export const EKUBO_ADDRESS = '0x00000005dd3d2f4429af886cd1a3b08289dbcea99a294197e9eb43b0e0325b4b';
export const ZKLEND_ADDRESS = '0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05';
Expand Down
17 changes: 0 additions & 17 deletions spotnet_tracker/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import time

from web_app.contract_tools.mixins.alert import AlertMixin
from web_app.tasks.claim_airdrops import AirdropClaimer

from .celery_config import app

Expand All @@ -33,19 +32,3 @@ def check_users_health_ratio() -> None:
except Exception as e:
logger.error(f"Error in check_users_health_ratio task: {e}")


@app.task(name="claim_airdrop_task")
def claim_airdrop_task() -> None:
"""
Background task to claim user airdrops.
:return: None
"""
try:
logger.info("Running claim_airdrop_task.")
logger.info("Task started at: ",time.strftime("%a, %d %b %Y %H:%M:%S"))
airdrop_claimer = AirdropClaimer()
asyncio.run(airdrop_claimer.claim_airdrops())
logger.info("Task started at: ", time.strftime("%a, %d %b %Y %H:%M:%S"))
except Exception as e:
logger.error(f"Error in claiming airdrop task: {e}")
41 changes: 41 additions & 0 deletions web_app/alembic/versions/b6eaae01419c_remove_airdrop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""remove_airdrop
Revision ID: b6eaae01419c
Revises: cda4342b007d
Create Date: 2024-12-10 19:37:04.898405
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision = 'b6eaae01419c'
down_revision = 'cda4342b007d'
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index('ix_airdrop_is_claimed', table_name='airdrop')
op.drop_index('ix_airdrop_user_id', table_name='airdrop')
op.drop_table('airdrop')
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('airdrop',
sa.Column('id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('user_id', sa.UUID(), autoincrement=False, nullable=False),
sa.Column('created_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=False),
sa.Column('amount', sa.NUMERIC(), autoincrement=False, nullable=True),
sa.Column('is_claimed', sa.BOOLEAN(), autoincrement=False, nullable=True),
sa.Column('claimed_at', postgresql.TIMESTAMP(), autoincrement=False, nullable=True),
sa.ForeignKeyConstraint(['user_id'], ['user.id'], name='airdrop_user_id_fkey'),
sa.PrimaryKeyConstraint('id', name='airdrop_pkey')
)
op.create_index('ix_airdrop_user_id', 'airdrop', ['user_id'], unique=False)
op.create_index('ix_airdrop_is_claimed', 'airdrop', ['is_claimed'], unique=False)
# ### end Alembic commands ###
6 changes: 4 additions & 2 deletions web_app/api/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from web_app.api.serializers.dashboard import DashboardResponse
from web_app.contract_tools.mixins import DashboardMixin, HealthRatioMixin
from web_app.db.crud import PositionDBConnector
from decimal import Decimal
from decimal import Decimal, DivisionByZero

router = APIRouter()
position_db_connector = PositionDBConnector()
Expand Down Expand Up @@ -59,12 +59,14 @@ async def get_dashboard(wallet_id: str) -> DashboardResponse:
if opened_positions
else collections.defaultdict(lambda: None)
)
if not first_opened_position:
return default_dashboard_response
try:
# Fetch zkLend position for the wallet ID
health_ratio, tvl = await HealthRatioMixin.get_health_ratio_and_tvl(
contract_address
)
except IndexError:
except (IndexError, DivisionByZero) as e:
return default_dashboard_response

position_multiplier = first_opened_position["multiplier"]
Expand Down
19 changes: 8 additions & 11 deletions web_app/api/position.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
TokenMultipliers,
)
from web_app.api.serializers.position import TokenMultiplierResponse
from web_app.contract_tools.mixins.deposit import DepositMixin
from web_app.contract_tools.mixins.dashboard import DashboardMixin
from web_app.contract_tools.mixins import DepositMixin, DashboardMixin, PositionMixin
from web_app.db.crud import PositionDBConnector

router = APIRouter() # Initialize the router
Expand Down Expand Up @@ -106,19 +105,17 @@ async def get_repay_data(
:return: Dict containing the repay transaction data
:raises: HTTPException :return: Dict containing status code and detail
"""
# TODO rework it too many requests to DB
if not wallet_id:
raise HTTPException(status_code=404, detail="Wallet not found")

contract_address = position_db_connector.get_contract_address_by_wallet_id(
wallet_id
)
position_id = position_db_connector.get_position_id_by_wallet_id(wallet_id)
position = position_db_connector.get_position_by_id(position_id)
if not position:
raise HTTPException(status_code=404, detail="Position not found")
contract_address, position_id, token_symbol = position_db_connector.get_repay_data(wallet_id)
is_opened_position = await PositionMixin.is_opened_position(contract_address)
if not is_opened_position:
raise HTTPException(status_code=400, detail="Position was closed")
if not position_id:
raise HTTPException(status_code=404, detail="Position not found or closed")

repay_data = await DepositMixin.get_repay_data(position.token_symbol)
repay_data = await DepositMixin.get_repay_data(token_symbol)
repay_data["contract_address"] = contract_address
repay_data["position_id"] = str(position_id)
return repay_data
Expand Down
21 changes: 0 additions & 21 deletions web_app/api/serializers/airdrop.py

This file was deleted.

6 changes: 4 additions & 2 deletions web_app/api/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
UpdateUserContractResponse,
UserHistoryResponse,
)
from web_app.contract_tools.mixins.dashboard import DashboardMixin
from web_app.contract_tools.mixins import PositionMixin, DashboardMixin
from web_app.db.crud import (
PositionDBConnector,
TelegramUserDBConnector,
Expand Down Expand Up @@ -45,7 +45,9 @@ async def has_user_opened_position(wallet_id: str) -> dict:
"""
try:
has_position = position_db.has_opened_position(wallet_id)
return {"has_opened_position": has_position}
contract_address = user_db.get_contract_address_by_wallet_id(wallet_id)
is_position_opened = await PositionMixin.is_opened_position(contract_address)
return {"has_opened_position": has_position or is_position_opened}
except ValueError as e:
raise HTTPException(
status_code=404, detail=f"Invalid wallet ID format: {str(e)}"
Expand Down
73 changes: 0 additions & 73 deletions web_app/contract_tools/airdrop.py

This file was deleted.

13 changes: 13 additions & 0 deletions web_app/contract_tools/blockchain_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,3 +325,16 @@ async def claim_airdrop(self, contract_address: str, proofs: list[str]) -> None:
selector="claim",
calldata=proofs,
)

async def is_opened_position(self, contract_address: str) -> bool:
"""
Checks if a position is opened on the Starknet blockchain.
:param contract_address: The contract address.
:return: A boolean indicating if the position is opened.
"""
return await self._func_call(
addr=self._convert_address(contract_address),
selector="is_position_open",
calldata=[],
)
8 changes: 8 additions & 0 deletions web_app/contract_tools/mixins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
Import all mixins here to make them available
to the rest of the application.
"""

from .dashboard import DashboardMixin
from .health_ratio import HealthRatioMixin
from .deposit import DepositMixin
from .alert import AlertMixin
from .position import PositionMixin
from web_app.contract_tools.blockchain_call import (
StarknetClient,
)


CLIENT = StarknetClient()
1 change: 1 addition & 0 deletions web_app/contract_tools/mixins/alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from web_app.contract_tools.mixins import HealthRatioMixin
from web_app.db.crud import UserDBConnector


logger = logging.getLogger(__name__)
ALERT_THRESHOLD = 3.2 # FIXME return to 1.1 after testing

Expand Down
22 changes: 5 additions & 17 deletions web_app/contract_tools/mixins/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
from typing import Dict
from decimal import Decimal

from web_app.contract_tools.blockchain_call import StarknetClient

from web_app.contract_tools.constants import TokenParams, MULTIPLIER_POWER
from web_app.contract_tools.api_request import APIRequest
from web_app.api.serializers.dashboard import DashboardResponse

logger = logging.getLogger(__name__)


CLIENT = StarknetClient()
# example of ARGENT_X_POSITION_URL
# "https://cloud.argent-api.com/v1/tokens/defi/decomposition/{wallet_id}?chain=starknet"
ARGENT_X_POSITION_URL = "https://cloud.argent-api.com/v1/tokens/defi/"
Expand Down Expand Up @@ -67,6 +65,8 @@ async def get_wallet_balances(cls, holder_address: str) -> Dict[str, str]:
:param holder_address: holder address
:return: Returns the wallet balances for the given holder address.
"""
from . import CLIENT

wallet_balances = {}

for token in TokenParams.tokens():
Expand All @@ -84,18 +84,6 @@ async def get_wallet_balances(cls, holder_address: str) -> Dict[str, str]:

return wallet_balances

@classmethod
async def get_zklend_position(
cls, contract_address: str, position: "Position"
) -> DashboardResponse:
"""
Get the zkLend position for the given wallet ID.
:param contract_address: contract address
:param position: Position db model
:return: zkLend position validated by Pydantic models
"""
pass

@classmethod
def _get_products(cls, dapps: list) -> list[dict]:
"""
Expand Down Expand Up @@ -133,8 +121,8 @@ async def get_current_position_sum(cls, position: dict) -> Decimal:
"""
current_prices = await cls.get_current_prices()
price = current_prices.get(position.get("token_symbol"), Decimal(0))
amount = Decimal(position.get("amount", 0))
multiplier = Decimal(position.get("multiplier", 0))
amount = Decimal(position.get("amount", 0) or 0)
multiplier = Decimal(position.get("multiplier", 0) or 0)
return cls._calculate_sum(price, amount, multiplier)

@classmethod
Expand Down
13 changes: 10 additions & 3 deletions web_app/contract_tools/mixins/deposit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
"""

from decimal import Decimal
from web_app.contract_tools.blockchain_call import StarknetClient
from web_app.contract_tools.constants import TokenParams

CLIENT = StarknetClient()

# alternative ARGENT_X_POSITION_URL
# "https://cloud.argent-api.com/v1/tokens/defi/decomposition/{wallet_id}?chain=starknet"
ARGENT_X_POSITION_URL = "https://cloud.argent-api.com/v1/tokens/defi/"
Expand Down Expand Up @@ -35,6 +34,8 @@ async def get_transaction_data(
:param borrowing_token: Borrowing token
:return: approve_data and loop_liquidity_data
"""
from . import CLIENT

deposit_token_address = TokenParams.get_token_address(deposit_token)
decimal = TokenParams.get_token_decimals(deposit_token_address)
amount = int(Decimal(amount) * 10**decimal)
Expand All @@ -52,8 +53,14 @@ async def get_repay_data(cls, supply_token: str) -> dict:
:param supply_token: Deposit token
:return: dict with repay data
"""
from . import CLIENT

deposit_token_address = TokenParams.get_token_address(supply_token)
debt_token_address = TokenParams.get_token_address("USDC") if supply_token != "USDC" else TokenParams.get_token_address("ETH")
debt_token_address = (
TokenParams.get_token_address("USDC")
if supply_token != "USDC"
else TokenParams.get_token_address("ETH")
)
repay_data = {
"supply_token": deposit_token_address,
"debt_token": debt_token_address,
Expand Down
Loading

0 comments on commit e4feca3

Please sign in to comment.