{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "## Calculation of Merkle Root and Proofs for Final Distribution"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import os\n",
    "from multiprocess import Pool\n",
    "from math import ceil\n",
    "import json\n",
    "from tqdm.notebook import tqdm\n",
    "from IPython.core.display import display, HTML\n",
    "\n",
    "from contract_utils import instantiate_contract, execute_contract, query_contract, get_proofs\n",
    "\n",
    "INITIAL_BALANCE = str(100_000_000_000)\n",
    "\n",
    "COEF_UP = str(13)\n",
    "COEF_DOWN = str(7)\n",
    "TARGET_CLAIM = str(10)\n",
    "\n",
    "NUMBER_OF_THREADS = 15\n",
    "BASH_SIZE = 1000\n",
    "\n",
    "WALLET_ADDRESS = os.getenv('WALLET_ADDRESS')\n",
    "DISPLAY_TX_EXECUTION = False\n",
    "\n",
    "INIT_SUBGRAPH_CONTRACTS = False\n",
    "SUBGRAPH_CODE_ID = str(40)\n",
    "NAME_SUBGRAPH_CONTRACT_ADDRESS = 'bostrom1rncw9n73gm30vhrv6e4p603hav0gue8y5y9fgqa84k4atf5pqvfqcrnpl6'\n",
    "AVATAR_SUBGRAPH_CONTRACT_ADDRESS = 'bostrom164w2vl7z7lpuvex6z3ru0v55fgq3dmvxuqt0aejp49w7fyc8g6kshreggq'\n",
    "PROOF_SUBGRAPH_CONTRACT_ADDRESS = 'bostrom1543j9n7slzff3curyac7ylf2ctg7rk9zjf9ehj08eqx57xj33zzqdy6ga4'\n",
    "\n",
    "INIT_PASSPORT_CONTRACT = False\n",
    "PASSPORT_CODE_ID = str(25)\n",
    "PASSPORT_CONTRACT_ADDRESS = 'bostrom15hzg7eaxgs6ecn46gmu4juc9tau2w45l9cnf8n0797nmmtkdv7jscv88ra'\n",
    "\n",
    "INIT_GIFT_CONTRACT = True\n",
    "GIFT_CODE_ID = str(20)\n",
    "GIFT_CONTRACT_ADDRESS = 'bostrom1rt2acjyhs4jfjdq56pftpu7762hy9gfl63je6fnhwrc5p5y4kmuqxg0262'\n",
    "MERKLE_ROOT = 'd8dfb2c769cac706bb3d9cea1b681ff6ba5f680f0af05cefbe68a74027317ab0'\n",
    "\n",
    "CALCULATE_PROOFS = False\n",
    "STATE_FILE_NAME = 'gift_state_final_220320.csv'\n",
    "ROOT_SOURCE_FILE_NAME = 'root_source_final.json'\n",
    "PROOF_FILE_NAME = 'proof_final.json'\n",
    "ROOT_FILE_NAME = 'root_final'"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Create source data for Merkle Tree"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [],
   "source": [
    "if CALCULATE_PROOFS:\n",
    "    state_df = pd.read_csv(STATE_FILE_NAME)\n",
    "    display(HTML(state_df.head().to_html(index=False, notebook=True, show_dimensions=False)))\n",
    "\n",
    "    state_agg_by_address = state_df.groupby('address')['gift'].sum().reset_index().rename(columns={'gift': 'amount'})\n",
    "    state_agg_by_address['amount'] = state_agg_by_address['amount'] * 1_000_000\n",
    "\n",
    "    root_source_list = state_agg_by_address.to_dict(orient='records')\n",
    "    number_of_addresses = len(root_source_list)\n",
    "    print(f'Number of addresses: {number_of_addresses:>,}')\n",
    "\n",
    "    with open(ROOT_SOURCE_FILE_NAME, 'w') as outfile:\n",
    "        outfile.write(str(root_source_list).replace(\"'\", '\"'))"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Calculate Merkle Root and Proofs"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [],
   "source": [
    "if CALCULATE_PROOFS:\n",
    "    tasks = list(\n",
    "        (\n",
    "        (ROOT_SOURCE_FILE_NAME,\n",
    "         f'final_temp/proofs_{i}.json',\n",
    "         i * BASH_SIZE,\n",
    "         min(number_of_addresses, (i + 1) * BASH_SIZE))\n",
    "        for i in range(ceil(number_of_addresses/BASH_SIZE))\n",
    "        )\n",
    "    )\n",
    "    print(f'First task: {tasks[0]}\\nLast task: {tasks[-1]}\\nTotal tasks: {len(tasks)}\\nThreads: {NUMBER_OF_THREADS:>,}')\n",
    "    with Pool(processes=NUMBER_OF_THREADS) as pool:\n",
    "        res = pool.starmap(get_proofs, tasks, 1)\n",
    "    assert res == [True] * len(res)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Get proofs and root from temporary files"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Merkle root: d8dfb2c769cac706bb3d9cea1b681ff6ba5f680f0af05cefbe68a74027317ab0\n",
      "Number of proofs: 4426091\n"
     ]
    },
    {
     "data": {
      "text/plain": "<IPython.core.display.HTML object>",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th>Unnamed: 0</th>\n      <th>address</th>\n      <th>amount</th>\n      <th>proof</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <td>0</td>\n      <td>0x0000000000000000000000000000000000000020</td>\n      <td>24000000</td>\n      <td>['1c12d0e0e5c8dd03999ed1b49e4f8bdc3deb2238c91c7...</td>\n    </tr>\n    <tr>\n      <td>1</td>\n      <td>0x00000000000000000000000000000000009a6ca0</td>\n      <td>24000000</td>\n      <td>['6f914877a2f44e37e2ad1937ba54e6a69078f40865d90...</td>\n    </tr>\n    <tr>\n      <td>2</td>\n      <td>0x000000000000000000000000000000000e297bdb</td>\n      <td>24000000</td>\n      <td>['28ab88ce80aa1d602c9273e3c01762a15db4a754326be...</td>\n    </tr>\n    <tr>\n      <td>3</td>\n      <td>0x000000000000000000000000000000000edd899b</td>\n      <td>137000000</td>\n      <td>['cf5c194a5ddb674c0feb1ed63f82d98ada8848db46759...</td>\n    </tr>\n    <tr>\n      <td>4</td>\n      <td>0x0000000000000000000000000000000053db6ff1</td>\n      <td>1505000000</td>\n      <td>['cd92981c19927509a95c585ccd131219ceccda3093684...</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "if CALCULATE_PROOFS:\n",
    "    roots = []\n",
    "    proofs = []\n",
    "    for task in tqdm(tasks):\n",
    "        with open(task[1], 'r') as proof_file:\n",
    "            root_and_proof_json = json.load(proof_file)\n",
    "        if len(proofs) == 0:\n",
    "            proofs = root_and_proof_json['proofs']\n",
    "        else:\n",
    "            proofs.extend(root_and_proof_json['proofs'])\n",
    "        roots.append(root_and_proof_json['merkle_root'])\n",
    "\n",
    "    assert roots == [roots[0]] * len(roots)\n",
    "    root = roots[0]\n",
    "    proofs_df = pd.DataFrame(proofs)\n",
    "    proofs_df.to_csv('proofs_final.csv', header=True, index=True)\n",
    "else:\n",
    "    root = MERKLE_ROOT\n",
    "    proofs_df = pd.read_csv('proofs_final.csv')\n",
    "print(f'Merkle root: {root}')\n",
    "print(f'Number of proofs: {len(proofs_df)}')\n",
    "display(HTML(proofs_df.head().to_html(index=False, notebook=True, show_dimensions=False)))"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Instantiate Contracts\n",
    "### Instantiate SUBGRAPH Contracts"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name subgraph contract address: bostrom1rncw9n73gm30vhrv6e4p603hav0gue8y5y9fgqa84k4atf5pqvfqcrnpl6\n",
      "Avatar subgraph contract address: bostrom164w2vl7z7lpuvex6z3ru0v55fgq3dmvxuqt0aejp49w7fyc8g6kshreggq\n",
      "Proof subgraph contract address: bostrom1543j9n7slzff3curyac7ylf2ctg7rk9zjf9ehj08eqx57xj33zzqdy6ga4\n"
     ]
    }
   ],
   "source": [
    "if INIT_SUBGRAPH_CONTRACTS:\n",
    "    name_subgraph_contract_address = \\\n",
    "        instantiate_contract(\n",
    "            init_query=f'''{{\"owner\":\"{WALLET_ADDRESS}\", \"executer\":\"{WALLET_ADDRESS}\"}}''',\n",
    "            contract_code_id=SUBGRAPH_CODE_ID,\n",
    "            contract_label='test name subgraph')\n",
    "    avatar_subgraph_contract_address = \\\n",
    "        instantiate_contract(\n",
    "            init_query=f'''{{\"owner\":\"{WALLET_ADDRESS}\", \"executer\":\"{WALLET_ADDRESS}\"}}''',\n",
    "            contract_code_id=SUBGRAPH_CODE_ID,\n",
    "            contract_label='test avatar subgraph')\n",
    "    proof_subgraph_contract_address = \\\n",
    "        instantiate_contract(\n",
    "            init_query=f'''{{\"owner\":\"{WALLET_ADDRESS}\", \"executer\":\"{WALLET_ADDRESS}\"}}''',\n",
    "            contract_code_id=SUBGRAPH_CODE_ID,\n",
    "            contract_label='test proof subgraph')\n",
    "else:\n",
    "    name_subgraph_contract_address = NAME_SUBGRAPH_CONTRACT_ADDRESS\n",
    "    avatar_subgraph_contract_address = AVATAR_SUBGRAPH_CONTRACT_ADDRESS\n",
    "    proof_subgraph_contract_address = PROOF_SUBGRAPH_CONTRACT_ADDRESS\n",
    "print(f'Name subgraph contract address: {name_subgraph_contract_address}\\n'\n",
    "      f'Avatar subgraph contract address: {avatar_subgraph_contract_address}\\n'\n",
    "      f'Proof subgraph contract address: {proof_subgraph_contract_address}')"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Instantiate Passport Contract"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Passport contract address: bostrom15hzg7eaxgs6ecn46gmu4juc9tau2w45l9cnf8n0797nmmtkdv7jscv88ra\n"
     ]
    }
   ],
   "source": [
    "if INIT_PASSPORT_CONTRACT:\n",
    "    passport_contract_address = \\\n",
    "        instantiate_contract(\n",
    "            init_query=f'''{{\"name\":\"CPT\", \"minter\":\"{WALLET_ADDRESS}\", \"owner\":\"{WALLET_ADDRESS}\", \"symbol\":\"CPT\", \"avatar_subgraph\": \"{avatar_subgraph_contract_address}\", \"name_subgraph\": \"{name_subgraph_contract_address}\", \"proof_subgraph\": \"{proof_subgraph_contract_address}\"}}''',\n",
    "            contract_code_id=PASSPORT_CODE_ID,\n",
    "            contract_label='test passport')\n",
    "else:\n",
    "    passport_contract_address = PASSPORT_CONTRACT_ADDRESS\n",
    "print(f'Passport contract address: {passport_contract_address}')"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Set executor in the Subgraph Contracts"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "outputs": [],
   "source": [
    "def set_executor_subgraph(subgraph_contract_address: str, new_executor_address: str, display_data: bool = False):\n",
    "    return execute_contract(execute_query=f'''{{\"update_executer\":{{\"new_executer\":\"{new_executor_address}\"}}}}''',\n",
    "                            contract_address=subgraph_contract_address,\n",
    "                            gas=600000,\n",
    "                            display_data=display_data)\n",
    "\n",
    "if INIT_PASSPORT_CONTRACT or INIT_SUBGRAPH_CONTRACTS:\n",
    "    set_executor_subgraph(subgraph_contract_address=name_subgraph_contract_address, new_executor_address=passport_contract_address)\n",
    "    set_executor_subgraph(subgraph_contract_address=avatar_subgraph_contract_address, new_executor_address=passport_contract_address)\n",
    "    set_executor_subgraph(subgraph_contract_address=proof_subgraph_contract_address, new_executor_address=passport_contract_address)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Instantiate Gift Contract"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gift contract address: bostrom1yhdxsta8qt7guughmerkekkxegrmkgycfyhxz9m4k8mu27su0hnq22ecn3\n"
     ]
    }
   ],
   "source": [
    "if INIT_GIFT_CONTRACT:\n",
    "    gift_contract_address = \\\n",
    "        instantiate_contract(\n",
    "            init_query=f'''{{\"owner\":\"{WALLET_ADDRESS}\", \"passport\":\"{passport_contract_address}\", \"allowed_native\":\"boot\", \"initial_balance\":\"{INITIAL_BALANCE}\", \"coefficient_up\":\"{COEF_UP}\", \"coefficient_down\":\"{COEF_DOWN}\", \"coefficient\":\"{COEF_UP}\", \"target_claim\":\"{TARGET_CLAIM}\"}}''',\n",
    "            contract_code_id=GIFT_CODE_ID,\n",
    "            amount=INITIAL_BALANCE,\n",
    "            contract_label='test gift')\n",
    "else:\n",
    "    gift_contract_address = GIFT_CONTRACT_ADDRESS\n",
    "print(f'Gift contract address: {gift_contract_address}')"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Register Merkle Root"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "outputs": [],
   "source": [
    "root_register_output = execute_contract(execute_query=f'''{{\"register_merkle_root\":{{\"merkle_root\":\"{root}\"}}}}''',\n",
    "                                        contract_address=gift_contract_address)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gift contract bostrom1yhdxsta8qt7guughmerkekkxegrmkgycfyhxz9m4k8mu27su0hnq22ecn3\n",
      "{'data': {'merkle_root': 'd8dfb2c769cac706bb3d9cea1b681ff6ba5f680f0af05cefbe68a74027317ab0'}}\n"
     ]
    }
   ],
   "source": [
    "print(f'Gift contract {gift_contract_address}')\n",
    "print(query_contract(query='''{\"merkle_root\": {}}''',\n",
    "                     contract_address=gift_contract_address))\n"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}

Local Graph