From 5803c7b42ece6224b903d66cf319183ad20630a1 Mon Sep 17 00:00:00 2001 From: Walter Lara Date: Wed, 4 Feb 2026 19:03:18 -0800 Subject: [PATCH] MOBILE-390 feat: add per-wallet allocation support to multi-chain NFT songs endpoint --- .../cardano/model/AllocatedNativeAsset.kt | 9 +++ .../features/cardano/model/CardanoNftSong.kt | 1 + .../cardano/parser/CardanoNftSongParser.kt | 4 +- .../cardano/repo/CardanoRepositoryImpl.kt | 81 +++++++++++-------- .../ethereum/model/EthereumNftSong.kt | 1 + .../ethereum/parser/EthereumNftSongParser.kt | 5 +- .../ethereum/repo/EthereumRepositoryImpl.kt | 45 +++++++---- .../server/features/nftsong/model/NftSong.kt | 1 + .../nftsong/model/NftWalletAllocation.kt | 12 +++ .../nftsong/repo/NftSongRepositoryImpl.kt | 12 +++ .../parser/CardanoNftSongParserTests.kt | 78 +++++++++++++++++- .../parser/EthereumNftSongParserTests.kt | 12 +-- 12 files changed, 202 insertions(+), 59 deletions(-) create mode 100644 newm-server/src/main/kotlin/io/newm/server/features/cardano/model/AllocatedNativeAsset.kt create mode 100644 newm-server/src/main/kotlin/io/newm/server/features/nftsong/model/NftWalletAllocation.kt diff --git a/newm-server/src/main/kotlin/io/newm/server/features/cardano/model/AllocatedNativeAsset.kt b/newm-server/src/main/kotlin/io/newm/server/features/cardano/model/AllocatedNativeAsset.kt new file mode 100644 index 000000000..2d41b331e --- /dev/null +++ b/newm-server/src/main/kotlin/io/newm/server/features/cardano/model/AllocatedNativeAsset.kt @@ -0,0 +1,9 @@ +package io.newm.server.features.cardano.model + +import io.newm.chain.grpc.NativeAsset +import java.util.UUID + +data class AllocatedNativeAsset( + val asset: NativeAsset, + val allocations: Map +) diff --git a/newm-server/src/main/kotlin/io/newm/server/features/cardano/model/CardanoNftSong.kt b/newm-server/src/main/kotlin/io/newm/server/features/cardano/model/CardanoNftSong.kt index c5b497d88..431a6ad46 100644 --- a/newm-server/src/main/kotlin/io/newm/server/features/cardano/model/CardanoNftSong.kt +++ b/newm-server/src/main/kotlin/io/newm/server/features/cardano/model/CardanoNftSong.kt @@ -13,6 +13,7 @@ data class CardanoNftSong( val assetName: String, val isStreamToken: Boolean, val amount: Long, + val allocations: Map<@Contextual UUID, Long>, val title: String, val imageUrl: String, val audioUrl: String, diff --git a/newm-server/src/main/kotlin/io/newm/server/features/cardano/parser/CardanoNftSongParser.kt b/newm-server/src/main/kotlin/io/newm/server/features/cardano/parser/CardanoNftSongParser.kt index fd1db64a1..f0f0e58bd 100644 --- a/newm-server/src/main/kotlin/io/newm/server/features/cardano/parser/CardanoNftSongParser.kt +++ b/newm-server/src/main/kotlin/io/newm/server/features/cardano/parser/CardanoNftSongParser.kt @@ -20,6 +20,7 @@ private val legacyPrefixRegex = "^\\d+\\.\\s*".toRegex() fun List.toNFTSongs( asset: NativeAsset, + allocations: Map, isStreamToken: Boolean, isNftCdnEnabled: Boolean ): List { @@ -108,7 +109,8 @@ fun List.toNFTSongs( policyId = asset.policy, assetName = assetName, isStreamToken = isStreamToken, - amount = asset.amount.toLong(), + amount = allocations.values.sum(), + allocations = allocations, title = title, audioUrl = file.src.takeUnless { isNftCdnEnabled }?.toResourceUrl() ?: nftCdnRepository.generateFileUrl( diff --git a/newm-server/src/main/kotlin/io/newm/server/features/cardano/repo/CardanoRepositoryImpl.kt b/newm-server/src/main/kotlin/io/newm/server/features/cardano/repo/CardanoRepositoryImpl.kt index c6be76969..e79940811 100644 --- a/newm-server/src/main/kotlin/io/newm/server/features/cardano/repo/CardanoRepositoryImpl.kt +++ b/newm-server/src/main/kotlin/io/newm/server/features/cardano/repo/CardanoRepositoryImpl.kt @@ -54,6 +54,7 @@ import io.newm.server.config.repo.ConfigRepository.Companion.CONFIG_KEY_NFTCDN_E import io.newm.server.features.cardano.database.KeyEntity import io.newm.server.features.cardano.database.KeyTable import io.newm.server.features.cardano.database.ScriptAddressWhitelistEntity +import io.newm.server.features.cardano.model.AllocatedNativeAsset import io.newm.server.features.cardano.model.CardanoNftSong import io.newm.server.features.cardano.model.EncryptionRequest import io.newm.server.features.cardano.model.GetWalletSongsResponse @@ -89,12 +90,12 @@ import io.newm.shared.koin.inject import io.newm.shared.ktx.isValidHex import io.newm.shared.ktx.isValidPassword import io.newm.txbuilder.ktx.fingerprint -import io.newm.txbuilder.ktx.mergeAmounts import io.newm.txbuilder.ktx.toCborObject import io.newm.txbuilder.ktx.toNativeAssetMap import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction import org.jetbrains.exposed.sql.transactions.transaction import org.springframework.security.crypto.encrypt.BytesEncryptor import org.springframework.security.crypto.encrypt.Encryptors @@ -597,22 +598,22 @@ internal class CardanoRepositoryImpl( includeLegacy: Boolean, useDripDropz: Boolean ): List { - val assets = if (useDripDropz) getDripDropzAssets(userId) else getWalletAssets(userId) + val allocatedAssets = if (useDripDropz) getDripDropzAssets(userId) else getWalletAssets(userId) val nftSongs = mutableListOf() val streamTokenPolicyIds = configRepository.getStrings(CONFIG_KEY_MINT_ALL_POLICY_IDS) val isNftCdnEnabled = configRepository.getBoolean(CONFIG_KEY_NFTCDN_ENABLED) - for (asset in assets) { + for ((asset, allocation) in allocatedAssets) { val metadata = getAssetMetadata(asset) if (includeLegacy || metadata.any { it.key.equals("music_metadata_version", true) }) { val isStreamToken = asset.policy in streamTokenPolicyIds - nftSongs += metadata.toNFTSongs(asset, isStreamToken, isNftCdnEnabled) + nftSongs += metadata.toNFTSongs(asset, allocation, isStreamToken, isNftCdnEnabled) } } return nftSongs } override suspend fun getWalletImages(userId: UserId): List { - val assets = getWalletAssets(userId) + val assets = getWalletAssets(userId).map { it.asset } return if (configRepository.getBoolean(CONFIG_KEY_NFTCDN_ENABLED)) { assets.map { nftCdnRepository.generateImageUrl(it.fingerprint()) } } else { @@ -622,36 +623,52 @@ internal class CardanoRepositoryImpl( } } - private fun getStakeAddressesByUserId(userId: UserId): List = - transaction { - WalletConnectionEntity.getAllByUserIdAndWalletChain(userId, WalletChain.Cardano).map { it.address } + private suspend fun getWalletAssets(userId: UserId): List = + getAssetsByUserId(userId) { address -> + client + .queryUtxosByStakeAddress(queryUtxosRequest { this.address = address }) + .utxosList + .flatMap { it.nativeAssetsList } } - private suspend fun getWalletAssets(userId: UserId): List = - getStakeAddressesByUserId(userId) - .flatMap { - client - .queryUtxosByStakeAddress( - queryUtxosRequest { - address = it - } - ).utxosList - .flatMap { it.nativeAssetsList } - }.mergeAmounts() - - private suspend fun getDripDropzAssets(userId: UserId): List = - getStakeAddressesByUserId(userId) - .flatMap { dripDropzRepository.checkAvailableTokens(it) } - .map { - nativeAsset { - policy = it.tokenPolicy - name = it.tokenAssetId - amount = it.availableQuantity - .movePointRight(6) - .toBigInteger() - .toString() + private suspend fun getDripDropzAssets(userId: UserId): List = + getAssetsByUserId(userId) { address -> + dripDropzRepository + .checkAvailableTokens(address) + .map { + nativeAsset { + policy = it.tokenPolicy + name = it.tokenAssetId + amount = it.availableQuantity + .movePointRight(6) + .toBigInteger() + .toString() + } } - }.mergeAmounts() + } + + private suspend fun getAssetsByUserId( + userId: UserId, + getAssetsByAddress: suspend (String) -> List + ): List = + newSuspendedTransaction { + WalletConnectionEntity.getAllByUserIdAndWalletChain(userId, WalletChain.Cardano).toList() + }.map { connection -> + connection.id.value to getAssetsByAddress(connection.address) + }.flatMap { (connectionId, assets) -> + assets.map { asset -> + Triple(asset.policy + asset.name, asset, connectionId to asset.amount.toLong()) + } + }.groupBy { it.first } + .map { (_, group) -> + AllocatedNativeAsset( + asset = group.first().second, + allocations = group + .map { it.third } + .groupBy({ it.first }, { it.second }) + .mapValues { (_, amounts) -> amounts.sum() } + ) + } private suspend fun getAssetMetadata(asset: NativeAsset): List = client diff --git a/newm-server/src/main/kotlin/io/newm/server/features/ethereum/model/EthereumNftSong.kt b/newm-server/src/main/kotlin/io/newm/server/features/ethereum/model/EthereumNftSong.kt index f52bdb21f..98e3691aa 100644 --- a/newm-server/src/main/kotlin/io/newm/server/features/ethereum/model/EthereumNftSong.kt +++ b/newm-server/src/main/kotlin/io/newm/server/features/ethereum/model/EthereumNftSong.kt @@ -12,6 +12,7 @@ data class EthereumNftSong( val tokenType: String, val tokenId: String, val amount: Long, + val allocations: Map<@Contextual UUID, Long>, val title: String, val imageUrl: String, val audioUrl: String, diff --git a/newm-server/src/main/kotlin/io/newm/server/features/ethereum/parser/EthereumNftSongParser.kt b/newm-server/src/main/kotlin/io/newm/server/features/ethereum/parser/EthereumNftSongParser.kt index d2220cf9c..a2923ee3f 100644 --- a/newm-server/src/main/kotlin/io/newm/server/features/ethereum/parser/EthereumNftSongParser.kt +++ b/newm-server/src/main/kotlin/io/newm/server/features/ethereum/parser/EthereumNftSongParser.kt @@ -51,7 +51,7 @@ private val MOOD_TRAIT_TYPES = listOf( private val AUDIO_URL_REGEX = "\\.(mp3|mp4|wav|flac|aiff|aac)$".toRegex(RegexOption.IGNORE_CASE) -fun EthereumNft.parseSong(): EthereumNftSong? { +fun EthereumNft.parseSong(allocations: Map): EthereumNftSong? { val audioUrl = (raw?.metadata?.animationUrl ?: animation?.cachedUrl ?: animation?.originalUrl)?.asHttpsUrl() return if (audioUrl != null && (audioUrl.matches(AUDIO_URL_REGEX) || animation?.contentType?.startsWith("audio/") == true)) { EthereumNftSong( @@ -59,7 +59,8 @@ fun EthereumNft.parseSong(): EthereumNftSong? { contractAddress = contract.address, tokenType = tokenType, tokenId = tokenId, - amount = balance, + amount = allocations.values.sum(), + allocations = allocations, title = trait(TITLE_TRAIT_TYPES) ?: raw?.metadata?.name ?: contract.name ?: name.orEmpty(), imageUrl = (raw?.metadata?.image ?: image?.cachedUrl ?: image?.originalUrl)?.asHttpsUrl().orEmpty(), audioUrl = audioUrl, diff --git a/newm-server/src/main/kotlin/io/newm/server/features/ethereum/repo/EthereumRepositoryImpl.kt b/newm-server/src/main/kotlin/io/newm/server/features/ethereum/repo/EthereumRepositoryImpl.kt index 5bb70b1a8..8e5216aeb 100644 --- a/newm-server/src/main/kotlin/io/newm/server/features/ethereum/repo/EthereumRepositoryImpl.kt +++ b/newm-server/src/main/kotlin/io/newm/server/features/ethereum/repo/EthereumRepositoryImpl.kt @@ -8,7 +8,6 @@ import io.ktor.client.request.get import io.ktor.client.request.parameter import io.ktor.http.ContentType import io.ktor.server.application.ApplicationEnvironment -import io.newm.server.features.ethereum.model.EthereumNft import io.newm.server.features.ethereum.model.EthereumNftSong import io.newm.server.features.ethereum.model.GetNftsByOwnerResponse import io.newm.server.features.ethereum.parser.parseSong @@ -18,7 +17,7 @@ import io.newm.server.ktx.checkedBody import io.newm.server.ktx.getSecureConfigString import io.newm.server.typealiases.UserId import io.newm.shared.ktx.getConfigString -import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction internal class EthereumRepositoryImpl( private val client: HttpClient, @@ -29,24 +28,36 @@ internal class EthereumRepositoryImpl( override suspend fun getWalletNftSongs(userId: UserId): List { logger.debug { "getWalletNftSongs: userId = $userId" } - val addresses = transaction { - WalletConnectionEntity.getAllByUserIdAndWalletChain(userId, WalletChain.Ethereum).map { it.address } + val connections = newSuspendedTransaction { + WalletConnectionEntity.getAllByUserIdAndWalletChain(userId, WalletChain.Ethereum).toList() } val apiUrl = environment.getConfigString("alchemy.apiUrl") val apiKey = environment.getSecureConfigString("alchemy.apiKey") val endpointUrl = "$apiUrl/nft/v3/$apiKey/getNFTsForOwner" - return addresses.flatMap { address -> - client - .get(endpointUrl) { - retry { - maxRetries = 2 - delayMillis { 500L } - } - accept(ContentType.Application.Json) - parameter("owner", address) - }.checkedBody() - .ownedNfts - .mapNotNull(EthereumNft::parseSong) - } + return connections + .map { connection -> + connection.id.value to client + .get(endpointUrl) { + retry { + maxRetries = 2 + delayMillis { 500L } + } + accept(ContentType.Application.Json) + parameter("owner", connection.address) + }.checkedBody() + .ownedNfts + }.flatMap { (connectionId, nfts) -> + nfts.map { nft -> + Triple(nft.contract.address + nft.tokenId, nft, connectionId to nft.balance) + } + }.groupBy { it.first } + .mapNotNull { (_, group) -> + val nft = group.first().second + val allocations = group + .map { it.third } + .groupBy({ it.first }, { it.second }) + .mapValues { (_, balances) -> balances.sum() } + nft.parseSong(allocations) + } } } diff --git a/newm-server/src/main/kotlin/io/newm/server/features/nftsong/model/NftSong.kt b/newm-server/src/main/kotlin/io/newm/server/features/nftsong/model/NftSong.kt index 3f1221446..8421ee4f8 100644 --- a/newm-server/src/main/kotlin/io/newm/server/features/nftsong/model/NftSong.kt +++ b/newm-server/src/main/kotlin/io/newm/server/features/nftsong/model/NftSong.kt @@ -16,5 +16,6 @@ data class NftSong( val genres: List, val moods: List, val amount: Long, + val allocations: List, val chainMetadata: NftChainMetadata ) diff --git a/newm-server/src/main/kotlin/io/newm/server/features/nftsong/model/NftWalletAllocation.kt b/newm-server/src/main/kotlin/io/newm/server/features/nftsong/model/NftWalletAllocation.kt new file mode 100644 index 000000000..e10f04803 --- /dev/null +++ b/newm-server/src/main/kotlin/io/newm/server/features/nftsong/model/NftWalletAllocation.kt @@ -0,0 +1,12 @@ +package io.newm.server.features.nftsong.model + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.util.UUID + +@Serializable +data class NftWalletAllocation( + @Contextual + val id: UUID, + val amount: Long +) diff --git a/newm-server/src/main/kotlin/io/newm/server/features/nftsong/repo/NftSongRepositoryImpl.kt b/newm-server/src/main/kotlin/io/newm/server/features/nftsong/repo/NftSongRepositoryImpl.kt index c992369d0..108194fa4 100644 --- a/newm-server/src/main/kotlin/io/newm/server/features/nftsong/repo/NftSongRepositoryImpl.kt +++ b/newm-server/src/main/kotlin/io/newm/server/features/nftsong/repo/NftSongRepositoryImpl.kt @@ -6,9 +6,11 @@ import io.newm.server.features.ethereum.model.EthereumNftSong import io.newm.server.features.ethereum.repo.EthereumRepository import io.newm.server.features.nftsong.model.NftChainMetadata import io.newm.server.features.nftsong.model.NftSong +import io.newm.server.features.nftsong.model.NftWalletAllocation import io.newm.server.typealiases.UserId import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope +import java.util.UUID internal class NftSongRepositoryImpl( private val cardanoRepository: CardanoRepository, @@ -40,6 +42,7 @@ internal class NftSongRepositoryImpl( genres = genres, moods = moods, amount = amount, + allocations = allocations.mapAllocations(), chainMetadata = NftChainMetadata.Cardano( fingerprint = fingerprint, policyId = policyId, @@ -59,10 +62,19 @@ internal class NftSongRepositoryImpl( genres = genres, moods = moods, amount = amount, + allocations = allocations.mapAllocations(), chainMetadata = NftChainMetadata.Ethereum( contractAddress = contractAddress, tokenType = tokenType, tokenId = tokenId ) ) + + private fun Map.mapAllocations(): List = + this.map { + NftWalletAllocation( + id = it.key, + amount = it.value + ) + } } diff --git a/newm-server/src/test/kotlin/io/newm/server/features/cardano/parser/CardanoNftSongParserTests.kt b/newm-server/src/test/kotlin/io/newm/server/features/cardano/parser/CardanoNftSongParserTests.kt index 13e9f4e0e..117353810 100644 --- a/newm-server/src/test/kotlin/io/newm/server/features/cardano/parser/CardanoNftSongParserTests.kt +++ b/newm-server/src/test/kotlin/io/newm/server/features/cardano/parser/CardanoNftSongParserTests.kt @@ -26,6 +26,8 @@ private const val TEST_SECURE = true // DO NOT COMMIT THIS TOKEN private const val JWT_TOKEN = "" +private val TEST_ALLOCATIONS = mapOf(UUID.randomUUID() to 1L) + @Disabled("Disabled - require JWT Token") class CardanoNftSongParserTests : BaseApplicationTests() { private lateinit var newmChainClient: NewmChainCoroutineStub @@ -45,6 +47,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "NEWM_0", isStreamToken = true, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Bigger Dreams", imageUrl = "https://arweave.net/CuPFY2Ln7yUUhJX09G530kdPf93eGhAVlhjrtR7Jh5w", audioUrl = "https://arweave.net/P141o0RDAjSYlVQgTDgHNAORQTkMYIVCprmD_dKMVss", @@ -70,6 +73,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "NEWM_0", isStreamToken = true, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Bigger Dreams", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 0), @@ -93,6 +97,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "NEWM_5", isStreamToken = true, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Daisuke", imageUrl = "https://arweave.net/GlMlqHIPjwUtlPUfQxDdX1jWSjlKK1BCTBIekXgA66A", audioUrl = "https://arweave.net/QpgjmWmAHNeRVgx_Ylwvh16i3aWd8BBgyq7f16gaUu0", @@ -118,6 +123,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "NEWM_5", isStreamToken = true, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Daisuke", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 0), @@ -141,6 +147,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "OSSDREAMLOFI", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Smoke and Fire - Dream Lofi", imageUrl = "https://ipfs.io/ipfs/QmUa8NEsbSRTsdsKSqkHb8ZgEWcoBppwA3RfecDhFGkG6f", audioUrl = "https://ipfs.io/ipfs/QmaiQ2mHc2LhkApA5cXPk8WfV6923ndgVDQoAtdHsSkXWE", @@ -166,6 +173,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "OSSDREAMLOFI", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Smoke and Fire - Dream Lofi", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 0), @@ -189,6 +197,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "SickCity442", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Paper Route", imageUrl = "https://ipfs.io/ipfs/QmNNuBTgPwqoWyNMtSwtQtb8ycVF1TrkrsUCGaFWqXvjkr", audioUrl = "https://ipfs.io/ipfs/QmNPg1BTnyouUL1uiHyWc4tQZXH5anEz4jmua7iidwEbiE", @@ -214,6 +223,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "SickCity442", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Paper Route", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 0), @@ -237,6 +247,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "JukeBox501", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Waterfalls", imageUrl = "https://ipfs.io/ipfs/QmYuTT1ci2Zj7QTEnHDwQ6pf422fHzFxXxaQPyptqvL5ki", audioUrl = "https://ipfs.io/ipfs/QmbchFjoQFxMTzecKnXnf7YaAretRJzVyq2qNEepnRinTv", @@ -262,6 +273,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "JukeBox501", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Waterfalls", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 0), @@ -285,6 +297,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "SickCity343", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "It Gets Better", imageUrl = "https://ipfs.io/ipfs/QmY6mAm1L6G4XSDtUKiNdYPkGXAKXXU4HXzEthxbMhzr8U", audioUrl = "https://ipfs.io/ipfs/QmcBtkxaKsFK3wvNHxULhuRhzaabqoX6Ryor4PvnaqcUSb", @@ -310,6 +323,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "SickCity343", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "It Gets Better", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 0), @@ -333,6 +347,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "SickCity344", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "4EVR", imageUrl = "https://ipfs.io/ipfs/QmSXPyRe9KzmY18R64pdzMyvMiacu1C8eosZWepw1Eexme", audioUrl = "https://ipfs.io/ipfs/QmY9LRJoKMgPbEc2hvvREWP7UBzYuZaqaWacAkp3HKFUzb", @@ -358,6 +373,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "SickCity344", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "4EVR", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 0), @@ -381,6 +397,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "SickCity349", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "You, I, and The Ocean", imageUrl = "https://ipfs.io/ipfs/QmdZtxeKLGTXGkpcWkWznCZW7qsyiGA78dFcDwy9cA4D1d", audioUrl = "https://ipfs.io/ipfs/QmczfeP54gZgjMVnbe2mLrBjQbkQu3zuA1zYKpgSVzzKBr", @@ -406,6 +423,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = "SickCity349", isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "You, I, and The Ocean", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 0), @@ -433,6 +451,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Finally (Master 2021)", imageUrl = "https://ipfs.io/ipfs/QmSVK4ts4E4UK9A7QeHPPCXsfv8aPaoH7dpJiatZQHUtpV", audioUrl = "https://ipfs.io/ipfs/QmduC7pkR14K3mhmvEazoyzGsMWVF4ji45HZ1XfEracKLv", @@ -448,6 +467,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Funky Squirrel (Master 2021)", imageUrl = "https://ipfs.io/ipfs/QmSVK4ts4E4UK9A7QeHPPCXsfv8aPaoH7dpJiatZQHUtpV", audioUrl = "https://ipfs.io/ipfs/QmW9sHugSArzf29JPuEC2MqjtbsNkDjd9xNUxZFLDXSDUY", @@ -463,6 +483,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Weekend Ride (Master 2021)", imageUrl = "https://ipfs.io/ipfs/QmSVK4ts4E4UK9A7QeHPPCXsfv8aPaoH7dpJiatZQHUtpV", audioUrl = "https://ipfs.io/ipfs/Qmb8fm7CkzscjjoJGVp3p7qjSVMknsk27d3cwjqM26ELVB", @@ -478,6 +499,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Rave Culture (Master 2021)", imageUrl = "https://ipfs.io/ipfs/QmSVK4ts4E4UK9A7QeHPPCXsfv8aPaoH7dpJiatZQHUtpV", audioUrl = "https://ipfs.io/ipfs/QmTwvwpgE9Fx6QZsjbXe5STHb3WVmaDuxFzafqCPueCmqc", @@ -493,6 +515,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Vibrate (Master 2021)", imageUrl = "https://ipfs.io/ipfs/QmSVK4ts4E4UK9A7QeHPPCXsfv8aPaoH7dpJiatZQHUtpV", audioUrl = "https://ipfs.io/ipfs/QmTETraR8WvExCaanc5aGT8EAUgCojyN8YSZYbGgmzVfja", @@ -508,6 +531,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Top 40's (Master 2021)", imageUrl = "https://ipfs.io/ipfs/QmSVK4ts4E4UK9A7QeHPPCXsfv8aPaoH7dpJiatZQHUtpV", audioUrl = "https://ipfs.io/ipfs/Qmdfr4PvuiZhi3a6EaDupGN6R33PKSy5kntwgFEzLQnPLR", @@ -523,6 +547,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Acid Trip (Master 2021)", imageUrl = "https://ipfs.io/ipfs/QmSVK4ts4E4UK9A7QeHPPCXsfv8aPaoH7dpJiatZQHUtpV", audioUrl = "https://ipfs.io/ipfs/QmSp4Cn7qrhLTovezS1ii7ct1VAPK6Gotd2GnxnBc6ngSv", @@ -538,6 +563,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "For The Win (Master 2021)", imageUrl = "https://ipfs.io/ipfs/QmSVK4ts4E4UK9A7QeHPPCXsfv8aPaoH7dpJiatZQHUtpV", audioUrl = "https://ipfs.io/ipfs/QmV8ihv8R6cCKsFJyFP8fhnnQjeKjS7HAAjmxMgUPftmw6", @@ -553,6 +579,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Sunday Sermon (Master 2021)", imageUrl = "https://ipfs.io/ipfs/QmSVK4ts4E4UK9A7QeHPPCXsfv8aPaoH7dpJiatZQHUtpV", audioUrl = "https://ipfs.io/ipfs/QmWux5UpX6BtYQ7pjugqRh6ySa2vVJN12iSC2AB1cAQynU", @@ -585,6 +612,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Finally (Master 2021)", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 1), @@ -600,6 +628,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Funky Squirrel (Master 2021)", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 2), @@ -615,6 +644,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Weekend Ride (Master 2021)", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 3), @@ -629,6 +659,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { policyId = policyId, assetName = assetName, amount = 1, + allocations = TEST_ALLOCATIONS, isStreamToken = false, title = "Rave Culture (Master 2021)", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), @@ -645,6 +676,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Vibrate (Master 2021)", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 5), @@ -660,6 +692,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Top 40's (Master 2021)", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 6), @@ -675,6 +708,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Acid Trip (Master 2021)", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 7), @@ -690,6 +724,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "For The Win (Master 2021)", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 8), @@ -705,6 +740,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "Sunday Sermon (Master 2021)", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 9), @@ -734,6 +770,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "1. doors open", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmZ7Cd1y586YEC2uc7pUxzoCck2ZC9yyDtdMyWgKHGRfu6", @@ -749,6 +786,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "2. cafè latte", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmSzRkmegDyegknPzjVqvmCG35jmGTHJfpnQjJzN1mfh8r", @@ -764,6 +802,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "3. windowpain", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmcsNULNnmjAxJspomPRZxJcQhh6YHXiMC53fvqHjkNkPg", @@ -779,6 +818,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "4. ghost of the past", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmPL1v1PCBH42PaBkWbiFhF1Fc38vKnWAAw4q3V4X4w6os", @@ -794,6 +834,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "5. no fear in love", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmPHR3iu4j17V2zqonKDQzUU9BVqjox6RungWF7gdQeH6t", @@ -809,6 +850,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "6. departing", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmbwpXSZbmuLwbGsf3oARfYf269e4af6ZUY66wcQ3uB8uR", @@ -824,6 +866,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "7. next stop", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmZhux1Xqy46CNa7nCqKmpHuwR2nM7sJ6826WdRjhTTDgv", @@ -839,6 +882,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "8. soda-soda", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmcquduiNWU6EWJj8wLPSKcR8AiTEXvpcPTU4vwyX5VDfr", @@ -854,6 +898,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "9. roadtrip", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmPYgMQekJPWbvNhLP7QJAqUT2twjsBkRf32br6WPKL8dR", @@ -869,6 +914,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "10. cruisin' together", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmQbSc3RYwuVG4qWKNbrQyrfcFXDZhFhAEt7VgBECC6HNN", @@ -884,6 +930,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "11. pass by the ville", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmSSwxTVZdfTRe9HoCAr1EUjB9jzMrxNLV39LHnbgLDRYi", @@ -899,6 +946,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "12. downtown alley", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmRkmwkfqi1KyaPFkFcHWQNXoB3DnmqJohTsQ7zyZU9PFb", @@ -914,6 +962,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "13. sunrise at the seaport", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmWRci2Ne5yyZ7ASV8NSFfeMnrTjy9cSe2uMKS1116Stf9", @@ -929,6 +978,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "14. morning thoughts", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmQQNTJDti9U4vv3ebKN5ACuu1spKzJCgodotwTWxdgdN5", @@ -944,6 +994,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "15. people come and go", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmRCZxguhLVnYLYN253F6KgT86haFExjX4szq1Bo9dpP22", @@ -959,6 +1010,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "16. gonna make it", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmTog3gpDC8aFCe7n8FWHsC3cSVFQbGDUkTUodeCL3BzC3", @@ -974,6 +1026,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "17. an old locksmith", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmUjJjzCh3FgoeJm5U1N2ixRX1Bc6tCSvCCdMgPS1PLAgr", @@ -989,6 +1042,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "18. when they arrive", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmRHHihTiaoeEn1ZznkBfUKC2aNVTeKsA6kSioHARJv8TN", @@ -1004,6 +1058,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "19. the penthouse", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/QmdSxVRRwPNXKfdn1ZxGfMD1tKFau53VfxZaqGWr6srBTr", @@ -1019,6 +1074,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "20. something beyond", imageUrl = "https://ipfs.io/ipfs/QmNbo9zTojUGxPGB6vV75naJ2hsSrDK2jk2yLg7VU3YyGH", audioUrl = "https://ipfs.io/ipfs/Qmdjpq6sNRMsSApUzhy2YmiDmyUHuuaEYcpEHXjQp9ntdA", @@ -1048,6 +1104,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "1. doors open", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 0), @@ -1063,6 +1120,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "2. cafè latte", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 1), @@ -1078,6 +1136,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "3. windowpain", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 2), @@ -1093,6 +1152,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "4. ghost of the past", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 3), @@ -1108,6 +1168,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "5. no fear in love", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 4), @@ -1123,6 +1184,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "6. departing", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 5), @@ -1138,6 +1200,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "7. next stop", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 6), @@ -1153,6 +1216,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "8. soda-soda", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 7), @@ -1168,6 +1232,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "9. roadtrip", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 8), @@ -1183,6 +1248,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "10. cruisin' together", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 9), @@ -1198,6 +1264,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "11. pass by the ville", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 10), @@ -1213,6 +1280,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "12. downtown alley", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 11), @@ -1228,6 +1296,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "13. sunrise at the seaport", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 12), @@ -1243,6 +1312,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "14. morning thoughts", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 13), @@ -1258,6 +1328,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "15. people come and go", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 14), @@ -1273,6 +1344,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "16. gonna make it", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 15), @@ -1288,6 +1360,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "17. an old locksmith", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 16), @@ -1303,6 +1376,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "18. when they arrive", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 17), @@ -1318,6 +1392,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "19. the penthouse", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 18), @@ -1333,6 +1408,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { assetName = assetName, isStreamToken = false, amount = 1, + allocations = TEST_ALLOCATIONS, title = "20. something beyond", imageUrl = nftCdnRepository.generateImageUrl(fingerprint), audioUrl = nftCdnRepository.generateFileUrl(fingerprint, 19), @@ -1367,7 +1443,7 @@ class CardanoNftSongParserTests : BaseApplicationTests() { policy = policyId name = assetNameHex } - ).ledgerAssetMetadataList.toNFTSongs(asset, isStreamToken, isNftCdnEnabled) + ).ledgerAssetMetadataList.toNFTSongs(asset, TEST_ALLOCATIONS, isStreamToken, isNftCdnEnabled) } private fun buildClient(): NewmChainCoroutineStub { diff --git a/newm-server/src/test/kotlin/io/newm/server/features/ethereum/parser/EthereumNftSongParserTests.kt b/newm-server/src/test/kotlin/io/newm/server/features/ethereum/parser/EthereumNftSongParserTests.kt index da4351154..f460f631b 100644 --- a/newm-server/src/test/kotlin/io/newm/server/features/ethereum/parser/EthereumNftSongParserTests.kt +++ b/newm-server/src/test/kotlin/io/newm/server/features/ethereum/parser/EthereumNftSongParserTests.kt @@ -10,6 +10,8 @@ import kotlinx.serialization.modules.SerializersModule import org.junit.jupiter.api.Test import java.util.UUID +private val TEST_ALLOCATIONS = mapOf(UUID.randomUUID() to 1L) + class EthereumNftSongParserTests { private val json = Json { ignoreUnknownKeys = true @@ -143,13 +145,12 @@ class EthereumNftSongParserTests { } """.trimIndent() val nft = json.decodeFromString(nftJson) - val result = nft.parseSong() + val result = nft.parseSong(TEST_ALLOCATIONS) assertThat(result).isEqualTo( nftSongOf( contractAddress = "0x328B49C56a8A15fb34aB3eCD8883Fac5F9512453", tokenType = "ERC721", tokenId = "107", - amount = 1L, title = "A Little Rain Must Fall", imageUrl = "https://cyan-adjacent-gazelle-655.mypinata.cloud/ipfs/QmSMVf3Atwjwqkf5KooKvd2kxuvwg3XZXVzb8bwVuRRCxb/107.png", audioUrl = "https://cyan-adjacent-gazelle-655.mypinata.cloud/ipfs/QmWAKnDzr9Yxn7wFQDkEdxq6GFLwQp2nHowVNEKJVKdKAv/A%20Little%20Rain%20Must%20Fall.mp3", @@ -280,13 +281,12 @@ class EthereumNftSongParserTests { } """.trimIndent() val nft = json.decodeFromString(nftJson) - val result = nft.parseSong() + val result = nft.parseSong(TEST_ALLOCATIONS) assertThat(result).isEqualTo( nftSongOf( contractAddress = "0x328B49C56a8A15fb34aB3eCD8883Fac5F9512453", tokenType = "ERC721", tokenId = "124", - amount = 1L, title = "Landed in Your Heart", imageUrl = "https://cyan-adjacent-gazelle-655.mypinata.cloud/ipfs/QmSMVf3Atwjwqkf5KooKvd2kxuvwg3XZXVzb8bwVuRRCxb/124.png", audioUrl = "https://cyan-adjacent-gazelle-655.mypinata.cloud/ipfs/QmWAKnDzr9Yxn7wFQDkEdxq6GFLwQp2nHowVNEKJVKdKAv/Landed%20in%20Your%20Heart.mp3", @@ -302,7 +302,6 @@ class EthereumNftSongParserTests { contractAddress: String, tokenType: String, tokenId: String, - amount: Long, title: String, imageUrl: String, audioUrl: String, @@ -316,7 +315,8 @@ class EthereumNftSongParserTests { contractAddress = contractAddress, tokenType = tokenType, tokenId = tokenId, - amount = amount, + amount = 1L, + allocations = TEST_ALLOCATIONS, title = title, imageUrl = imageUrl, audioUrl = audioUrl,