Skip to content

Commit

Permalink
Merge pull request #70 from OpenFuturePlatform/interoperability
Browse files Browse the repository at this point in the history
Interoperability
  • Loading branch information
borbuevbeksultan authored May 16, 2022
2 parents 02d9992 + 7d1eb20 commit 4cc6882
Show file tree
Hide file tree
Showing 22 changed files with 191 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import org.web3j.protocol.core.methods.response.EthBlock
import org.web3j.utils.Convert

@Component
//@ConditionalOnProperty(value = ["production.mode.enabled"], havingValue = "true")
@ConditionalOnProperty(value = ["production.mode.enabled"], havingValue = "true")
class EthereumBlockchain(private val web3j: Web3j) : Blockchain() {

override suspend fun getLastBlockNumber(): Int = web3j.ethBlockNumber()
Expand All @@ -39,7 +39,7 @@ class EthereumBlockchain(private val web3j: Web3j) : Blockchain() {
.map { tx ->
val to = tx.to ?: findContractAddress(tx.hash)
val amount = Convert.fromWei(tx.value.toBigDecimal(), Convert.Unit.ETHER)
UnifiedTransaction(tx.hash, tx.from, to, amount)
UnifiedTransaction(tx.hash, tx.from, to, amount, true, to)
}

private suspend fun findContractAddress(transactionHash: String) = web3j.ethGetTransactionReceipt(transactionHash)
Expand Down
75 changes: 65 additions & 10 deletions src/main/kotlin/io/openfuture/state/blockchain/RopstenBlockchain.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ import io.openfuture.state.domain.CurrencyCode
import io.openfuture.state.util.toLocalDateTime
import kotlinx.coroutines.future.await
import org.springframework.stereotype.Component
import org.web3j.abi.FunctionReturnDecoder
import org.web3j.abi.TypeReference
import org.web3j.abi.Utils
import org.web3j.abi.datatypes.Address
import org.web3j.abi.datatypes.generated.Uint256
import org.web3j.protocol.Web3j
import org.web3j.protocol.core.DefaultBlockParameterNumber
import org.web3j.protocol.core.methods.response.EthBlock
import org.web3j.utils.Convert
import java.math.BigDecimal
import java.math.BigInteger

@Component
class RopstenBlockchain(private val web3jTest: Web3j): Blockchain() {
Expand All @@ -24,6 +31,7 @@ class RopstenBlockchain(private val web3jTest: Web3j): Blockchain() {
.sendAsync().await()
.block
val transactions = obtainTransactions(block)

val date = block.timestamp.toLong().toLocalDateTime()
return UnifiedBlock(transactions, date, block.number.toLong(), block.hash)
}
Expand All @@ -32,16 +40,63 @@ class RopstenBlockchain(private val web3jTest: Web3j): Blockchain() {
return CurrencyCode.ETHEREUM
}

private suspend fun obtainTransactions(ethBlock: EthBlock.Block): List<UnifiedTransaction> = ethBlock.transactions
.map { it.get() as EthBlock.TransactionObject }
.map { tx ->
val to = tx.to ?: findContractAddress(tx.hash)
val amount = Convert.fromWei(tx.value.toBigDecimal(), Convert.Unit.ETHER)
UnifiedTransaction(tx.hash, tx.from, to, amount)
private suspend fun obtainTransactions(ethBlock: EthBlock.Block): List<UnifiedTransaction> {
val transactions = ethBlock.transactions
.map { it.get() as EthBlock.TransactionObject }
.filter { it.to != null }

val tokenTransfers = transactions
.filter { isErc20Transfer(it) }
.map { mapErc20Transaction(it) }

val nativeTransfers = transactions
.filter { isNativeTransfer(it) }
.map { UnifiedTransaction(it.hash, it.from, it.to, Convert.fromWei(it.value.toBigDecimal(), Convert.Unit.ETHER), true, it.from) }

return tokenTransfers + nativeTransfers
}

private fun isNativeTransfer(tx: EthBlock.TransactionObject): Boolean = tx.input == "0x"

private fun isErc20Transfer(tx: EthBlock.TransactionObject): Boolean = tx.input.startsWith(TRANSFER_METHOD_SIGNATURE)
&& tx.input.length >= TRANSFER_INPUT_LENGTH

private suspend fun mapErc20Transaction(tx: EthBlock.TransactionObject): UnifiedTransaction {
val result = FunctionReturnDecoder.decode(tx.input.drop(TRANSFER_METHOD_SIGNATURE.length), DECODE_TYPES)
val contractAddress = findContractAddress(tx.hash)

return UnifiedTransaction(
tx.hash,
tx.from,
result[0].value as String,
BigDecimal(result[1].value as BigInteger),
false,
contractAddress
)
}

private suspend fun findContractAddress(transactionHash: String): String{
val transactionReceipt = web3jTest.ethGetTransactionReceipt(transactionHash)
.sendAsync().await()
.transactionReceipt

var address = "";
transactionReceipt.get().logs.forEach{
address = it.address
}

private suspend fun findContractAddress(transactionHash: String) = web3jTest.ethGetTransactionReceipt(transactionHash)
.sendAsync().await()
.transactionReceipt.get()
.contractAddress
return address
}

companion object {
private val DECODE_TYPES = Utils.convert(
listOf(
object : TypeReference<Address>(true) {},
object : TypeReference<Uint256>() {}
)
)

private const val TRANSFER_METHOD_SIGNATURE = "0xa9059cbb"
private const val TRANSFER_INPUT_LENGTH = 138
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class BinanceBlockchain(@Qualifier("web3jBinance") private val web3jBinance: Web
.map { tx ->
val to = tx.to ?: findContractAddress(tx.hash)
val amount = Convert.fromWei(tx.value.toBigDecimal(), Convert.Unit.ETHER)
UnifiedTransaction(tx.hash, tx.from, to, amount)
UnifiedTransaction(tx.hash, tx.from, to, amount, true, to)
}

private suspend fun findContractAddress(transactionHash: String) = web3jBinance.ethGetTransactionReceipt(transactionHash)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import org.web3j.protocol.core.DefaultBlockParameterNumber
import org.web3j.protocol.core.methods.response.EthBlock
import org.web3j.utils.Convert

@Component
//@Component
class BinanceTestnetBlockchain(@Qualifier("web3jBinanceTestnet") private val web3jBinanceTestnet: Web3j): Blockchain() {

override suspend fun getLastBlockNumber(): Int = web3jBinanceTestnet.ethBlockNumber()
Expand All @@ -39,7 +39,7 @@ class BinanceTestnetBlockchain(@Qualifier("web3jBinanceTestnet") private val web
.map { tx ->
val to = tx.to ?: findContractAddress(tx.hash)
val amount = Convert.fromWei(tx.value.toBigDecimal(), Convert.Unit.ETHER)
UnifiedTransaction(tx.hash, tx.from, to, amount)
UnifiedTransaction(tx.hash, tx.from, to, amount, true, to)
}

private suspend fun findContractAddress(transactionHash: String) = web3jBinanceTestnet.ethGetTransactionReceipt(transactionHash)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class BitcoinBlockchain(private val client: BitcoinClient) : Blockchain() {
return transaction.outputs
.filter { it.addresses.isNotEmpty() }
.filter { !containsChangeAddresses(inputAddresses, it.addresses) }
.map { UnifiedTransaction(transaction.hash, inputAddresses, it.addresses.first(), it.value) }
.map { UnifiedTransaction(transaction.hash, inputAddresses, it.addresses.first(), it.value, true, it.addresses.first()) }
}

private fun containsChangeAddresses(inputAddresses: Set<String>, outputAddresses: Set<String>): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ data class UnifiedTransaction(
val hash: String,
val from: Set<String>,
val to: String,
val amount: BigDecimal
val amount: BigDecimal,
val native: Boolean,
val contractAddress: String?
) {
constructor(hash: String, from: String, to: String, amount: BigDecimal) : this(hash, setOf(from), to, amount)
constructor(hash: String, from: String, to: String, amount: BigDecimal, native: Boolean, contractAddress: String?) : this(hash, setOf(from), to, amount, native, contractAddress)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.openfuture.state.component.open

import io.openfuture.state.domain.CustomToken
import io.openfuture.state.webhook.WebhookPayloadDto
import org.springframework.stereotype.Component
import org.springframework.web.client.RestTemplate
Expand All @@ -13,4 +14,10 @@ class DefaultOpenApi(
val response = openRestTemplate.postForEntity(url, woocommerceDto, String::class.java)
return response.body!!
}

override suspend fun getTokens(): Array<CustomToken> {
val url = "/token/list"
val response = openRestTemplate.getForEntity(url, Array<CustomToken>::class.java)
return response.body!!
}
}
2 changes: 2 additions & 0 deletions src/main/kotlin/io/openfuture/state/component/open/OpenApi.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package io.openfuture.state.component.open

import io.openfuture.state.domain.CustomToken
import io.openfuture.state.webhook.WebhookPayloadDto

interface OpenApi {

suspend fun generateSignature(address: String, woocommerceDto: WebhookPayloadDto.WebhookWoocommerceDto): String
suspend fun getTokens(): Array<CustomToken>
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,17 @@ class OrderController(
val transactionsResponse = transactions.map {
TransactionResponse(
it.hash,
it.from.first(),
it.from,
it.to, it.amount,
it.date,
it.blockHeight,
it.blockHash,
wallet.rate
wallet.rate,
it.native,
it.token
)
}
return WalletResponse(wallet.identity.address, wallet.identity.blockchain, transactionsResponse)
return WalletResponse(wallet.identity.address, wallet.identity.blockchain, wallet.rate, transactionsResponse)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,19 @@ data class OrderStateResponse(
data class WalletResponse(
val address: String,
val blockchain: String,
val rate: BigDecimal,
val transactions: List<TransactionResponse>
)

data class TransactionResponse(
val hash: String,
val from: String,
val from: Set<String>,
val to: String,
val amount: BigDecimal,
val date: LocalDateTime,
val blockHeight: Long,
val blockHash: String,
val rate: BigDecimal
val rate: BigDecimal,
val native: Boolean?,
val token: String?
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.openfuture.state.controller

import io.openfuture.state.controller.request.ManualTransactionRequest
import io.openfuture.state.domain.Transaction
import io.openfuture.state.domain.WalletTransactionDetail
import io.openfuture.state.service.BlockchainLookupService
import io.openfuture.state.service.DefaultWalletService
Expand All @@ -25,6 +26,11 @@ class TransactionController(
return walletTransactionFacade.findByOrder(orderKey)
}

@GetMapping("/{address}")
suspend fun getTransaction(@PathVariable address: String): List<Transaction> {
return walletTransactionFacade.getTransaction(address)
}

@PostMapping("/admin/sendManualTransaction")
suspend fun sendManualTransaction(@RequestBody request: ManualTransactionRequest) {
val blockchain = blockchainLookupService.findBlockchain(request.blockchainName)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.openfuture.state.controller

import io.openfuture.state.webhook.DefaultWebhookExecutor
import io.openfuture.state.webhook.WebhookExecutor
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
Expand Down
9 changes: 9 additions & 0 deletions src/main/kotlin/io/openfuture/state/domain/CustomToken.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.openfuture.state.domain


data class CustomToken(
val name: String,
val symbol: String,
val address: String,
val decimal: Int
)
2 changes: 2 additions & 0 deletions src/main/kotlin/io/openfuture/state/domain/Transaction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ data class Transaction(
val date: LocalDateTime,
val blockHeight: Long,
val blockHash: String,
val native: Boolean?,
val token: String?,
@MongoId
val id: String = ObjectId().toHexString()
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ import reactor.core.publisher.Mono
@Repository
interface OrderRepository : ReactiveMongoRepository<Order, String>{
suspend fun findByOrderKey(orderId: String): Flux<Order>
suspend fun findByOrderId(orderId: String): Mono<Order>
suspend fun findFirstByOrderId(orderId: String): Mono<Order>
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ import reactor.core.publisher.Flux

@Repository
interface TransactionRepository : ReactiveMongoRepository<Transaction, String>{
suspend fun findAllByWalletIdentityAddress(walletIdentity_address: String): Flux<Transaction>
suspend fun findAllByWalletIdentityAddress(walletIdentityAddress: String): Flux<Transaction>
suspend fun existsTransactionByHash(trxHash: String): Boolean
}
Loading

0 comments on commit 4cc6882

Please sign in to comment.