Skip to content

Commit

Permalink
TokenInfoManager verify tokens according to EIP-21 and set correct type
Browse files Browse the repository at this point in the history
  • Loading branch information
MrStahlfelge committed Feb 23, 2022
1 parent 5e8a599 commit 337756b
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class TokenInformationDialogFragment : BottomSheetDialogFragment() {
it.ergValue,
walletSyncManager,
AndroidStringProvider(requireContext())
)
) + " [${it.priceSource}]"
}

binding.labelBalanceAmount.visibility = if (showBalance) View.VISIBLE else View.GONE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
import org.ergoplatform.ErgoApiService
import org.ergoplatform.TokenInfoManager
import org.ergoplatform.tokens.TokenInfoManager
import org.ergoplatform.android.AppDatabase
import org.ergoplatform.android.Preferences
import org.ergoplatform.persistance.TokenInformation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.ergoplatform.persistance

import org.ergoplatform.appkit.Eip4Token
import org.ergoplatform.appkit.ErgoValue
import java.math.BigDecimal

data class TokenPrice(
Expand Down Expand Up @@ -28,7 +30,34 @@ data class TokenInformation(
val thumbnailBytes: ByteArray? = null,
val thumbnailType: Int = THUMBNAIL_TYPE_NONE,
val updatedMs: Long = 0
)
) {
constructor(
tokenInformation: TokenInformation,
genuineFlag: Int = GENUINE_UNKNOWN,
issuerLink: String? = null,
thumbnailBytes: ByteArray? = null,
thumbnailType: Int = THUMBNAIL_TYPE_NONE,
updatedMs: Long = 0
) : this(
tokenInformation.tokenId,
tokenInformation.issuingBoxId, tokenInformation.mintingTxId,
tokenInformation.displayName, tokenInformation.description, tokenInformation.decimals,
tokenInformation.fullSupply, tokenInformation.reg7hex, tokenInformation.reg8hex,
tokenInformation.reg9hex,
genuineFlag, issuerLink, thumbnailBytes, thumbnailType, updatedMs
)

fun toEip4Token(): Eip4Token = Eip4Token(
tokenId,
fullSupply,
displayName,
description,
decimals,
reg7hex?.let { ErgoValue.fromHex(it) },
reg8hex?.let { ErgoValue.fromHex(it) },
reg9hex?.let { ErgoValue.fromHex(it) }
)
}

const val THUMBNAIL_TYPE_NONE = 0
const val THUMBNAIL_TYPE_NFT_IMG = 10
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package org.ergoplatform
package org.ergoplatform.tokens

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.ergoplatform.ErgoApiService
import org.ergoplatform.appkit.Eip4Token
import org.ergoplatform.appkit.impl.Eip4TokenBuilder
import org.ergoplatform.explorer.client.model.OutputInfo
import org.ergoplatform.persistance.TokenDbProvider
import org.ergoplatform.persistance.TokenInformation
import org.ergoplatform.persistance.*
import org.ergoplatform.utils.LogUtils

class TokenInfoManager {
Expand Down Expand Up @@ -45,10 +46,65 @@ class TokenInfoManager {
): TokenInformation? {
val fromDb = tokenDbProvider.loadTokenInformation(tokenId)

// TODO mark for update if necessary
fromDb?.let {
updateTokenInformationWhenNecessary(it, tokenDbProvider, null)
}

return fromDb
}

private fun updateTokenInformationWhenNecessary(
token: TokenInformation,
tokenDbProvider: TokenDbProvider,
eip4Token: Eip4Token?
) {
if (System.currentTimeMillis() - token.updatedMs > 1000L * 60 * 60) {
GlobalScope.launch(Dispatchers.IO) {

// check if genuine
val genuineToken = TokenVerifier.checkTokenGenuine(token.tokenId, token.displayName)

val tokenGenuine = when {
genuineToken == null -> GENUINE_UNKNOWN
genuineToken.tokenId == token.tokenId -> GENUINE_VERIFIED
else -> GENUINE_SUSPICIOUS
}

// check for NFT
val thumbnailType =
if (token.thumbnailType == THUMBNAIL_TYPE_BYTES_PNG && token.thumbnailBytes != null)
THUMBNAIL_TYPE_BYTES_PNG else
try {
val eip4 = eip4Token ?: token.toEip4Token()

when (eip4.assetType) {
Eip4Token.AssetType.NFT_PICTURE -> THUMBNAIL_TYPE_NFT_IMG
Eip4Token.AssetType.NFT_AUDIO -> THUMBNAIL_TYPE_NFT_AUDIO
Eip4Token.AssetType.NFT_VIDEO -> THUMBNAIL_TYPE_NFT_VID
else -> THUMBNAIL_TYPE_NONE
}
} catch (t: Throwable) {
LogUtils.logDebug("TokenInfoManager", "Error processing EIP4 token", t)
THUMBNAIL_TYPE_NONE
}

val timeNow = System.currentTimeMillis()
val newToken = TokenInformation(
token,
tokenGenuine,
if (tokenGenuine == GENUINE_VERIFIED) genuineToken!!.issuer else null,
token.thumbnailBytes,
thumbnailType,
timeNow
)

tokenDbProvider.insertOrReplaceTokenInformation(newToken)
tokenDbProvider.pruneUnusedTokenInformation()
lastRepoRefresh.value = timeNow
}
}
}

private fun fetchTokenInformationFromApi(
apiService: ErgoApiService,
tokenDbProvider: TokenDbProvider,
Expand All @@ -74,8 +130,6 @@ class TokenInfoManager {
boxInfo.additionalRegisters
)

// TODO fill more fields with Eip4Token Information

val tokenInformation = TokenInformation(
tokenId,
issuingBoxId,
Expand All @@ -91,15 +145,14 @@ class TokenInfoManager {

GlobalScope.launch(Dispatchers.IO) {
tokenDbProvider.insertOrReplaceTokenInformation(tokenInformation)
lastRepoRefresh.value = System.currentTimeMillis()

// TODO mark for update
updateTokenInformationWhenNecessary(tokenInformation, tokenDbProvider, eip4Token)
}

return tokenInformation
}

// TODO prune old objects after an update

companion object {

// For Singleton instantiation
Expand Down
47 changes: 47 additions & 0 deletions common-jvm/src/main/java/org/ergoplatform/tokens/TokenVerifier.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.ergoplatform.tokens

import org.ergoplatform.WalletStateSyncManager

object TokenVerifier {
private val genuineTokens: List<Eip21Token> = listOf(
Eip21Token(
"03faf2cb329f2e90d6d23b58d91bbb6c046aa143261cc21f52fbe2824bfcbf04",
"SigUSD",
true,
"sigmausd.io"
),
Eip21Token(
"003bd19d0187117f130b62e1bcab0939929ff5c7709f843c5c4dd158949285d0",
"SigRSV",
true,
"sigmausd.io"
),
)

fun checkTokenGenuine(tokenId: String, tokenDisplayName: String): Eip21Token? {
// check EIP-21
val eip21token = genuineTokens.find { it.tokenId.equals(tokenId, true) }
?: genuineTokens.find { it.uniqueName && it.displayName.equals(tokenDisplayName, true) }

if (eip21token != null)
return eip21token

// if this token is not found for EIP-21, check the price list
val priceTokenList = WalletStateSyncManager.getInstance().tokenPrices
return (priceTokenList[tokenId] ?: priceTokenList.values.find {
it.displayName.equals(
tokenDisplayName,
true
)
})?.let {
Eip21Token(it.tokenId, it.displayName ?: "???", true, null)
}
}
}

data class Eip21Token(
val tokenId: String,
val displayName: String,
val uniqueName: Boolean,
val issuer: String?
)

0 comments on commit 337756b

Please sign in to comment.