예제 #1
0
def unlock(aergo_to: herapy.Aergo, receiver: str, burn_proof: AttributeDict,
           token_origin: str, bridge_to: str, gas_limit: int,
           gas_price: int) -> Tuple[str, Transaction]:
    """ Unlock the receiver's deposit balance on aergo_to. """
    if not is_aergo_address(receiver):
        raise InvalidArgumentsError(
            "Receiver {} must be an Aergo address".format(receiver))
    if not is_aergo_address(token_origin):
        raise InvalidArgumentsError(
            "token_origin {} must be an Aergo address".format(token_origin))
    ap = format_proof_for_lua(burn_proof.storageProof[0].proof)
    balance = int.from_bytes(burn_proof.storageProof[0].value, "big")
    ubig_balance = {'_bignum': str(balance)}
    # call unlock on aergo_to with the burn proof from aergo_from
    tx, result = aergo_to.call_sc(
        bridge_to, "unlock", args=[receiver, ubig_balance, token_origin, ap])
    if result.status != herapy.CommitStatus.TX_OK:
        raise TxError("Unlock asset Tx commit failed : {}".format(result))

    result = aergo_to.wait_tx_result(tx.tx_hash)
    if result.status != herapy.TxResultStatus.SUCCESS:
        raise TxError("Unlock asset Tx execution failed : {}".format(result))
    logger.info("\u26fd Aergo gas used: %s", result.gas_used)
    return str(tx.tx_hash), result
예제 #2
0
 def get_asset_address(self, asset_name, from_chain, to_chain):
     try:
         addr = self.wallet.config_data(
             'networks', from_chain, 'tokens', asset_name, 'addr')
         return addr
     except KeyError:
         pass
     try:
         addr = self.wallet.config_data(
             'networks', to_chain, 'tokens', asset_name, 'pegs', from_chain)
         return addr
     except KeyError:
         pass
     raise InvalidArgumentsError(
         'asset not properly registered in config.json')
예제 #3
0
def build_burn_proof(
    w3: Web3,
    aergo_to: herapy.Aergo,
    receiver: str,
    bridge_from: str,
    bridge_to: str,
    burn_height: int,
    token_origin: str,
):
    """ Check the last anchored root includes the lock and build
    a lock proof for that root
    """
    if not is_aergo_address(receiver):
        raise InvalidArgumentsError(
            "Receiver {} must be an Aergo address".format(receiver))
    if not is_aergo_address(token_origin):
        raise InvalidArgumentsError(
            "token_origin {} must be an Aergo address".format(token_origin))
    account_ref = (receiver + token_origin).encode('utf-8')
    # 'Burns is the 8th state var defined in solitity contract
    position = b'\x07'
    trie_key = keccak(account_ref + position.rjust(32, b'\0'))
    return _build_deposit_proof(w3, aergo_to, bridge_from, bridge_to,
                                burn_height, trie_key)
예제 #4
0
    def burn_to_eth(
        self,
        from_chain: str,
        to_chain: str,
        asset_name: str,
        amount: int,
        receiver: str,
        privkey_name: str = 'default',
        privkey_pwd: str = None,
    ) -> Tuple[int, str]:
        """ Initiate minted token transfer back to ethereum origin"""
        logger.info(from_chain + ' -> ' + to_chain)
        if not is_ethereum_address(receiver):
            raise InvalidArgumentsError(
                "receiver {} must be an Ethereum address".format(receiver))
        aergo_from = self.get_aergo(from_chain, privkey_name, privkey_pwd)
        sender = str(aergo_from.account.address)
        bridge_from = self.get_bridge_contract_address(from_chain, to_chain)
        token_pegged = self.get_asset_address(asset_name,
                                              from_chain,
                                              asset_origin_chain=to_chain)

        gas_limit = 300000
        balance = aergo_u.get_balance(sender, token_pegged, aergo_from)
        if balance < amount:
            raise InsufficientBalanceError("not enough token balance")
        logger.info("\U0001f4b0 %s balance on origin before transfer: %s",
                    asset_name, balance / 10**18)

        aer_balance = aergo_u.get_balance(sender, 'aergo', aergo_from)
        if aer_balance < gas_limit * self.aergo_gas_price:
            err = "not enough aer balance to pay tx fee"
            raise InsufficientBalanceError(err)

        burn_height, tx_hash, _ = aergo_to_eth.burn(aergo_from, bridge_from,
                                                    receiver, amount,
                                                    token_pegged, gas_limit,
                                                    self.aergo_gas_price)
        logger.info('\U0001f525 Burn success: %s', tx_hash)

        # remaining balance on origin : aer or asset
        balance = aergo_u.get_balance(sender, token_pegged, aergo_from)
        logger.info(
            "\U0001f4b0 remaining %s balance on origin after transfer: %s",
            asset_name, balance / 10**18)

        aergo_from.disconnect()
        return burn_height, tx_hash
예제 #5
0
    def unlock_to_aergo(
        self,
        from_chain: str,
        to_chain: str,
        asset_name: str,
        receiver: str,
        burn_height: int = 0,
        privkey_name: str = 'default',
        privkey_pwd: str = None,
    ) -> str:
        """ Finalize Aergo Standard token transfer back to Aergo Origin"""
        logger.info(from_chain + ' -> ' + to_chain)
        if not is_aergo_address(receiver):
            raise InvalidArgumentsError(
                "Receiver {} must be an Aergo address".format(receiver))
        w3 = self.get_web3(from_chain)
        aergo_to = self.get_aergo(to_chain, privkey_name, privkey_pwd)
        tx_sender = str(aergo_to.account.address)
        bridge_to = self.get_bridge_contract_address(to_chain, from_chain)
        bridge_from = self.get_bridge_contract_address(from_chain, to_chain)
        asset_address = self.get_asset_address(asset_name, to_chain)

        burn_proof = eth_to_aergo.build_burn_proof(w3, aergo_to, receiver,
                                                   bridge_from, bridge_to,
                                                   burn_height, asset_address)
        logger.info("\u2699 Built burn proof")

        balance = aergo_u.get_balance(receiver, asset_address, aergo_to)
        logger.info("\U0001f4b0 %s balance on destination before transfer: %s",
                    asset_name, balance / 10**18)

        gas_limit = 300000
        aer_balance = aergo_u.get_balance(tx_sender, 'aergo', aergo_to)
        if aer_balance < gas_limit * self.aergo_gas_price:
            err = "not enough aer balance to pay tx fee"
            raise InsufficientBalanceError(err)

        tx_hash, _ = eth_to_aergo.unlock(aergo_to, receiver, burn_proof,
                                         asset_address, bridge_to, gas_limit,
                                         self.aergo_gas_price)
        logger.info('\U0001f513 Unlock success: %s', tx_hash)

        # new balance on origin
        balance = aergo_u.get_balance(receiver, asset_address, aergo_to)
        logger.info("\U0001f4b0 %s balance on destination after transfer: %s",
                    asset_name, balance / 10**18)

        return tx_hash
예제 #6
0
def get_abi_function(w3: Web3, asset_addr: str, abi: str, spender: str,
                     amount: int):
    token_contract = w3.eth.contract(address=asset_addr, abi=abi)
    try:
        function = token_contract.functions.increaseAllowance(spender, amount)
        return function
    except MismatchedABI:
        pass
    try:
        function = token_contract.functions.increaseApproval(spender, amount)
        return function
    except MismatchedABI:
        pass
    raise InvalidArgumentsError(
        "Impossible to send ERC20 tokens to bridge contract: "
        "'increaseAllowance' or 'increaseApproval' must be included "
        "in ERC20 abi")
예제 #7
0
def _build_deposit_proof(
    aergo_from: herapy.Aergo,
    w3: Web3,
    bridge_from: str,
    bridge_to: str,
    bridge_to_abi: str,
    deposit_height: int,
    trie_key: bytes,
):
    """ Check the last anchored root includes the deposit and build
    a deposit proof for that root
    """
    # check last merged height
    eth_bridge = w3.eth.contract(address=bridge_to, abi=bridge_to_abi)
    try:
        last_merged_height_to = eth_bridge.functions._anchorHeight().call()
    except BadFunctionCallOutput as e:
        raise InvalidArgumentsError(e, bridge_to)
    # waite for anchor containing our transfer
    if last_merged_height_to < deposit_height:
        logger.info(
            "\u23F0 deposit not recorded in current anchor, waiting new "
            "anchor event... / deposit height : %s / last anchor height : %s ",
            deposit_height, last_merged_height_to)
        while last_merged_height_to < deposit_height:
            time.sleep(1)
            last_merged_height_to = eth_bridge.functions._anchorHeight().call()
    # get inclusion proof of lock in last merged block
    merge_block_from = aergo_from.get_block_headers(
        block_height=last_merged_height_to, list_size=1)
    root_from = merge_block_from[0].blocks_root_hash
    proof = aergo_from.query_sc_state(bridge_from, [trie_key],
                                      root=root_from,
                                      compressed=True)
    if not proof.verify_proof(root_from):
        raise InvalidMerkleProofError("Unable to verify deposit proof", proof)
    if not proof.account.state_proof.inclusion:
        raise InvalidMerkleProofError(
            "Contract doesnt exist in state, check contract deployed and "
            "chain synced {}".format(proof))
    if not proof.var_proofs[0].inclusion:
        raise InvalidMerkleProofError(
            "No tokens deposited for this account reference: {}".format(proof))
    return proof
예제 #8
0
 def get_balance_aergo(self,
                       asset_name: str,
                       network_name: str,
                       asset_origin_chain: str = None,
                       account_name: str = 'default',
                       account_addr: str = None) -> Tuple[int, str]:
     """ Get account name balance of asset_name on network_name,
     and specify asset_origin_chain for a pegged asset query,
     """
     if account_addr is None:
         account_addr = self.config_data('wallet', account_name, 'addr')
     if not is_aergo_address(account_addr):
         raise InvalidArgumentsError(
             "Account {} must be an Aergo address".format(account_addr))
     aergo = self.connect_aergo(network_name)
     asset_addr = self.get_asset_address(asset_name, network_name,
                                         asset_origin_chain)
     balance = aergo_u.get_balance(account_addr, asset_addr, aergo)
     aergo.disconnect()
     return balance, asset_addr
예제 #9
0
    def prompt_signing_key(self, wallet_name):
        """Prompt user to select a private key.

        Note:
            Keys are displayed by name and should have been registered in
            wallet config.

        """
        accounts = self.wallet.config_data(wallet_name)
        if len(accounts) == 0:
            raise InvalidArgumentsError(
                "No private key available, first register a private key for "
                "signing transactions")
        questions = [{
            'type': 'list',
            'name': 'privkey_name',
            'message': 'Choose account to sign transaction : ',
            'choices': [name for name in accounts]
        }]
        answers = inquirer.prompt(questions, style=aergo_style)
        return answers['privkey_name']
예제 #10
0
    def freeze(
        self,
        from_chain: str,
        to_chain: str,
        amount: int,
        receiver: str,
        privkey_name: str = 'default',
        privkey_pwd: str = None,
    ) -> Tuple[int, str]:
        """ Initiate Aer transfer back to Ethereum AergoERC20 sidechain"""
        logger.info(from_chain + ' -> ' + to_chain)
        if not is_ethereum_address(receiver):
            raise InvalidArgumentsError(
                "receiver {} must be an Ethereum address".format(receiver))
        asset_name = 'aergo_erc20'
        aergo_from = self.get_aergo(from_chain, privkey_name, privkey_pwd)
        sender = str(aergo_from.account.address)
        bridge_from = self.get_bridge_contract_address(from_chain, to_chain)

        gas_limit = 300000
        balance = aergo_u.get_balance(sender, 'aergo', aergo_from)
        if balance < amount + gas_limit * self.aergo_gas_price:
            raise InsufficientBalanceError("not enough token balance")
        logger.info("\U0001f4b0 %s balance on origin before transfer: %s",
                    asset_name, balance / 10**18)

        freeze_height, tx_hash, _ = aergo_to_eth.freeze(
            aergo_from, bridge_from, receiver, amount, gas_limit,
            self.aergo_gas_price)
        logger.info('\u2744 Freeze success: %s', tx_hash)

        # remaining balance on origin : aer or asset
        balance = aergo_u.get_balance(sender, 'aergo', aergo_from)
        logger.info(
            "\U0001f4b0 remaining %s balance on origin after transfer: %s",
            asset_name, balance / 10**18)

        aergo_from.disconnect()
        return freeze_height, tx_hash
예제 #11
0
def transfer(
    value: int,
    to: str,
    asset_addr: str,
    aergo: herapy.Aergo,
    sender: str,
    fee_limit: int,
    fee_price: int,
) -> str:
    """ Support 3 types of transfers : simple aer transfers, token transfer,
    and signed token transfers (token owner != tx signer)
    """
    if not is_aergo_address(to):
        raise InvalidArgumentsError(
            "Receiver {} must be an Aergo address".format(to))
    aergo.get_account()  # get the latest nonce for making tx
    if asset_addr == "aergo":
        # transfer aer on network_name
        tx, result = aergo.send_payload(to_address=to,
                                        amount=value,
                                        payload=None)
    else:
        # transfer token (issued or pegged) on network_name
        tx, result = aergo.call_sc(asset_addr,
                                   "transfer",
                                   args=[to, {
                                       "_bignum": str(value)
                                   }],
                                   amount=0)

    if result.status != herapy.CommitStatus.TX_OK:
        raise TxError("Transfer asset Tx commit failed : {}".format(result))

    # Check lock success
    result = aergo.wait_tx_result(tx.tx_hash)
    if result.status != herapy.TxResultStatus.SUCCESS:
        raise TxError("Transfer asset Tx execution failed : {}".format(result))

    return str(tx.tx_hash)
예제 #12
0
def lock(w3: Web3,
         signer_acct,
         receiver: str,
         amount: int,
         bridge_from: str,
         bridge_from_abi: str,
         erc20_address: str,
         gas_limit: int,
         gas_price: int,
         next_nonce: int = None) -> Tuple[int, str, AttributeDict]:
    """ Lock an Ethereum ERC20 token. """
    if not is_aergo_address(receiver):
        raise InvalidArgumentsError(
            "Receiver {} must be an Aergo address".format(receiver))
    bridge_from = Web3.toChecksumAddress(bridge_from)
    eth_bridge = w3.eth.contract(address=bridge_from, abi=bridge_from_abi)
    if next_nonce is None:
        next_nonce = w3.eth.getTransactionCount(signer_acct.address)
    construct_txn = eth_bridge.functions.lock(erc20_address, amount,
                                              receiver).buildTransaction({
                                                  'chainId':
                                                  w3.eth.chainId,
                                                  'from':
                                                  signer_acct.address,
                                                  'nonce':
                                                  next_nonce,
                                                  'gas':
                                                  gas_limit,
                                                  'gasPrice':
                                                  w3.toWei(gas_price, 'gwei')
                                              })
    signed = signer_acct.sign_transaction(construct_txn)
    tx_hash = w3.eth.sendRawTransaction(signed.rawTransaction)
    receipt = w3.eth.waitForTransactionReceipt(tx_hash)
    if receipt.status != 1:
        raise TxError("Lock asset Tx execution failed: {}".format(receipt))
    logger.info("\u26fd Eth Gas used: %s", receipt.gasUsed)
    return receipt.blockNumber, tx_hash.hex(), receipt
예제 #13
0
    def mint_to_eth(
        self,
        from_chain: str,
        to_chain: str,
        asset_name: str,
        receiver: str = None,
        lock_height: int = 0,
        privkey_name: str = 'default',
        privkey_pwd: str = None,
    ) -> Tuple[str, str]:
        """ Finalize Aergo Standard Token transfer to Ethereum sidechain
        NOTE anybody can mint so sender is not necessary.
        The amount to mint is the difference between total deposit and
        already minted amount.
        Bridge tempo is taken from config_data
        """
        logger.info(from_chain + ' -> ' + to_chain)
        bridge_to_abi = self.load_bridge_abi(to_chain, from_chain)
        minted_erc20_abi = self.load_minted_erc20_abi(to_chain, from_chain)
        aergo_from = self.connect_aergo(from_chain)
        w3 = self.get_web3(to_chain)
        signer_acct = self.get_signer(w3, privkey_name, privkey_pwd)
        tx_sender = signer_acct.address
        if receiver is None:
            receiver = tx_sender
        if not is_ethereum_address(receiver):
            raise InvalidArgumentsError(
                "receiver {} must be an Ethereum address".format(receiver))
        bridge_from = self.get_bridge_contract_address(from_chain, to_chain)
        bridge_to = self.get_bridge_contract_address(to_chain, from_chain)
        asset_address = self.get_asset_address(asset_name, from_chain)

        save_pegged_token_address = False
        try:
            token_pegged = self.get_asset_address(
                asset_name, to_chain, asset_origin_chain=from_chain)
            balance = eth_u.get_balance(receiver, token_pegged, w3,
                                        minted_erc20_abi)
            logger.info(
                "\U0001f4b0 %s balance on destination before transfer : %s",
                asset_name, balance / 10**18)
        except KeyError:
            logger.info("Pegged token unknow by wallet")
            save_pegged_token_address = True

        gas_limit = 2000000
        eth_balance = eth_u.get_balance(tx_sender, 'ether', w3)
        if eth_balance * 10**9 < gas_limit * self.eth_gas_price:
            err = "not enough aer balance to pay tx fee"
            raise InsufficientBalanceError(err)

        lock_proof = aergo_to_eth.build_lock_proof(aergo_from, w3, receiver,
                                                   bridge_from, bridge_to,
                                                   bridge_to_abi, lock_height,
                                                   asset_address)
        logger.info("\u2699 Built lock proof")

        token_pegged, tx_hash, _ = aergo_to_eth.mint(w3, signer_acct, receiver,
                                                     lock_proof, asset_address,
                                                     bridge_to, bridge_to_abi,
                                                     gas_limit,
                                                     self.eth_gas_price)
        logger.info('\u26cf Mint success: %s', tx_hash)

        # new balance on sidechain
        balance = eth_u.get_balance(receiver, token_pegged, w3,
                                    minted_erc20_abi)
        logger.info("\U0001f4b0 %s balance on destination after transfer : %s",
                    asset_name, balance / 10**18)

        aergo_from.disconnect()

        # record mint address in file
        if save_pegged_token_address:
            logger.info("------ Store mint address in config.json -----------")
            self.config_data('networks',
                             from_chain,
                             'tokens',
                             asset_name,
                             'pegs',
                             to_chain,
                             value=token_pegged)
            self.save_config()
        return token_pegged, tx_hash
예제 #14
0
    def mint_to_aergo(
        self,
        from_chain: str,
        to_chain: str,
        asset_name: str,
        receiver: str = None,
        lock_height: int = 0,
        privkey_name: str = 'default',
        privkey_pwd: str = None,
    ) -> str:
        """ Finalize ERC20 token or Ether transfer to Aergo sidechain """
        logger.info(from_chain + ' -> ' + to_chain)
        w3 = self.get_web3(from_chain)
        aergo_to = self.get_aergo(to_chain, privkey_name, privkey_pwd)
        tx_sender = str(aergo_to.account.address)
        bridge_to = self.get_bridge_contract_address(to_chain, from_chain)
        bridge_from = self.get_bridge_contract_address(from_chain, to_chain)
        asset_address = self.get_asset_address(asset_name, from_chain)
        if receiver is None:
            receiver = tx_sender
        if not is_aergo_address(receiver):
            raise InvalidArgumentsError(
                "Receiver {} must be an Aergo address".format(receiver))

        save_pegged_token_address = False
        try:
            token_pegged = self.get_asset_address(
                asset_name, to_chain, asset_origin_chain=from_chain)
            balance = aergo_u.get_balance(receiver, token_pegged, aergo_to)
            logger.info(
                "\U0001f4b0 %s balance on destination before transfer: %s",
                asset_name, balance / 10**18)
        except KeyError:
            logger.info("Pegged token unknow by wallet")
            save_pegged_token_address = True

        gas_limit = 300000
        aer_balance = aergo_u.get_balance(tx_sender, 'aergo', aergo_to)
        if aer_balance < gas_limit * self.aergo_gas_price:
            err = "not enough aer balance to pay tx fee"
            raise InsufficientBalanceError(err)

        lock_proof = eth_to_aergo.build_lock_proof(w3, aergo_to, receiver,
                                                   bridge_from, bridge_to,
                                                   lock_height, asset_address)
        logger.info("\u2699 Built lock proof")

        token_pegged, tx_hash, _ = eth_to_aergo.mint(aergo_to, receiver,
                                                     lock_proof, asset_address,
                                                     bridge_to, gas_limit,
                                                     self.aergo_gas_price)
        logger.info('\u26cf Mint success: %s', tx_hash)
        # new balance on destination
        balance = aergo_u.get_balance(receiver, token_pegged, aergo_to)
        logger.info("\U0001f4b0 %s balance on destination after transfer: %s",
                    asset_name, balance / 10**18)
        aergo_to.disconnect()

        # record mint address in file
        if save_pegged_token_address:
            logger.info("------ Store mint address in config.json -----------")
            self.config_data('networks',
                             from_chain,
                             'tokens',
                             asset_name,
                             'pegs',
                             to_chain,
                             value=token_pegged)
            self.save_config()
        return tx_hash
예제 #15
0
def bridge_withdrawable_balance(
    account_addr: str,
    asset_address_origin: str,
    bridge_from: str,
    bridge_to: str,
    aergo_from: herapy.Aergo,
    aergo_to: herapy.Aergo,
    deposit_key: str,
    withdraw_key: str,
) -> Tuple[int, int]:
    account_ref = account_addr + asset_address_origin
    # total_deposit : total latest deposit including pending
    _, block_height = aergo_from.get_blockchain_status()
    block_from = aergo_from.get_block_headers(block_height=block_height,
                                              list_size=1)
    root_from = block_from[0].blocks_root_hash

    deposit_proof = aergo_from.query_sc_state(bridge_from,
                                              [deposit_key + account_ref],
                                              root=root_from,
                                              compressed=False)
    if not deposit_proof.account.state_proof.inclusion:
        raise InvalidArgumentsError(
            "Contract doesnt exist in state, check contract deployed and "
            "chain synced {}".format(deposit_proof))
    total_deposit = 0
    if deposit_proof.var_proofs[0].inclusion:
        total_deposit = int(
            deposit_proof.var_proofs[0].value.decode('utf-8')[1:-1])

    # get total withdrawn and last anchor height
    withdraw_proof = aergo_to.query_sc_state(
        bridge_to, ["_sv__anchorHeight", withdraw_key + account_ref],
        compressed=False)
    if not withdraw_proof.account.state_proof.inclusion:
        raise InvalidArgumentsError(
            "Contract doesnt exist in state, check contract deployed and "
            "chain synced {}".format(withdraw_proof))
    if not withdraw_proof.var_proofs[0].inclusion:
        raise InvalidArgumentsError("Cannot query last anchored height",
                                    withdraw_proof)
    total_withdrawn = 0
    if withdraw_proof.var_proofs[1].inclusion:
        total_withdrawn = int(
            withdraw_proof.var_proofs[1].value.decode('utf-8')[1:-1])
    last_anchor_height = int(withdraw_proof.var_proofs[0].value)

    # get anchored deposit : total deposit before the last anchor
    block_from = aergo_from.get_block_headers(block_height=last_anchor_height,
                                              list_size=1)
    root_from = block_from[0].blocks_root_hash
    deposit_proof = aergo_from.query_sc_state(bridge_from,
                                              [deposit_key + account_ref],
                                              root=root_from,
                                              compressed=False)
    if not deposit_proof.account.state_proof.inclusion:
        raise InvalidArgumentsError(
            "Contract doesnt exist in state, check contract deployed and "
            "chain synced {}".format(deposit_proof))
    anchored_deposit = 0
    if deposit_proof.var_proofs[0].inclusion:
        anchored_deposit = int(
            deposit_proof.var_proofs[0].value.decode('utf-8')[1:-1])
    withdrawable_balance = anchored_deposit - total_withdrawn
    pending = total_deposit - anchored_deposit
    return withdrawable_balance, pending
예제 #16
0
def build_deposit_proof(
    aergo_from: herapy.Aergo,
    aergo_to: herapy.Aergo,
    receiver: str,
    bridge_from: str,
    bridge_to: str,
    deposit_height: int,
    token_origin: str,
    key_word: str
) -> herapy.obj.sc_state.SCState:
    """ Check the last anchored root includes the lock and build
    a lock proof for that root
    """
    if not is_aergo_address(receiver):
        raise InvalidArgumentsError(
            "Receiver {} must be an Aergo address".format(receiver)
        )
    # check last merged height
    anchor_info = aergo_to.query_sc_state(bridge_to, ["_sv__anchorHeight"])
    if not anchor_info.account.state_proof.inclusion:
        raise InvalidArgumentsError(
            "Contract doesnt exist in state, check contract deployed and "
            "chain synced {}".format(anchor_info))
    if not anchor_info.var_proofs[0].inclusion:
        raise InvalidArgumentsError("Cannot query last anchored height",
                                    anchor_info)
    last_merged_height_to = int(anchor_info.var_proofs[0].value)
    _, current_height = aergo_to.get_blockchain_status()
    # waite for anchor containing our transfer
    stream = aergo_to.receive_event_stream(bridge_to, "newAnchor",
                                           start_block_no=current_height)
    while last_merged_height_to < deposit_height:
        logger.info(
            "deposit not recorded in current anchor, waiting new anchor "
            "event... / deposit height : %s / last anchor height : %s ",
            deposit_height, last_merged_height_to
        )
        new_anchor_event = next(stream)
        last_merged_height_to = new_anchor_event.arguments[1]
    stream.stop()
    # get inclusion proof of lock in last merged block
    merge_block_from = aergo_from.get_block_headers(
        block_height=last_merged_height_to, list_size=1)
    root_from = merge_block_from[0].blocks_root_hash
    account_ref = receiver + token_origin
    proof = aergo_from.query_sc_state(
        bridge_from, [key_word + account_ref],
        root=root_from, compressed=False
    )
    if not proof.verify_proof(root_from):
        raise InvalidMerkleProofError("Unable to verify {} proof"
                                      .format(key_word))
    if not proof.account.state_proof.inclusion:
        raise InvalidMerkleProofError(
            "Contract doesnt exist in state, check contract deployed and "
            "chain synced {}".format(proof))
    if not proof.var_proofs[0].inclusion:
        raise InvalidMerkleProofError(
            "No tokens deposited for this account reference: {}"
            .format(proof))
    return proof