Skip to content

Commit

Permalink
Add EthSigner for signing byte strings and structured data (EIP712)
Browse files Browse the repository at this point in the history
  • Loading branch information
omurovch committed May 17, 2021
1 parent 696b46a commit e8e30ce
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 1 deletion.
4 changes: 4 additions & 0 deletions ethereumkit/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ dependencies {
implementation 'androidx.room:room-rxjava2:2.2.5'
kapt 'androidx.room:room-compiler:2.2.5'

//Eip712
def kethereum_version = "0.83.6"
implementation "com.github.komputing.kethereum:erc712:$kethereum_version"

// Test helpers
testImplementation 'junit:junit:4.13'
testImplementation 'org.mockito:mockito-core:3.3.3'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import io.horizontalsystems.ethereumkit.api.models.AccountState
import io.horizontalsystems.ethereumkit.api.models.EthereumKitState
import io.horizontalsystems.ethereumkit.api.storage.ApiStorage
import io.horizontalsystems.ethereumkit.crypto.CryptoUtils
import io.horizontalsystems.ethereumkit.crypto.EIP712Encoder
import io.horizontalsystems.ethereumkit.crypto.EthSigner
import io.horizontalsystems.ethereumkit.crypto.InternalBouncyCastleProvider
import io.horizontalsystems.ethereumkit.models.*
import io.horizontalsystems.ethereumkit.network.*
Expand Down Expand Up @@ -43,6 +45,7 @@ class EthereumKit(
val walletId: String,
val etherscanService: EtherscanService,
private val decorationManager: DecorationManager,
private val ethSigner: EthSigner,
private val state: EthereumKitState = EthereumKitState()
) : IBlockchainListener {

Expand Down Expand Up @@ -194,6 +197,14 @@ class EthereumKit(
return transactionBuilder.encode(rawTransaction, signature)
}

fun signByteArray(message: ByteArray): ByteArray {
return ethSigner.signByteArray(message)
}

fun signTypedData(rawJsonMessage: String): ByteArray {
return ethSigner.signTypedData(rawJsonMessage)
}

fun getLogs(address: Address?, topics: List<ByteArray?>, fromBlock: Long, toBlock: Long, pullTimestamps: Boolean): Single<List<TransactionLog>> {
return blockchain.getLogs(address, topics, fromBlock, toBlock, pullTimestamps)
}
Expand Down Expand Up @@ -390,8 +401,9 @@ class EthereumKit(

val transactionManager = TransactionManager(address, transactionSyncManager, transactionStorage)
val decorationManager = DecorationManager(address)
val ethSigner = EthSigner(privateKey, CryptoUtils, EIP712Encoder())

val ethereumKit = EthereumKit(blockchain, transactionManager, transactionSyncManager, transactionBuilder, transactionSigner, connectionManager, address, networkType, walletId, etherscanService, decorationManager)
val ethereumKit = EthereumKit(blockchain, transactionManager, transactionSyncManager, transactionBuilder, transactionSigner, connectionManager, address, networkType, walletId, etherscanService, decorationManager, ethSigner)

blockchain.listener = ethereumKit
transactionSyncManager.set(ethereumKit)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.horizontalsystems.ethereumkit.crypto

import com.google.gson.Gson
import pm.gnosis.eip712.EIP712JsonAdapter
import pm.gnosis.eip712.EIP712JsonParser
import pm.gnosis.eip712.typedDataHash
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader

class EIP712Encoder {

private val eip712JsonAdapter = EIP712GsonAdapter()

fun encodeTypedDataHash(rawJsonMessage: String): ByteArray {
val domainWithMessage = EIP712JsonParser(eip712JsonAdapter).parseMessage(rawJsonMessage)
return typedDataHash(domainWithMessage.message, domainWithMessage.domain)
}

private class EIP712GsonAdapter : EIP712JsonAdapter {
private val gson = Gson()

override fun parse(inputStream: InputStream): EIP712JsonAdapter.Result {
val typedData = gson.fromJson(BufferedReader(InputStreamReader(inputStream)), TypedData::class.java)
return parse(typedData)
}

override fun parse(typedDataJson: String): EIP712JsonAdapter.Result {
val typedData = gson.fromJson(typedDataJson, TypedData::class.java)
return parse(typedData)
}

private fun parse(typedData: TypedData): EIP712JsonAdapter.Result {
return EIP712JsonAdapter.Result(
primaryType = typedData.primaryType,
domain = typedData.domain,
message = typedData.message,
types = typedData.types.mapValues { (_, types) -> types.map { EIP712JsonAdapter.Parameter(it.name, it.type) } }
)
}

data class TypedData(
val types: Map<String, List<TypeParam>>,
val primaryType: String,
val domain: Map<String, Any>,
val message: Map<String, Any>
)

data class TypeParam(
val name: String,
val type: String
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.horizontalsystems.ethereumkit.crypto

import java.math.BigInteger

class EthSigner(
private val privateKey: BigInteger,
private val cryptoUtils: CryptoUtils,
private val eip712Encoder: EIP712Encoder
) {

fun signByteArray(message: ByteArray): ByteArray {
val prefix = "\u0019Ethereum Signed Message:\n" + message.size
val hashedMessage = cryptoUtils.sha3(prefix.toByteArray() + message)
return sign(hashedMessage)
}

fun signTypedData(rawJsonMessage: String): ByteArray {
val encodedMessage = eip712Encoder.encodeTypedDataHash(rawJsonMessage)
return sign(encodedMessage)
}

private fun sign(message: ByteArray): ByteArray = cryptoUtils.ellipticSign(message, privateKey)

}

0 comments on commit e8e30ce

Please sign in to comment.