|
| 1 | +from decimal import Decimal |
| 2 | +from typing import List |
| 3 | +import time |
| 4 | +from datetime import datetime |
| 5 | + |
| 6 | + |
| 7 | +class LimitOrderAsset: |
| 8 | + def __init__(self, symbol: str): |
| 9 | + self.symbol = symbol |
| 10 | + |
| 11 | + def validate(self): |
| 12 | + # Ensure symbol is not empty |
| 13 | + assert self.symbol, "Symbol must not be empty" |
| 14 | + |
| 15 | +class LimitOrder: |
| 16 | + def __init__(self, tick_id: int, order_id: int, order_direction: str, owner: str, quantity: str, etas: str, |
| 17 | + claim_bounty: str, placed_quantity: str, placed_at: int, price: str, percentClaimed: str, |
| 18 | + totalFilled: str, percentFilled: str, orderbookAddress: str, status: str, output: str, |
| 19 | + quote_asset: dict, base_asset: dict): |
| 20 | + self.tick_id = int(tick_id) |
| 21 | + self.order_id = int(order_id) |
| 22 | + self.order_direction = order_direction |
| 23 | + self.owner = owner |
| 24 | + self.quantity = Decimal(quantity) |
| 25 | + self.etas = Decimal(etas) |
| 26 | + self.claim_bounty = Decimal(claim_bounty) |
| 27 | + self.placed_quantity = Decimal(placed_quantity) |
| 28 | + self.placed_at = int(placed_at) |
| 29 | + self.price = Decimal(price) |
| 30 | + self.percent_claimed = Decimal(percentClaimed) # Changed variable name |
| 31 | + self.total_filled = Decimal(totalFilled) |
| 32 | + self.percent_filled = Decimal(percentFilled) |
| 33 | + self.orderbook_address = orderbookAddress |
| 34 | + self.status = status |
| 35 | + self.output = Decimal(output) |
| 36 | + self.quote_asset = LimitOrderAsset(**quote_asset) |
| 37 | + self.base_asset = LimitOrderAsset(**base_asset) |
| 38 | + |
| 39 | + def validate(self, owner_address=None): |
| 40 | + # Check if order_id is non-negative |
| 41 | + assert self.order_id >= 0, f"Order ID {self.order_id} cannot be negative" |
| 42 | + |
| 43 | + # Check if order_direction is either "bid" or "ask" |
| 44 | + assert self.order_direction in ['bid', 'ask'], f"Order direction {self.order_direction} must be 'bid' or 'ask'" |
| 45 | + |
| 46 | + # Validate owner address (Osmosis address format) |
| 47 | + assert self.owner == owner_address, f"Owner address {self.owner} is invalid" |
| 48 | + |
| 49 | + # Check if quantity is non-negative |
| 50 | + assert self.quantity > 0, f"Quantity {self.quantity} cannot be negative" |
| 51 | + |
| 52 | + # Check if claim_bounty is non-negative |
| 53 | + assert self.claim_bounty > 0, f"Claim bounty {self.claim_bounty} cannot be negative" |
| 54 | + |
| 55 | + # Validate placed_quantity is non-negative |
| 56 | + assert self.placed_quantity > 0, f"Placed quantity {self.placed_quantity} cannot be negative" |
| 57 | + |
| 58 | + # Validate placed_at is a valid Unix timestamp |
| 59 | + assert 0 <= self.placed_at <= int(time.time()), f"Placed_at timestamp {self.placed_at} is invalid" |
| 60 | + |
| 61 | + # Check if price is positive |
| 62 | + assert self.price > 0, f"Price {self.price} must be positive" |
| 63 | + |
| 64 | + # Check if percent_claimed is between 0 and 100 |
| 65 | + assert 0 <= self.percent_claimed <= 100, f"Percent claimed {self.percent_claimed} must be between 0 and 100" |
| 66 | + |
| 67 | + # Check if total_filled is non-negative |
| 68 | + assert self.total_filled >= 0, f"Total filled {self.total_filled} cannot be negative" |
| 69 | + |
| 70 | + # Check if percent_filled is between 0 and 100 |
| 71 | + assert 0 <= self.percent_filled <= 100, f"Percent filled {self.percent_filled} must be between 0 and 100" |
| 72 | + |
| 73 | + # Ensure status is not empty |
| 74 | + assert self.status, "Status must not be empty" |
| 75 | + |
| 76 | + # Ensure orderbook_address is not empty |
| 77 | + assert self.orderbook_address, "Orderbook address must not be empty" |
| 78 | + |
| 79 | + # Check if output is non-negative |
| 80 | + assert self.output >= 0, f"Output {self.output} cannot be negative" |
| 81 | + |
| 82 | + # Validate quote_asset |
| 83 | + self.quote_asset.validate() |
| 84 | + |
| 85 | + # Validate base_asset |
| 86 | + self.base_asset.validate() |
| 87 | + |
| 88 | + @staticmethod |
| 89 | + def _is_valid_unix_timestamp(timestamp): |
| 90 | + try: |
| 91 | + datetime.utcfromtimestamp(int(timestamp)) |
| 92 | + return True |
| 93 | + except (ValueError, OverflowError): |
| 94 | + return False |
| 95 | + |
| 96 | + |
| 97 | +class OrderbookActiveOrdersResponse: |
| 98 | + def __init__(self, orders: List[dict], is_best_effort: bool): |
| 99 | + self.orders = [LimitOrder(**order) for order in orders] |
| 100 | + self.is_best_effort = is_best_effort |
| 101 | + |
| 102 | + def validate(self, owner_address): |
| 103 | + # Validate each order |
| 104 | + order_ids = set() |
| 105 | + for order in self.orders: |
| 106 | + order.validate(owner_address) |
| 107 | + |
| 108 | + # Ensure order_id is unique |
| 109 | + if order.order_id in order_ids: |
| 110 | + raise ValueError(f"Duplicate order_id found: {order.order_id}") |
| 111 | + order_ids.add(order.order_id) |
0 commit comments