{"functions": ["trade_pair_enable", "trade_set_quote_token", "trade_market_order", "trade_pair_create", "trade_limit_order_cancel", "trade_vote_treasure_manager", "trade_limit_order", "trade_pair_disable"], "snippet": "K = 10**18\n\ndef _insert_order(addr, pair, order_type, order_start, order_new, quote_value, base_value):\n assert order_type in ['buy', 'sell']\n order_id = order_start\n while True:\n order, _ = get('trade', f'{pair}_{order_type}', None, str(order_id))\n price = - quote_value * K // base_value\n\n if order is None:\n put(addr, 'trade', f'{pair}_{order_type}',\n [addr, base_value, quote_value, price, None, None], str(order_new))\n order_new += 1\n put(addr, 'trade', f'{pair}_{order_type}_new', order_new)\n break\n\n if order_type == 'buy':\n cond = price > order[3]\n else:\n cond = price < order[3]\n\n if cond:\n next_order_id = order[5]\n put(addr, 'trade', f'{pair}_{order_type}',\n [addr, base_value, quote_value, price, order_id, next_order_id], str(order_new))\n if next_order_id is None:\n order_start = order_new\n put(addr, 'trade', f'{pair}_{order_type}_start', order_new)\n order[5] = order_new\n order_new += 1\n put(addr, 'trade', f'{pair}_{order_type}_new', order_new)\n\n put(addr, 'trade', f'{pair}_{order_type}', order, str(order_id))\n if next_order_id is not None:\n next_order, _ = get('trade', f'{pair}_{order_type}', None, str(next_order_id))\n if next_order is not None:\n next_order[4] = order[5]\n put(addr, 'trade', f'{pair}_{order_type}', next_order, str(next_order_id))\n break\n\n if order[4] is None:\n put(addr, 'trade', f'{pair}_{order_type}',\n [addr, base_value, quote_value, price, None, order_id], str(order_new))\n put(addr, 'trade', f'{pair}_{order_type}',\n [order[0], order[1], order[2], order[3], order_new, order[5]], str(order_id))\n order_new += 1\n put(addr, 'trade', f'{pair}_{order_type}_new', order_new)\n break\n\n order_id = order[4]\n return order_start, order_new\n\n\ndef _remove_order(addr, pair, order, order_start, buy_or_sell):\n assert buy_or_sell in ['buy', 'sell']\n if order[4]:\n prev_order, _ = get('trade', f'{pair}_{buy_or_sell}', None, str(order[4]))\n prev_order[5] = order[5]\n put(prev_order[0], 'trade', f'{pair}_{buy_or_sell}', prev_order, str(order[4]))\n\n if order[5]:\n next_order, _ = get('trade', f'{pair}_{buy_or_sell}', None, str(order[5]))\n next_order[4] = order[4]\n put(next_order[0], 'trade', f'{pair}_{buy_or_sell}', next_order, str(order[5]))\n\n if order[4] is not None and order[5] is None:\n order_start = order[4]\n put(addr, 'trade', f'{pair}_{buy_or_sell}_start', order_start)\n\n elif order[4] is None and order[5] is None:\n order_new, _ = get('trade', f'{pair}_{buy_or_sell}_new', 1)\n order_start = order_new\n put(addr, 'trade', f'{pair}_{buy_or_sell}_start', order_start)\n\n return order_start\n\n\ndef trade_limit_order(info, args):\n assert args['f'] == 'trade_limit_order'\n sender = info['sender']\n addr = handle_lookup(sender)\n\n base_tick = args['a'][0]\n quote_tick = args['a'][2]\n assert set(base_tick) <= set(string.ascii_uppercase+'_')\n assert set(quote_tick) <= set(string.ascii_uppercase+'_')\n\n pair = '%s_%s' % tuple([base_tick, quote_tick])\n base_value = int(args['a'][1])\n quote_value = int(args['a'][3])\n assert base_value * quote_value < 0\n\n trade_buy_start, _ = get('trade', f'{pair}_buy_start', 1)\n trade_buy_new, _ = get('trade', f'{pair}_buy_new', 1)\n trade_sell_start, _ = get('trade', f'{pair}_sell_start', 1)\n trade_sell_new, _ = get('trade', f'{pair}_sell_new', 1)\n\n if base_value < 0 and quote_value > 0:\n buy_or_sell = 'sell'\n balance, _ = get(base_tick, 'balance', 0, addr)\n balance += base_value\n make_base = - base_value\n assert balance >= 0\n put(addr, base_tick, 'balance', balance, addr)\n\n order_id = trade_sell_new\n trade_sell_start, trade_sell_new = _insert_order(addr, pair, 'sell', trade_sell_start, trade_sell_new, quote_value, base_value)\n\n elif base_value > 0 and quote_value < 0:\n buy_or_sell = 'buy'\n balance, _ = get(quote_tick, 'balance', 0, addr)\n balance += quote_value\n make_base = base_value\n assert balance >= 0\n put(addr, quote_tick, 'balance', balance, addr)\n\n order_id = trade_buy_new\n trade_buy_start, trade_buy_new = _insert_order(addr, pair, 'buy', trade_buy_start, trade_buy_new, quote_value, base_value)\n\n trade_sell_id = trade_sell_start\n highest_buy_price = None\n\n # take_amount = 0\n take_base = 0\n take_quote = 0\n while True:\n sell, _ = get('trade', f'{pair}_sell', None, str(trade_sell_id))\n if not sell:\n break\n sell_price = sell[3]\n if highest_buy_price and sell_price > highest_buy_price:\n break\n\n trade_buy_id = trade_buy_start\n while True:\n buy, _ = get('trade', f'{pair}_buy', None, str(trade_buy_id))\n if not buy:\n break\n buy_price = buy[3]\n if highest_buy_price is None:\n highest_buy_price = buy_price\n if sell_price > buy_price:\n trade_buy_id = buy[4]\n continue\n\n matched_price = sell_price\n dx_base = min(-sell[1], buy[1])\n dx_quote = dx_base * matched_price // K\n sell[1] += dx_base\n sell[2] -= dx_quote\n buy[1] -= dx_base\n buy[2] += dx_quote\n take_base += dx_base\n take_quote += dx_quote\n # if buy_or_sell == 'buy':\n # take_amount += dx_quote\n # else:\n # take_amount += dx_base\n balance, _ = get(base_tick, 'balance', 0, buy[0])\n balance += dx_base\n assert balance >= 0\n put(buy[0], base_tick, 'balance', balance, buy[0])\n\n balance, _ = get(quote_tick, 'balance', 0, sell[0])\n balance += dx_quote\n assert balance >= 0\n put(sell[0], quote_tick, 'balance', balance, sell[0])\n\n if buy[1] == 0:\n trade_buy_start = _remove_order(addr, pair, buy, trade_buy_start, 'buy')\n\n if buy[2] < 0:\n balance, _ = get(quote_tick, 'balance', 0, buy[0])\n balance -= buy[2]\n assert balance >= 0\n put(buy[0], quote_tick, 'balance', balance, buy[0])\n \n put(buy[0], 'trade', f'{pair}_buy', None, str(trade_buy_id))\n else:\n put(buy[0], 'trade', f'{pair}_buy', buy, str(trade_buy_id))\n\n if sell[1] == 0:\n break\n if buy[4] is None:\n break\n trade_buy_id = buy[4]\n\n if sell[1] == 0:\n trade_sell_start = _remove_order(addr, pair, sell, trade_sell_start, 'sell')\n\n if sell[1] < 0:\n balance, _ = get(base_tick, 'balance', 0, sell[0])\n balance -= sell[1]\n assert balance >= 0\n put(sell[0], base_tick, 'balance', balance, sell[0])\n\n put(sell[0], 'trade', f'{pair}_sell', None, str(trade_sell_id))\n else:\n put(sell[0], 'trade', f'{pair}_sell', sell, str(trade_sell_id))\n\n if sell[4] is None:\n break\n trade_sell_id = sell[4]\n\n make_base -= take_base\n assert make_base >= 0\n make_price = - quote_value * K // base_value\n event('TradeLimitMake', [pair, buy_or_sell, addr, make_base, make_price, order_id])\n if take_base > 0:\n take_price = take_quote * K // take_base\n event('TradeLimitTake', [pair, buy_or_sell, addr, take_base, take_price, order_id])\n\n\ndef trade_market_order(info, args):\n assert args['f'] == 'trade_market_order'\n sender = info['sender']\n addr = handle_lookup(sender)\n\n base_tick = args['a'][0]\n quote_tick = args['a'][2]\n assert set(base_tick) <= set(string.ascii_uppercase+'_')\n assert set(quote_tick) <= set(string.ascii_uppercase+'_')\n pair = '%s_%s' % tuple([base_tick, quote_tick])\n\n base_value = args['a'][1]\n quote_value = args['a'][3]\n trade_sell_start, _ = get('trade', f'{pair}_sell_start', 1)\n trade_buy_start, _ = get('trade', f'{pair}_buy_start', 1)\n\n take_base = 0\n take_quote = 0\n if quote_value is None and int(base_value) < 0:\n buy_or_sell = 'sell'\n base_value = int(args['a'][1])\n base_balance, _ = get(base_tick, 'balance', 0, addr)\n # base_sum = 0\n\n trade_buy_id = trade_buy_start\n while True:\n buy, _ = get('trade', f'{pair}_buy', None, str(trade_buy_id))\n if buy is None:\n break\n\n price = buy[3]\n dx_base = min(buy[1], -buy[2] * K // price, -base_value)\n dx_quote = dx_base * price // K\n if dx_base == 0 or dx_quote == 0:\n break\n if base_balance - dx_base < 0:\n break\n buy[1] -= dx_base\n buy[2] += dx_quote\n take_base += dx_base\n take_quote += dx_quote\n base_balance -= dx_base\n # base_sum += dx_base\n\n if buy[1] == 0 or buy[1] // price == 0:\n trade_buy_start = _remove_order(addr, pair, buy, trade_buy_start, 'buy')\n\n if buy[2] < 0:\n balance, _ = get(quote_tick, 'balance', 0, buy[0])\n balance -= buy[2]\n assert balance >= 0\n put(buy[0], quote_tick, 'balance', balance, buy[0])\n \n put(buy[0], 'trade', f'{pair}_buy', None, str(trade_buy_id))\n else:\n put(buy[0], 'trade', f'{pair}_buy', buy, str(trade_buy_id))\n\n balance, _ = get(base_tick, 'balance', 0, buy[0])\n balance += dx_base\n assert balance >= 0\n put(addr, base_tick, 'balance', balance, buy[0])\n\n base_value += dx_base\n assert base_value <= 0\n balance, _ = get(quote_tick, 'balance', 0, addr)\n balance += dx_quote\n assert balance >= 0\n put(addr, quote_tick, 'balance', balance, addr)\n\n if buy[4] is None:\n break\n trade_buy_id = buy[4]\n\n balance, _ = get(base_tick, 'balance', 0, addr)\n balance -= take_base\n assert balance >= 0\n put(addr, base_tick, 'balance', balance, addr)\n\n elif quote_value is None and int(base_value) > 0:\n buy_or_sell = 'buy'\n base_value = int(args['a'][1])\n quote_balance, _ = get(quote_tick, 'balance', 0, addr)\n # quote_sum = 0\n\n trade_sell_id = trade_sell_start\n while True:\n sell, _ = get('trade', f'{pair}_sell', None, str(trade_sell_id))\n if sell is None:\n break\n\n price = sell[3]\n dx_base = min(-sell[1], quote_balance * K // price, base_value)\n dx_quote = dx_base * price // K\n if dx_base == 0 or dx_quote == 0:\n break\n if quote_balance - dx_quote < 0:\n break\n\n sell[1] += dx_base\n sell[2] -= dx_quote\n take_base += dx_base\n take_quote += dx_quote\n quote_balance -= dx_quote\n # quote_sum += dx_quote\n\n if sell[1] == 0 or sell[1] // price == 0:\n trade_sell_start = _remove_order(addr, pair, sell, trade_sell_start, 'sell')\n\n if sell[1] < 0:\n balance, _ = get(base_tick, 'balance', 0, sell[0])\n balance -= sell[1]\n assert balance >= 0\n put(sell[0], base_tick, 'balance', balance, sell[0])\n\n put(sell[0], 'trade', f'{pair}_sell', None, str(trade_sell_id))\n else:\n put(sell[0], 'trade', f'{pair}_sell', sell, str(trade_sell_id))\n\n balance, _ = get(quote_tick, 'balance', 0, sell[0])\n balance += dx_quote\n assert balance >= 0\n put(addr, quote_tick, 'balance', balance, sell[0])\n\n base_value -= dx_base\n assert base_value >= 0\n balance, _ = get(base_tick, 'balance', 0, addr)\n balance += dx_base\n assert balance >= 0\n put(addr, base_tick, 'balance', balance, addr)\n\n if sell[4] is None:\n break\n trade_sell_id = sell[4]\n\n balance, _ = get(quote_tick, 'balance', 0, addr)\n balance -= take_quote\n assert balance >= 0\n put(addr, quote_tick, 'balance', balance, addr)\n\n elif base_value is None and int(quote_value) < 0:\n buy_or_sell = 'buy'\n quote_value = int(args['a'][3])\n quote_balance, _ = get(quote_tick, 'balance', 0, addr)\n # quote_sum = 0\n\n trade_sell_id = trade_sell_start\n while True:\n sell, _ = get('trade', f'{pair}_sell', None, str(trade_sell_id))\n if sell is None:\n break\n\n price = sell[3]\n dx_base = min(-sell[1], -quote_value * K // price)\n dx_quote = dx_base * price // K\n if dx_base == 0 or dx_quote == 0:\n break\n if quote_balance - dx_quote < 0:\n break\n\n sell[1] += dx_base\n sell[2] -= dx_quote\n take_base += dx_base\n take_quote += dx_quote\n quote_balance -= dx_quote\n # quote_sum += dx_quote\n\n if sell[1] == 0 or sell[1] // price == 0:\n trade_sell_start = _remove_order(addr, pair, sell, trade_sell_start, 'sell')\n\n if sell[1] < 0:\n balance, _ = get(base_tick, 'balance', 0, sell[0])\n balance -= sell[1]\n assert balance >= 0\n put(sell[0], base_tick, 'balance', balance, sell[0])\n\n put(sell[0], 'trade', f'{pair}_sell', None, str(trade_sell_id))\n else:\n put(sell[0], 'trade', f'{pair}_sell', sell, str(trade_sell_id))\n\n balance, _ = get(quote_tick, 'balance', 0, sell[0])\n balance += dx_quote\n assert balance >= 0\n put(addr, quote_tick, 'balance', balance, sell[0])\n\n quote_value += dx_quote\n assert quote_value <= 0\n balance, _ = get(base_tick, 'balance', 0, addr)\n balance += dx_base\n assert balance >= 0\n put(addr, base_tick, 'balance', balance, addr)\n\n if sell[4] is None:\n break\n trade_sell_id = sell[4]\n\n balance, _ = get(quote_tick, 'balance', 0, addr)\n balance -= take_quote\n assert balance >= 0\n put(addr, quote_tick, 'balance', balance, addr)\n\n elif base_value is None and int(quote_value) > 0:\n buy_or_sell = 'sell'\n quote_value = int(args['a'][3])\n base_balance, _ = get(base_tick, 'balance', 0, addr)\n # base_sum = 0\n\n trade_buy_id = trade_buy_start\n while True:\n buy, _ = get('trade', f'{pair}_buy', None, str(trade_buy_id))\n if buy is None:\n break\n\n price = buy[3]\n dx_base = min(buy[1], base_balance, quote_value * K // price)\n dx_quote = dx_base * price // K\n if dx_base == 0 or dx_quote == 0:\n break\n if base_balance - dx_base < 0:\n break\n\n buy[1] -= dx_base\n buy[2] += dx_quote\n take_base += dx_base\n take_quote += dx_quote\n base_balance -= dx_base\n # base_sum += dx_base\n\n if buy[1] == 0 or buy[1] // price == 0:\n trade_buy_start = _remove_order(addr, pair, buy, trade_buy_start, 'buy')\n\n if buy[2] < 0:\n balance, _ = get(quote_tick, 'balance', 0, buy[0])\n balance -= buy[2]\n assert balance >= 0\n put(buy[0], quote_tick, 'balance', balance, buy[0])\n \n put(buy[0], 'trade', f'{pair}_buy', None, str(trade_buy_id))\n else:\n put(buy[0], 'trade', f'{pair}_buy', buy, str(trade_buy_id))\n\n balance, _ = get(base_tick, 'balance', 0, buy[0])\n balance += dx_base\n assert balance >= 0\n put(addr, base_tick, 'balance', balance, buy[0])\n\n quote_value -= dx_quote\n assert quote_value >= 0\n balance, _ = get(quote_tick, 'balance', 0, addr)\n balance += dx_quote\n assert balance >= 0\n put(addr, quote_tick, 'balance', balance, addr)\n\n if buy[4] is None:\n break\n trade_buy_id = buy[4]\n\n balance, _ = get(base_tick, 'balance', 0, addr)\n balance -= take_base\n assert balance >= 0\n put(addr, base_tick, 'balance', balance, addr)\n\n if take_base > 0:\n price = take_quote * K // take_base\n event('TradeMarketTake', [pair, buy_or_sell, addr, take_base, price])\n\n\ndef trade_limit_order_cancel(info, args):\n assert args['f'] == 'trade_limit_order_cancel'\n sender = info['sender']\n addr = handle_lookup(sender)\n\n base_tick = args['a'][0]\n assert set(base_tick) <= set(string.ascii_uppercase + '_')\n quote_tick = args['a'][1]\n assert set(quote_tick) <= set(string.ascii_uppercase + '_')\n buy_or_sell = args['a'][2]\n assert buy_or_sell in ['buy', 'sell']\n trade_order_id = int(args['a'][3])\n\n pair = '%s_%s' % (base_tick, quote_tick)\n order_key = f'{pair}_{buy_or_sell}'\n order, _ = get('trade', order_key, None, str(trade_order_id))\n\n assert order is not None, \"Order does not exist\"\n assert order[0] == addr, \"Sender is not the owner of the order\"\n\n prev_order_id = order[4]\n next_order_id = order[5]\n\n if prev_order_id is not None:\n prev_order, _ = get('trade', order_key, None, str(prev_order_id))\n if prev_order:\n prev_order[5] = next_order_id\n put(prev_order[0], 'trade', order_key, prev_order, str(prev_order_id))\n\n if next_order_id is not None:\n next_order, _ = get('trade', order_key, None, str(next_order_id))\n if next_order:\n next_order[4] = prev_order_id\n put(next_order[0], 'trade', order_key, next_order, str(next_order_id))\n\n start_key = f'{pair}_{buy_or_sell}_start'\n current_start, _ = get('trade', start_key, 1)\n if current_start == trade_order_id:\n if prev_order_id is not None:\n put(addr, 'trade', start_key, prev_order_id)\n else:\n new_start_key = f'{pair}_{buy_or_sell}_new'\n new_start_val, _ = get('trade', new_start_key, 1)\n put(addr, 'trade', start_key, new_start_val)\n\n if buy_or_sell == 'sell':\n if order[1] < 0:\n balance, _ = get(base_tick, 'balance', 0, addr)\n balance -= order[1]\n put(addr, base_tick, 'balance', balance, addr)\n elif buy_or_sell == 'buy':\n if order[2] < 0:\n balance, _ = get(quote_tick, 'balance', 0, addr)\n balance -= order[2]\n put(addr, quote_tick, 'balance', balance, addr)\n\n put(addr, 'trade', order_key, None, str(trade_order_id))\n event('TradeOrderCancel', [trade_order_id, buy_or_sell, pair])\n\n\ndef trade_pair_create(info, args):\n assert args['f'] == 'trade_pair_create'\n sender = info['sender']\n addr = handle_lookup(sender)\n\n base_tick = args['a'][0]\n quote_tick = args['a'][1]\n\n quote_tokens, _ = get('trade', 'quote_tokens', [])\n assert quote_tick in quote_tokens, f\"{quote_tick} is not a designated quote token\"\n\n owner, _ = get('asset', 'owner', None, base_tick)\n assert owner == addr, f\"Sender must be the owner of the base token ({base_tick})\"\n pair = f'{base_tick}_{quote_tick}'\n enable, _ = get('trade', f'{pair}_enable', None)\n assert enable is None, \"Pair already exists\"\n\n put(addr, 'trade', f'{pair}_enable', True)\n put(addr, 'trade', f'{pair}_buy_start', 1)\n put(addr, 'trade', f'{pair}_buy_new', 1)\n put(addr, 'trade', f'{pair}_sell_start', 1)\n put(addr, 'trade', f'{pair}_sell_new', 1)\n\n\ndef trade_pair_enable(info, args):\n assert args['f'] == 'trade_pair_enable'\n sender = info['sender']\n addr = handle_lookup(sender)\n\n base_tick = args['a'][0]\n quote_tick = args['a'][1]\n pair = f'{base_tick}_{quote_tick}'\n\n owner, _ = get('asset', 'owner', None, base_tick)\n assert owner == addr, f\"Sender must be the owner of the base token ({base_tick})\"\n\n put(addr, 'trade', f'{pair}_enable', True)\n\n\ndef trade_pair_disable(info, args):\n assert args['f'] == 'trade_pair_disable'\n sender = info['sender']\n addr = handle_lookup(sender)\n\n base_tick = args['a'][0]\n quote_tick = args['a'][1]\n pair = f'{base_tick}_{quote_tick}'\n\n owner, _ = get('asset', 'owner', None, base_tick)\n assert owner == addr, f\"Sender must be the owner of the base token ({base_tick})\"\n\n put(addr, 'trade', f'{pair}_enable', False)\n\n\ndef trade_set_quote_token(info, args):\n assert args['f'] == 'trade_set_quote_token'\n sender = info['sender']\n addr = handle_lookup(sender)\n\n treasure_manager, _ = get('trade', 'treasure_manager', None)\n assert treasure_manager is not None, \"Treasure manager not set\"\n assert addr == treasure_manager, \"Only the treasure manager can add quote tokens\"\n\n new_tokens = args['a'][0]\n assert isinstance(new_tokens, list), \"Quote tokens must be a list\"\n\n quote_tokens, _ = get('trade', 'quote_tokens', [])\n\n for token in new_tokens:\n assert isinstance(token, str), \"Token ticker must be a string\"\n assert set(token) <= set(string.ascii_uppercase+'_'), \"Invalid characters in token ticker\"\n if token not in quote_tokens:\n quote_tokens.append(token)\n\n put(addr, 'trade', 'quote_tokens', quote_tokens)\n\n\ndef trade_vote_treasure_manager(info, args):\n assert args['f'] == 'trade_vote_treasure_manager'\n sender = info['sender']\n addr = handle_lookup(sender)\n\n committee_members, _ = get('committee', 'members', [])\n committee_members = set(committee_members)\n assert addr in committee_members, \"Only committee members can vote\"\n\n user = args['a'][0]\n assert isinstance(user, str), \"User address must be a string\"\n\n proposal_key = f'trade_treasure_manager:{user}'\n votes, _ = get('committee', 'proposal', [], proposal_key)\n votes = set(votes)\n votes.add(addr)\n\n if len(votes) >= len(committee_members) * 2 // 3:\n put(addr, 'trade', 'treasure_manager', user)\n put(addr, 'committee', 'proposal', [], proposal_key)\n else:\n put(addr, 'committee', 'proposal', list(votes), proposal_key)"}