Beispiel #1
0
    def catch_up(self, to_block: int):
        from_block = SwapTrackerObject.last_processed('Ethereum') + 1
        self.logger.debug(f'Starting to catch up from block {from_block}')
        if self.config.eth_start_block > from_block:
            self.logger.debug(
                f'Due to config fast forwarding to block {self.config.eth_start_block}'
            )
            from_block = self.config.eth_start_block
            SwapTrackerObject.update_last_processed('Ethereum', from_block)

        if to_block <= 0 or to_block < from_block:
            return

        self.logger.debug(f'Catching up to current block: {to_block}')

        evt_filter = self.contract.contract.events.Swap.createFilter(
            fromBlock=from_block, toBlock=to_block)
        for event in evt_filter.get_all_entries():
            self._handle(event)

        evt_filter = self.contract.contract.events.SwapToken.createFilter(
            fromBlock=from_block, toBlock=to_block)
        for event in evt_filter.get_all_entries():
            self._handle(event)

        # for event_name in self.contract.tracked_event():
        #     for event in self.event_listener.events_in_range(event_name, from_block, to_block):
        #         self.logger.info(f'Found new event at block: {event["blockNumber"]}')

        SwapTrackerObject.update_last_processed('Ethereum', to_block)
def test_3_confirm_tx(web3_provider, ethr_signers, configuration: Config,
                      erc20_contract, ethr_leader):

    secret_token_addr = TokenPairing.objects().get(src_network="Ethereum",
                                                   src_coin="ERC").dst_address

    assert increase_block_number(web3_provider,
                                 configuration.eth_confirmations)
    # To allow the new EthrSigner to "catch up", we start it after the event submission event in Ethereum
    # ethr_signers[-1].start()

    sleep(configuration.sleep_interval + 3)
    # Validate the tx is confirmed in the smart contract
    last_nonce = SwapTrackerObject.last_processed(src=secret_token_addr)
    assert last_nonce > -1
    # account for fee

    fee = erc20_contract.contract.functions.balanceOf(PAYABLE_ADDRESS).call()
    assert fee > 0
    assert TRANSFER_AMOUNT_ERC == erc20_contract.contract.functions.balanceOf(
        ethr_leader.signer.address).call() + fee

    assert increase_block_number(web3_provider,
                                 configuration.eth_confirmations)
    sleep(configuration.sleep_interval)

    last_nonce = SwapTrackerObject.last_processed(secret_token_addr)
    swap = Swap.objects().get(src_tx_hash=f'{last_nonce}|{secret_token_addr}')
    assert swap.status == Status.SWAP_CONFIRMED
def test_3_confirm_and_finalize_eth_tx(web3_provider, ethr_signers,
                                       configuration: Config):
    # To allow the new EthrSigner to "catch up", we start it after the event submission event in Ethereum
    secret_token_addr = TokenPairing.objects().get(src_network="Ethereum",
                                                   src_coin="ETH").dst_address
    prev_bal = web3_provider.eth.getBalance(zero_address, "latest")
    prev_bal_fee = web3_provider.eth.getBalance(PAYABLE_ADDRESS, "latest")
    ethr_signers[-1].start()
    sleep(1)
    assert increase_block_number(web3_provider,
                                 configuration.eth_confirmations)

    sleep(configuration.sleep_interval * 5)
    # Validate the tx is confirmed in the smart contract
    last_nonce = SwapTrackerObject.last_processed(secret_token_addr)
    # ethr_signers[-1].signer.multisig_contract.contract.functions.confirmations(last_nonce,
    #                                                                            ethr_signers[-1].account).call()

    assert last_nonce >= 0

    bal_fee = web3_provider.eth.getBalance(PAYABLE_ADDRESS, "latest")
    assert bal_fee > prev_bal_fee

    bal = web3_provider.eth.getBalance(zero_address, "latest")
    assert bal > prev_bal

    last_nonce = SwapTrackerObject.last_processed(secret_token_addr)

    swap = Swap.objects().get(src_tx_hash=f'{last_nonce}|{secret_token_addr}')
    assert swap.status == Status.SWAP_CONFIRMED
    configuration.eth_start_block = web3_provider.eth.blockNumber
Beispiel #4
0
def test_2_swap_s20_to_eth(setup, web3_provider, ethr_leader, configuration: Config, ethr_signers, scrt_signers):

    swap_contract_addr = configuration['scrt_swap_address']
    secret_token_addr = TokenPairing.objects().get(src_network="Ethereum", src_coin="ETH").dst_address

    # start the eth signers
    for signer in ethr_signers[:-1]:
        signer.start()

    # Generate swap tx on secret network
    swap = {"send": {"amount": str(TRANSFER_AMOUNT_ETH),
                     "msg": base64.standard_b64encode(zero_address.encode()).decode(),
                     "recipient": swap_contract_addr}}

    sleep(configuration['sleep_interval'])
    last_nonce = SwapTrackerObject.last_processed(secret_token_addr)
    print(f"last processed before: {last_nonce}")
    tx_hash = run(f"secretcli tx compute execute {secret_token_addr} "
                  f"'{json.dumps(swap)}' --from t1 --gas 300000 -y", shell=True, stdout=PIPE, stderr=PIPE)
    tx_hash = json.loads(tx_hash.stdout)['txhash']

    sleep(configuration['sleep_interval'] + 6)
    assert query_data_success(tx_hash) != {}

    last_nonce_after = SwapTrackerObject.last_processed(secret_token_addr)
    print(f"last processed before: {last_nonce_after}")
    assert last_nonce + 1 == last_nonce_after

    # Give ethr signers time to handle the secret20 swap tx
    increase_block_number(web3_provider, configuration['eth_confirmations'])
    sleep(configuration['sleep_interval'] + 5)
Beispiel #5
0
    def _handle(self, event: AttributeDict):
        """Extracts tx data from @event and add unsigned_tx to db"""
        if not self.contract.verify_destination(event):
            return

        amount = str(self.contract.extract_amount(event))

        try:
            block_number, tx_hash, recipient, token = self.contract.parse_swap_event(
                event)
            if token is None:
                token = 'native'
        except ValueError:
            return

        try:
            s20 = self._get_s20(token)
            mint = mint_json(amount, tx_hash, recipient, s20.address)
            unsigned_tx = create_unsigned_tx(self.config.scrt_swap_address,
                                             mint, self.config.chain_id,
                                             self.config.enclave_key,
                                             self.config.swap_code_hash,
                                             self.multisig.address)

            tx = Swap(src_tx_hash=tx_hash,
                      status=Status.SWAP_UNSIGNED,
                      unsigned_tx=unsigned_tx,
                      src_coin=token,
                      dst_coin=s20.name,
                      dst_address=s20.address,
                      src_network="Ethereum",
                      sequence=self.sequence,
                      amount=amount)
            tx.save(force_insert=True)
            self.sequence = self.sequence + 1
            self.logger.info(
                f"saved new Ethereum -> Secret transaction {tx_hash}, for {amount} {s20.name}"
            )
            # SwapTrackerObject.update_last_processed(src=Source.ETH.value, update_val=block_number)
        except (IndexError, AttributeError, KeyError) as e:
            self.logger.error(f"Failed on tx {tx_hash}, block {block_number}, "
                              f"due to error: {e}")
        except RuntimeError as e:
            self.logger.error(
                f"Failed to create swap tx for eth hash {tx_hash}, block {block_number}. Error: {e}"
            )
        except NotUniqueError as e:
            self.logger.error(
                f"Tried to save duplicate TX, might be a catch up issue - {e}")
        # return block_number, tx_hash, recipient, s20
        SwapTrackerObject.update_last_processed('Ethereum', block_number)
Beispiel #6
0
    def _scan_swap(self):
        """ Scans secret network contract for swap events """
        self.logger.info(
            f'Starting for account {self.signer.address} with tokens: {self.token_map=}'
        )
        while not self.stop_event.is_set():
            for token in self.token_map:
                try:
                    swap_tracker = SwapTrackerObject.get_or_create(src=token)
                    next_nonce = swap_tracker.nonce + 1

                    self.logger.debug(
                        f'Scanning token {token} for query #{next_nonce}')

                    swap_data = query_scrt_swap(
                        next_nonce, self.config["scrt_swap_address"], token)

                    self._handle_swap(swap_data, token,
                                      self.token_map[token].address)
                    swap_tracker.nonce = next_nonce
                    swap_tracker.save()
                    next_nonce += 1

                except CalledProcessError as e:
                    if b'ERROR: query result: encrypted: Failed to get swap for token' not in e.stderr:
                        self.logger.error(
                            f"Failed to query swap: stdout: {e.stdout} stderr: {e.stderr}"
                        )
                        # if b'ERROR: query result: encrypted: Failed to get swap for key' not in e.stderr:

            self.stop_event.wait(self.config['sleep_interval'])
Beispiel #7
0
    def choose_starting_block(self) -> int:
        """Returns the block from which we start scanning Ethereum for new tx"""
        obj = SwapTrackerObject.get_or_create(src=signer_id(self.account))
        if obj.nonce == -1:
            obj.update(nonce=self.config.eth_start_block)

        return obj.nonce
Beispiel #8
0
    def run(self):
        self.logger.info("Starting")

        # todo: fix so tracker doesn't start from 0
        from_block = SwapTrackerObject.get_or_create(src="Ethereum").nonce

        self.event_listener.register(self.confirmer.submit, ['Submission'], from_block=from_block)
        self.event_listener.register(self.confirmer.withdraw, ['Withdraw'], from_block=from_block)
        self.event_listener.register(self.confirmer.failed_withdraw, ['WithdrawFailure'], from_block=from_block)
        self.event_listener.start()

        self._scan_swap()
Beispiel #9
0
def test_2_swap_s20_to_erc(web3_provider, ethr_leader, configuration: Config, ethr_signers, erc20_contract):

    swap_contract_addr = configuration['scrt_swap_address']
    secret_token_addr = TokenPairing.objects().get(src_network="Ethereum", src_coin="ERC").dst_address

    # for signer in ethr_signers[:-1]:
    #     signer.start()

    # Generate swap tx on secret network
    swap = {"send": {"amount": str(TRANSFER_AMOUNT_ERC),
                     "msg": base64.b64encode(ethr_leader.signer.address.encode()).decode(),
                     "recipient": swap_contract_addr}}

    last_nonce = SwapTrackerObject.last_processed(src=secret_token_addr)
    tx_hash = run(f"secretcli tx compute execute {secret_token_addr} "
                  f"'{json.dumps(swap)}' --from t1 -b block -y --gas 300000", shell=True, stdout=PIPE, stderr=PIPE)
    tx_hash = json.loads(tx_hash.stdout)['txhash']
    print(f'{tx_hash=}')
    # Verify that leader recognized the burn tx
    assert increase_block_number(web3_provider, configuration['eth_confirmations'])
    sleep(configuration['sleep_interval'])

    assert last_nonce + 1 == SwapTrackerObject.last_processed(src=secret_token_addr)
    def _set_tx_result(self, nonce, token, success=True):
        try:
            swap = self.get_swap(nonce, token)
        except Exception as e:
            self.logger.error(f'Error handling swap {build_hash(nonce, token)}: {e}')
            return

        if swap.status != Status.SWAP_SUBMITTED:
            return
        if success:
            swap.update(status=Status.SWAP_CONFIRMED)
        else:
            swap.update(status=Status.SWAP_FAILED)

        obj = SwapTrackerObject.get_or_create(self._confirmer_id(token))
        obj.update(nonce=nonce)
Beispiel #11
0
    def _scan_swap(self):
        """ Scans secret network contract for swap events """
        self.logger.info(f'Starting for account {self.signer.address} with tokens: {self.token_map=}')
        while not self.stop_event.is_set():

            num_of_tokens = TokenPairing.objects(src_network=self.network).count()
            if num_of_tokens != len(self.token_map.keys()):
                self._refresh_token_map()
                self.logger.info(f'Refreshed tracked tokens. Now tracking {len(self.token_map.keys())} tokens')

            for transaction in Swap.objects(status=Status.SWAP_RETRY, src_network="Secret"):
                # self._handle_swap(swap_data, token, self.token_map[token].address)
                try:
                    token, nonce = _parse_db_tx(transaction)
                    swap_data = query_scrt_swap(nonce, self.config.scrt_swap_address, token)
                    # self._retry(transaction)
                    self._handle_swap(swap_data, token, self.token_map[token].address, True)
                except Exception as e:  # pylint: disable=broad-except
                    self.logger.error(f'Failed to retry swap: {e}')
                    transaction.update(status=Status.SWAP_FAILED)

            for token in self.token_map:
                try:
                    swap_tracker = SwapTrackerObject.get_or_create(src=token)
                    next_nonce = swap_tracker.nonce + 1

                    self.logger.debug(f'Scanning token {token} for query #{next_nonce}')

                    swap_data = query_scrt_swap(next_nonce, self.config.scrt_swap_address, token)

                    self._handle_swap(swap_data, token, self.token_map[token].address)
                    swap_tracker.nonce = next_nonce
                    swap_tracker.save()
                    next_nonce += 1

                except CalledProcessError as e:
                    if b'ERROR: query result: encrypted: Failed to get swap for token' not in e.stderr:
                        self.logger.error(f"Failed to query swap: stdout: {e.stdout} stderr: {e.stderr}")
                        # if b'ERROR: query result: encrypted: Failed to get swap for key' not in e.stderr:

            self.stop_event.wait(self.config.sleep_interval)
Beispiel #12
0
 def update_tracker_object(self, submission_event):
     obj = SwapTrackerObject.objects().get(src=signer_id(self.account))
     obj.update(nonce=submission_event["blockNumber"])