def finalize_transfer_unlock(self, from_chain: str, to_chain: str, asset_name: str, receiver: str = None, burn_height: int = 0, privkey_name: str = 'default', privkey_pwd: str = None) -> str: """ Finalize a transfer of assets from a sidechain by unlocking then after the burn is final and a new anchor was made. NOTE anybody can unlock so sender is not necessary. The amount to unlock is the difference between total burn and already unlocked amount. Bridge tempo is taken from config_data """ logger.info(from_chain + ' -> ' + to_chain) aergo_from = self._connect_aergo(from_chain) aergo_to = self.get_aergo(to_chain, privkey_name, privkey_pwd) tx_sender = str(aergo_to.account.address) if receiver is None: receiver = tx_sender bridge_to = self.config_data('networks', to_chain, 'bridges', from_chain, 'addr') bridge_from = self.config_data('networks', from_chain, 'bridges', to_chain, 'addr') asset_address = self.config_data('networks', to_chain, 'tokens', asset_name, 'addr') burn_proof = build_burn_proof(aergo_from, aergo_to, receiver, bridge_from, bridge_to, burn_height, asset_address) logger.info("\u2699 Built burn proof") balance = 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 = get_balance(tx_sender, 'aergo', aergo_to) if aer_balance < gas_limit * self.gas_price: err = "not enough aer balance to pay tx fee" raise InsufficientBalanceError(err) tx_hash = unlock(aergo_to, receiver, burn_proof, asset_address, bridge_to, gas_limit, self.gas_price) logger.info('\U0001f513 Unlock success: %s', tx_hash) # new balance on origin balance = get_balance(receiver, asset_address, aergo_to) logger.info("\U0001f4b0 %s balance on destination after transfer: %s", asset_name, balance / 10**18) aergo_to.disconnect() aergo_from.disconnect() return tx_hash
def unfreeze( self, from_chain: str, to_chain: str, receiver: str = None, lock_height: int = 0, privkey_name: str = 'default', privkey_pwd: str = None, ) -> str: """ Finalize ERC20Aergo transfer to Aergo Mainnet by unfreezing (aers are already minted and freezed in the bridge contract) """ logger.info(from_chain + ' -> ' + to_chain) asset_name = 'aergo_erc20' 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)) balance = aergo_u.get_balance(receiver, 'aergo', aergo_to) logger.info("\U0001f4b0 %s balance on destination before transfer: %s", asset_name, balance / 10**18) gas_limit = 300000 if receiver != tx_sender: 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") tx_hash, _ = eth_to_aergo.unfreeze(aergo_to, receiver, lock_proof, bridge_to, gas_limit, self.aergo_gas_price) logger.info('\U0001f4a7 Unfreeze success: %s', tx_hash) # new balance on destination balance = aergo_u.get_balance(receiver, 'aergo', 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 return tx_hash
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
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
def lock_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 Aergo Standard Token transfer to Ethereum sidechain""" logger.info(from_chain + ' -> ' + to_chain) if not is_ethereum_address(receiver): raise InvalidArgumentsError( "receiver {} must be an Ethereum address".format(receiver)) if asset_name == 'aergo': raise InvalidArgumentsError( 'aer cannot be locked on Aergo, must be frozen') 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) asset_address = self.get_asset_address(asset_name, from_chain) gas_limit = 300000 balance = aergo_u.get_balance(sender, asset_address, 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) lock_height, tx_hash, _ = aergo_to_eth.lock(aergo_from, bridge_from, receiver, amount, asset_address, gas_limit, self.aergo_gas_price) logger.info('\U0001f512 Lock success: %s', tx_hash) # remaining balance on origin : aer or asset balance = aergo_u.get_balance(sender, asset_address, aergo_from) logger.info( "\U0001f4b0 remaining %s balance on origin after transfer: %s", asset_name, balance / 10**18) aergo_from.disconnect() return lock_height, tx_hash
def initiate_transfer_burn( self, from_chain: str, to_chain: str, asset_name: str, amount: int, receiver: str = None, privkey_name: str = 'default', privkey_pwd: str = None, ) -> Tuple[int, str]: """ Initiate a transfer from a sidechain by burning the assets. """ logger.info(from_chain + ' -> ' + to_chain) aergo_from = self.get_aergo(from_chain, privkey_name, privkey_pwd) sender = str(aergo_from.account.address) if receiver is None: receiver = sender bridge_from = self.config_data('networks', from_chain, 'bridges', to_chain, 'addr') token_pegged = self.config_data('networks', to_chain, 'tokens', asset_name, 'pegs', from_chain) balance = get_balance(sender, token_pegged, aergo_from) logger.info("\U0001f4b0 %s balance on sidechain before transfer: %s", asset_name, balance / 10**18) if balance < amount: raise InsufficientBalanceError("not enough balance") gas_limit = 300000 aer_balance = get_balance(sender, 'aergo', aergo_from) if aer_balance < gas_limit * self.gas_price: err = "not enough aer balance to pay tx fee" raise InsufficientBalanceError(err) burn_height, tx_hash = burn(aergo_from, bridge_from, receiver, amount, token_pegged, gas_limit, self.gas_price) logger.info('\U0001f525 Burn success: %s', tx_hash) # remaining balance on sidechain balance = get_balance(sender, token_pegged, aergo_from) logger.info( "\U0001f4b0 remaining %s balance on sidechain after transfer: %s", asset_name, balance / 10**18) aergo_from.disconnect() return burn_height, tx_hash
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
def get_balance(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.get_wallet_address(account_name) aergo = self._connect_aergo(network_name) if asset_name == 'aergo': asset_addr = 'aergo' else: asset_addr = self.get_asset_address(asset_name, network_name, asset_origin_chain) balance = get_balance(account_addr, asset_addr, aergo) aergo.disconnect() return balance, asset_addr
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
def finalize_transfer_mint(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 a transfer of assets to a sidechain by minting then after the lock is final and a new anchor was made. 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) aergo_from = self._connect_aergo(from_chain) aergo_to = self.get_aergo(to_chain, privkey_name, privkey_pwd) tx_sender = str(aergo_to.account.address) if receiver is None: receiver = tx_sender bridge_from = self.config_data('networks', from_chain, 'bridges', to_chain, 'addr') bridge_to = self.config_data('networks', to_chain, 'bridges', from_chain, 'addr') asset_address = self.config_data('networks', from_chain, 'tokens', asset_name, 'addr') save_pegged_token_address = False try: token_pegged = self.config_data('networks', from_chain, 'tokens', asset_name, 'pegs', to_chain) balance = 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 = get_balance(tx_sender, 'aergo', aergo_to) if aer_balance < gas_limit * self.gas_price: err = "not enough aer balance to pay tx fee" raise InsufficientBalanceError(err) lock_proof = build_lock_proof(aergo_from, aergo_to, receiver, bridge_from, bridge_to, lock_height, asset_address) logger.info("\u2699 Built lock proof") token_pegged, tx_hash = mint(aergo_to, receiver, lock_proof, asset_address, bridge_to, gas_limit, self.gas_price) logger.info('\u26cf Mint success: %s', tx_hash) # new balance on sidechain balance = get_balance(receiver, token_pegged, aergo_to) logger.info("\U0001f4b0 %s balance on destination after transfer : %s", asset_name, balance / 10**18) aergo_from.disconnect() 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 token_pegged, tx_hash
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