{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "## Gift Contract Testing"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/grovybear/.local/lib/python3.9/site-packages/ipfshttpclient/client/__init__.py:75: VersionMismatch: Unsupported daemon version '0.12.2' (not in range: 0.5.0 โ‰ค โ€ฆ < 0.9.0)\n",
      "  warnings.warn(exceptions.VersionMismatch(version, minimum, maximum))\n"
     ]
    }
   ],
   "source": [
    "from web3.auto import w3\n",
    "import pandas as pd\n",
    "from cyberpy import generate_wallet, address_to_address\n",
    "from cyberpy._message_signer import Message\n",
    "from cyberpy._wallet import seed_to_privkey\n",
    "from eth_account.messages import encode_defunct\n",
    "import json\n",
    "import random\n",
    "from time import time, sleep\n",
    "import ipfshttpclient\n",
    "from tqdm.notebook import tqdm\n",
    "from base64 import b64encode\n",
    "from multiprocess import Pool\n",
    "from math import ceil\n",
    "from dotenv import dotenv_values\n",
    "from itertools import chain\n",
    "\n",
    "from contract_utils import execute_bash, instantiate_contract, execute_contract_bash, query_contract, get_ipfs_cid_from_str, get_proofs, ContractUtils\n",
    "\n",
    "\n",
    "ipfs_client = ipfshttpclient.connect()\n",
    "\n",
    "NUMBER_OF_PARTICIPANTS = 20_000\n",
    "NUMBER_OF_ACTIVATED_PARTICIPANTS = 5_000\n",
    "INITIAL_BALANCE = str(30_000_000_000)\n",
    "COEF_UP = str(13)\n",
    "COEF_DOWN = str(7)\n",
    "TARGET_CLAIM = str(2_000)\n",
    "CLAIM_AMOUNT_LIST = [int(round(20_000 * random.random(), -3)) + 20_000 for _ in range(NUMBER_OF_PARTICIPANTS)]\n",
    "\n",
    "NUMBER_OF_THREADS = 100\n",
    "KEY_PHRASE = 'KEY PHRASE'\n",
    "NICKNAME_LIST = [f'john{round(time())}{number}' for number in range(NUMBER_OF_PARTICIPANTS)]\n",
    "AVATAR_CID_LIST = [get_ipfs_cid_from_str(_nickname + '_avatar') for _nickname in NICKNAME_LIST]\n",
    "PREFIXES = ['cosmos', 'osmo', 'terra']\n",
    "\n",
    "WALLET_ADDRESS = dotenv_values('.env')['WALLET_ADDRESS']\n",
    "WALLET_SEED = dotenv_values('.env')['WALLET_SEED']\n",
    "PYTHON_PATH = dotenv_values('.env')['PYTHON_PATH']\n",
    "\n",
    "DISPLAY_TX_EXECUTION = False\n",
    "CALCULATE_ADDRESS_SET = True\n",
    "CALCULATE_PROOFS = True\n",
    "SEND_COINS = True\n",
    "\n",
    "INIT_SUBGRAPH_CONTRACTS = False\n",
    "SUBGRAPH_CODE_ID = str(4)\n",
    "NAME_SUBGRAPH_CONTRACT_ADDRESS = 'bostrom1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftq67yzdk'\n",
    "AVATAR_SUBGRAPH_CONTRACT_ADDRESS = 'bostrom1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqxkr9dg'\n",
    "PROOF_SUBGRAPH_CONTRACT_ADDRESS = 'bostrom1xt4ahzz2x8hpkc0tk6ekte9x6crw4w6u0r67cyt3kz9syh24pd7s4t9edr'\n",
    "\n",
    "INIT_PASSPORT_CONTRACT = False\n",
    "PASSPORT_CODE_ID = str(7)\n",
    "PASSPORT_CONTRACT_ADDRESS = 'bostrom1fzm6gzyccl8jvdv3qq6hp9vs6ylaruervs4m06c7k0ntzn2f8faq7ha2z2'\n",
    "\n",
    "INIT_TREASURY_CONTRACT = False\n",
    "TREASURY_CODE_ID = str(5)\n",
    "TREASURY_CONTRACT_ADDRESS = 'bostrom19ttnpna4fpwuhw9dwjukah5esz9ruutquuvhxa7ulyyk047vvpvs7nh8wu'\n",
    "\n",
    "INIT_GIFT_CONTRACT = False\n",
    "GIFT_CODE_ID = str(2)\n",
    "GIFT_CONTRACT_ADDRESS = 'bostrom1gc5wcdn9ges00w0l2cfxd7r2puyflak5dmkg26rsh083afmnrjxq3q6aaa'\n",
    "\n",
    "PARTICIPANTS_FILE_NAME = 'temp/participants_test_data_' + str(NUMBER_OF_PARTICIPANTS) + '_addresses.csv'\n",
    "ROOT_SOURCE_FILE_NAME = 'temp/root_testing_source_' + str(NUMBER_OF_PARTICIPANTS) + '_addresses.json'\n",
    "PROOF_FILE_NAME = 'temp/proof_testing_' + str(NUMBER_OF_PARTICIPANTS) + '_addresses.json'\n",
    "ROOT_FILE_NAME = 'temp/root_testing_' + str(NUMBER_OF_PARTICIPANTS) + '_addresses'"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Generate addresses and sign messages"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "data": {
      "text/plain": "   Unnamed: 0  amount         nickname  \\\n0           0   34000  john16548361750   \n1           1   34000  john16548361751   \n2           2   33000  john16548361752   \n3           3   32000  john16548361753   \n4           4   38000  john16548361754   \n\n                                           avatar  \\\n0  QmaaXjnSDLGwpSRHdzUU8XrLjVJPt6E5pE5JavMyTCD381   \n1  QmT7Qs7FRxLjjzJD5QxY7BDZ4R1VgdavE4NcNjQzr3EV1D   \n2  QmQrf4uaZFS8YyouRuYW7RdSjZAY18jxB9t6NrWWqa9WKn   \n3  QmYLg2fgKA6ptwXa4mFXyq2JqjEyTWMrFXwvu3J23zbepW   \n4  QmNWX5GLuXzhhtZdxNAnWWC42gqJsA6A2fjsseB5HPVDyw   \n\n                             ethereum_address  \\\n0  0x3691db823a183aee18e998f2ddd77076a11fd74c   \n1  0xb42fe61f2d97178c18d6f36c637e55ec207a5441   \n2  0x597ad4478d64d2702ad3187fd07ed2159a9b38d3   \n3  0xff0cf02f40e8021a91c48b79b7412c7b1c568b2f   \n4  0xd8b950ffa0b84b4d73e377a5ca86ea0c233a83c7   \n\n                                ethereum_private_key  \\\n0  0x2aa29fbec6aed68bf55a7025c4280b85d38683edf00a...   \n1  0xe6df5403ea994063ff6e8ae25596433c157bf2cc1e97...   \n2  0x046508e879cf32970d3150c439b20dbf4b5aedeccbe6...   \n3  0x17ab2a2fbc4dc59d3d837892de0af854d922e79117bd...   \n4  0x66907d36d32bd3e99be73912172ebb6198a768dfa049...   \n\n                                  bostrom_address  \\\n0  bostrom14qx4d5nwyx5vj4e2gs6zfamjzydnvruydrj6gy   \n1  bostrom17wuryy4kexsgyq6rq2k3x0735n4ntqeq3flav5   \n2  bostrom1ag0uyutudtdtr7aenpc0c0jaedrwrsjf0jfury   \n3  bostrom1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfad5ulu4   \n4  bostrom1x9966p9dwtcju7vy6lcc4mvvqsj5rnffxsz79q   \n\n                                  cosmos_address  \\\n0   terra14qx4d5nwyx5vj4e2gs6zfamjzydnvruyg5uf5r   \n1    osmo17wuryy4kexsgyq6rq2k3x0735n4ntqeq6pc7yp   \n2   terra1ag0uyutudtdtr7aenpc0c0jaedrwrsjf2980lr   \n3  cosmos1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfaw8gvzj   \n4  cosmos1x9966p9dwtcju7vy6lcc4mvvqsj5rnff9rkdm8   \n\n                                         cosmos_seed  \\\n0  hope captain swallow label fish clarify demise...   \n1  science surprise lunar hip truth citizen excha...   \n2  broccoli year exclude ship butter install goss...   \n3  autumn nominee slab attend iron odor antique w...   \n4  aware card grass item rural swallow alcohol co...   \n\n                                             message  \\\n0  bostrom14qx4d5nwyx5vj4e2gs6zfamjzydnvruydrj6gy...   \n1  bostrom17wuryy4kexsgyq6rq2k3x0735n4ntqeq3flav5...   \n2  bostrom1ag0uyutudtdtr7aenpc0c0jaedrwrsjf0jfury...   \n3  bostrom1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfad5ulu4...   \n4  bostrom1x9966p9dwtcju7vy6lcc4mvvqsj5rnffxsz79q...   \n\n                          ethereum_message_signature  \\\n0  0xb38a11a271602c2dc33c81602ad994810f9cf48dfb4d...   \n1  0x84c8f25ca81c784d243e406ec8a4a1e389aa728dc235...   \n2  0xfc895e22ddcfc885b17b91fbc21146aa422d64e2ac43...   \n3  0x9a6179bbb941309bd5247e82a30f6b1fab4f63bcdc87...   \n4  0x59f2175d252ba9a551c8f9e957e26592769e2181e594...   \n\n                           cosmos_message_signed_row  \\\n0  {'pub_key': 'AyjWt69QbKZ4V09ZCXKDN+bRgnw0H3R9B...   \n1  {'pub_key': 'A9bjehAjjY32eiYHqWier3WVEOdZUwZ8Q...   \n2  {'pub_key': 'AtTl2h3Nafoifz384IlN2M97SvoX/oZiQ...   \n3  {'pub_key': 'Amw0GvH82F8z30EaAGnRqT75oSpWxMWzI...   \n4  {'pub_key': 'AtDo/b+BravMbmqq8qoD40ROzNA84J2iY...   \n\n                            cosmos_message_signature  \n0  eyJwdWJfa2V5IjoiQXlqV3Q2OVFiS1o0VjA5WkNYS0ROK2...  \n1  eyJwdWJfa2V5IjoiQTliamVoQWpqWTMyZWlZSHFXaWVyM1...  \n2  eyJwdWJfa2V5IjoiQXRUbDJoM05hZm9pZnozODRJbE4yTT...  \n3  eyJwdWJfa2V5IjoiQW13MEd2SDgyRjh6MzBFYUFHblJxVD...  \n4  eyJwdWJfa2V5IjoiQXREby9iK0JyYXZNYm1xcThxb0Q0MF...  ",
      "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></th>\n      <th>Unnamed: 0</th>\n      <th>amount</th>\n      <th>nickname</th>\n      <th>avatar</th>\n      <th>ethereum_address</th>\n      <th>ethereum_private_key</th>\n      <th>bostrom_address</th>\n      <th>cosmos_address</th>\n      <th>cosmos_seed</th>\n      <th>message</th>\n      <th>ethereum_message_signature</th>\n      <th>cosmos_message_signed_row</th>\n      <th>cosmos_message_signature</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0</td>\n      <td>34000</td>\n      <td>john16548361750</td>\n      <td>QmaaXjnSDLGwpSRHdzUU8XrLjVJPt6E5pE5JavMyTCD381</td>\n      <td>0x3691db823a183aee18e998f2ddd77076a11fd74c</td>\n      <td>0x2aa29fbec6aed68bf55a7025c4280b85d38683edf00a...</td>\n      <td>bostrom14qx4d5nwyx5vj4e2gs6zfamjzydnvruydrj6gy</td>\n      <td>terra14qx4d5nwyx5vj4e2gs6zfamjzydnvruyg5uf5r</td>\n      <td>hope captain swallow label fish clarify demise...</td>\n      <td>bostrom14qx4d5nwyx5vj4e2gs6zfamjzydnvruydrj6gy...</td>\n      <td>0xb38a11a271602c2dc33c81602ad994810f9cf48dfb4d...</td>\n      <td>{'pub_key': 'AyjWt69QbKZ4V09ZCXKDN+bRgnw0H3R9B...</td>\n      <td>eyJwdWJfa2V5IjoiQXlqV3Q2OVFiS1o0VjA5WkNYS0ROK2...</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>1</td>\n      <td>34000</td>\n      <td>john16548361751</td>\n      <td>QmT7Qs7FRxLjjzJD5QxY7BDZ4R1VgdavE4NcNjQzr3EV1D</td>\n      <td>0xb42fe61f2d97178c18d6f36c637e55ec207a5441</td>\n      <td>0xe6df5403ea994063ff6e8ae25596433c157bf2cc1e97...</td>\n      <td>bostrom17wuryy4kexsgyq6rq2k3x0735n4ntqeq3flav5</td>\n      <td>osmo17wuryy4kexsgyq6rq2k3x0735n4ntqeq6pc7yp</td>\n      <td>science surprise lunar hip truth citizen excha...</td>\n      <td>bostrom17wuryy4kexsgyq6rq2k3x0735n4ntqeq3flav5...</td>\n      <td>0x84c8f25ca81c784d243e406ec8a4a1e389aa728dc235...</td>\n      <td>{'pub_key': 'A9bjehAjjY32eiYHqWier3WVEOdZUwZ8Q...</td>\n      <td>eyJwdWJfa2V5IjoiQTliamVoQWpqWTMyZWlZSHFXaWVyM1...</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>2</td>\n      <td>33000</td>\n      <td>john16548361752</td>\n      <td>QmQrf4uaZFS8YyouRuYW7RdSjZAY18jxB9t6NrWWqa9WKn</td>\n      <td>0x597ad4478d64d2702ad3187fd07ed2159a9b38d3</td>\n      <td>0x046508e879cf32970d3150c439b20dbf4b5aedeccbe6...</td>\n      <td>bostrom1ag0uyutudtdtr7aenpc0c0jaedrwrsjf0jfury</td>\n      <td>terra1ag0uyutudtdtr7aenpc0c0jaedrwrsjf2980lr</td>\n      <td>broccoli year exclude ship butter install goss...</td>\n      <td>bostrom1ag0uyutudtdtr7aenpc0c0jaedrwrsjf0jfury...</td>\n      <td>0xfc895e22ddcfc885b17b91fbc21146aa422d64e2ac43...</td>\n      <td>{'pub_key': 'AtTl2h3Nafoifz384IlN2M97SvoX/oZiQ...</td>\n      <td>eyJwdWJfa2V5IjoiQXRUbDJoM05hZm9pZnozODRJbE4yTT...</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>3</td>\n      <td>32000</td>\n      <td>john16548361753</td>\n      <td>QmYLg2fgKA6ptwXa4mFXyq2JqjEyTWMrFXwvu3J23zbepW</td>\n      <td>0xff0cf02f40e8021a91c48b79b7412c7b1c568b2f</td>\n      <td>0x17ab2a2fbc4dc59d3d837892de0af854d922e79117bd...</td>\n      <td>bostrom1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfad5ulu4</td>\n      <td>cosmos1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfaw8gvzj</td>\n      <td>autumn nominee slab attend iron odor antique w...</td>\n      <td>bostrom1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfad5ulu4...</td>\n      <td>0x9a6179bbb941309bd5247e82a30f6b1fab4f63bcdc87...</td>\n      <td>{'pub_key': 'Amw0GvH82F8z30EaAGnRqT75oSpWxMWzI...</td>\n      <td>eyJwdWJfa2V5IjoiQW13MEd2SDgyRjh6MzBFYUFHblJxVD...</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>4</td>\n      <td>38000</td>\n      <td>john16548361754</td>\n      <td>QmNWX5GLuXzhhtZdxNAnWWC42gqJsA6A2fjsseB5HPVDyw</td>\n      <td>0xd8b950ffa0b84b4d73e377a5ca86ea0c233a83c7</td>\n      <td>0x66907d36d32bd3e99be73912172ebb6198a768dfa049...</td>\n      <td>bostrom1x9966p9dwtcju7vy6lcc4mvvqsj5rnffxsz79q</td>\n      <td>cosmos1x9966p9dwtcju7vy6lcc4mvvqsj5rnff9rkdm8</td>\n      <td>aware card grass item rural swallow alcohol co...</td>\n      <td>bostrom1x9966p9dwtcju7vy6lcc4mvvqsj5rnffxsz79q...</td>\n      <td>0x59f2175d252ba9a551c8f9e957e26592769e2181e594...</td>\n      <td>{'pub_key': 'AtDo/b+BravMbmqq8qoD40ROzNA84J2iY...</td>\n      <td>eyJwdWJfa2V5IjoiQXREby9iK0JyYXZNYm1xcThxb0Q0MF...</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def generate_wallet_data(i: int, prefixes: list = PREFIXES) -> dict:\n",
    "\n",
    "    prefix = random.choice(prefixes)\n",
    "\n",
    "    claim_item = {'amount': CLAIM_AMOUNT_LIST[i],\n",
    "              'nickname': NICKNAME_LIST[i],\n",
    "              'avatar': AVATAR_CID_LIST[i]}\n",
    "\n",
    "    # Generate Ethereum wallet\n",
    "    ethereum_wallet = w3.eth.account.create(KEY_PHRASE)\n",
    "    claim_item['ethereum_address'] = ethereum_wallet.address.lower()\n",
    "    claim_item['ethereum_private_key'] = ethereum_wallet.privateKey.hex()\n",
    "\n",
    "    # Generate Bostrom and Cosmos wallet\n",
    "    bostrom_wallet = generate_wallet()\n",
    "    claim_item['bostrom_address'] = bostrom_wallet['address']\n",
    "    claim_item['cosmos_address'] = address_to_address(bostrom_wallet['address'], prefix)\n",
    "    claim_item['cosmos_seed'] = bostrom_wallet['seed']\n",
    "\n",
    "    # Create message\n",
    "    claim_item['message'] = f\"{claim_item['bostrom_address']}:QmRX8qYgeZoYM3M5zzQaWEpVFdpin6FvVXvp6RPQK3oufV\"\n",
    "\n",
    "    # Sign message form Ethereum address\n",
    "    ethereum_signed_message = \\\n",
    "        w3.eth.account.sign_message(\n",
    "            signable_message=encode_defunct(text=claim_item['message']),\n",
    "            private_key=ethereum_wallet.privateKey)\n",
    "    claim_item['ethereum_message_signature'] = ethereum_signed_message.signature.hex()\n",
    "\n",
    "    # Sign message form Cosmos address\n",
    "    cosmos_msg = Message(privkey=seed_to_privkey(seed=claim_item['cosmos_seed']))\n",
    "    cosmos_msg.add_message(signing_message=claim_item['message'], signer_prefix=prefix)\n",
    "    claim_item['cosmos_message_signed_row'] = cosmos_msg.get_signed_message()\n",
    "    claim_item['cosmos_message_signature'] = b64encode(json.dumps(claim_item['cosmos_message_signed_row']).replace('\\n', '').replace(' ', '').encode('utf-8')).decode(\"utf-8\")\n",
    "\n",
    "    # Verify message\n",
    "    assert claim_item['ethereum_address'] == w3.eth.account.recover_message(\n",
    "        signable_message=encode_defunct(text=claim_item['message']),\n",
    "        signature=claim_item['ethereum_message_signature']).lower()\n",
    "\n",
    "    return claim_item\n",
    "\n",
    "\n",
    "if CALCULATE_ADDRESS_SET:\n",
    "\n",
    "    tasks = list(range(NUMBER_OF_PARTICIPANTS))\n",
    "    print(f'Number of tasks: {len(tasks)}')\n",
    "    print(f'Number of threads: {NUMBER_OF_THREADS}')\n",
    "    with Pool(processes=NUMBER_OF_THREADS) as pool:\n",
    "        claims_list = list(tqdm(pool.imap(generate_wallet_data, tasks), total=len(tasks)))\n",
    "\n",
    "    claims_df = pd.DataFrame(claims_list)\n",
    "    claims_df.to_csv('temp/claims_ethereum_test_data_without_proof_' + str(NUMBER_OF_PARTICIPANTS) + '_addresses.csv')\n",
    "else:\n",
    "    claims_df = pd.read_csv('temp/claims_ethereum_test_data_without_proof_' + str(NUMBER_OF_PARTICIPANTS) + '_addresses.csv')\n",
    "claims_df.head()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Create Merkle Tree, Get Root and Proofs"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [],
   "source": [
    "root_source_list_ethereum = \\\n",
    "    [{'address': _item[0],\n",
    "      'amount': str(_item[1])}\n",
    "     for _item in claims_df.loc[:, ['ethereum_address', 'amount']].values.tolist()]\n",
    "root_source_list_cosmos = \\\n",
    "    [{'address': _item[0],\n",
    "      'amount': str(_item[1])}\n",
    "     for _item in claims_df.loc[:, ['cosmos_address', 'amount']].values.tolist()]\n",
    "root_source_list = list(chain.from_iterable(zip(root_source_list_ethereum, root_source_list_cosmos)))\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": "code",
   "execution_count": 4,
   "outputs": [],
   "source": [
    "NUMBER_OF_THREADS = 30\n",
    "BASH_SIZE = 2000\n",
    "\n",
    "tasks = set(\n",
    "    (\n",
    "        (ROOT_SOURCE_FILE_NAME,\n",
    "         f'temp/proofs_{i}.json',\n",
    "         i * BASH_SIZE,\n",
    "         min(NUMBER_OF_ACTIVATED_PARTICIPANTS * 2 + 1, (i + 1) * BASH_SIZE + 1))\n",
    "        for i in range(ceil(2 * NUMBER_OF_ACTIVATED_PARTICIPANTS/BASH_SIZE))\n",
    "    )\n",
    ")\n",
    "if CALCULATE_PROOFS:\n",
    "    print(f'Number of addresses: {2 * NUMBER_OF_PARTICIPANTS:>,}\\nNumber of activated participants: {NUMBER_OF_ACTIVATED_PARTICIPANTS:>,}\\nNumber of threads: {NUMBER_OF_THREADS:>,}\\nBash size: {BASH_SIZE:>,}\\nNumber of tasks: {len(tasks):>,}')\n",
    "    with Pool(processes=NUMBER_OF_THREADS) as pool:\n",
    "        res = pool.starmap(get_proofs, tqdm(tasks, total=len(tasks)))\n",
    "    assert res == [True] * len(res)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [
    {
     "data": {
      "text/plain": "   Unnamed: 0  amount         nickname  \\\n0           0   34000  john16548361750   \n1           1   34000  john16548361751   \n2           2   33000  john16548361752   \n3           3   32000  john16548361753   \n4           4   38000  john16548361754   \n\n                                           avatar  \\\n0  QmaaXjnSDLGwpSRHdzUU8XrLjVJPt6E5pE5JavMyTCD381   \n1  QmT7Qs7FRxLjjzJD5QxY7BDZ4R1VgdavE4NcNjQzr3EV1D   \n2  QmQrf4uaZFS8YyouRuYW7RdSjZAY18jxB9t6NrWWqa9WKn   \n3  QmYLg2fgKA6ptwXa4mFXyq2JqjEyTWMrFXwvu3J23zbepW   \n4  QmNWX5GLuXzhhtZdxNAnWWC42gqJsA6A2fjsseB5HPVDyw   \n\n                             ethereum_address  \\\n0  0x3691db823a183aee18e998f2ddd77076a11fd74c   \n1  0xb42fe61f2d97178c18d6f36c637e55ec207a5441   \n2  0x597ad4478d64d2702ad3187fd07ed2159a9b38d3   \n3  0xff0cf02f40e8021a91c48b79b7412c7b1c568b2f   \n4  0xd8b950ffa0b84b4d73e377a5ca86ea0c233a83c7   \n\n                                ethereum_private_key  \\\n0  0x2aa29fbec6aed68bf55a7025c4280b85d38683edf00a...   \n1  0xe6df5403ea994063ff6e8ae25596433c157bf2cc1e97...   \n2  0x046508e879cf32970d3150c439b20dbf4b5aedeccbe6...   \n3  0x17ab2a2fbc4dc59d3d837892de0af854d922e79117bd...   \n4  0x66907d36d32bd3e99be73912172ebb6198a768dfa049...   \n\n                                  bostrom_address  \\\n0  bostrom14qx4d5nwyx5vj4e2gs6zfamjzydnvruydrj6gy   \n1  bostrom17wuryy4kexsgyq6rq2k3x0735n4ntqeq3flav5   \n2  bostrom1ag0uyutudtdtr7aenpc0c0jaedrwrsjf0jfury   \n3  bostrom1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfad5ulu4   \n4  bostrom1x9966p9dwtcju7vy6lcc4mvvqsj5rnffxsz79q   \n\n                                  cosmos_address  \\\n0   terra14qx4d5nwyx5vj4e2gs6zfamjzydnvruyg5uf5r   \n1    osmo17wuryy4kexsgyq6rq2k3x0735n4ntqeq6pc7yp   \n2   terra1ag0uyutudtdtr7aenpc0c0jaedrwrsjf2980lr   \n3  cosmos1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfaw8gvzj   \n4  cosmos1x9966p9dwtcju7vy6lcc4mvvqsj5rnff9rkdm8   \n\n                                         cosmos_seed  \\\n0  hope captain swallow label fish clarify demise...   \n1  science surprise lunar hip truth citizen excha...   \n2  broccoli year exclude ship butter install goss...   \n3  autumn nominee slab attend iron odor antique w...   \n4  aware card grass item rural swallow alcohol co...   \n\n                                             message  \\\n0  bostrom14qx4d5nwyx5vj4e2gs6zfamjzydnvruydrj6gy...   \n1  bostrom17wuryy4kexsgyq6rq2k3x0735n4ntqeq3flav5...   \n2  bostrom1ag0uyutudtdtr7aenpc0c0jaedrwrsjf0jfury...   \n3  bostrom1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfad5ulu4...   \n4  bostrom1x9966p9dwtcju7vy6lcc4mvvqsj5rnffxsz79q...   \n\n                          ethereum_message_signature  \\\n0  0xb38a11a271602c2dc33c81602ad994810f9cf48dfb4d...   \n1  0x84c8f25ca81c784d243e406ec8a4a1e389aa728dc235...   \n2  0xfc895e22ddcfc885b17b91fbc21146aa422d64e2ac43...   \n3  0x9a6179bbb941309bd5247e82a30f6b1fab4f63bcdc87...   \n4  0x59f2175d252ba9a551c8f9e957e26592769e2181e594...   \n\n                           cosmos_message_signed_row  \\\n0  {'pub_key': 'AyjWt69QbKZ4V09ZCXKDN+bRgnw0H3R9B...   \n1  {'pub_key': 'A9bjehAjjY32eiYHqWier3WVEOdZUwZ8Q...   \n2  {'pub_key': 'AtTl2h3Nafoifz384IlN2M97SvoX/oZiQ...   \n3  {'pub_key': 'Amw0GvH82F8z30EaAGnRqT75oSpWxMWzI...   \n4  {'pub_key': 'AtDo/b+BravMbmqq8qoD40ROzNA84J2iY...   \n\n                            cosmos_message_signature  \\\n0  eyJwdWJfa2V5IjoiQXlqV3Q2OVFiS1o0VjA5WkNYS0ROK2...   \n1  eyJwdWJfa2V5IjoiQTliamVoQWpqWTMyZWlZSHFXaWVyM1...   \n2  eyJwdWJfa2V5IjoiQXRUbDJoM05hZm9pZnozODRJbE4yTT...   \n3  eyJwdWJfa2V5IjoiQW13MEd2SDgyRjh6MzBFYUFHblJxVD...   \n4  eyJwdWJfa2V5IjoiQXREby9iK0JyYXZNYm1xcThxb0Q0MF...   \n\n                                      ethereum_proof  \\\n0  [4710b3ef8cb686c8b316654c7a6587fe33c256755bd65...   \n1  [cc3c069b0ce8d95d69e48a7b4f3728d892a36270e3e52...   \n2  [50a1a2537255c5e1f077442076b2273671acc7b2d5a46...   \n3  [e069f04ee7b66a3181a7fcc473cde8fb80b10ef8077f3...   \n4  [5239d46e245ce4af1f69ec17f7786c6042fea7f62a0d8...   \n\n                                        cosmos_proof  \n0  [172e89389492e7389a96c98cae5190ffcae04a8d2eb85...  \n1  [5398e38c29e181c2ff18cd4df1215ca90677cca24eeb6...  \n2  [ad1576871f19a385d00e90552c06a38d084ba80aa043f...  \n3  [0da1f0fe7351add378fb84ade27270a297bce88360b95...  \n4  [9bb1d32faec7ad21dd219cce62196c374806fd1d77d36...  ",
      "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></th>\n      <th>Unnamed: 0</th>\n      <th>amount</th>\n      <th>nickname</th>\n      <th>avatar</th>\n      <th>ethereum_address</th>\n      <th>ethereum_private_key</th>\n      <th>bostrom_address</th>\n      <th>cosmos_address</th>\n      <th>cosmos_seed</th>\n      <th>message</th>\n      <th>ethereum_message_signature</th>\n      <th>cosmos_message_signed_row</th>\n      <th>cosmos_message_signature</th>\n      <th>ethereum_proof</th>\n      <th>cosmos_proof</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>0</td>\n      <td>34000</td>\n      <td>john16548361750</td>\n      <td>QmaaXjnSDLGwpSRHdzUU8XrLjVJPt6E5pE5JavMyTCD381</td>\n      <td>0x3691db823a183aee18e998f2ddd77076a11fd74c</td>\n      <td>0x2aa29fbec6aed68bf55a7025c4280b85d38683edf00a...</td>\n      <td>bostrom14qx4d5nwyx5vj4e2gs6zfamjzydnvruydrj6gy</td>\n      <td>terra14qx4d5nwyx5vj4e2gs6zfamjzydnvruyg5uf5r</td>\n      <td>hope captain swallow label fish clarify demise...</td>\n      <td>bostrom14qx4d5nwyx5vj4e2gs6zfamjzydnvruydrj6gy...</td>\n      <td>0xb38a11a271602c2dc33c81602ad994810f9cf48dfb4d...</td>\n      <td>{'pub_key': 'AyjWt69QbKZ4V09ZCXKDN+bRgnw0H3R9B...</td>\n      <td>eyJwdWJfa2V5IjoiQXlqV3Q2OVFiS1o0VjA5WkNYS0ROK2...</td>\n      <td>[4710b3ef8cb686c8b316654c7a6587fe33c256755bd65...</td>\n      <td>[172e89389492e7389a96c98cae5190ffcae04a8d2eb85...</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>1</td>\n      <td>34000</td>\n      <td>john16548361751</td>\n      <td>QmT7Qs7FRxLjjzJD5QxY7BDZ4R1VgdavE4NcNjQzr3EV1D</td>\n      <td>0xb42fe61f2d97178c18d6f36c637e55ec207a5441</td>\n      <td>0xe6df5403ea994063ff6e8ae25596433c157bf2cc1e97...</td>\n      <td>bostrom17wuryy4kexsgyq6rq2k3x0735n4ntqeq3flav5</td>\n      <td>osmo17wuryy4kexsgyq6rq2k3x0735n4ntqeq6pc7yp</td>\n      <td>science surprise lunar hip truth citizen excha...</td>\n      <td>bostrom17wuryy4kexsgyq6rq2k3x0735n4ntqeq3flav5...</td>\n      <td>0x84c8f25ca81c784d243e406ec8a4a1e389aa728dc235...</td>\n      <td>{'pub_key': 'A9bjehAjjY32eiYHqWier3WVEOdZUwZ8Q...</td>\n      <td>eyJwdWJfa2V5IjoiQTliamVoQWpqWTMyZWlZSHFXaWVyM1...</td>\n      <td>[cc3c069b0ce8d95d69e48a7b4f3728d892a36270e3e52...</td>\n      <td>[5398e38c29e181c2ff18cd4df1215ca90677cca24eeb6...</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>2</td>\n      <td>33000</td>\n      <td>john16548361752</td>\n      <td>QmQrf4uaZFS8YyouRuYW7RdSjZAY18jxB9t6NrWWqa9WKn</td>\n      <td>0x597ad4478d64d2702ad3187fd07ed2159a9b38d3</td>\n      <td>0x046508e879cf32970d3150c439b20dbf4b5aedeccbe6...</td>\n      <td>bostrom1ag0uyutudtdtr7aenpc0c0jaedrwrsjf0jfury</td>\n      <td>terra1ag0uyutudtdtr7aenpc0c0jaedrwrsjf2980lr</td>\n      <td>broccoli year exclude ship butter install goss...</td>\n      <td>bostrom1ag0uyutudtdtr7aenpc0c0jaedrwrsjf0jfury...</td>\n      <td>0xfc895e22ddcfc885b17b91fbc21146aa422d64e2ac43...</td>\n      <td>{'pub_key': 'AtTl2h3Nafoifz384IlN2M97SvoX/oZiQ...</td>\n      <td>eyJwdWJfa2V5IjoiQXRUbDJoM05hZm9pZnozODRJbE4yTT...</td>\n      <td>[50a1a2537255c5e1f077442076b2273671acc7b2d5a46...</td>\n      <td>[ad1576871f19a385d00e90552c06a38d084ba80aa043f...</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>3</td>\n      <td>32000</td>\n      <td>john16548361753</td>\n      <td>QmYLg2fgKA6ptwXa4mFXyq2JqjEyTWMrFXwvu3J23zbepW</td>\n      <td>0xff0cf02f40e8021a91c48b79b7412c7b1c568b2f</td>\n      <td>0x17ab2a2fbc4dc59d3d837892de0af854d922e79117bd...</td>\n      <td>bostrom1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfad5ulu4</td>\n      <td>cosmos1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfaw8gvzj</td>\n      <td>autumn nominee slab attend iron odor antique w...</td>\n      <td>bostrom1gqz7pm32fcvzzskk7dg3kp0vgzs4aqfad5ulu4...</td>\n      <td>0x9a6179bbb941309bd5247e82a30f6b1fab4f63bcdc87...</td>\n      <td>{'pub_key': 'Amw0GvH82F8z30EaAGnRqT75oSpWxMWzI...</td>\n      <td>eyJwdWJfa2V5IjoiQW13MEd2SDgyRjh6MzBFYUFHblJxVD...</td>\n      <td>[e069f04ee7b66a3181a7fcc473cde8fb80b10ef8077f3...</td>\n      <td>[0da1f0fe7351add378fb84ade27270a297bce88360b95...</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>4</td>\n      <td>38000</td>\n      <td>john16548361754</td>\n      <td>QmNWX5GLuXzhhtZdxNAnWWC42gqJsA6A2fjsseB5HPVDyw</td>\n      <td>0xd8b950ffa0b84b4d73e377a5ca86ea0c233a83c7</td>\n      <td>0x66907d36d32bd3e99be73912172ebb6198a768dfa049...</td>\n      <td>bostrom1x9966p9dwtcju7vy6lcc4mvvqsj5rnffxsz79q</td>\n      <td>cosmos1x9966p9dwtcju7vy6lcc4mvvqsj5rnff9rkdm8</td>\n      <td>aware card grass item rural swallow alcohol co...</td>\n      <td>bostrom1x9966p9dwtcju7vy6lcc4mvvqsj5rnffxsz79q...</td>\n      <td>0x59f2175d252ba9a551c8f9e957e26592769e2181e594...</td>\n      <td>{'pub_key': 'AtDo/b+BravMbmqq8qoD40ROzNA84J2iY...</td>\n      <td>eyJwdWJfa2V5IjoiQXREby9iK0JyYXZNYm1xcThxb0Q0MF...</td>\n      <td>[5239d46e245ce4af1f69ec17f7786c6042fea7f62a0d8...</td>\n      <td>[9bb1d32faec7ad21dd219cce62196c374806fd1d77d36...</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "if CALCULATE_PROOFS:\n",
    "    roots = []\n",
    "    proofs_df = pd.DataFrame(columns=['address', 'amount', 'proof'])\n",
    "    for task in tasks:\n",
    "        with open(task[1], 'r') as proof_file:\n",
    "            root_and_proof_json = json.load(proof_file)\n",
    "        roots.append(root_and_proof_json['merkle_root'])\n",
    "        proofs_df = pd.concat([proofs_df, pd.DataFrame(root_and_proof_json['proofs'])], ignore_index=True)\n",
    "    assert roots == [roots[0]] * len(roots)\n",
    "    root = roots[0]\n",
    "\n",
    "    cosmos_proofs_df = proofs_df[~proofs_df.address.str.startswith('0x')]'address', 'proof'\n",
    "    ethereum_proofs_df = proofs_df[proofs_df.address.str.startswith('0x')]'address', 'proof'\n",
    "\n",
    "    claims_with_proofs_df = claims_df\\\n",
    "        .merge(\n",
    "            ethereum_proofs_df.rename(columns={'address': 'ethereum_address', 'proof': 'ethereum_proof'}),\n",
    "            how='inner',\n",
    "            on='ethereum_address')\\\n",
    "        .merge(\n",
    "            cosmos_proofs_df.rename(columns={'address': 'cosmos_address', 'proof': 'cosmos_proof'}),\n",
    "            how='inner',\n",
    "            on='cosmos_address')\n",
    "\n",
    "    claims_with_proofs_df.to_csv(PARTICIPANTS_FILE_NAME)\n",
    "else:\n",
    "    claims_with_proofs_df = pd.read_csv(PARTICIPANTS_FILE_NAME)\n",
    "    claims_with_proofs_df.loc[:, 'ethereum_proof'] = claims_with_proofs_df['ethereum_proof'].map(lambda x: x.replace('\\'', '').replace('[', '').replace(']', '').split(', '))\n",
    "    claims_with_proofs_df.loc[:, 'cosmos_proof'] = claims_with_proofs_df['cosmos_proof'].map(lambda x: x.replace('\\'', '').replace('[', '').replace(']', '').split(', '))\n",
    "    with open('temp/proofs_1.json', 'r') as proof_file:\n",
    "        root_and_proof_json = json.load(proof_file)\n",
    "    root = root_and_proof_json['merkle_root']\n",
    "claims_with_proofs_df.head()"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [],
   "source": [
    "for i in range(ceil(NUMBER_OF_ACTIVATED_PARTICIPANTS/10_000)):\n",
    "    claims_with_proofs_df.loc[i*10_000:(i+1)*10_000,:].to_csv(f'temp/{i}_{PARTICIPANTS_FILE_NAME.split(\"/\")[1]}')"
   ],
   "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": 7,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name subgraph contract address: bostrom1zwv6feuzhy6a9wekh96cd57lsarmqlwxdypdsplw6zhfncqw6ftq67yzdk\n",
      "Avatar subgraph contract address: bostrom1ghd753shjuwexxywmgs4xz7x2q732vcnkm6h2pyv9s6ah3hylvrqxkr9dg\n",
      "Proof subgraph contract address: bostrom1xt4ahzz2x8hpkc0tk6ekte9x6crw4w6u0r67cyt3kz9syh24pd7s4t9edr\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",
    "            from_address=WALLET_ADDRESS)\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",
    "            from_address=WALLET_ADDRESS)\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": 8,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Passport contract address: bostrom1fzm6gzyccl8jvdv3qq6hp9vs6ylaruervs4m06c7k0ntzn2f8faq7ha2z2\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",
    "            from_address=WALLET_ADDRESS)\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": 9,
   "outputs": [],
   "source": [
    "def set_executor_subgraph(subgraph_contract_address: str, new_executor_address: str, display_data: bool = False):\n",
    "    return execute_contract_bash(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 Treasury Contract"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Treasury contract address: bostrom19ttnpna4fpwuhw9dwjukah5esz9ruutquuvhxa7ulyyk047vvpvs7nh8wu\n"
     ]
    }
   ],
   "source": [
    "if INIT_TREASURY_CONTRACT:\n",
    "    treasury_contract_address = \\\n",
    "        instantiate_contract(\n",
    "            init_query=f'''{{\"admins\": [\"{WALLET_ADDRESS}\"], \"mutable\": true}}''',\n",
    "            contract_code_id=TREASURY_CODE_ID,\n",
    "            amount=INITIAL_BALANCE,\n",
    "            contract_label='test treasury',\n",
    "            from_address=WALLET_ADDRESS,\n",
    "            display_data=False)\n",
    "else:\n",
    "    treasury_contract_address = TREASURY_CONTRACT_ADDRESS\n",
    "print(f'Treasury contract address: {treasury_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": 11,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gift contract address: bostrom1gc5wcdn9ges00w0l2cfxd7r2puyflak5dmkg26rsh083afmnrjxq3q6aaa\n"
     ]
    }
   ],
   "source": [
    "if INIT_GIFT_CONTRACT:\n",
    "    gift_contract_address = \\\n",
    "        instantiate_contract(\n",
    "            init_query=f'''{{\"owner\":\"{WALLET_ADDRESS}\", \"passport\":\"{passport_contract_address}\", \"treasury\":\"{treasury_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",
    "            contract_label='test gift',\n",
    "            from_address=WALLET_ADDRESS,\n",
    "            display_data=False)\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": [
    "### Initiate Class of Output Parsing"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [],
   "source": [
    "contract_utils = ContractUtils(ipfs_client=ipfs_client,\n",
    "                               address_dict= {\n",
    "                                   gift_contract_address: 'Gift Contract',\n",
    "                                   passport_contract_address: 'Passport Contract',\n",
    "                                   treasury_contract_address: 'Treasury Contract',\n",
    "                                   WALLET_ADDRESS: 'Passport Owner Address',\n",
    "                                   name_subgraph_contract_address: 'Name Subgraph Contract',\n",
    "                                   avatar_subgraph_contract_address: 'Avatar Subgraph Contract',\n",
    "                                   proof_subgraph_contract_address: 'Proof Subgraph Contract'})"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Set Allowance in Treasury contract"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Events\n",
      "\n",
      "coin received\n",
      "\treceiver: Treasury Contract\n",
      "\tamount: 30000000000boot\n",
      "\n",
      "coin spent\n",
      "\tspender: Passport Owner Address\n",
      "\tamount: 30000000000boot\n",
      "\n",
      "message from bank bostrom1mxdtr8lruutugqtxgpw2sf2tl2mhzlq5fd2du0 /cosmos.bank.v1beta1.MsgMultiSend\n",
      "\n",
      "transfer\n",
      "\trecipient: Treasury Contract\n",
      "\tamount: 30000000000boot\n",
      "Gas used: 86,568\n",
      "Tx hash: 823B7CB39E0B68EDD6ABC409CF595F9923BE936A7E7A386996185C83981C081E\n"
     ]
    }
   ],
   "source": [
    "contract_utils.parse_contract_execution_json(\n",
    "    contract_utils.send_coins(\n",
    "        from_seed=WALLET_SEED,\n",
    "        to_addresses=[treasury_contract_address],\n",
    "        amounts=[INITIAL_BALANCE],\n",
    "        gas=min(100_000 + 25_000, int(20e6)),\n",
    "        display_data=DISPLAY_TX_EXECUTION))"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Events\n",
      "\n",
      "execute\n",
      "\texecute contract: Treasury Contract\n",
      "\n",
      "message from Passport Owner Address wasm /cosmwasm.wasm.v1.MsgExecuteContract\n",
      "\n",
      "wasm\n",
      "\t_contract_address: Treasury Contract\n",
      "\taction: increase_allowance\n",
      "\towner: Passport Owner Address\n",
      "\tspender: Gift Contract\n",
      "\tdenomination: boot\n",
      "\tamount: 30,000,000,000\n",
      "Gas used: 135,339\n",
      "Tx hash: B680702CE0A4CBF4AA2E2A2CFA0221F6D30DC067528965E94476F1C9137EF913\n"
     ]
    }
   ],
   "source": [
    "def set_allowance(amount: str = INITIAL_BALANCE, display_data: bool = False):\n",
    "    return contract_utils.execute_contract(\n",
    "        execute_msg={\"increase_allowance\": {\"spender\": gift_contract_address, \"amount\": {\"amount\": amount, \"denom\": 'boot'}}},\n",
    "        contract_address=treasury_contract_address,\n",
    "        mnemonic=WALLET_SEED,\n",
    "        gas=600000,\n",
    "        display_data=display_data)\n",
    "\n",
    "contract_utils.parse_contract_execution_json(\n",
    "    set_allowance(display_data=False))"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Register Merkle Root"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Events\n",
      "\n",
      "execute\n",
      "\texecute contract: Gift Contract\n",
      "\n",
      "message from Passport Owner Address wasm /cosmwasm.wasm.v1.MsgExecuteContract\n",
      "\n",
      "wasm\n",
      "\t_contract_address: Gift Contract\n",
      "\taction: register_merkle_root\n",
      "\tmerkle_root: 0cd70e3c34ff111de47721ca40ece8fad8d49549bfc16d29f5d074781bdd3ff1\n",
      "Gas used: 130,976\n",
      "Tx hash: F20198A196F13F8D1FB93E66116A66ADE77C7E43726AA8BEBAF419ADBD316E82\n"
     ]
    }
   ],
   "source": [
    "root_register_output = contract_utils.execute_contract(\n",
    "    execute_msg={\"register_merkle_root\": {\"merkle_root\": root}},\n",
    "    mnemonic=WALLET_SEED,\n",
    "    contract_address=gift_contract_address)\n",
    "contract_utils.parse_contract_execution_json(root_register_output)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### Get Merkle Root form the Gift Contract"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "execution_count": 156
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gift contract bostrom1gc5wcdn9ges00w0l2cfxd7r2puyflak5dmkg26rsh083afmnrjxq3q6aaa\n",
      "{'data': {'merkle_root': '0cd70e3c34ff111de47721ca40ece8fad8d49549bfc16d29f5d074781bdd3ff1'}}\n"
     ]
    }
   ],
   "source": [
    "print(f'Gift contract {gift_contract_address}')\n",
    "print(query_contract(query='''{\"merkle_root\": {}}''',\n",
    "                     contract_address=gift_contract_address))"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Send coins to new addresses"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "outputs": [
    {
     "data": {
      "text/plain": "0it [00:00, ?it/s]",
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "9888696f1aa7491e9d667c08d72ffbac"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "NUMBER_ADDRESSES_IN_SENDING_CHUNK = 800\n",
    "\n",
    "bostrom_addresses = claims_with_proofs_df.bostrom_address.to_list()\n",
    "bostrom_addresses_chunks = [bostrom_addresses[i: i+ NUMBER_ADDRESSES_IN_SENDING_CHUNK] for i in range(0, len(bostrom_addresses), NUMBER_ADDRESSES_IN_SENDING_CHUNK)]\n",
    "\n",
    "send_output = []\n",
    "for i, bostrom_addresses_item in tqdm(enumerate(bostrom_addresses_chunks)):\n",
    "    try:\n",
    "        send_output.append(\n",
    "            contract_utils.send_coins(\n",
    "                from_seed=WALLET_SEED,\n",
    "                to_addresses=bostrom_addresses_item,\n",
    "                amounts=[1] * len(bostrom_addresses_item),\n",
    "                gas=min(150_000 + 30_000 * len(bostrom_addresses_item), int(22e6)),\n",
    "                display_data=DISPLAY_TX_EXECUTION))\n",
    "    except Exception as e:\n",
    "        print(f'Error in the {i} chunk: {e}')\n",
    "        sleep(15)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "contract_utils.parse_contract_execution_json(contract_execution_json=send_output[0])"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Create Passports, Proof Addresses and Claim Gift"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "def execute_participation(row_index: int) -> bool:\n",
    "    _output, _error = execute_bash(bash_command=f'{PYTHON_PATH} create_passport_and_claim_job.py temp/{row_index//10_000}_{PARTICIPANTS_FILE_NAME.split(\"/\")[1]} {row_index} {gift_contract_address}')\n",
    "    if _output:\n",
    "        return _output\n",
    "    else:\n",
    "        return _error\n",
    "\n",
    "NUMBER_OF_THREADS = 100\n",
    "\n",
    "tasks = list(range(NUMBER_OF_ACTIVATED_PARTICIPANTS))\n",
    "print(f'Number of tasks: {len(tasks):>,}')\n",
    "print(f'Number of threads: {NUMBER_OF_THREADS:>,}')\n",
    "\n",
    "\n",
    "with Pool(processes=NUMBER_OF_THREADS) as pool:\n",
    "    res_participation = list(tqdm(pool.imap(execute_participation, tasks), total=len(tasks)))"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "import json\n",
    "with open('temp/contract_participation_execution_log_2.txt', 'r') as f:\n",
    "    data = json.load(f)\n",
    "data"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "contract_utils.parse_contract_execution_json(data['create'], row=claims_with_proofs_df.loc[1,:])"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "contract_utils.parse_contract_execution_json(data['proof_ethereum'], row=claims_with_proofs_df.loc[1,:])"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "contract_utils.parse_contract_execution_json(data['proof_cosmos'], row=claims_with_proofs_df.loc[1,:])"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "contract_utils.parse_contract_execution_json(data['claim_cosmos'], row=claims_with_proofs_df.loc[1,:])"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Release Gift"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of tasks: 5,000\n",
      "Number of threads: 100\n"
     ]
    },
    {
     "data": {
      "text/plain": "  0%|          | 0/5000 [00:00<?, ?it/s]",
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "3cd12ba642ae447981b9cb45a1799224"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def execute_release(row_index: int) -> bool:\n",
    "    _output, _error = execute_bash(bash_command=f'{PYTHON_PATH} create_passport_and_claim_job.py temp/{row_index//10_000}_{PARTICIPANTS_FILE_NAME.split(\"/\")[1]} {row_index} {gift_contract_address} True')\n",
    "    if _output:\n",
    "        return _output\n",
    "    else:\n",
    "        return _error\n",
    "\n",
    "\n",
    "NUMBER_OF_THREADS = 100\n",
    "\n",
    "tasks = list(range(NUMBER_OF_ACTIVATED_PARTICIPANTS))\n",
    "print(f'Number of tasks: {len(tasks):>,}')\n",
    "print(f'Number of threads: {NUMBER_OF_THREADS:>,}')\n",
    "\n",
    "\n",
    "with Pool(processes=NUMBER_OF_THREADS) as pool:\n",
    "    res_release = list(tqdm(pool.imap(execute_release, tasks), total=len(tasks)))"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "with open('temp/contract_release_execution_log_1.txt', 'r') as f:\n",
    "    release_data = json.load(f)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "release_data"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "contract_utils.parse_contract_execution_json(release_data['release_ethereum'], row=claims_with_proofs_df.loc[1,:])"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "contract_utils.parse_contract_execution_json(release_data['release_cosmos'], row=claims_with_proofs_df.loc[1,:])"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Passport NFT testing"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "def get_passport_id(bostrom_address: str) -> str:\n",
    "    try:\n",
    "        return query_contract(query=f'''{{\"tokens\": {{\"owner\": \"{bostrom_address}\"}}}}''',\n",
    "                              contract_address=passport_contract_address)['data']['tokens'][0]\n",
    "    except (json.JSONDecodeError, IndexError) as e:\n",
    "        print(f'Error in the get passport: {e}')\n",
    "        return ''"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "def execute_passport_test(row_index: int, contract_utils=contract_utils) -> bool:\n",
    "    row = claims_with_proofs_df.iloc[row_index]\n",
    "    if row_index % 5 == 1:\n",
    "        transfer_passport_json = contract_utils.transfer_passport(\n",
    "            row,\n",
    "            token_id=get_passport_id(row['bostrom_address']),\n",
    "            to_address=WALLET_ADDRESS,\n",
    "            display_data=DISPLAY_TX_EXECUTION)\n",
    "        if row_index < 6:\n",
    "            print('\\nTRANSFER')\n",
    "            contract_utils.parse_contract_execution_json(transfer_passport_json, row=row)\n",
    "    elif row_index % 5 == 2:\n",
    "        burn_passport_json = contract_utils.burn_passport(\n",
    "            row,\n",
    "            token_id=get_passport_id(row['bostrom_address']),\n",
    "            display_data=DISPLAY_TX_EXECUTION)\n",
    "        if row_index < 6:\n",
    "            print('\\nBURN')\n",
    "            contract_utils.parse_contract_execution_json(burn_passport_json, row=row)\n",
    "    elif row_index % 5 == 3:\n",
    "        update_name_json = contract_utils.update_name(\n",
    "            row,\n",
    "            new_nickname=row['nickname'] + '_new',\n",
    "            display_data=DISPLAY_TX_EXECUTION)\n",
    "        if row_index < 6:\n",
    "            print('\\nUPDATE NAME')\n",
    "            contract_utils.parse_contract_execution_json(update_name_json, row=row)\n",
    "    elif row_index % 5 == 4:\n",
    "        update_avatar_json = contract_utils.update_avatar(\n",
    "            row,\n",
    "            new_avatar=get_ipfs_cid_from_str(row['nickname'] + '_new_avatar'),\n",
    "            display_data=DISPLAY_TX_EXECUTION)\n",
    "        if row_index < 6:\n",
    "            print('\\nUPDATE AVATAR')\n",
    "            contract_utils.parse_contract_execution_json(update_avatar_json, row=row)\n",
    "    elif row_index % 5 == 0:\n",
    "       remove_address_json = contract_utils.remove_address(\n",
    "            row,\n",
    "            removed_address=row['cosmos_address'],\n",
    "            display_data=DISPLAY_TX_EXECUTION)\n",
    "       if row_index < 6:\n",
    "           print('\\nREMOVE ADDRESS')\n",
    "           contract_utils.parse_contract_execution_json(remove_address_json, row=row)\n",
    "    print(f'Finish: {row_index}')\n",
    "    return True\n",
    "\n",
    "NUMBER_OF_THREADS = 100\n",
    "\n",
    "tasks = list(range(NUMBER_OF_ACTIVATED_PARTICIPANTS))[:20]\n",
    "print(f'Number of tasks: {len(tasks):>,}')\n",
    "print(f'Number of threads: {NUMBER_OF_THREADS:>,}')\n",
    "\n",
    "for row_index in tqdm(range(34, NUMBER_OF_ACTIVATED_PARTICIPANTS)):\n",
    "    execute_passport_test(row_index)\n",
    "# with Pool(processes=NUMBER_OF_THREADS) as pool:\n",
    "#     # res_passport_test = list(tqdm(pool.imap(execute_passport_test, tasks), total=len(tasks)))\n",
    "#     res_passport_test = list(pool.imap(execute_passport_test, tasks))"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "# claims_with_proofs_df\n",
    "execute_passport_test(0)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### Add tests for Passport contract\n",
    "#### create_passport +\n",
    "#### update_name +\n",
    "#### update_avatar +\n",
    "#### proof_address +\n",
    "#### remove_address +\n",
    "#### set_minter\n",
    "#### set_owner\n",
    "#### set_active\n",
    "#### set_subgraphs +\n",
    "#### transfer_nft +\n",
    "#### send_nft\n",
    "#### mint\n",
    "#### burn +\n",
    "#### approve\n",
    "#### approve_all\n",
    "#### revoke\n",
    "#### revoke_all\n",
    "#### Expirations\n",
    "##### at_height\n",
    "##### at_time\n",
    "##### never\n",
    "\n",
    "### Add tests for Gift contract\n",
    "#### update_owner\n",
    "#### update_passport_addr\n",
    "#### update_target\n",
    "#### register_merkle_root +\n",
    "#### claim +\n",
    "#### release +\n",
    "\n",
    "### Add tests for subgraph contract\n",
    "#### update_owner\n",
    "#### update_executer +"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [],
   "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