def setup(make_project, db, configuration: Config, erc20_token):

    configuration['token_contract_addr'] = erc20_token.address

    eth_token, eth_token_hash = init_token_contract(configuration)
    swap_contract, swap_contract_hash = init_swap_contract(
        configuration, eth_token, eth_token_hash)
    add_minter(eth_token, swap_contract)
    erc_token, erc_token_hash = init_token_contract(configuration,
                                                    swap_contract)

    add_to_whitelist(swap_contract, erc_token, erc_token_hash)

    change_owner(swap_contract, configuration["multisig_acc_addr"])

    # add token pairings to db
    TokenPairing(src_network="Ethereum",
                 src_coin="ETH",
                 src_address="native",
                 dst_network="Secret",
                 dst_coin="secret-ETH",
                 dst_address=eth_token).save()
    TokenPairing(src_network="Ethereum",
                 src_coin="ERC",
                 src_address=erc20_token.address,
                 dst_network="Secret",
                 dst_coin="secret-ERC",
                 dst_address=erc_token).save()

    configuration["swap_code_hash"] = swap_contract_hash
    configuration["scrt_swap_address"] = swap_contract
Exemple #2
0
def configure_db():

    with database("test_db", "cluster0.dka2m.mongodb.net", "leader",
                  "6FXQ3gHXQQAkbpmI"):
        # TokenPairing(src_network="Ethereum", src_coin="ETH", src_address="native",
        #              dst_network="Secret", dst_coin="secret-ETH", dst_address="secret1nk5c3agzt3ytpkl8csfhf4e3qwleauex9ay69t").save()
        TokenPairing.objects().get(
            src_network="Ethereum", dst_coin="secret-TUSD").update(
                src_address="0x1cB0906955623920c86A3963593a02a405Bb97fC")
Exemple #3
0
def configure_db():

    with database():
        # TokenPairing(src_network="Ethereum", src_coin="ETH", src_address="native",
        #              dst_network="Secret", dst_coin="secret-ETH", dst_address="secret1nk5c3agzt3ytpkl8csfhf4e3qwleauex9ay69t").save()
        TokenPairing.objects().get(
            src_network="Ethereum",
            dst_address="secret13lj8gqvdfn45d03lfrrl087dje5d6unzus2usv",
            dst_coin="secret-YEENUS").delete()
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
Exemple #5
0
    def __init__(self, multisig_wallet: MultisigWallet,
                 signer: CryptoManagerBase, dst_network: str, config: Config,
                 **kwargs):
        self.config = config
        self.multisig_wallet = multisig_wallet
        self.erc20 = erc20_contract()

        token_map = {}
        pairs = TokenPairing.objects(dst_network=dst_network,
                                     src_network=self.network)
        for pair in pairs:
            token_map.update(
                {pair.dst_address: Token(pair.src_address, pair.src_coin)})
        self.signer = signer
        # self.private_key = private_key
        # self.default_account = account
        self.token_map = token_map
        self.logger = get_logger(db_name=self.config['db_name'],
                                 logger_name=config.get(
                                     'logger_name', self.__class__.__name__))
        self.stop_event = Event()
        super().__init__(group=None,
                         name="EtherLeader",
                         target=self.run,
                         **kwargs)
Exemple #6
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)
Exemple #7
0
    def __init__(self, secret_multisig: SecretAccount,
                 contract: MultisigWallet, src_network: str, config: Config,
                 *args, **kwargs):
        super().__init__(*args, **kwargs)

        token_map = {}
        pairs = TokenPairing.objects(dst_network=self.network,
                                     src_network=src_network)
        for pair in pairs:
            token_map.update(
                {pair.src_address: Token(pair.dst_address, pair.dst_coin)})

        self.multisig_name = secret_multisig.name
        self.config = config
        self.manager = SecretManager(contract, token_map, secret_multisig,
                                     config)
        self.logger = get_logger(
            db_name=self.config['db_name'],
            logger_name=config.get(
                'logger_name',
                f"{self.__class__.__name__}-{self.multisig_name}"))
        self.stop_event = Event()

        super().__init__(group=None,
                         name="SecretLeader",
                         target=self.run,
                         **kwargs)
Exemple #8
0
    def __init__(self, multisig_wallet: MultisigWallet,
                 signer: CryptoManagerBase, dst_network: str, config: Config,
                 **kwargs):
        self.config = config
        self.multisig_wallet = multisig_wallet
        self.erc20 = erc20_contract()
        self.pending_txs: List[str] = []
        token_map = {}
        confirmer_token_map = {}
        pairs = TokenPairing.objects(dst_network=dst_network,
                                     src_network=self.network)
        for pair in pairs:
            token_map.update(
                {pair.dst_address: Token(pair.src_address, pair.src_coin)})
            confirmer_token_map.update(
                {pair.src_address: Token(pair.dst_address, pair.dst_coin)})
        self.signer = signer
        self.token_map = token_map

        self.logger = get_logger(db_name=config.db_name,
                                 loglevel=config.log_level,
                                 logger_name=config.logger_name
                                 or self.__class__.__name__)
        self.stop_event = Event()

        self.confirmer = EthConfirmer(self.multisig_wallet,
                                      confirmer_token_map, self.logger)
        self.event_listener = EthEventListener(self.multisig_wallet, config)

        self.stop_event = Event()
        super().__init__(group=None,
                         name="EtherLeader",
                         target=self.run,
                         **kwargs)
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
Exemple #10
0
    def _refresh_token_map(self):
        token_map = {}
        pairs = TokenPairing.objects(src_network=self.network)
        for pair in pairs:
            token_map.update({pair.dst_address: Token(pair.src_address, pair.src_coin)})

        self.token_map = token_map
Exemple #11
0
 def __getitem__(self, key: str):
     _key = key.lower()
     if _key not in self:
         for coin in TokenPairing.objects():
             if self._key(coin) not in self:
                 self.update({self._key(coin): Coin.from_db(coin)})
         if _key in self:
             return self.data[_key]
         raise KeyError(f"Coin not found for key: {key}")
     return self.data[_key]
Exemple #12
0
    def _tx_erc20_params(self, amount, dest_address, dst_token: str, retry: bool) -> Tuple[bytes, str, int, str, int]:
        # if fee isn't 0 this will fail because tx_token isn't the ERC20 address from which to collect the fee
        if retry:
            fee = 0
        elif self.config.network == "mainnet":
            decimals = self._coins.decimals(dst_token)
            try:
                x_rate = BridgeOracle.x_rate('ETH', self._coins.coin(dst_token))
            except Exception:  # pylint: disable=broad-except
                self.logger.warning(f"Failed to get price for token {dst_token} - falling back to db price")
                eth = TokenPairing.objects().get(name="Ethereum").price
                token = TokenPairing.objects().get(src_address=dst_token).price
                x_rate = float(eth) / float(token)

            self.logger.info(f'Calculated exchange rate: {x_rate=}')
            gas_price = BridgeOracle.gas_price()
            fee = BridgeOracle.calculate_fee(self.multisig_wallet.SUBMIT_GAS,
                                             gas_price,
                                             decimals,
                                             x_rate,
                                             amount)
            self.logger.info(f'Fee taken: {fee}')
        # for testing mostly
        else:
            fee = 1

        if fee >= amount:
            raise ValueError

        checksum_addr = w3.toChecksumAddress(dest_address)
        data = self.erc20.encodeABI(fn_name='transfer', args=[checksum_addr, amount - fee])
        tx_dest = dst_token
        tx_token = dst_token
        tx_amount = 0

        return data, tx_dest, tx_amount, tx_token, fee
Exemple #13
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)
Exemple #14
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)
Exemple #15
0
    def __init__(self, multisig_contract: MultisigWallet,
                 signer: CryptoManagerBase, dst_network: str, config: Config):
        # todo: simplify this, pylint is right
        self.multisig_contract = multisig_contract
        self.account = signer.address
        self.signer = signer
        self.config = config
        self.logger = get_logger(
            db_name=config['db_name'],
            logger_name=config.get(
                'logger_name',
                f"{self.__class__.__name__}-{self.account[0:5]}"))

        self.erc20 = erc20_contract()
        self.catch_up_complete = False

        self.token_map = {}
        pairs = TokenPairing.objects(dst_network=dst_network,
                                     src_network=self.network)
        for pair in pairs:
            self.token_map.update(
                {pair.src_address: Token(pair.dst_address, pair.dst_coin)})

        self.tracked_tokens = self.token_map.keys()
Exemple #16
0
 def __init__(self, **kwargs):
     super().__init__(**kwargs)
     for coin in TokenPairing.objects():
         self.update({self._key(coin): Coin.from_db(coin)})
def test_11_swap_erc_to_s20(scrt_leader, scrt_signers, web3_provider,
                            configuration: Config, erc20_contract,
                            multisig_wallet, ethr_leader):

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

    # scrt_leader.start()
    # for signer in scrt_signers:
    #     signer.start()

    t1_address = get_key_signer(
        "t1", Path.joinpath(project_base_path(),
                            configuration.path_to_keys))['address']
    # swap ethr for secret20 token, deliver tokens to address of 'a'.
    # (we will use 'a' later to check it received the money)

    # add usdt to the whitelisted token list
    account = web3_provider.eth.account.from_key(configuration.leader_key)
    nonce = web3_provider.eth.getTransactionCount(account.address, "pending")
    tx = multisig_wallet.contract.functions.addToken(erc20_contract.address, 1)
    raw_tx = tx.buildTransaction(transaction={
        'from': account.address,
        'gas': 3000000,
        'nonce': nonce
    })
    signed_tx = account.sign_transaction(raw_tx)
    tx_hash = web3_provider.eth.sendRawTransaction(signed_tx.rawTransaction)

    # Get transaction hash from deployed contract
    tx_receipt = web3_provider.eth.waitForTransactionReceipt(tx_hash)

    # this will likely fail since the test before also allocates the allowance - just ignore if it fails
    try:
        _ = erc20_contract.contract.functions.approve(multisig_wallet.address, TRANSFER_AMOUNT_ERC). \
            transact({'from': web3_provider.eth.coinbase})
    except ValueError:
        pass

    tx_hash = multisig_wallet\
        .contract\
        .functions\
        .swapToken(t1_address.encode(), TRANSFER_AMOUNT_ERC, erc20_contract.address)\
        .transact({'from': web3_provider.eth.coinbase}).hex().lower()

    assert TRANSFER_AMOUNT_ERC == erc20_contract.contract.functions.balanceOf(
        multisig_wallet.address).call()

    # increase number of blocks to reach the confirmation threshold
    assert increase_block_number(web3_provider,
                                 configuration.eth_confirmations - 1)

    sleep(configuration.sleep_interval + 2)

    assert Swap.objects(src_tx_hash=tx_hash).count(
    ) == 0  # verify blocks confirmation threshold wasn't meet
    assert increase_block_number(web3_provider,
                                 1)  # add the 'missing' confirmation block

    # give event listener and manager time to process tx
    sleep(configuration.sleep_interval + 2)
    assert Swap.objects(
        src_tx_hash=tx_hash).count() == 1  # verify swap event recorded

    swap = Swap.objects(src_tx_hash=tx_hash).get()

    sleep(1)
    # check signers were notified of the tx and signed it
    assert Signatures.objects(tx_id=swap.id).count() == len(scrt_signers)

    # give time for manager to process the signatures
    sleep(configuration.sleep_interval + 2)
    assert Swap.objects().get(
        src_tx_hash=tx_hash).status in (Status.SWAP_SUBMITTED,
                                        Status.SWAP_CONFIRMED)

    _, log = event_log(tx_hash, ['SwapToken'], web3_provider,
                       multisig_wallet.contract)
    transfer_amount = multisig_wallet.extract_amount(log)
    dest = multisig_wallet.extract_addr(log)

    # validate swap tx on ethr delivers to the destination
    viewing_key_set = '{"set_viewing_key": {"key": "lol"}}'
    _ = run(
        f"secretcli tx compute execute {secret_token_addr} "
        f"'{viewing_key_set}' --from {dest} -b block -y | jq '.txhash'",
        shell=True,
        stdout=PIPE)
    sleep(6)

    balance = f'{{"balance": {{"key": "lol", "address": "{dest}"}} }}'
    res = run(f"secretcli q compute query {secret_token_addr} "
              f"'{balance}'",
              shell=True,
              stdout=PIPE)

    print(f"{res.stdout=}")

    amount = json.loads(res.stdout)["balance"]["amount"]

    print(f"swap amount: {transfer_amount}, dest balance amount: {amount}")

    # give scrt_leader time to multi-sign already existing signatures
    sleep(configuration.sleep_interval + 5)
    assert Swap.objects().get(
        src_tx_hash=tx_hash).status == Status.SWAP_CONFIRMED
Exemple #18
0
def deploy_scrt():

    # docker exec -it secretdev secretcli tx compute store "/token.wasm.gz" --from a --gas 2000000 -b block -y
    #
    # docker exec -it secretdev secretcli tx compute store "/swap.wasm.gz" --from a --gas 2000000 -b block -y
    # 0xd475b764D1B2DCa1FE598247e5D49205E6Ac5E8e
    multisig_account = config.multisig_acc_addr
    deployer = "secret18839huzvv5v6v0z3tm6um2ascnt6vrqfsp8d4g"

    tokens = [{
        "address": "0x1cB0906955623920c86A3963593a02a405Bb97fC",
        "name": "True USD",
        "decimals": 18,
        "symbol": "TUSD"
    }, {
        "address": "0xF6fF95D53E08c9660dC7820fD5A775484f77183A",
        "name": "YEENUS",
        "decimals": 8,
        "symbol": "YNUS"
    }, {
        "address": "native",
        "name": "Ethereum",
        "decimals": 15,
        "symbol": "ETH"
    }]

    swap_contract, swap_contract_hash = init_swap_contract(deployer)
    # swap_contract = "secret1u8mgmspdeakpf7u8leq68d5xtkykskwrytevyn"
    # swap_contract_hash = "5C36ABD74F5959DD9E8BCECB2EA308BEFEAFF2A50B9BCBD2338C079266F9F0BF"
    print(f"Swap contract deployed at: {swap_contract}")
    for token in tokens:

        config.token_contract_addr = token

        scrt_token, scrt_token_code = init_token_contract(
            deployer, token["decimals"], f'S{token["symbol"]}',
            f'Secret {token["name"]}', swap_contract)
        add_minter(scrt_token, deployer)
        print(f"Secret {token['name']}, Deployed at: {scrt_token}")
        add_to_whitelist(swap_contract, scrt_token, scrt_token_code,
                         pow(10, token["decimals"]))

        import os
        uri = os.environ.get("db_uri")
        with database(uri):
            try:
                TokenPairing.objects().get(
                    src_network="Ethereum",
                    src_address=token["address"]).update(
                        dst_address=scrt_token)
                print("Updated DB record")
            except:
                print("Added new pair to db")
                TokenPairing(src_network="Ethereum",
                             src_coin=token["name"],
                             src_address=token["address"],
                             dst_network="Secret",
                             dst_coin=f"secret-{token['name']}",
                             dst_address=scrt_token,
                             decimals=18,
                             name="Ethereum").save()

    change_owner(swap_contract, config.multisig_acc_addr)
def test_1_swap_eth_to_s20(setup, scrt_signers, scrt_leader, web3_provider,
                           configuration: Config, multisig_wallet):

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

    scrt_leader.start()
    for signer in scrt_signers:
        signer.start()

    fee_collector = multisig_wallet.contract.functions.getFeeCollector().call()

    print(f"{fee_collector=}")

    t1_address = get_key_signer(
        "t1", Path.joinpath(project_base_path(),
                            configuration.path_to_keys))['address']
    # swap ethr for secret20 token, deliver tokens to address of 'a'
    # (we will use 'a' later to check it received the money)
    print(
        f"Creating new swap transaction at {web3_provider.eth.getBlock('latest').number + 1}"
    )
    tx_hash = multisig_wallet.contract.functions.swap(t1_address.encode()). \
        transact({'from': web3_provider.eth.coinbase, 'value': TRANSFER_AMOUNT_ETH}).hex().lower()
    # TODO: validate ethr increase of the smart contract
    # increase number of blocks to reach the confirmation threshold
    assert increase_block_number(web3_provider,
                                 configuration.eth_confirmations - 1)

    sleep(configuration.sleep_interval + 2)

    assert Swap.objects(src_tx_hash=tx_hash).count(
    ) == 0  # verify blocks confirmation threshold wasn't meet
    assert increase_block_number(web3_provider,
                                 1)  # add the 'missing' confirmation block

    # give event listener and manager time to process tx
    sleep(configuration.sleep_interval + 5)
    assert Swap.objects(
        src_tx_hash=tx_hash).count() == 1  # verify swap event recorded

    sleep(1)
    # check signers were notified of the tx and signed it
    assert Signatures.objects().count() == len(scrt_signers)

    sleep(5)

    if Swap.objects().get().status == Status.SWAP_SUBMITTED:
        sleep(configuration.sleep_interval + 5)
    assert Swap.objects().get().status == Status.SWAP_CONFIRMED

    # get tx details
    tx_hash = Swap.objects().get().src_tx_hash
    _, log = event_log(tx_hash, ['Swap'], web3_provider,
                       multisig_wallet.contract)
    transfer_amount = log.args.amount
    dest = log.args.recipient.decode()

    # validate swap tx on ethr delivers to the destination
    viewing_key_set = '{"set_viewing_key": {"key": "lol"}}'
    tx_hash = run(
        f"secretcli tx compute execute {secret_token_addr} "
        f"'{viewing_key_set}' --from {dest} -b block -y | jq '.txhash'",
        shell=True,
        stdout=PIPE)
    sleep(6)

    balance = f'{{"balance": {{"key": "lol", "address": "{dest}"}} }}'
    res = run(f"secretcli q compute query {secret_token_addr} "
              f"'{balance}'",
              shell=True,
              stdout=PIPE)

    print(f"{res.stdout=}")

    amount = json.loads(res.stdout)["balance"]["amount"]

    print(f"swap amount: {transfer_amount}, dest balance amount: {amount}")

    assert int(amount) == log.args.amount