Skip to content

Commit 835e9f5

Browse files
committed
ETH blockchain additional methods added, like broadcast, getGasLimit/GasPrice etc.
1 parent 1c88250 commit 835e9f5

17 files changed

+368
-36
lines changed

src/main/kotlin/io/openfuture/state/blockchain/Blockchain.kt

+5-6
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@ import java.math.BigInteger
88
abstract class Blockchain {
99

1010
abstract suspend fun getLastBlockNumber(): Int
11-
11+
abstract suspend fun getNonce(address: String): BigInteger
12+
abstract suspend fun broadcastTransaction(signedTransaction: String): String
13+
abstract suspend fun getTransactionStatus(transactionHash: String): Boolean
1214
abstract suspend fun getBlock(blockNumber: Int): UnifiedBlock
13-
15+
abstract suspend fun getGasPrice(): BigInteger
16+
abstract suspend fun getGasLimit(): BigInteger
1417
abstract suspend fun getBalance(address: String): BigDecimal
15-
1618
abstract suspend fun getContractBalance(address: String, contractAddress: String): BigDecimal
17-
1819
open fun getName(): String = javaClass.simpleName
19-
2020
abstract suspend fun getCurrencyCode(): CurrencyCode
21-
2221
override fun toString(): String {
2322
return getName()
2423
}

src/main/kotlin/io/openfuture/state/blockchain/binance/BinanceBlockchain.kt

+37-1
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import io.openfuture.state.blockchain.dto.UnifiedBlock
55
import io.openfuture.state.blockchain.dto.UnifiedTransaction
66
import io.openfuture.state.domain.CurrencyCode
77
import io.openfuture.state.util.toLocalDateTime
8+
import kotlinx.coroutines.Dispatchers
89
import kotlinx.coroutines.future.await
10+
import kotlinx.coroutines.withContext
911
import org.springframework.beans.factory.annotation.Qualifier
1012
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
1113
import org.springframework.stereotype.Component
1214
import org.web3j.abi.FunctionEncoder
13-
import org.web3j.abi.FunctionReturnDecoder
1415
import org.web3j.abi.TypeReference
1516
import org.web3j.abi.datatypes.Address
1617
import org.web3j.abi.datatypes.generated.Uint256
@@ -21,6 +22,7 @@ import org.web3j.protocol.core.methods.request.Transaction
2122
import org.web3j.protocol.core.methods.response.EthBlock
2223
import org.web3j.protocol.core.methods.response.EthCall
2324
import org.web3j.utils.Convert
25+
import java.lang.Exception
2426
import java.math.BigDecimal
2527
import java.math.BigInteger
2628

@@ -33,6 +35,30 @@ class BinanceBlockchain(@Qualifier("web3jBinance") private val web3jBinance: Web
3335
.sendAsync().await()
3436
.blockNumber.toInt()
3537

38+
override suspend fun getNonce(address: String): BigInteger = web3jBinance.ethGetTransactionCount(address,
39+
DefaultBlockParameterName.LATEST
40+
).send().transactionCount
41+
42+
override suspend fun broadcastTransaction(signedTransaction: String): String {
43+
val result = web3jBinance.ethSendRawTransaction(signedTransaction).send()
44+
45+
if (result.hasError()) {
46+
throw Exception(result.error.message)
47+
}
48+
49+
while (!web3jBinance.ethGetTransactionReceipt(result.transactionHash).send().transactionReceipt.isPresent) {
50+
withContext(Dispatchers.IO) {
51+
Thread.sleep(1000)
52+
}
53+
}
54+
55+
return web3jBinance.ethGetTransactionReceipt(result.transactionHash).send().transactionReceipt.get().transactionHash
56+
}
57+
58+
override suspend fun getTransactionStatus(transactionHash: String): Boolean {
59+
TODO("Not yet implemented")
60+
}
61+
3662
override suspend fun getBlock(blockNumber: Int): UnifiedBlock {
3763
val parameter = DefaultBlockParameterNumber(blockNumber.toLong())
3864
val block = web3jBinance.ethGetBlockByNumber(parameter, true)
@@ -76,6 +102,16 @@ class BinanceBlockchain(@Qualifier("web3jBinance") private val web3jBinance: Web
76102
return Convert.fromWei(contractBalance.toString(), Convert.Unit.ETHER)
77103
}
78104

105+
override suspend fun getGasPrice(): BigInteger {
106+
return web3jBinance.ethGasPrice().sendAsync().await().gasPrice
107+
}
108+
109+
override suspend fun getGasLimit(): BigInteger {
110+
return web3jBinance
111+
.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, false)
112+
.sendAsync().await()
113+
.block.gasLimit
114+
}
79115
private suspend fun obtainTransactions(ethBlock: EthBlock.Block): List<UnifiedTransaction> = ethBlock.transactions
80116
.map { it.get() as EthBlock.TransactionObject }
81117
.map { tx ->

src/main/kotlin/io/openfuture/state/blockchain/binance/BinanceTestnetBlockchain.kt

+38
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import io.openfuture.state.blockchain.dto.UnifiedBlock
55
import io.openfuture.state.blockchain.dto.UnifiedTransaction
66
import io.openfuture.state.domain.CurrencyCode
77
import io.openfuture.state.util.toLocalDateTime
8+
import kotlinx.coroutines.Dispatchers
89
import kotlinx.coroutines.future.await
10+
import kotlinx.coroutines.withContext
911
import org.springframework.beans.factory.annotation.Qualifier
1012
import org.springframework.stereotype.Component
1113
import org.web3j.abi.FunctionEncoder
@@ -21,6 +23,7 @@ import org.web3j.protocol.core.methods.request.Transaction
2123
import org.web3j.protocol.core.methods.response.EthBlock
2224
import org.web3j.protocol.core.methods.response.EthCall
2325
import org.web3j.utils.Convert
26+
import java.lang.Exception
2427
import java.math.BigDecimal
2528
import java.math.BigInteger
2629

@@ -32,6 +35,30 @@ class BinanceTestnetBlockchain(@Qualifier("web3jBinanceTestnet") private val web
3235
.sendAsync().await()
3336
.blockNumber.toInt()
3437

38+
override suspend fun getNonce(address: String): BigInteger = web3jBinanceTestnet.ethGetTransactionCount(address,
39+
DefaultBlockParameterName.LATEST
40+
).send().transactionCount
41+
42+
override suspend fun broadcastTransaction(signedTransaction: String): String {
43+
val result = web3jBinanceTestnet.ethSendRawTransaction(signedTransaction).send()
44+
45+
if (result.hasError()) {
46+
throw Exception(result.error.message)
47+
}
48+
49+
while (!web3jBinanceTestnet.ethGetTransactionReceipt(result.transactionHash).send().transactionReceipt.isPresent) {
50+
withContext(Dispatchers.IO) {
51+
Thread.sleep(1000)
52+
}
53+
}
54+
55+
return web3jBinanceTestnet.ethGetTransactionReceipt(result.transactionHash).send().transactionReceipt.get().transactionHash
56+
}
57+
58+
override suspend fun getTransactionStatus(transactionHash: String): Boolean {
59+
TODO("Not yet implemented")
60+
}
61+
3562
override suspend fun getBlock(blockNumber: Int): UnifiedBlock {
3663
val parameter = DefaultBlockParameterNumber(blockNumber.toLong())
3764
val block = web3jBinanceTestnet.ethGetBlockByNumber(parameter, true)
@@ -78,6 +105,17 @@ class BinanceTestnetBlockchain(@Qualifier("web3jBinanceTestnet") private val web
78105
return CurrencyCode.BINANCE
79106
}
80107

108+
override suspend fun getGasPrice(): BigInteger {
109+
return web3jBinanceTestnet.ethGasPrice().sendAsync().await().gasPrice
110+
}
111+
112+
override suspend fun getGasLimit(): BigInteger {
113+
return web3jBinanceTestnet
114+
.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, false)
115+
.sendAsync().await()
116+
.block.gasLimit
117+
}
118+
81119
private suspend fun obtainTransactions(ethBlock: EthBlock.Block): List<UnifiedTransaction> = ethBlock.transactions
82120
.map { it.get() as EthBlock.TransactionObject }
83121
.map { tx ->

src/main/kotlin/io/openfuture/state/blockchain/bitcoin/BitcoinBlockchain.kt

+21-2
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,36 @@ class BitcoinBlockchain(private val client: BitcoinClient) : Blockchain() {
2121
return client.getBlockHeight(latestBlockHash)
2222
}
2323

24+
override suspend fun getNonce(address: String): BigInteger {
25+
TODO("Not yet implemented")
26+
}
27+
28+
override suspend fun broadcastTransaction(signedTransaction: String): String {
29+
TODO("Not yet implemented")
30+
}
31+
32+
override suspend fun getTransactionStatus(transactionHash: String): Boolean {
33+
TODO("Not yet implemented")
34+
}
35+
2436
override suspend fun getBlock(blockNumber: Int): UnifiedBlock {
2537
val blockHash = client.getBlockHash(blockNumber)
2638
val block = client.getBlock(blockHash)
2739

2840
return toUnifiedBlock(block)
2941
}
3042

31-
//todo - implement
43+
override suspend fun getGasPrice(): BigInteger {
44+
TODO("Not yet implemented")
45+
}
46+
47+
override suspend fun getGasLimit(): BigInteger {
48+
TODO("Not yet implemented")
49+
}
50+
3251
override suspend fun getBalance(address: String): BigDecimal {
3352
val balance = client.getAddressBalance(address)
34-
return BigDecimal.ZERO
53+
return balance.toBigDecimal()
3554
}
3655

3756
override suspend fun getContractBalance(address: String, contractAddress: String): BigDecimal {

src/main/kotlin/io/openfuture/state/blockchain/bitcoin/BitcoinClient.kt

+10
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ class BitcoinClient(
4040
return response.result.height
4141
}
4242

43+
suspend fun broadcastRawTransaction(signature: String): Int {
44+
val command = BitcoinCommand("send")
45+
val response = client.post()
46+
.contentType(MediaType.APPLICATION_JSON)
47+
.body(BodyInserters.fromValue(command))
48+
.retrieve()
49+
.awaitBody<BitcoinResponse<BlockHeightBitcoinResponse>>()
50+
return response.result.height
51+
}
52+
4353
suspend fun getBlockHash(blockHeight: Int): String {
4454
val command = BitcoinCommand("getblockhash", listOf(blockHeight))
4555
val response = client.post()

src/main/kotlin/io/openfuture/state/blockchain/ethereum/EthereumBlockchain.kt

+38-3
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import io.openfuture.state.blockchain.dto.UnifiedBlock
55
import io.openfuture.state.blockchain.dto.UnifiedTransaction
66
import io.openfuture.state.domain.CurrencyCode
77
import io.openfuture.state.util.toLocalDateTime
8+
import kotlinx.coroutines.Dispatchers
89
import kotlinx.coroutines.future.await
10+
import kotlinx.coroutines.withContext
911
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
1012
import org.springframework.stereotype.Component
1113
import org.web3j.abi.FunctionEncoder
1214
import org.web3j.abi.FunctionReturnDecoder
15+
import org.web3j.protocol.core.DefaultBlockParameterName.LATEST
1316
import org.web3j.abi.TypeReference
1417
import org.web3j.abi.datatypes.Address
1518
import org.web3j.abi.datatypes.generated.Uint256
@@ -20,6 +23,7 @@ import org.web3j.protocol.core.methods.request.Transaction
2023
import org.web3j.protocol.core.methods.response.EthBlock
2124
import org.web3j.protocol.core.methods.response.EthCall
2225
import org.web3j.utils.Convert
26+
import java.lang.Exception
2327
import java.math.BigDecimal
2428
import java.math.BigInteger
2529

@@ -31,6 +35,27 @@ class EthereumBlockchain(private val web3j: Web3j) : Blockchain() {
3135
.sendAsync().await()
3236
.blockNumber.toInt()
3337

38+
override suspend fun getNonce(address: String): BigInteger = web3j.ethGetTransactionCount(address, LATEST).send().transactionCount
39+
override suspend fun broadcastTransaction(signedTransaction: String): String {
40+
val result = web3j.ethSendRawTransaction(signedTransaction).send()
41+
42+
if (result.hasError()) {
43+
throw Exception(result.error.message)
44+
}
45+
46+
while (!web3j.ethGetTransactionReceipt(result.transactionHash).send().transactionReceipt.isPresent) {
47+
withContext(Dispatchers.IO) {
48+
Thread.sleep(1000)
49+
}
50+
}
51+
52+
return web3j.ethGetTransactionReceipt(result.transactionHash).send().transactionReceipt.get().transactionHash
53+
}
54+
55+
override suspend fun getTransactionStatus(transactionHash: String): Boolean {
56+
TODO("Not yet implemented")
57+
}
58+
3459
override suspend fun getBlock(blockNumber: Int): UnifiedBlock {
3560
val parameter = DefaultBlockParameterNumber(blockNumber.toLong())
3661
val block = web3j.ethGetBlockByNumber(parameter, true)
@@ -42,8 +67,7 @@ class EthereumBlockchain(private val web3j: Web3j) : Blockchain() {
4267
}
4368

4469
override suspend fun getBalance(address: String): BigDecimal {
45-
val parameter = DefaultBlockParameterName.LATEST
46-
val balanceWei = web3j.ethGetBalance(address, parameter)
70+
val balanceWei = web3j.ethGetBalance(address, LATEST)
4771
.sendAsync().await()
4872
.balance
4973
return Convert.fromWei(balanceWei.toString(), Convert.Unit.ETHER)
@@ -59,7 +83,7 @@ class EthereumBlockchain(private val web3j: Web3j) : Blockchain() {
5983
val encodedFunction = FunctionEncoder.encode(functionBalance)
6084
val ethCall: EthCall = web3j.ethCall(
6185
Transaction.createEthCallTransaction(address, contractAddress, encodedFunction),
62-
DefaultBlockParameterName.LATEST
86+
LATEST
6387
).sendAsync().await()
6488

6589
val value = ethCall.value
@@ -68,6 +92,17 @@ class EthereumBlockchain(private val web3j: Web3j) : Blockchain() {
6892
return Convert.fromWei(contractBalance.toString(), Convert.Unit.ETHER)
6993
}
7094

95+
override suspend fun getGasPrice(): BigInteger {
96+
return web3j.ethGasPrice().sendAsync().await().gasPrice
97+
}
98+
99+
override suspend fun getGasLimit(): BigInteger {
100+
return web3j
101+
.ethGetBlockByNumber(LATEST, false)
102+
.sendAsync().await()
103+
.block.gasLimit
104+
}
105+
71106
override suspend fun getCurrencyCode(): CurrencyCode {
72107
return CurrencyCode.ETHEREUM
73108
}

0 commit comments

Comments
 (0)