mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-07-22 09:05:48 +00:00
Add read-only Tron (TRC20) chain family support (#9)
* Add read-only Tron (TRC20) chain family support Adds Tron as a third chain family alongside Substrate and EVM: address derivation (BIP44 coin type 195, secp256k1 reused from the existing Ethereum path, Base58Check encoding), TronGrid-backed TRX and TRC20 USDT balance display, and a Room migration for the new per-account Tron key/address columns. Read-only only — no send, signing, or broadcast support yet. * fix: exhaustive when branches for Trc20/TronNative asset types ChainExt.kt's onChainAssetId and Common.kt's existentialDepositError both switch exhaustively over Chain.Asset.Type and didn't have cases for the new Trc20/TronNative variants, breaking compilation. Trc20 mirrors EvmErc20 (contract address as the on-chain id, dust burns rather than transfers on removal); TronNative mirrors EvmNative.
This commit is contained in:
+8
@@ -29,6 +29,8 @@ class TypeBasedAssetSourceRegistry(
|
||||
private val evmErc20Source: Lazy<AssetSource>,
|
||||
private val evmNativeSource: Lazy<AssetSource>,
|
||||
private val equilibriumAssetSource: Lazy<AssetSource>,
|
||||
private val tronNativeSource: Lazy<AssetSource>,
|
||||
private val trc20Source: Lazy<AssetSource>,
|
||||
private val unsupportedBalanceSource: AssetSource,
|
||||
|
||||
private val nativeAssetEventDetector: NativeAssetEventDetector,
|
||||
@@ -45,6 +47,8 @@ class TypeBasedAssetSourceRegistry(
|
||||
is Chain.Asset.Type.EvmErc20 -> evmErc20Source.get()
|
||||
is Chain.Asset.Type.EvmNative -> evmNativeSource.get()
|
||||
is Chain.Asset.Type.Equilibrium -> equilibriumAssetSource.get()
|
||||
is Chain.Asset.Type.TronNative -> tronNativeSource.get()
|
||||
is Chain.Asset.Type.Trc20 -> trc20Source.get()
|
||||
Chain.Asset.Type.Unsupported -> unsupportedBalanceSource
|
||||
}
|
||||
}
|
||||
@@ -57,6 +61,8 @@ class TypeBasedAssetSourceRegistry(
|
||||
add(evmNativeSource.get())
|
||||
add(evmErc20Source.get())
|
||||
add(equilibriumAssetSource.get())
|
||||
add(tronNativeSource.get())
|
||||
add(trc20Source.get())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +70,8 @@ class TypeBasedAssetSourceRegistry(
|
||||
return when (chainAsset.type) {
|
||||
is Chain.Asset.Type.Equilibrium,
|
||||
Chain.Asset.Type.EvmNative,
|
||||
is Chain.Asset.Type.TronNative,
|
||||
is Chain.Asset.Type.Trc20,
|
||||
|
||||
Chain.Asset.Type.Unsupported -> UnsupportedEventDetector()
|
||||
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.balances.trc20
|
||||
|
||||
import io.novafoundation.nova.core.updater.SharedRequestsBuilder
|
||||
import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount
|
||||
import io.novafoundation.nova.feature_wallet_api.data.cache.AssetCache
|
||||
import io.novafoundation.nova.feature_wallet_api.data.cache.updateNonLockableAsset
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.AssetBalance
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.BalanceSyncUpdate
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.model.ChainAssetBalance
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.model.TransferableBalanceUpdatePoint
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.balances.tronNative.pollingBalanceFlow
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.tron.TronGridApi
|
||||
import io.novafoundation.nova.runtime.ext.addressOf
|
||||
import io.novafoundation.nova.runtime.ext.requireTronGridBaseUrl
|
||||
import io.novafoundation.nova.runtime.ext.requireTrc20
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.math.BigInteger
|
||||
|
||||
/**
|
||||
* TRC-20 token balance on a Tron-based chain. Read-only (Phase 1): fetches via TronGrid's REST API (the same
|
||||
* `/v1/accounts/{address}` endpoint used for native TRX - TronGrid returns both in one response) and polls for
|
||||
* updates. No transfer/history support here - see `TronAssetsModule`.
|
||||
*/
|
||||
class Trc20AssetBalance(
|
||||
private val assetCache: AssetCache,
|
||||
private val tronGridApi: TronGridApi,
|
||||
) : AssetBalance {
|
||||
|
||||
override suspend fun startSyncingBalanceLocks(
|
||||
metaAccount: MetaAccount,
|
||||
chain: Chain,
|
||||
chainAsset: Chain.Asset,
|
||||
accountId: AccountId,
|
||||
subscriptionBuilder: SharedRequestsBuilder
|
||||
): Flow<*> {
|
||||
// TRC-20 tokens do not support locks
|
||||
return emptyFlow<Nothing>()
|
||||
}
|
||||
|
||||
override fun isSelfSufficient(chainAsset: Chain.Asset): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun existentialDeposit(chainAsset: Chain.Asset): BigInteger {
|
||||
// TRC-20 tokens do not have an existential deposit concept
|
||||
return BigInteger.ZERO
|
||||
}
|
||||
|
||||
override suspend fun queryAccountBalance(chain: Chain, chainAsset: Chain.Asset, accountId: AccountId): ChainAssetBalance {
|
||||
val contractAddress = chainAsset.requireTrc20().contractAddress
|
||||
val address = chain.addressOf(accountId)
|
||||
|
||||
val balance = tronGridApi.fetchTrc20Balance(chain.requireTronGridBaseUrl(), address, contractAddress)
|
||||
|
||||
return ChainAssetBalance.fromFree(chainAsset, balance)
|
||||
}
|
||||
|
||||
override suspend fun subscribeAccountBalanceUpdatePoint(
|
||||
chain: Chain,
|
||||
chainAsset: Chain.Asset,
|
||||
accountId: AccountId,
|
||||
): Flow<TransferableBalanceUpdatePoint> {
|
||||
// Not on the critical sync path (mirrors EvmNativeAssetBalance) - out of scope for Phase 1 read-only support.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun startSyncingBalance(
|
||||
chain: Chain,
|
||||
chainAsset: Chain.Asset,
|
||||
metaAccount: MetaAccount,
|
||||
accountId: AccountId,
|
||||
subscriptionBuilder: SharedRequestsBuilder
|
||||
): Flow<BalanceSyncUpdate> {
|
||||
val contractAddress = chainAsset.requireTrc20().contractAddress
|
||||
val baseUrl = chain.requireTronGridBaseUrl()
|
||||
val address = chain.addressOf(accountId)
|
||||
|
||||
return pollingBalanceFlow { tronGridApi.fetchTrc20Balance(baseUrl, address, contractAddress) }
|
||||
.map { balance ->
|
||||
assetCache.updateNonLockableAsset(metaAccount.id, chainAsset, balance)
|
||||
|
||||
BalanceSyncUpdate.NoCause
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.balances.tronNative
|
||||
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
|
||||
private const val TRON_BALANCE_POLLING_INTERVAL_MS = 30_000L
|
||||
|
||||
/**
|
||||
* TronGrid is a plain REST API with no push/subscription mechanism (unlike Ethereum nodes, which expose a
|
||||
* `newHeads`-style websocket subscription EVM balance sync piggybacks on). So balance updates for Tron-based
|
||||
* assets are polled instead of pushed: fetch immediately, then re-fetch on an interval, only emitting when the
|
||||
* balance actually changed.
|
||||
*/
|
||||
internal fun pollingBalanceFlow(
|
||||
intervalMs: Long = TRON_BALANCE_POLLING_INTERVAL_MS,
|
||||
fetch: suspend () -> Balance
|
||||
): Flow<Balance> = flow {
|
||||
var lastEmitted: Balance? = null
|
||||
|
||||
while (true) {
|
||||
val latest = fetch()
|
||||
|
||||
if (latest != lastEmitted) {
|
||||
lastEmitted = latest
|
||||
emit(latest)
|
||||
}
|
||||
|
||||
delay(intervalMs)
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.balances.tronNative
|
||||
|
||||
import io.novafoundation.nova.core.updater.SharedRequestsBuilder
|
||||
import io.novafoundation.nova.feature_account_api.domain.model.MetaAccount
|
||||
import io.novafoundation.nova.feature_wallet_api.data.cache.AssetCache
|
||||
import io.novafoundation.nova.feature_wallet_api.data.cache.updateNonLockableAsset
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.AssetBalance
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.BalanceSyncUpdate
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.model.ChainAssetBalance
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.balances.model.TransferableBalanceUpdatePoint
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.tron.TronGridApi
|
||||
import io.novafoundation.nova.runtime.ext.addressOf
|
||||
import io.novafoundation.nova.runtime.ext.requireTronGridBaseUrl
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novasama.substrate_sdk_android.runtime.AccountId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.emptyFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.math.BigInteger
|
||||
|
||||
/**
|
||||
* Native TRX balance on a Tron-based chain. Read-only (Phase 1): fetches via TronGrid's REST API and polls for
|
||||
* updates, since TronGrid has no push/subscription mechanism. No transfer/history support here - see
|
||||
* `TronAssetsModule` for how this is paired with `UnsupportedAssetTransfers`/`UnsupportedAssetHistory`.
|
||||
*/
|
||||
class TronNativeAssetBalance(
|
||||
private val assetCache: AssetCache,
|
||||
private val tronGridApi: TronGridApi,
|
||||
) : AssetBalance {
|
||||
|
||||
override suspend fun startSyncingBalanceLocks(
|
||||
metaAccount: MetaAccount,
|
||||
chain: Chain,
|
||||
chainAsset: Chain.Asset,
|
||||
accountId: AccountId,
|
||||
subscriptionBuilder: SharedRequestsBuilder
|
||||
): Flow<*> {
|
||||
// Tron native balance does not support locks
|
||||
return emptyFlow<Nothing>()
|
||||
}
|
||||
|
||||
override fun isSelfSufficient(chainAsset: Chain.Asset): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun existentialDeposit(chainAsset: Chain.Asset): BigInteger {
|
||||
// Tron does not have an existential deposit concept
|
||||
return BigInteger.ZERO
|
||||
}
|
||||
|
||||
override suspend fun queryAccountBalance(chain: Chain, chainAsset: Chain.Asset, accountId: AccountId): ChainAssetBalance {
|
||||
val balance = tronGridApi.fetchNativeBalance(chain.requireTronGridBaseUrl(), chain.addressOf(accountId))
|
||||
|
||||
return ChainAssetBalance.fromFree(chainAsset, balance)
|
||||
}
|
||||
|
||||
override suspend fun subscribeAccountBalanceUpdatePoint(
|
||||
chain: Chain,
|
||||
chainAsset: Chain.Asset,
|
||||
accountId: AccountId,
|
||||
): Flow<TransferableBalanceUpdatePoint> {
|
||||
// Not on the critical sync path (mirrors EvmNativeAssetBalance, which also leaves this unimplemented) -
|
||||
// out of scope for Phase 1 read-only support.
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun startSyncingBalance(
|
||||
chain: Chain,
|
||||
chainAsset: Chain.Asset,
|
||||
metaAccount: MetaAccount,
|
||||
accountId: AccountId,
|
||||
subscriptionBuilder: SharedRequestsBuilder
|
||||
): Flow<BalanceSyncUpdate> {
|
||||
val baseUrl = chain.requireTronGridBaseUrl()
|
||||
val address = chain.addressOf(accountId)
|
||||
|
||||
return pollingBalanceFlow { tronGridApi.fetchNativeBalance(baseUrl, address) }
|
||||
.map { balance ->
|
||||
assetCache.updateNonLockableAsset(metaAccount.id, chainAsset, balance)
|
||||
|
||||
BalanceSyncUpdate.NoCause
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -120,6 +120,7 @@ private fun Chain.Asset.existentialDepositError(amount: BigDecimal): WillRemoveA
|
||||
is Type.Orml -> WillRemoveAccount.WillBurnDust
|
||||
is Type.Statemine -> WillRemoveAccount.WillTransferDust(amount)
|
||||
is Type.EvmErc20, is Type.EvmNative -> WillRemoveAccount.WillBurnDust
|
||||
is Type.Trc20, Type.TronNative -> WillRemoveAccount.WillBurnDust
|
||||
is Type.Equilibrium -> WillRemoveAccount.WillBurnDust
|
||||
Type.Unsupported -> throw IllegalArgumentException("Unsupported")
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package io.novafoundation.nova.feature_wallet_impl.data.network.tron
|
||||
|
||||
import io.novafoundation.nova.common.data.network.UserAgent
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.tron.model.TronAccountResponse
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Headers
|
||||
import retrofit2.http.Url
|
||||
|
||||
interface RetrofitTronGridApi {
|
||||
|
||||
@GET
|
||||
@Headers(UserAgent.NOVA)
|
||||
suspend fun getAccount(@Url url: String): TronAccountResponse
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package io.novafoundation.nova.feature_wallet_impl.data.network.tron
|
||||
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.types.Balance
|
||||
import java.math.BigInteger
|
||||
|
||||
interface TronGridApi {
|
||||
|
||||
suspend fun fetchNativeBalance(baseUrl: String, address: String): Balance
|
||||
|
||||
suspend fun fetchTrc20Balance(baseUrl: String, address: String, contractAddress: String): Balance
|
||||
}
|
||||
|
||||
class RealTronGridApi(
|
||||
private val retrofitApi: RetrofitTronGridApi
|
||||
) : TronGridApi {
|
||||
|
||||
override suspend fun fetchNativeBalance(baseUrl: String, address: String): Balance {
|
||||
val accountData = fetchAccountData(baseUrl, address) ?: return BigInteger.ZERO
|
||||
|
||||
return accountData.balance?.toBigInteger() ?: BigInteger.ZERO
|
||||
}
|
||||
|
||||
override suspend fun fetchTrc20Balance(baseUrl: String, address: String, contractAddress: String): Balance {
|
||||
val accountData = fetchAccountData(baseUrl, address) ?: return BigInteger.ZERO
|
||||
|
||||
val rawBalance = accountData.trc20.orEmpty()
|
||||
.firstNotNullOfOrNull { entry -> entry[contractAddress] }
|
||||
|
||||
return rawBalance?.toBigIntegerOrNull() ?: BigInteger.ZERO
|
||||
}
|
||||
|
||||
private suspend fun fetchAccountData(baseUrl: String, address: String) = retrofitApi.getAccount(
|
||||
url = accountUrl(baseUrl, address)
|
||||
).data?.firstOrNull()
|
||||
|
||||
private fun accountUrl(baseUrl: String, address: String): String {
|
||||
return "${baseUrl.trimEnd('/')}/v1/accounts/$address"
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package io.novafoundation.nova.feature_wallet_impl.data.network.tron.model
|
||||
|
||||
/**
|
||||
* Response shape of TronGrid's `GET /v1/accounts/{address}`.
|
||||
*
|
||||
* An account that has never received any TRX/TRC20 transfer is not yet "activated" on-chain and TronGrid
|
||||
* returns an empty `data` array for it (not an error) - callers should treat that as a zero balance.
|
||||
*/
|
||||
class TronAccountResponse(
|
||||
val data: List<TronAccountData>? = null,
|
||||
val success: Boolean = true
|
||||
)
|
||||
|
||||
class TronAccountData(
|
||||
/**
|
||||
* Native TRX balance, denominated in SUN (1 TRX = 1_000_000 SUN), matching this chain's configured `precision: 6`.
|
||||
* Absent for freshly-activated accounts that hold TRX but have never been observed with a balance field by the indexer.
|
||||
*/
|
||||
val balance: Long? = null,
|
||||
|
||||
/**
|
||||
* List of single-entry maps: TRC20 contract address (Base58Check, same format as our chain config's `contractAddress`) -> balance string.
|
||||
* Only contains entries for tokens the account has ever interacted with; a token missing from this list means a zero balance.
|
||||
*/
|
||||
val trc20: List<Map<String, String>>? = null
|
||||
)
|
||||
+5
@@ -21,6 +21,7 @@ import io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets
|
||||
EvmErc20AssetsModule::class,
|
||||
EvmNativeAssetsModule::class,
|
||||
EquilibriumAssetsModule::class,
|
||||
TronAssetsModule::class,
|
||||
UnsupportedAssetsModule::class
|
||||
]
|
||||
)
|
||||
@@ -35,6 +36,8 @@ class AssetsModule {
|
||||
@EvmErc20Assets evmErc20: Lazy<AssetSource>,
|
||||
@EvmNativeAssets evmNative: Lazy<AssetSource>,
|
||||
@EquilibriumAsset equilibrium: Lazy<AssetSource>,
|
||||
@TronNativeAssets tronNative: Lazy<AssetSource>,
|
||||
@Trc20Assets trc20: Lazy<AssetSource>,
|
||||
@UnsupportedAssets unsupported: AssetSource,
|
||||
|
||||
nativeAssetEventDetector: NativeAssetEventDetector,
|
||||
@@ -48,6 +51,8 @@ class AssetsModule {
|
||||
evmErc20Source = evmErc20,
|
||||
evmNativeSource = evmNative,
|
||||
equilibriumAssetSource = equilibrium,
|
||||
tronNativeSource = tronNative,
|
||||
trc20Source = trc20,
|
||||
unsupportedBalanceSource = unsupported,
|
||||
|
||||
nativeAssetEventDetector = nativeAssetEventDetector,
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package io.novafoundation.nova.feature_wallet_impl.di.modules
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.novafoundation.nova.common.data.network.NetworkApiCreator
|
||||
import io.novafoundation.nova.common.di.scope.FeatureScope
|
||||
import io.novafoundation.nova.feature_wallet_api.data.cache.AssetCache
|
||||
import io.novafoundation.nova.feature_wallet_api.data.network.blockhain.assets.AssetSource
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.StaticAssetSource
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.balances.trc20.Trc20AssetBalance
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.balances.tronNative.TronNativeAssetBalance
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.history.UnsupportedAssetHistory
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.blockchain.assets.transfers.UnsupportedAssetTransfers
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.tron.RealTronGridApi
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.tron.RetrofitTronGridApi
|
||||
import io.novafoundation.nova.feature_wallet_impl.data.network.tron.TronGridApi
|
||||
import javax.inject.Qualifier
|
||||
|
||||
@Qualifier
|
||||
annotation class TronNativeAssets
|
||||
|
||||
@Qualifier
|
||||
annotation class Trc20Assets
|
||||
|
||||
/**
|
||||
* Tron/TRC-20 support - Phase 1, read-only.
|
||||
*
|
||||
* Only `balance` is implemented for real; `transfers`/`history` reuse the same `Unsupported*` stubs the rest of
|
||||
* the app uses for asset types with no send/history support yet (see `UnsupportedAssetsModule`). This is
|
||||
* intentional: no transaction-building/signing code exists for Tron yet - that is future, separate work.
|
||||
*/
|
||||
@Module
|
||||
class TronAssetsModule {
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideRetrofitTronGridApi(
|
||||
networkApiCreator: NetworkApiCreator
|
||||
): RetrofitTronGridApi = networkApiCreator.create(RetrofitTronGridApi::class.java)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTronGridApi(retrofitTronGridApi: RetrofitTronGridApi): TronGridApi = RealTronGridApi(retrofitTronGridApi)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTronNativeBalance(assetCache: AssetCache, tronGridApi: TronGridApi) = TronNativeAssetBalance(assetCache, tronGridApi)
|
||||
|
||||
@Provides
|
||||
@FeatureScope
|
||||
fun provideTrc20Balance(assetCache: AssetCache, tronGridApi: TronGridApi) = Trc20AssetBalance(assetCache, tronGridApi)
|
||||
|
||||
@Provides
|
||||
@TronNativeAssets
|
||||
@FeatureScope
|
||||
fun provideTronNativeAssetSource(
|
||||
tronNativeAssetBalance: TronNativeAssetBalance,
|
||||
unsupportedAssetTransfers: UnsupportedAssetTransfers,
|
||||
unsupportedAssetHistory: UnsupportedAssetHistory,
|
||||
): AssetSource = StaticAssetSource(
|
||||
transfers = unsupportedAssetTransfers,
|
||||
balance = tronNativeAssetBalance,
|
||||
history = unsupportedAssetHistory
|
||||
)
|
||||
|
||||
@Provides
|
||||
@Trc20Assets
|
||||
@FeatureScope
|
||||
fun provideTrc20AssetSource(
|
||||
trc20AssetBalance: Trc20AssetBalance,
|
||||
unsupportedAssetTransfers: UnsupportedAssetTransfers,
|
||||
unsupportedAssetHistory: UnsupportedAssetHistory,
|
||||
): AssetSource = StaticAssetSource(
|
||||
transfers = unsupportedAssetTransfers,
|
||||
balance = trc20AssetBalance,
|
||||
history = unsupportedAssetHistory
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user