Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NftKit additions #256

Merged
merged 1 commit into from
Sep 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
NftKit additions
- add support for eip721 and eip1155 transfer methods and decorations
- add ability to fetch NftBalance by contract address and token id
  • Loading branch information
omurovch committed Sep 22, 2022
commit 8f2f5cc36d7e3488a6fa91d63640fa2c7d719723
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ class NftsViewModelFactory(private val evmKit: EthereumKit) : ViewModelProvider.
override fun <T : ViewModel> create(modelClass: Class<T>): T {

val nftKit = NftKit.getInstance(App.instance, evmKit)
NftKit.addEip1155TransactionSyncer(nftKit, evmKit)
NftKit.addEip1155Decorators(nftKit, evmKit)
NftKit.addEip721TransactionSyncer(nftKit, evmKit)
NftKit.addEip721Decorators(nftKit, evmKit)
nftKit.addEip1155TransactionSyncer()
nftKit.addEip1155Decorators()
nftKit.addEip721TransactionSyncer()
nftKit.addEip721Decorators()

return NftsViewModel(nftKit) as T
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class Eip20TransactionDecorator(
contractMethod.to,
contractMethod.value,
contractMethod.to == userAddress,
eventInstances.mapNotNull { it as TransferEventInstance }.firstOrNull { it.contractAddress == to }?.tokenInfo
eventInstances.mapNotNull { it as? TransferEventInstance }.firstOrNull { it.contractAddress == to }?.tokenInfo
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ class OutgoingEip20Decoration(
) : TransactionDecoration() {

override fun tags(): List<String> =
listOf(contractAddress.hex, TransactionTag.EIP20_TRANSFER, TransactionTag.eip20Outgoing(contractAddress.hex), TransactionTag.OUTGOING)
listOf(contractAddress.hex, TransactionTag.EIP20_TRANSFER, TransactionTag.tokenOutgoing(contractAddress.hex), TransactionTag.OUTGOING)

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ class TransferEventInstance(
val tags = mutableListOf(contractAddress.hex, TransactionTag.EIP20_TRANSFER)

if (from == userAddress) {
tags.add(TransactionTag.eip20Outgoing(contractAddress.hex))
tags.add(TransactionTag.tokenOutgoing(contractAddress.hex))
tags.add(TransactionTag.OUTGOING)
}

if (to == userAddress) {
tags.add(TransactionTag.eip20Incoming(contractAddress.hex))
tags.add(TransactionTag.tokenIncoming(contractAddress.hex))
tags.add(TransactionTag.INCOMING)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class TransactionTag(
const val EIP20_TRANSFER = "eip20Transfer"
const val EIP20_APPROVE = "eip20Approve"

fun eip20Incoming(contractAddress: String): String = "${contractAddress}_$INCOMING"
fun eip20Outgoing(contractAddress: String): String = "${contractAddress}_$OUTGOING"
fun tokenIncoming(contractAddress: String): String = "${contractAddress}_$INCOMING"
fun tokenOutgoing(contractAddress: String): String = "${contractAddress}_$OUTGOING"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.horizontalsystems.nftkit.contracts

import io.horizontalsystems.ethereumkit.contracts.ContractMethodFactories

object Eip1155ContractMethodFactories : ContractMethodFactories() {
init {
registerMethodFactories(listOf(Eip1155SafeTransferFromMethodFactory()))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.horizontalsystems.nftkit.contracts

import io.horizontalsystems.ethereumkit.contracts.ContractMethod
import io.horizontalsystems.ethereumkit.models.Address
import java.math.BigInteger

class Eip1155SafeTransferFromMethod(
val from: Address,
val to: Address,
val tokenId: BigInteger,
val value: BigInteger,
val data: ByteArray
) : ContractMethod() {

override val methodSignature = Companion.methodSignature
override fun getArguments() = listOf(from, to, tokenId, value, data)

companion object {
const val methodSignature = "safeTransferFrom(address,address,uint256,uint256,bytes)"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.horizontalsystems.nftkit.contracts

import io.horizontalsystems.ethereumkit.contracts.ContractMethod
import io.horizontalsystems.ethereumkit.contracts.ContractMethodFactory
import io.horizontalsystems.ethereumkit.contracts.ContractMethodHelper
import io.horizontalsystems.ethereumkit.models.Address
import io.horizontalsystems.ethereumkit.spv.core.toBigInteger

class Eip1155SafeTransferFromMethodFactory : ContractMethodFactory {
override val methodId = ContractMethodHelper.getMethodId(Eip1155SafeTransferFromMethod.methodSignature)

override fun createMethod(inputArguments: ByteArray): ContractMethod {
val from = Address(inputArguments.copyOfRange(12, 32))
val to = Address(inputArguments.copyOfRange(44, 64))
val tokenId = inputArguments.copyOfRange(64, 96).toBigInteger()
val value = inputArguments.copyOfRange(96, 128).toBigInteger()
val data = inputArguments.copyOfRange(128, 160)

return Eip1155SafeTransferFromMethod(from, to, tokenId, value, data)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.horizontalsystems.nftkit.contracts

import io.horizontalsystems.ethereumkit.contracts.ContractMethodFactories

object Eip721ContractMethodFactories : ContractMethodFactories() {
init {
registerMethodFactories(listOf(Eip721SafeTransferFromMethodFactory()))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.horizontalsystems.nftkit.contracts

import io.horizontalsystems.ethereumkit.contracts.ContractMethod
import io.horizontalsystems.ethereumkit.models.Address
import java.math.BigInteger

class Eip721SafeTransferFromMethod(
val from: Address,
val to: Address,
val tokenId: BigInteger,
val data: ByteArray
) : ContractMethod() {

override val methodSignature = Companion.methodSignature
override fun getArguments() = listOf(from, to, tokenId, data)

companion object {
const val methodSignature = "safeTransferFrom(address,address,uint256,bytes)"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.horizontalsystems.nftkit.contracts

import io.horizontalsystems.ethereumkit.contracts.ContractMethod
import io.horizontalsystems.ethereumkit.contracts.ContractMethodFactory
import io.horizontalsystems.ethereumkit.contracts.ContractMethodHelper
import io.horizontalsystems.ethereumkit.models.Address
import io.horizontalsystems.ethereumkit.spv.core.toBigInteger

class Eip721SafeTransferFromMethodFactory : ContractMethodFactory {
override val methodId = ContractMethodHelper.getMethodId(Eip721SafeTransferFromMethod.methodSignature)

override fun createMethod(inputArguments: ByteArray): ContractMethod {
val from = Address(inputArguments.copyOfRange(12, 32))
val to = Address(inputArguments.copyOfRange(44, 64))
val tokenId = inputArguments.copyOfRange(64, 96).toBigInteger()
val data = inputArguments.copyOfRange(96, 128)

return Eip721SafeTransferFromMethod(from, to, tokenId, data)
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package io.horizontalsystems.nftkit.core

import io.horizontalsystems.ethereumkit.models.Address
import io.horizontalsystems.nftkit.models.Nft
import io.horizontalsystems.nftkit.models.NftBalance
import io.horizontalsystems.nftkit.models.NftType
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import java.math.BigInteger

class BalanceManager(
private val balanceSyncManager: BalanceSyncManager,
Expand All @@ -24,6 +26,9 @@ class BalanceManager(
syncNftBalances()
}

fun nftBalance(contractAddress: Address, tokenId: BigInteger): NftBalance? =
storage.existingNftBalance(contractAddress, tokenId)

private suspend fun handleNftsFromTransactions(type: NftType, nfts: List<Nft>) {
val existingBalances = storage.nftBalances(type)
val existingNfts = existingBalances.map { it.nft }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.horizontalsystems.nftkit.core

import io.horizontalsystems.ethereumkit.contracts.ContractMethod
import io.horizontalsystems.ethereumkit.contracts.ContractMethodFactories
import io.horizontalsystems.ethereumkit.core.IMethodDecorator

class Eip1155MethodDecorator(
private val contractMethodFactories: ContractMethodFactories
) : IMethodDecorator {
override fun contractMethod(input: ByteArray): ContractMethod? {
return contractMethodFactories.createMethodFromInput(input)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.horizontalsystems.nftkit.core

import io.horizontalsystems.ethereumkit.contracts.ContractEventInstance
import io.horizontalsystems.ethereumkit.contracts.ContractMethod
import io.horizontalsystems.ethereumkit.core.ITransactionDecorator
import io.horizontalsystems.ethereumkit.decorations.TransactionDecoration
import io.horizontalsystems.ethereumkit.models.Address
import io.horizontalsystems.ethereumkit.models.InternalTransaction
import io.horizontalsystems.nftkit.contracts.Eip1155SafeTransferFromMethod
import io.horizontalsystems.nftkit.decorations.OutgoingEip1155Decoration
import io.horizontalsystems.nftkit.events.Eip1155TransferEventInstance
import java.math.BigInteger

class Eip1155TransactionDecorator(
private val userAddress: Address
) : ITransactionDecorator {

override fun decoration(
from: Address?,
to: Address?,
value: BigInteger?,
contractMethod: ContractMethod?,
internalTransactions: List<InternalTransaction>,
eventInstances: List<ContractEventInstance>
): TransactionDecoration? {
if (from == null || to == null || value == null || contractMethod == null) return null

return when {
contractMethod is Eip1155SafeTransferFromMethod && from == userAddress -> {
OutgoingEip1155Decoration(
contractAddress = to,
to = contractMethod.to,
tokenId = contractMethod.tokenId,
value = contractMethod.value,
sentToSelf = contractMethod.to == userAddress,
tokenInfo = eventInstances.mapNotNull { it as? Eip1155TransferEventInstance }.firstOrNull { it.contractAddress == to }?.tokenInfo
)
}
else -> null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.horizontalsystems.nftkit.core

import io.horizontalsystems.ethereumkit.contracts.ContractMethod
import io.horizontalsystems.ethereumkit.contracts.ContractMethodFactories
import io.horizontalsystems.ethereumkit.core.IMethodDecorator

class Eip721MethodDecorator(
private val contractMethodFactories: ContractMethodFactories
) : IMethodDecorator {
override fun contractMethod(input: ByteArray): ContractMethod? {
return contractMethodFactories.createMethodFromInput(input)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.horizontalsystems.nftkit.core

import io.horizontalsystems.ethereumkit.contracts.ContractEventInstance
import io.horizontalsystems.ethereumkit.contracts.ContractMethod
import io.horizontalsystems.ethereumkit.core.ITransactionDecorator
import io.horizontalsystems.ethereumkit.decorations.TransactionDecoration
import io.horizontalsystems.ethereumkit.models.Address
import io.horizontalsystems.ethereumkit.models.InternalTransaction
import io.horizontalsystems.nftkit.contracts.Eip721SafeTransferFromMethod
import io.horizontalsystems.nftkit.decorations.OutgoingEip721Decoration
import io.horizontalsystems.nftkit.events.Eip721TransferEventInstance
import java.math.BigInteger

class Eip721TransactionDecorator(
private val userAddress: Address
) : ITransactionDecorator {

override fun decoration(
from: Address?,
to: Address?,
value: BigInteger?,
contractMethod: ContractMethod?,
internalTransactions: List<InternalTransaction>,
eventInstances: List<ContractEventInstance>
): TransactionDecoration? {
if (from == null || to == null || value == null || contractMethod == null) return null

return when {
contractMethod is Eip721SafeTransferFromMethod && from == userAddress -> {
OutgoingEip721Decoration(
contractAddress = to,
to = contractMethod.to,
tokenId = contractMethod.tokenId,
sentToSelf = contractMethod.to == userAddress,
tokenInfo = eventInstances.mapNotNull { it as? Eip721TransferEventInstance }.firstOrNull { it.contractAddress == to }?.tokenInfo
)
}
else -> null
}
}
}
Loading