private async Task <BusinessFundAsset> MapFundAssetAsync(FundSettings.FundAsset asset, decimal fundValue, CurrencyCode currencyCode)
        {
            var sanitisedId     = asset.Name.Replace(" ", "-").Replace(".", "-").ToLower().Trim();
            var coinloreId      = GetAssetInfo(asset.Symbol)?.CoinLore ?? sanitisedId;
            var coinGecko       = GetAssetInfo(asset.Symbol)?.CoinGecko;
            var coinMarketCapId = GetAssetInfo(asset.Symbol)?.CoinMarketCap ?? sanitisedId;
            var assetInfo       = GetAssetInfo(asset.Symbol);
            var contractAddress = !string.IsNullOrWhiteSpace(asset.ContractAddress)
                ? new EthereumAddress(asset.ContractAddress)
                : default(EthereumAddress?);

            var marketValuePerToken = default(decimal?);

            if (contractAddress.HasValue)
            {
                marketValuePerToken = assetInfo?.PoolAddress == null
                    ? (await ethplorerClient.GetTokenInfoAsync(contractAddress.Value)).Price?.MarketValuePerToken
                    : await graphClient.GetUniswapPriceAsync(assetInfo.PoolAddress.Value, contractAddress.Value);
            }

            if (coinGecko != null && !marketValuePerToken.HasValue)
            {
                marketValuePerToken = (await coinGeckoClient.GetCoinAsync(coinGecko)).Market.Price.Value;
            }

            var total = asset.Quantity != default && marketValuePerToken.HasValue
                ? CurrencyConverter.Convert(marketValuePerToken.Value * asset.Quantity, currencyCode)
                : CurrencyConverter.Convert(asset.Value, currencyCode);

            return(new BusinessFundAsset()
            {
                Holding = new BusinessHolding()
                {
                    Name = asset.Name,
                    Symbol = asset.Symbol,
                    HexColour = GetAssetInfo(asset.Symbol)?.Colour,
                    ContractAddress = !string.IsNullOrEmpty(asset.ContractAddress)
                        ? new EthereumAddress(asset.ContractAddress)
                        : default(EthereumAddress?),
                    Decimals = asset.Decimals,
                    IsCoin = asset.IsCoin,
                    Link = assetInfo?.PoolAddress != null
                        ? new Uri(string.Format(PoolTemplate, assetInfo.PoolAddress.Value), UriKind.Absolute)
                        : asset.Link
                           ?? new Uri(string.Format(LinkTemplate, coinMarketCapId), UriKind.Absolute),
                    ImageLink = asset.ImageLink
                                ?? new Uri(string.Format(ImageTemplate, coinloreId), UriKind.Absolute),
                    MarketLink = asset.Tradable
                        ? new Uri(string.Format(MarketTemplate, coinloreId, currencyCode), UriKind.Absolute)
                        : null
                },
                Quantity = asset.Quantity,
                PricePerToken = marketValuePerToken ?? decimal.Zero,
                Total = total,
                Share = total / fundValue * 100
            });
        }