Updated on 2026-08-14
This commit is contained in:
parent
392547c7b6
commit
22a43ca524
4 changed files with 86 additions and 10 deletions
1
.idea/gradle.xml
generated
1
.idea/gradle.xml
generated
|
|
@ -11,6 +11,7 @@
|
|||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
<option value="$PROJECT_DIR$/blockchain" />
|
||||
<option value="$PROJECT_DIR$/server-android" />
|
||||
<option value="$PROJECT_DIR$/tangem-card-old" />
|
||||
<option value="$PROJECT_DIR$/tangem-core" />
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ data class Amount(
|
|||
val currencySymbol: String,
|
||||
val value: BigDecimal?,
|
||||
val address: String,
|
||||
val decimals: Int,
|
||||
val decimals: Byte,
|
||||
val type: AmountType = AmountType.Coin
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import org.kethereum.crypto.toAddress
|
|||
import org.kethereum.functions.isValid
|
||||
import org.kethereum.model.Address
|
||||
import org.kethereum.model.PublicKey
|
||||
import org.kethereum.wallet.model.WalletCrypto
|
||||
|
||||
object EthereumAddressFactory {
|
||||
fun makeAddress(cardPublicKey: ByteArray, testNet: Boolean = false): String =
|
||||
|
|
|
|||
|
|
@ -3,13 +3,22 @@ package com.tangem.blockchain.eth
|
|||
import com.tangem.blockchain.common.*
|
||||
import com.tangem.blockchain.wallets.CurrencyWallet
|
||||
import com.tangem.tasks.TaskEvent
|
||||
import org.kethereum.DEFAULT_GAS_LIMIT
|
||||
import org.kethereum.ETH_IN_WEI
|
||||
import org.kethereum.crypto.api.ec.ECDSASignature
|
||||
import org.kethereum.crypto.determineRecId
|
||||
import org.kethereum.crypto.impl.ec.canonicalise
|
||||
import org.kethereum.functions.encodeRLP
|
||||
import org.kethereum.keccakshortcut.keccak
|
||||
import org.kethereum.model.*
|
||||
import java.math.BigInteger
|
||||
|
||||
class EthereumWalletManager(
|
||||
private val cardId: String,
|
||||
private val walletPublicKey: ByteArray,
|
||||
private val isTestNet: Boolean,
|
||||
walletConfig: WalletConfig
|
||||
) : WalletManager,
|
||||
TransactionEstimator,
|
||||
TransactionSender,
|
||||
FeeProvider {
|
||||
|
||||
|
|
@ -17,39 +26,104 @@ class EthereumWalletManager(
|
|||
private val address = blockchain.makeAddress(walletPublicKey)
|
||||
override var wallet: Wallet = CurrencyWallet(walletConfig, address)
|
||||
|
||||
|
||||
override fun update() {
|
||||
|
||||
}
|
||||
|
||||
override fun getEstimateSize(transactionData: TransactionData): Int {
|
||||
|
||||
}
|
||||
|
||||
override fun send(transactionData: TransactionData, signer: TransactionSigner) {
|
||||
val builder = EthereumTransactionBuilder()
|
||||
val hashes = builder.buildToSign(transactionData, walletPublicKey)
|
||||
signer.sign(hashes.toTypedArray(), cardId) {
|
||||
when (it) {
|
||||
is TaskEvent.Event -> builder.buildToSend(transactionData, it.data.signature)
|
||||
is TaskEvent.Event -> builder.buildToSend(it.data.signature, walletPublicKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFee(amount: Amount, source: String, destination: String): List<Amount> {
|
||||
val gasPrices: List<Long> = getEthGasPrices()
|
||||
val gasLimit = getGasLimit(amount).value
|
||||
|
||||
val fees = mutableListOf<Amount>()
|
||||
for (gasPrice in gasPrices) {
|
||||
val feeValue = (gasPrice * gasLimit).toBigDecimal().divide(ETH_IN_WEI.toBigDecimal())
|
||||
fees.add(Amount(blockchain.currency, feeValue, address, blockchain.decimals))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class EthereumTransactionBuilder {
|
||||
|
||||
private class EthereumTransactionBuilder {
|
||||
var nonce: BigInteger? = null
|
||||
var transaction: Transaction? = null
|
||||
var hashToSign: ByteArray? = null
|
||||
|
||||
fun buildToSign(transactionData: TransactionData, publicKey: ByteArray): List<ByteArray> {
|
||||
val from = Address(transactionData.sourceAddress)
|
||||
val to = Address(transactionData.destinationAddress)
|
||||
val value = transactionData.amount.value!!
|
||||
.movePointRight(transactionData.amount.decimals.toInt()).toBigInteger()
|
||||
val fee = transactionData.fee!!.value!!
|
||||
.movePointRight(transactionData.fee.decimals.toInt()).toBigInteger()
|
||||
val gasPrice = fee.divide(DEFAULT_GAS_LIMIT)
|
||||
|
||||
transaction = createTransactionWithDefaults(
|
||||
from = from,
|
||||
to = to,
|
||||
value = value,
|
||||
gasPrice = gasPrice,
|
||||
gasLimit = DEFAULT_GAS_LIMIT,
|
||||
nonce = nonce,
|
||||
chain = ChainId(Chain.Mainnet.id)
|
||||
)
|
||||
|
||||
val transactionToSign = transaction!!
|
||||
.encodeRLP(SignatureData().apply { v = transaction!!.chain!! })
|
||||
hashToSign = transactionToSign.keccak()
|
||||
|
||||
return listOf(hashToSign!!)
|
||||
}
|
||||
|
||||
fun buildToSend(transactionData: TransactionData, signature: ByteArray) {
|
||||
fun buildToSend(signature: ByteArray, walletPublicKey: ByteArray): ByteArray {
|
||||
val r = BigInteger(1, signature.copyOfRange(0, 32))
|
||||
var s = BigInteger(1, signature.copyOfRange(32, 64))
|
||||
|
||||
val ecdsaSignature = ECDSASignature(r, s).canonicalise()
|
||||
|
||||
val recId = ecdsaSignature.determineRecId(hashToSign!!, PublicKey(walletPublicKey))
|
||||
val v = (recId + 27 + Chain.Mainnet.id).toBigInteger() // TODO: where to put chainId?
|
||||
val signatureData = SignatureData(ecdsaSignature.r, ecdsaSignature.s, v)
|
||||
|
||||
return transaction!!.encodeRLP(signatureData)
|
||||
}
|
||||
}
|
||||
|
||||
private enum class Chain(val id: Long) {
|
||||
Mainnet(1),
|
||||
Morden(2),
|
||||
Ropsten(3),
|
||||
Rinkeby(4),
|
||||
Rootstock_mainnet(30),
|
||||
Rootstock_testnet(31),
|
||||
Kovan(42),
|
||||
Ethereum_Classic_mainnet(61),
|
||||
Ethereum_Classic_testnet(62),
|
||||
Geth_private_chains(1337),
|
||||
Matic_Testnet(8995);
|
||||
}
|
||||
|
||||
private enum class GasLimit(val value: Long) {
|
||||
Default(210000),
|
||||
Token(60000),
|
||||
High(300000)
|
||||
}
|
||||
|
||||
private fun getGasLimit(amount: Amount): GasLimit {
|
||||
return when (amount.currencySymbol) {
|
||||
"ETH" -> GasLimit.Default
|
||||
"DGX" -> GasLimit.High
|
||||
else -> GasLimit.Token
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue