{"functions": [], "snippet": "\ndef _decimal(tick):\n dec, _ = get(tick, 'decimal', None)\n if dec is None:\n dec = 0\n return dec\n\ndef _insert_order(addr, pair, order_type, order_start, order_new, quote_value, base_value, quote_scale):\n assert order_type in ['buy', 'sell']\n order_id = order_start\n price = - quote_value * quote_scale // base_value\n while True:\n order, _ = get('spot', f'{pair}_{order_type}', None, str(order_id))\n\n if order is None:\n put(addr, 'spot', f'{pair}_{order_type}',\n [addr, base_value, quote_value, price, None, None], str(order_new))\n order_new += 1\n put(addr, 'spot', 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, 'spot', 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, 'spot', f'{pair}_{order_type}_start', order_new)\n order[5] = order_new\n order_new += 1\n put(addr, 'spot', f'{pair}_{order_type}_new', order_new)\n\n put(addr, 'spot', f'{pair}_{order_type}', order, str(order_id))\n if next_order_id is not None:\n next_order, _ = get('spot', 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, 'spot', f'{pair}_{order_type}', next_order, str(next_order_id))\n break\n\n if order[4] is None:\n put(addr, 'spot', f'{pair}_{order_type}',\n [addr, base_value, quote_value, price, None, order_id], str(order_new))\n put(addr, 'spot', 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, 'spot', 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('spot', f'{pair}_{buy_or_sell}', None, str(order[4]))\n prev_order[5] = order[5]\n put(prev_order[0], 'spot', f'{pair}_{buy_or_sell}', prev_order, str(order[4]))\n\n if order[5]:\n next_order, _ = get('spot', f'{pair}_{buy_or_sell}', None, str(order[5]))\n next_order[4] = order[4]\n put(next_order[0], 'spot', 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, 'spot', f'{pair}_{buy_or_sell}_start', order_start)\n\n elif order[4] is None and order[5] is None:\n order_new, _ = get('spot', f'{pair}_{buy_or_sell}_new', 1)\n order_start = order_new\n put(addr, 'spot', f'{pair}_{buy_or_sell}_start', order_start)\n\n return order_start\n\n\ndef spot_limit_order(info, args):\n assert args['f'] == 'spot_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 quote_scale = 10 ** _decimal(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 spot_buy_start, _ = get('spot', f'{pair}_buy_start', 1)\n spot_buy_new, _ = get('spot', f'{pair}_buy_new', 1)\n spot_sell_start, _ = get('spot', f'{pair}_sell_start', 1)\n spot_sell_new, _ = get('spot', 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 = spot_sell_new\n spot_sell_start, spot_sell_new = _insert_order(addr, pair, 'sell', spot_sell_start, spot_sell_new, quote_value, base_value, quote_scale)\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 = spot_buy_new\n spot_buy_start, spot_buy_new = _insert_order(addr, pair, 'buy', spot_buy_start, spot_buy_new, quote_value, base_value, quote_scale)\n\n spot_sell_id = spot_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('spot', f'{pair}_sell', None, str(spot_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 spot_buy_id = spot_buy_start\n while True:\n buy, _ = get('spot', f'{pair}_buy', None, str(spot_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 spot_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 // quote_scale\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 spot_buy_start = _remove_order(addr, pair, buy, spot_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], 'spot', f'{pair}_buy', None, str(spot_buy_id))\n else:\n put(buy[0], 'spot', f'{pair}_buy', buy, str(spot_buy_id))\n\n if sell[1] == 0:\n break\n if buy[4] is None:\n break\n spot_buy_id = buy[4]\n\n if sell[1] == 0:\n spot_sell_start = _remove_order(addr, pair, sell, spot_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], 'spot', f'{pair}_sell', None, str(spot_sell_id))\n else:\n put(sell[0], 'spot', f'{pair}_sell', sell, str(spot_sell_id))\n\n if sell[4] is None:\n break\n spot_sell_id = sell[4]\n\n make_base -= take_base\n assert make_base >= 0\n make_price = - quote_value * quote_scale // base_value\n event('SpotLimitMake', [pair, buy_or_sell, addr, make_base, make_price, order_id])\n if take_base > 0:\n take_price = take_quote * quote_scale // take_base\n event('SpotLimitTake', [pair, buy_or_sell, addr, take_base, take_price, order_id])\n\n\ndef spot_market_order(info, args):\n assert args['f'] == 'spot_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 quote_scale = 10 ** _decimal(quote_tick)\n spot_sell_start, _ = get('spot', f'{pair}_sell_start', 1)\n spot_buy_start, _ = get('spot', 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 spot_buy_id = spot_buy_start\n while True:\n buy, _ = get('spot', f'{pair}_buy', None, str(spot_buy_id))\n if buy is None:\n break\n\n price = buy[3]\n dx_base = min(buy[1], -buy[2] * quote_scale // price, -base_value)\n dx_quote = dx_base * price // quote_scale\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 spot_buy_start = _remove_order(addr, pair, buy, spot_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], 'spot', f'{pair}_buy', None, str(spot_buy_id))\n else:\n put(buy[0], 'spot', f'{pair}_buy', buy, str(spot_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 spot_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 spot_sell_id = spot_sell_start\n while True:\n sell, _ = get('spot', f'{pair}_sell', None, str(spot_sell_id))\n if sell is None:\n break\n\n price = sell[3]\n dx_base = min(-sell[1], quote_balance * quote_scale // price, base_value)\n dx_quote = dx_base * price // quote_scale\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 spot_sell_start = _remove_order(addr, pair, sell, spot_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], 'spot', f'{pair}_sell', None, str(spot_sell_id))\n else:\n put(sell[0], 'spot', f'{pair}_sell', sell, str(spot_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 spot_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 spot_sell_id = spot_sell_start\n while True:\n sell, _ = get('spot', f'{pair}_sell', None, str(spot_sell_id))\n if sell is None:\n break\n\n price = sell[3]\n dx_base = min(-sell[1], -quote_value * quote_scale // price)\n dx_quote = dx_base * price // quote_scale\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 spot_sell_start = _remove_order(addr, pair, sell, spot_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], 'spot', f'{pair}_sell', None, str(spot_sell_id))\n else:\n put(sell[0], 'spot', f'{pair}_sell', sell, str(spot_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 spot_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 spot_buy_id = spot_buy_start\n while True:\n buy, _ = get('spot', f'{pair}_buy', None, str(spot_buy_id))\n if buy is None:\n break\n\n price = buy[3]\n dx_base = min(buy[1], base_balance, quote_value * quote_scale // price)\n dx_quote = dx_base * price // quote_scale\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 spot_buy_start = _remove_order(addr, pair, buy, spot_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], 'spot', f'{pair}_buy', None, str(spot_buy_id))\n else:\n put(buy[0], 'spot', f'{pair}_buy', buy, str(spot_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 spot_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 * quote_scale // take_base\n event('SpotMarketTake', [pair, buy_or_sell, addr, take_base, price])\n\n\ndef spot_limit_order_cancel(info, args):\n assert args['f'] == 'spot_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 spot_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('spot', order_key, None, str(spot_order_id))\n\n if order is None:\n return\n\n assert order[0] == addr, \"Sender is not the owner of the order\"\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('spot', order_key, None, str(prev_order_id))\n if prev_order:\n prev_order[5] = next_order_id\n put(prev_order[0], 'spot', order_key, prev_order, str(prev_order_id))\n\n if next_order_id is not None:\n next_order, _ = get('spot', order_key, None, str(next_order_id))\n if next_order:\n next_order[4] = prev_order_id\n put(next_order[0], 'spot', order_key, next_order, str(next_order_id))\n\n start_key = f'{pair}_{buy_or_sell}_start'\n current_start, _ = get('spot', start_key, 1)\n if current_start == spot_order_id:\n if prev_order_id is not None:\n put(addr, 'spot', start_key, prev_order_id)\n else:\n new_start_key = f'{pair}_{buy_or_sell}_new'\n new_start_val, _ = get('spot', new_start_key, 1)\n put(addr, 'spot', 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, 'spot', order_key, None, str(spot_order_id))\n event('SpotOrderCancel', [spot_order_id, buy_or_sell, pair])\n\n\ndef spot_pair_create(info, args):\n assert args['f'] == 'spot_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('spot', '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('spot', f'{pair}_enable', None)\n assert enable is None, \"Pair already exists\"\n\n put(addr, 'spot', f'{pair}_enable', True)\n put(addr, 'spot', f'{pair}_buy_start', 1)\n put(addr, 'spot', f'{pair}_buy_new', 1)\n put(addr, 'spot', f'{pair}_sell_start', 1)\n put(addr, 'spot', f'{pair}_sell_new', 1)\n\n\ndef spot_pair_enable(info, args):\n assert args['f'] == 'spot_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, 'spot', f'{pair}_enable', True)\n\n\ndef spot_pair_disable(info, args):\n assert args['f'] == 'spot_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, 'spot', f'{pair}_enable', False)\n\n\ndef spot_set_quote_tokens(info, args):\n assert args['f'] == 'spot_set_quote_tokens'\n sender = info['sender']\n addr = handle_lookup(sender)\n\n manager, _ = get('spot', 'manager', None)\n assert manager is not None, \"Manager not set\"\n assert addr == manager, \"Only the 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('spot', '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, 'spot', 'quote_tokens', quote_tokens)\n\n\ndef spot_vote_manager(info, args):\n assert args['f'] == 'spot_vote_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'spot_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, 'spot', 'manager', user)\n put(addr, 'committee', 'proposal', [], proposal_key)\n else:\n put(addr, 'committee', 'proposal', list(votes), proposal_key)\n"}