public Task ScanContractAsync(
            string address,
            string contractAddress,
            CancellationToken cancellationToken = default)
        {
            return(Task.Run(async() =>
            {
                var tezosConfig = _tezosAccount.Config;

                var bcdSettings = tezosConfig.BcdApiSettings;

                var bcdApi = new BcdApi(bcdSettings);

                var tokenContractsResult = await bcdApi
                                           .GetTokenContractsAsync(address, cancellationToken)
                                           .ConfigureAwait(false);

                if (tokenContractsResult.HasError)
                {
                    Log.Error($"Error while get token contracts for " +
                              $"address: {address}. " +
                              $"Code: {tokenContractsResult.Error.Code}. " +
                              $"Description: {tokenContractsResult.Error.Description}.");

                    return;
                }

                // upsert contracts
                if (tokenContractsResult.Value.Any())
                {
                    await _tezosAccount.DataRepository
                    .UpsertTezosTokenContractsAsync(tokenContractsResult.Value.Values)
                    .ConfigureAwait(false);
                }

                var contractWithMetadata = tokenContractsResult.Value.TryGetValue(contractAddress, out var contract)
                    ? contract
                    : null;

                await ScanContractAsync(
                    address,
                    contractAddress,
                    contractWithMetadata,
                    cancellationToken)
                .ConfigureAwait(false);
            }, cancellationToken));
        }
        public Task ScanAsync(
            string address,
            CancellationToken cancellationToken = default)
        {
            return(Task.Run(async() =>
            {
                var tezosConfig = _tezosAccount.Config;

                var bcdSettings = tezosConfig.BcdApiSettings;

                var bcdApi = new BcdApi(bcdSettings);

                var tokenContractsResult = await bcdApi
                                           .GetTokenContractsAsync(address, cancellationToken)
                                           .ConfigureAwait(false);

                if (tokenContractsResult.HasError)
                {
                    Log.Error($"Error while get token contracts for " +
                              $"address: {address}. " +
                              $"Code: {tokenContractsResult.Error.Code}. " +
                              $"Description: {tokenContractsResult.Error.Description}.");

                    return;
                }

                // upsert contracts
                if (tokenContractsResult.Value.Any())
                {
                    await _tezosAccount.DataRepository
                    .UpsertTezosTokenContractsAsync(tokenContractsResult.Value.Values)
                    .ConfigureAwait(false);
                }

                // contracts from local db
                var contracts = (await _tezosAccount.DataRepository
                                 .GetTezosTokenAddressesAsync(address)
                                 .ConfigureAwait(false))
                                .Select(a => a.TokenBalance.Contract)
                                .ToList();

                // add contracts from network
                if (tokenContractsResult.Value.Any())
                {
                    contracts.AddRange(tokenContractsResult.Value.Keys);
                }

                contracts = contracts
                            .Distinct()
                            .ToList();

                // scan by address and contract
                foreach (var contractAddress in contracts)
                {
                    var contractWithMetadata = tokenContractsResult.Value.TryGetValue(contractAddress, out var contract)
                        ? contract
                        : null;

                    await ScanContractAsync(
                        address,
                        contractAddress,
                        contractWithMetadata,
                        cancellationToken)
                    .ConfigureAwait(false);
                }
            }, cancellationToken));
        }