# -*- coding: utf-8 -*-

# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code

from ccxt.base.exchange import Exchange
from ccxt.abstract.aftermath import ImplicitAPI
from ccxt.base.types import Account, Any, Balances, Currencies, Currency, Int, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Trade, TradingFeeInterface, Transaction, TransferEntry
from typing import List
from ccxt.base.errors import ExchangeError
from ccxt.base.errors import ArgumentsRequired
from ccxt.base.errors import NotSupported
from ccxt.base.decimal_to_precision import TICK_SIZE


class aftermath(Exchange, ImplicitAPI):

    def describe(self) -> Any:
        return self.deep_extend(super(aftermath, self).describe(), {
            'id': 'aftermath',
            'name': 'AftermathFinance',
            'countries': [],
            'version': 'v1',
            'rateLimit': 50,  # 1200 requests per minute, 20 request per second
            'certified': False,
            'pro': True,
            'dex': True,
            'has': {
                'CORS': None,
                'spot': False,
                'margin': False,
                'swap': True,
                'future': False,
                'option': False,
                'addMargin': True,
                'cancelOrder': True,
                'cancelOrders': True,
                'createOrder': True,
                'createOrders': True,
                'editOrder': False,
                'fetchAccounts': True,
                'fetchBalance': True,
                'fetchCurrencies': True,
                'fetchDepositAddress': False,
                'fetchDeposits': False,
                'fetchLedger': False,
                'fetchMarkets': True,
                'fetchMyTrades': False,
                'fetchOHLCV': True,
                'fetchOpenOrders': True,
                'fetchOrder': False,
                'fetchOrderBook': True,
                'fetchOrders': False,
                'fetchPosition': True,
                'fetchPositions': True,
                'fetchTicker': True,
                'fetchTickers': True,
                'fetchTrades': True,
                'fetchTradingFee': True,
                'fetchTradingFees': False,
                'fetchTradingLimits': False,
                'fetchTransactions': False,
                'fetchWithdrawals': False,
                'reduceMargin': True,
                'setLeverage': True,
                'transfer': True,
                'withdraw': True,
            },
            'timeframes': {
                '1m': '1m',
                '3m': '3m',
                '5m': '5m',
                '15m': '15m',
                '30m': '30m',
                '1h': '1h',
                '2h': '2h',
                '4h': '4h',
                '8h': '8h',
                '12h': '12h',
                '1d': '1d',
                '3d': '3d',
                '1w': '1w',
                '1M': '1M',
            },
            'urls': {
                'logo': 'https://github.com/user-attachments/assets/70e5ae86-2f3a-4755-976b-aedb9d3c2807',
                'api': {
                    'rest': 'https://aftermath.finance/api/ccxt',
                },
                'test': {
                    'rest': 'https://testnet.aftermath.finance/api/ccxt',
                },
                'docs': 'https://docs.aftermath.finance',
            },
            'api': {
                'public': {
                    'get': {
                        'markets': 1,
                        'currencies': 1,
                    },
                    'post': {
                        'ticker': 1,
                        'orderbook': 1,
                        'trades': 1,
                        'OHLCV': 1,
                    },
                },
                'private': {
                    'post': {
                        'accounts': 1,
                        'balance': 1,
                        'myPendingOrders': 1,
                        'positions': 1,
                        'build/allocate': 1,
                        'build/cancelOrders': 1,
                        'build/createAccount': 1,
                        'build/createOrders': 1,
                        'build/deallocate': 1,
                        'build/deposit': 1,
                        'build/setLeverage': 1,
                        'build/withdraw': 1,
                        'submit/allocate': 1,
                        'submit/cancelOrders': 1,
                        'submit/createAccount': 1,
                        'submit/createOrders': 1,
                        'submit/deallocate': 1,
                        'submit/deposit': 1,
                        'submit/setLeverage': 1,
                        'submit/withdraw': 1,
                    },
                },
            },
            'requiredCredentials': {
                'apiKey': False,
                'secret': False,
                'walletAddress': True,
                'privateKey': True,
            },
            'precisionMode': TICK_SIZE,
            'options': {
                'defaultType': 'swap',
                'sandboxMode': False,
            },
            'exceptions': {
                'exact': {},
                'broad': {},
            },
            'features': {
                'default': {
                    'sandbox': True,
                    'createOrder': {
                        'timeInForce': {
                            'IOC': True,
                            'FOK': True,
                            'PO': True,
                            'GTD': False,
                        },
                        'leverage': False,
                        'marketBuyRequiresPrice': False,
                        'marketBuyByCost': False,
                        'selfTradePrevention': False,
                        'trailing': False,
                        'iceberg': False,
                    },
                },
            },
        })

    def fetch_currencies(self, params={}) -> Currencies:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/currencies

        fetches all available currencies on an exchange
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: an associative dictionary of currencies
        """
        response = self.publicGetCurrencies(params)
        currencies = self.parse_currencies(response)
        #
        # {
        #     "BTC": {
        #         "id": "BTC",
        #         "code": "BTC",
        #         "precision": 1e-9,
        #         "name": "BTC",
        #         "active": True,
        #         "deposit": False,
        #         "withdraw": False,
        #         "limits": {
        #             "amount": {},
        #             "withdraw": {}
        #         },
        #         "networks": {}
        #     }
        # }
        #
        return currencies

    def parse_currency(self, rawCurrency: dict) -> Currency:
        return self.safe_currency_structure({
            'id': self.safe_string(rawCurrency, 'id'),
            'code': self.safe_string(rawCurrency, 'code'),
            'name': self.safe_string(rawCurrency, 'name'),
            'active': self.safe_bool(rawCurrency, 'active'),
            'deposit': self.safe_bool(rawCurrency, 'deposit'),
            'withdraw': self.safe_bool(rawCurrency, 'withdraw'),
            'precision': self.safe_number(rawCurrency, 'precision'),
            'type': 'crypto',
            'info': rawCurrency,
        })

    def fetch_markets(self, params={}) -> List[Market]:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/markets

        retrieves data on all markets for woo
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict[]: an array of objects representing market data
        """
        response = self.publicGetMarkets(params)
        #
        # [
        #     {
        #         "id": "0x49bd40cc7880bd358465116157f0271c25d23361b94eace9a25dc2019b449bfc",
        #         "symbol": "BTC/USD:USDC",
        #         "base": "BTC",
        #         "quote": "USD",
        #         "baseId": "BTC",
        #         "quoteId": "USD",
        #         "active": True,
        #         "type": "swap",
        #         "spot": False,
        #         "margin": False,
        #         "swap": True,
        #         "future": False,
        #         "option": False,
        #         "contract": True,
        #         "settle": "USDC",
        #         "settleId": "0x457049371f5b5dc2bda857bb804ca6e93c5a3cae1636d0cd17bb6b6070d19458::usdc::USDC",
        #         "contractSize": 0.00001,
        #         "linear": True,
        #         "inverse": False,
        #         "taker": 0.001,
        #         "maker": 0.0,
        #         "percentage": True,
        #         "tierBased": False,
        #         "precision": {
        #             "amount": 0.00001,
        #             "price": 0.0001
        #         },
        #         "limits": {
        #             "cost": {
        #                 "min": 1.0
        #             },
        #             "leverage": {
        #                 "max": 50.0
        #             }
        #         },
        #         "marginModes": {
        #             "isolated": True,
        #             "cross": False
        #         },
        #         "subType": "linear"
        #     }
        # ]
        #
        return self.parse_markets(response)

    def parse_market(self, market: dict) -> Market:
        #
        #     {
        #         "id": "0x49bd40cc7880bd358465116157f0271c25d23361b94eace9a25dc2019b449bfc",
        #         "symbol": "BTC/USD:USDC",
        #         "base": "BTC",
        #         "quote": "USD",
        #         "baseId": "BTC",
        #         "quoteId": "USD",
        #         "active": True,
        #         "type": "swap",
        #         "spot": False,
        #         "margin": False,
        #         "swap": True,
        #         "future": False,
        #         "option": False,
        #         "contract": True,
        #         "settle": "USDC",
        #         "settleId": "0x457049371f5b5dc2bda857bb804ca6e93c5a3cae1636d0cd17bb6b6070d19458::usdc::USDC",
        #         "contractSize": 0.00001,
        #         "linear": True,
        #         "inverse": False,
        #         "taker": 0.001,
        #         "maker": 0.0,
        #         "percentage": True,
        #         "tierBased": False,
        #         "precision": {
        #             "amount": 0.00001,
        #             "price": 0.0001
        #         },
        #         "limits": {
        #             "cost": {
        #                 "min": 1.0
        #             },
        #             "leverage": {
        #                 "max": 50.0
        #             }
        #         },
        #         "marginModes": {
        #             "isolated": True,
        #             "cross": False
        #         },
        #         "subType": "linear"
        #     }
        #
        precision = self.safe_dict(market, 'precision')
        limits = self.safe_dict(market, 'limits')
        return self.safe_market_structure({
            'id': self.safe_string(market, 'id'),
            'symbol': self.safe_string(market, 'symbol'),
            'base': self.safe_string(market, 'base'),
            'quote': self.safe_string(market, 'quote'),
            'settle': self.safe_string(market, 'settle'),
            'baseId': self.safe_string(market, 'baseId'),
            'quoteId': self.safe_string(market, 'quoteId'),
            'settleId': self.safe_string(market, 'settleId'),
            'type': self.safe_string(market, 'type'),
            'subType': self.safe_string(market, 'subType'),
            'spot': self.safe_bool(market, 'spot'),
            'margin': self.safe_bool(market, 'margin'),
            'swap': self.safe_bool(market, 'swap'),
            'future': self.safe_bool(market, 'future'),
            'option': self.safe_bool(market, 'option'),
            'active': self.safe_bool(market, 'active'),
            'contract': self.safe_bool(market, 'contract'),
            'linear': self.safe_bool(market, 'linear'),
            'inverse': self.safe_bool(market, 'inverse'),
            'tierBased': self.safe_bool(market, 'tierBased'),
            'percentage': self.safe_bool(market, 'percentage'),
            'contractSize': self.safe_number(market, 'contractSize'),
            'expiry': None,
            'expiryDatetime': None,
            'strike': None,
            'optionType': None,
            'taker': self.safe_number(market, 'taker'),
            'maker': self.safe_number(market, 'maker'),
            'precision': {
                'amount': self.safe_number(precision, 'amount'),
                'price': self.safe_number(precision, 'price'),
            },
            'limits': {
                'leverage': {
                    'min': None,
                    'max': self.safe_number(limits['leverage'], 'max'),
                },
                'amount': {
                    'min': None,
                    'max': None,
                },
                'price': {
                    'min': None,
                    'max': None,
                },
                'cost': {
                    'min': self.safe_number(limits['cost'], 'min'),
                    'max': None,
                },
            },
            'marginModes': self.safe_dict(market, 'marginModes'),
            'created': None,
            'info': market,
        })

    def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/markets

        fetch the trading fees for a market
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `fee structure <https://docs.ccxt.com/?id=fee-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        return self.parse_trading_fee(market)

    def parse_trading_fee(self, market: Market = None) -> TradingFeeInterface:
        symbol = self.safe_string(market, 'symbol')
        return {
            'info': market,
            'symbol': symbol,
            'maker': self.safe_number(market, 'maker'),
            'taker': self.safe_number(market, 'taker'),
            'percentage': True,
            'tierBased': None,
        }

    def fetch_ticker(self, symbol: str, params={}) -> Ticker:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/ticker

        fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
        :param str symbol: unified symbol of the market to fetch the ticker for
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `ticker structure <https://docs.ccxt.com/?id=ticker-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        request = {
            'chId': market['id'],
        }
        response = self.publicPostTicker(self.extend(request, params))
        #
        # {
        #     "ask": 0.1,
        #     "askVolume": 0.1,
        #     "average": 0.1,
        #     "baseVolume": 0.1,
        #     "bid": 0.1,
        #     "bidVolume": 0.1,
        #     "change": 0.1,
        #     "close": 0.1,
        #     "high": 0.1,
        #     "indexPrice": 0.1,
        #     "last": 0.1,
        #     "low": 0.1,
        #     "markPrice": 0.1,
        #     "open": 0.1,
        #     "percentage": 0.1,
        #     "previousClose": 0.1,
        #     "quoteVolume": 0.1,
        #     "symbol": "string",
        #     "timestamp": null,
        #     "vwap": 0.1
        # }
        #
        return self.parse_ticker(response, market)

    def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
        timestamp = self.safe_integer(ticker, 'timestamp')
        return self.safe_ticker({
            'symbol': self.safe_string(ticker, 'symbol'),
            'timestamp': timestamp,
            'datetime': self.iso8601(timestamp),
            'high': self.safe_string(ticker, 'high'),
            'low': self.safe_string(ticker, 'low'),
            'bid': self.safe_string(ticker, 'bid'),
            'bidVolume': self.safe_string(ticker, 'bidVolume'),
            'ask': self.safe_string(ticker, 'ask'),
            'askVolume': self.safe_string(ticker, 'askVolume'),
            'vwap': self.safe_string(ticker, 'vwap'),
            'open': self.safe_string(ticker, 'open'),
            'close': None,
            'last': None,
            'previousClose': None,
            'change': self.safe_string(ticker, 'change'),
            'percentage': None,
            'average': None,
            'baseVolume': self.safe_string(ticker, 'baseVolume'),
            'quoteVolume': self.safe_string(ticker, 'quoteVolume'),
            'markPrice': None,
            'indexPrice': self.safe_string(ticker, 'indexPrice'),
            'info': ticker,
        }, market)

    def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/orderbook

        fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
        :param str symbol: unified symbol of the market to fetch the order book for
        :param int [limit]: the maximum amount of order book entries to return
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/?id=order-book-structure>` indexed by market symbols
        """
        self.load_markets()
        market = self.market(symbol)
        chId = self.safe_string(market, 'id')
        request = {
            'chId': chId,
        }
        response = self.publicPostOrderbook(self.extend(request, params))
        #
        # {
        #     "asks":[
        #         [76228.1534,11.58777]
        #     ],
        #     "bids":[
        #         [76213.4842,11.96145],
        #     ],
        #     "datetime":"2025-04-07 09:29:28.213 UTC",
        #     "timestamp":1744018168213,
        #     "symbol":"BTC/USD:USDC"
        # }
        #
        timestamp = self.safe_integer(response, 'timestamp')
        orderbook = self.parse_order_book(response, symbol, timestamp)
        orderbook['nonce'] = self.safe_integer(response, 'nonce')
        return orderbook

    def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/trades

        get the list of most recent trades for a particular symbol
        :param str symbol: unified symbol of the market to fetch trades for
        :param int [since]: timestamp in ms of the earliest trade to fetch
        :param int [limit]: the maximum amount of trades to fetch
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.until]: the latest time in ms to fetch trades for
        :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/?id=public-trades>`
        """
        self.load_markets()
        market = self.market(symbol)
        chId = self.safe_string(market, 'id')
        request = {
            'chId': chId,
        }
        if limit is not None:
            request['limit'] = min(limit, 50)
        response = self.publicPostTrades(self.extend(request, params))
        #
        #     {
        #         "trades": [
        #             {
        #                 "amount": 0.03378,
        #                 "datetime": "2025-12-29 22:43:54.639 UTC",
        #                 "price": 87239.09499000001,
        #                 "timestamp": 1767048234639,
        #                 "side": "buy",
        #                 "symbol": "BTC/USD:USDC"
        #             }
        #         ],
        #         "nextCursor": 573
        #     }
        #
        data = self.safe_list(response, 'trades', [])
        return self.parse_trades(data, market, since, limit)

    def parse_trade(self, rawTrade: dict, market: Market = None) -> Trade:
        trade = self.safe_trade(self.extend({'info': rawTrade}, rawTrade))
        trade['id'] = ''
        trade['order'] = None
        trade['takerOrMaker'] = None
        trade['timestamp'] = self.safe_integer(rawTrade, 'timestamp')
        return trade

    def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/ohlcv

        fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
        :param str symbol: unified symbol of the market to fetch OHLCV data for
        :param str timeframe: the length of time each candle represents
        :param int [since]: timestamp in ms of the earliest candle to fetch
        :param int [limit]: max=1000, max=100 when since is defined and is less than(now - (999 * (timeframe in ms)))
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns int[][]: A list of candles ordered, open, high, low, close, volume
        """
        self.load_markets()
        market = self.market(symbol)
        chId = self.safe_string(market, 'id')
        request = {
            'chId': chId,
            'timeframe': timeframe,
        }
        if since is not None:
            request['since'] = since
        if limit is not None:
            request['limit'] = limit
        response = self.publicPostOHLCV(self.extend(request, params))
        #
        # [
        #     [
        #         1743932340000,
        #         83093.5445,
        #         83093.5445,
        #         83093.5445,
        #         83093.5445,
        #         0.0
        #     ]
        # ]
        #
        return self.parse_ohlcvs(response, market, timeframe, since, limit)

    def fetch_balance(self, params={}) -> Balances:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/balance

        query for balance and get the amount of funds available for trading or funds locked in positions
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param str [params.account]: account object ID, required
        :returns dict: a `balance structure <https://docs.ccxt.com/?id=balance-structure>`
        """
        account = None
        account, params = self.handle_option_and_params(params, 'fetchBalance', 'account')
        request = {
            'account': account,
        }
        if account is None:
            raise ArgumentsRequired(self.id + ' fetchBalance() requires account')
        response = self.privatePostBalance(self.extend(request, params))
        #
        # {
        #     "timestamp": 1744045700352,
        #     "balances": {
        #         "USDC": {
        #             "free": 7.726913939320065,
        #             "used": 22.273086060679937,
        #             "total": 30.0
        #         }
        #     }
        # }
        #
        return self.parse_balance(response)

    def parse_balance(self, response) -> Balances:
        result: dict = {
            'info': response,
        }
        balances = self.safe_dict(response, 'balances', [])
        currencies = list(balances.keys())
        for i in range(0, len(currencies)):
            code = currencies[i]
            balance = balances[code]
            account = self.account()
            account['free'] = self.safe_string(balance, 'free')
            account['used'] = self.safe_string(balance, 'used')
            account['total'] = self.safe_string(balance, 'total')
            result[code] = account
        timestamp = self.safe_integer(response, 'timestamp')
        result['timestamp'] = timestamp
        result['datetime'] = self.iso8601(timestamp)
        return self.safe_balance(result)

    def fetch_accounts(self, params={}) -> List[Account]:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/accounts

        query for accounts owned by the walletAddress. An Account is needed for all trading methods.
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns Array: a list of `account structures <https://github.com/ccxt/ccxt/wiki/Manual#accounts>`
        """
        self.load_markets()
        request = {
            'address': self.walletAddress,
        }
        response = self.privatePostAccounts(self.extend(request, params))
        #
        # [
        #     {
        #         "id": "0x22c5e3d2f5bcfd4351a62cd70874878b7923b56d79d04225ed96370a7ac844c4",
        #         "type": "primary",
        #         "code": "USDC",
        #         "accountNumber": 14822
        #     }
        # ]
        #
        return self.parse_accounts(response)

    def parse_account(self, account: dict) -> Account:
        return {
            'id': self.safe_string(account, 'id'),
            'type': self.safe_string(account, 'type'),
            'code': self.safe_string(account, 'code'),
            'info': account,
        }

    def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/my_pending_orders

        fetch all unfilled currently open orders
        :param str symbol: unified market symbol
        :param int [since]: the earliest time in ms to fetch open orders for
        :param int [limit]: the maximum number of  open orders structures to retrieve
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.accountNumber]: account number to query orders for, required
        :returns Order[]: a list of `order structures <https://docs.ccxt.com/?id=order-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        accountNumber = None
        accountNumber, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'accountNumber')
        if accountNumber is None:
            raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires an accountNumber parameter in params')
        request = {
            'chId': self.safe_string(market, 'id'),
            'accountNumber': accountNumber,
        }
        response = self.privatePostMyPendingOrders(self.extend(request, params))
        #
        # [
        #     {
        #         "id": "340282366919093789037556908196463492660",
        #         "datetime": "2025-04-07 14:10:49.472 UTC",
        #         "timestamp": 1744035049472,
        #         "status": "open",
        #         "symbol": "BTC/USD:USDC",
        #         "type": "limit",
        #         "side": "buy",
        #         "price": 10000.0,
        #         "amount": 0.0001,
        #         "filled": 0.0,
        #         "remaining": 0.0001,
        #         "cost": 0.0,
        #         "trades": [],
        #         "fee": {}
        #     }
        # ]
        #
        return self.parse_orders(response)

    def fetch_position(self, symbol: str, params={}):
        """
        fetch data on an open position

        https://testnet.aftermath.finance/docs/#/CCXT/positions

        :param str symbol: unified market symbol of the market the position is held in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.accountNumber]: account number to query positions for, required
        :returns dict: a `position structure <https://docs.ccxt.com/?id=position-structure>`
        """
        positions = self.fetch_positions([symbol], params)
        return self.safe_dict(positions, 0, {})

    def fetch_positions(self, symbols: Strings = None, params={}):
        """

        https://testnet.aftermath.finance/docs/#/CCXT/positions

        fetch all open positions
        :param str[] symbols: list of unified market symbols
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param int [params.accountNumber]: account number to query positions for, required
        :returns dict[]: a list of `position structure <https://docs.ccxt.com/?id=position-structure>`
        """
        self.load_markets()
        accountNumber = None
        accountNumber, params = self.handle_option_and_params(params, 'fetchPositions', 'accountNumber')
        if accountNumber is None:
            raise ArgumentsRequired(self.id + ' fetchPositions() requires an accountNumber parameter in params')
        request = {
            'accountNumber': accountNumber,
        }
        response = self.privatePostPositions(self.extend(request, params))
        #
        # [
        #     {
        #         "id": "0xb60c5078b060e4aede8e670089c9b1bc6eb231b4bcc0bfb3e97534770ace4d0c:101",
        #         "symbol": "BTC/USD",
        #         "timestamp": 1744360128358,
        #         "datetime": "2025-04-11 08:28:48.358 UTC",
        #         "side": "long",
        #         "contracts": 0.001,
        #         "contractSize": 81299.8225,
        #         "entryPrice": 0.000012292609480106,
        #         "notional": 81.30326975863777,
        #         "leverage": 2.091737393826,
        #         "collateral": 38.918646841955464,
        #         "initialMargin": 2.0325817439659444,
        #         "maintenanceMargin": 1.0162908719829722,
        #         "initialMarginPercentage": 0.025,
        #         "maintenanceMarginPercentage": 0.0125,
        #         "unrealizedPnl": -0.0498699,
        #         "liquidationPrice": 42969.81843916013,
        #         "marginMode": "isolated",
        #         "marginRatio": 0.4780714839977587
        #     }
        # ]
        #
        return self.parse_positions(response, symbols)

    def parse_position(self, position: dict, market: Market = None) -> Position:
        return self.safe_position(position)

    def parse_create_edit_order_args(self, id: Str, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        market = self.market(symbol)
        symbol = market['symbol']
        order = {
            'symbol': symbol,
            'type': type,
            'side': side,
            'amount': amount,
            'price': price,
            'params': params,
        }
        if id is not None:
            order['id'] = id
        return order

    def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
        """
        create a trade order

        https://testnet.aftermath.finance/docs/#/CCXT/build_create_orders
        https://testnet.aftermath.finance/docs/#/CCXT/submit_create_orders

        :param str symbol: unified symbol of the market to create an order in
        :param str type: 'market' or 'limit'
        :param str side: 'buy' or 'sell'
        :param float amount: how much of currency you want to trade in units of base currency
        :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param bool [params.reduceOnly]: True or False whether the order is reduce-only
        :param Account [params.account]: account id to use, required
        :returns dict: an `order structure <https://docs.ccxt.com/?id=order-structure>`
        """
        self.load_markets()
        account = None
        account, params = self.handle_option_and_params(params, 'createOrder', 'account')
        order = self.parse_create_edit_order_args(None, symbol, type, side, amount, price, params)
        accountObj = {'account': account}
        orders = self.create_orders([order], accountObj)
        return orders[0]

    def create_orders(self, orders: List[OrderRequest], params={}) -> List[Order]:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/build_create_orders
        https://testnet.aftermath.finance/docs/#/CCXT/submit_create_orders

        create a list of trade orders
        :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param Account [params.account]: account id to use, required
        :returns dict: an `order structure <https://docs.ccxt.com/?id=order-structure>`
        """
        self.load_markets()
        ordersRequest = []
        for i in range(0, len(orders)):
            order = self.clone(orders[i])
            symbol = self.safe_string(order, 'symbol')
            market = self.market(symbol)
            price = self.safe_string(order, 'price')
            amount = self.safe_string(order, 'amount')
            orderParams = self.safe_dict(order, 'params', {})
            reduceOnly = self.safe_bool(orderParams, 'reduceOnly')
            if reduceOnly is not None:
                order['reduceOnly'] = reduceOnly
            del order['symbol']
            del order['params']
            order['chId'] = market['id']
            if price is not None:
                order['price'] = self.parse_to_numeric(self.price_to_precision(symbol, price))
            order['amount'] = self.parse_to_numeric(self.amount_to_precision(symbol, amount))
            ordersRequest.append(order)
        account = None
        account, params = self.handle_option_and_params(params, 'createOrders', 'account')
        txRequest = {
            'accountId': account,
            'metadata': {
                'sender': self.walletAddress,
            },
            'orders': ordersRequest,
            'deallocateFreeCollateral': False,
        }
        tx = self.privatePostBuildCreateOrders(self.extend(txRequest, params))
        request = self.sign_tx_ed25519(tx)
        response = self.privatePostSubmitCreateOrders(request)
        #
        # [
        #     {
        #         "id": "340282366919093604570116171100942992979",
        #         "datetime": "2025-04-10 10:38:39.323 UTC",
        #         "timestamp": 1744281519323,
        #         "status": "open",
        #         "symbol": "BTC/USD:USDC",
        #         "type": "limit",
        #         "side": "buy",
        #         "price": 10001.0,
        #         "average": 0.0,
        #         "amount": 0.01,
        #         "filled": 0.0,
        #         "remaining": 0.01,
        #         "cost": 0.0,
        #         "trades": [],
        #         "fee": {}
        #     }
        # ]
        #
        return self.parse_orders(response)

    def cancel_order(self, id: str, symbol: Str = None, params={}):
        """
        cancels an open order

        https://testnet.aftermath.finance/docs/#/CCXT/build_cancel_orders
        https://testnet.aftermath.finance/docs/#/CCXT/submit_cancel_orders

        :param str id: order id
        :param str symbol: unified symbol of the market the order was made in
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: An `order structure <https://docs.ccxt.com/?id=order-structure>`
        """
        orders = self.cancel_orders([id], symbol, params)
        return self.safe_dict(orders, 0)

    def cancel_orders(self, ids: List[str], symbol: Str = None, params={}) -> List[Order]:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/build_cancel_orders
        https://testnet.aftermath.finance/docs/#/CCXT/submit_cancel_orders

        cancel multiple orders
        :param str[] ids: order ids
        :param str [symbol]: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param Account [params.account]: account to cancel orders for, required
        :returns Order[]: an list of `order structures <https://docs.ccxt.com/?id=order-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        account = None
        account, params = self.handle_option_and_params(params, 'cancelOrders', 'account')
        txRequest = {
            'accountId': account,
            'metadata': {
                'sender': self.walletAddress,
            },
            'chId': market['id'],
            'orderIds': ids,
        }
        tx = self.privatePostBuildCancelOrders(txRequest)
        request = self.sign_tx_ed25519(tx)
        response = self.privatePostSubmitCancelOrders(request)
        #
        # [
        #     {
        #         "id": "340282366919093604570116171100942992979",
        #         "datetime": "2025-04-10 10:45:16.765 UTC",
        #         "timestamp": 1744281916765,
        #         "status": "closed",
        #         "symbol": "BTC/USD:USDC",
        #         "type": "limit",
        #         "side": "buy",
        #         "price": 10001.0,
        #         "amount": 0.01,
        #         "filled": 0.0,
        #         "remaining": 0.0,
        #         "cost": 0.0,
        #         "trades": [],
        #         "fee": {}
        #     }
        # ]
        #
        return self.parse_orders(response)

    def create_account(self, symbol: str, params={}) -> List[Order]:
        self.load_markets()
        market = self.market(symbol)
        settleId = market['settleId']
        txRequest = {
            'metadata': {
                'sender': self.walletAddress,
            },
            'settleId': settleId,
        }
        tx = self.privatePostBuildCreateAccount(txRequest)
        request = self.sign_tx_ed25519(tx)
        response = self.privatePostSubmitCreateAccount(request)
        #
        # [
        #     {
        #         "id": "0x2238b380cdf548cf9922a76ad8cf41cd886a04c1a68e7d0f99100b84b0b1ee48",
        #         "type": "primary",
        #         "code": "USDC",
        #         "accountNumber": 357
        #     },
        #     {
        #         "id": "0x6048be1c533a25226e2b505f5c7b8c4d731c87e9fb775dc577052c66febf1c93",
        #         "type": "subaccount",
        #         "code": "USDC",
        #         "accountNumber": 357
        #     }
        # ]
        #
        return response

    def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/build_allocate
        https://testnet.aftermath.finance/docs/#/CCXT/submit_allocate

        add margin
        :param str symbol: unified market symbol
        :param float amount: amount of margin to add
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param Account [params.account]: account id to use, required
        :returns dict: a `margin structure <https://docs.ccxt.com/?id=add-margin-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        account = None
        account, params = self.handle_option_and_params_2(params, 'addMargin', 'account', 'accountId')
        txRequest = {
            'accountId': account,
            'chId': market['id'],
            'amount': self.parse_to_numeric(self.amount_to_precision(symbol, amount)),
            'metadata': {
                'sender': self.walletAddress,
            },
        }
        tx = self.privatePostBuildAllocate(txRequest)
        request = self.sign_tx_ed25519(tx)
        response = self.privatePostSubmitAllocate(request)
        #
        # {
        #     "id": "0xb60c5078b060e4aede8e670089c9b1bc6eb231b4bcc0bfb3e97534770ace4d0c:101",
        #     "symbol": "BTC/USD",
        #     "contracts": 0.0,
        #     "contractSize": 81656.98359916,
        #     "notional": 0.0,
        #     "leverage": 0.0,
        #     "collateral": 40.0,
        #     "initialMargin": 0.0,
        #     "maintenanceMargin": 0.0,
        #     "initialMarginPercentage": 0.025,
        #     "maintenanceMarginPercentage": 0.0125,
        #     "unrealizedPnl": 0.0,
        #     "marginMode": "isolated"
        # }
        #
        return response

    def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/build_deallocate
        https://testnet.aftermath.finance/docs/#/CCXT/submit_deallocate

        remove margin from a position
        :param str symbol: unified market symbol
        :param float amount: amount of margin to remove
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param Account [params.account]: account id to use, required
        :returns dict: a `margin structure <https://docs.ccxt.com/?id=reduce-margin-structure>`
        """
        self.load_markets()
        market = self.market(symbol)
        account = None
        account, params = self.handle_option_and_params_2(params, 'reduceMargin', 'account', 'accountId')
        txRequest = {
            'accountId': account,
            'chId': market['id'],
            'amount': self.parse_to_numeric(self.amount_to_precision(symbol, amount)),
            'metadata': {
                'sender': self.walletAddress,
            },
        }
        tx = self.privatePostBuildDeallocate(txRequest)
        request = self.sign_tx_ed25519(tx)
        response = self.privatePostSubmitDeallocate(request)
        #
        # {
        #     "id": "0xb60c5078b060e4aede8e670089c9b1bc6eb231b4bcc0bfb3e97534770ace4d0c:101",
        #     "symbol": "BTC/USD",
        #     "contracts": 0.0,
        #     "contractSize": 81678.2625,
        #     "notional": 0.0,
        #     "leverage": 0.0,
        #     "collateral": 39.0,
        #     "initialMargin": 0.0,
        #     "maintenanceMargin": 0.0,
        #     "initialMarginPercentage": 0.025,
        #     "maintenanceMarginPercentage": 0.0125,
        #     "unrealizedPnl": 0.0,
        #     "marginMode": "isolated"
        # }
        #
        return response

    def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/build_deposit
        https://testnet.aftermath.finance/docs/#/CCXT/submit_deposit

        transfer currency internally between wallets on the same account
        :param str code: unified currency code
        :param float amount: amount to transfer
        :param str fromAccount: account to transfer from
        :param str toAccount: account to transfer to
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :returns dict: a `transfer structure <https://docs.ccxt.com/?id=transfer-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        txRequest = {
            'metadata': {
                'sender': self.walletAddress,
            },
            'accountId': toAccount,
            'amount': amount,
        }
        tx = self.privatePostBuildDeposit(txRequest)
        request = self.sign_tx_ed25519(tx)
        response = self.privatePostSubmitDeposit(request)
        #
        # {
        #     "id": "0xf93f9bb8bf97eb570410caada92cfa3e66c7ed3a203a164f51d22d41eabe09c0",
        #     "type": "subaccount",
        #     "code": "USDC",
        #     "accountNumber": 101,
        #     "collateral": 1.0
        # }
        #
        return self.extend(self.parse_transfer(response, currency), {
            'fromAccount': self.walletAddress,
            'toAccount': toAccount,
            'amount': amount,
        })

    def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
        currencyId = self.safe_string(transfer, 'code')
        return {
            'info': transfer,
            'id': self.safe_string(transfer, 'id'),
            'timestamp': None,
            'datetime': None,
            'currency': self.safe_currency_code(currencyId, currency),
            'amount': None,
            'fromAccount': None,
            'toAccount': None,
            'status': None,
        }

    def withdraw(self, code: str, amount: float, address: str, tag: Str = None, params={}) -> Transaction:
        """

        https://testnet.aftermath.finance/docs/#/CCXT/build_withdraw
        https://testnet.aftermath.finance/docs/#/CCXT/submit_withdraw

        make a withdrawal
        :param str code: unified currency code
        :param float amount: the amount to withdraw
        :param str address: the address to withdraw to
        :param str tag:
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param Account [params.account]: account id to use, required
        :returns dict: a `transaction structure <https://docs.ccxt.com/?id=transaction-structure>`
        """
        self.load_markets()
        currency = self.currency(code)
        account = None
        account, params = self.handle_option_and_params(params, 'withdraw', 'account')
        if account is None:
            raise ArgumentsRequired(self.id + ' withdraw() requires a account parameter in params')
        txRequest = {
            'accountId': account,
            'metadata': {
                'sender': self.walletAddress,
            },
            'amount': amount,
        }
        tx = self.privatePostBuildWithdraw(txRequest)
        request = self.sign_tx_ed25519(tx)
        response = self.privatePostSubmitWithdraw(request)
        #
        # {
        #     "id": "0xf93f9bb8bf97eb570410caada92cfa3e66c7ed3a203a164f51d22d41eabe09c0",
        #     "type": "subaccount",
        #     "code": "USDC",
        #     "accountNumber": 101,
        #     "collateral": 39.0
        # }
        #
        parsedTx = self.parse_transaction(response, currency)
        parsedTx['addressFrom '] = account
        parsedTx['amount'] = amount
        return parsedTx
        # return self.extend(, {
        #     'addressFrom': account,
        #     'amount': amount,
        # })

    def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
        return {
            'info': transaction,
            'id': self.safe_string(transaction, 'id'),
            'txid': self.safe_string(transaction, 'tx_id'),
            'timestamp': None,
            'datetime': None,
            'address': None,
            'addressFrom': None,
            'addressTo': None,
            'tag': None,
            'tagFrom': None,
            'tagTo': None,
            'type': None,
            'amount': None,
            'currency': self.safe_string(transaction, 'code'),
            'status': None,
            'updated': None,
            'comment': None,
            'internal': None,
            'fee': None,
            'network': None,
        }

    def set_leverage(self, leverage: int, symbol: Str = None, params={}):
        """
        set the level of leverage for a market

        https://testnet.aftermath.finance/docs/#/CCXT/build_set_leverage
        https://testnet.aftermath.finance/docs/#/CCXT/submit_set_leverage

        :param float leverage: the rate of leverage
        :param str symbol: unified market symbol
        :param dict [params]: extra parameters specific to the exchange API endpoint
        :param Account [params.account]: account id to use, required
        :returns dict: response from the exchange
        """
        if symbol is None:
            raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
        self.load_markets()
        market = self.market(symbol)
        account = None
        account, params = self.handle_option_and_params_2(params, 'setLeverage', 'account', 'accountId')
        txRequest = {
            'accountId': account,
            'chId': market['id'],
            'leverage': leverage,
            'metadata': {
                'sender': self.walletAddress,
            },
        }
        tx = self.privatePostBuildSetLeverage(txRequest)
        request = self.sign_tx_ed25519(tx)
        response = self.privatePostSubmitSetLeverage(request)
        #
        # {
        #     "id": "0xyydsxxxxxxxxyydsxxxxxxx:141",
        #     "symbol": "BTC/USD:USDC",
        #     "marginMode": "isolated",
        #     "side": "long",
        #     "contracts": 0.001,
        #     "contractSize": 88506.195911625,
        #     "entryPrice": 90999.0,
        #     "notional": 88.50907726931732,
        #     "marginRatio": 1.0000000000041465,
        #     "leverage": 0.9999999999958537,
        #     "collateral": 91.00196251238035,
        #     "initialMargin": 2.212726931732933,
        #     "maintenanceMargin": 1.1063634658664665,
        #     "initialMarginPercentage": 0.025,
        #     "maintenanceMarginPercentage": 0.0125,
        #     "unrealizedPnl": -2.492804088375008,
        #     "liquidationPrice": -3.71625538227e-7
        # }
        #
        return response

    def sign_tx_ed25519(self, tx: dict) -> dict:
        """
        Helper to sign some transaction bytes and return a generic transaction execution request.
        :param dict [tx]: transaction bytes and the signing digest for them
        :returns dict: the input transaction bytes and the signed digest
        """
        if self.privateKey.find('suiprivkey') >= 0:
            raise NotSupported(self.id + ' only support hex encoding private key, please transform bech32 encoding private key')
        signingDigest = self.safe_string(tx, 'signingDigest')
        digest = self.base64_to_binary(signingDigest)
        privateKey = self.base16_to_binary(self.privateKey)
        signature = self.eddsa(digest, privateKey, 'ed25519')
        hexPublicKey = self.safe_string(self.options, 'publicKey')
        if hexPublicKey is None:
            raise ArgumentsRequired(self.id + ' requires hex encoding public key in options')
        publicKey = self.base16_to_binary(hexPublicKey)
        suiSignature = self.binary_concat(self.base16_to_binary('00'), self.binary_concat(self.base64_to_binary(signature), publicKey))
        base64Sig = self.binary_to_base64(suiSignature)
        transactionBytes = self.safe_string(tx, 'transactionBytes')
        signatures = [base64Sig]
        return {'transactionBytes': transactionBytes, 'signatures': signatures}

    def parse_order(self, order: dict, market: Market = None) -> Order:
        return self.safe_order(order, market)

    def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
        if not response:
            return None  # fallback to default error handler
        #
        # Error with ID:  #68498f1e536664f31a7b1aa7
        #
        if body.find('Error') >= 0:
            self.throw_broadly_matched_exception(self.exceptions['broad'], body, '')
            raise ExchangeError(body)
        return None

    def sign(self, path, api='public', method='POST', params={}, headers=None, body=None):
        url = self.urls['api']['rest'] + '/' + path
        if api == 'private':
            self.check_required_credentials()
        if method == 'POST':
            headers = {
                'Content-Type': 'application/json',
            }
            body = self.json(params)
        return {'url': url, 'method': method, 'body': body, 'headers': headers}
