diff --git a/library/src/androidTest/java/org/xmtp/android/library/SmartContractWalletTest.kt b/library/src/androidTest/java/org/xmtp/android/library/SmartContractWalletTest.kt index d43a9fd52..4d0634bdb 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/SmartContractWalletTest.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/SmartContractWalletTest.kt @@ -6,9 +6,6 @@ import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith -import org.web3j.crypto.Credentials -import org.web3j.protocol.Web3j -import org.web3j.protocol.http.HttpService @RunWith(AndroidJUnit4::class) class SmartContractWalletTest { @@ -21,12 +18,7 @@ class SmartContractWalletTest { 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F ) val context = InstrumentationRegistry.getInstrumentation().targetContext - val web3j = Web3j.build(HttpService("http://10.0.2.2:8545")) - Thread.sleep(1000L) - - val credentials = - Credentials.create("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") - val davonSCW = FakeSCWWallet.generate(web3j, credentials) + val davonSCW = FakeSCWWallet.generate() val options = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, false), enableV3 = true, diff --git a/library/src/androidTest/java/org/xmtp/android/library/TestHelpers.kt b/library/src/androidTest/java/org/xmtp/android/library/TestHelpers.kt index fc37f1f66..e8c57c40d 100644 --- a/library/src/androidTest/java/org/xmtp/android/library/TestHelpers.kt +++ b/library/src/androidTest/java/org/xmtp/android/library/TestHelpers.kt @@ -1,15 +1,13 @@ package org.xmtp.android.library -import android.util.Log -import com.google.protobuf.kotlin.toByteString import kotlinx.coroutines.runBlocking import org.web3j.abi.FunctionEncoder import org.web3j.abi.datatypes.DynamicBytes import org.web3j.abi.datatypes.Uint import org.web3j.crypto.Credentials -import org.web3j.crypto.Hash import org.web3j.crypto.Sign import org.web3j.protocol.Web3j +import org.web3j.protocol.http.HttpService import org.web3j.tx.gas.DefaultGasProvider import org.web3j.utils.Numeric import org.xmtp.android.library.artifact.CoinbaseSmartWallet @@ -20,13 +18,10 @@ import org.xmtp.android.library.messages.PrivateKey import org.xmtp.android.library.messages.PrivateKeyBuilder import org.xmtp.android.library.messages.Signature import org.xmtp.android.library.messages.Topic -import org.xmtp.android.library.messages.consentProofText import org.xmtp.android.library.messages.ethHash import org.xmtp.android.library.messages.toPublicKeyBundle import org.xmtp.android.library.messages.walletAddress -import org.xmtp.proto.message.contents.SignatureOuterClass import java.math.BigInteger -import java.security.SecureRandom import java.util.Date class FakeWallet : SigningKey { @@ -59,19 +54,12 @@ class FakeWallet : SigningKey { get() = privateKey.walletAddress } -class FakeSCWWallet( - private val web3j: Web3j, - private val credentials: Credentials, -) : SigningKey { +class FakeSCWWallet : SigningKey { + private var web3j: Web3j = Web3j.build(HttpService("http://10.0.2.2:8545")) + private val credentials: Credentials = + Credentials.create("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") var walletAddress: String = "" - init { - runBlocking { - createSmartContractWallet() - } - } - - // Override address to return the created smart contract wallet address override val address: String get() = walletAddress @@ -81,58 +69,37 @@ class FakeSCWWallet( override var chainId: Long = 31337L companion object { - fun generate( - web3j: Web3j, - credentials: Credentials, - ): FakeSCWWallet { - return FakeSCWWallet(web3j, credentials).apply { - runBlocking { createSmartContractWallet() } + fun generate(): FakeSCWWallet { + return FakeSCWWallet().apply { + createSmartContractWallet() } } } - override suspend fun sign(data: ByteArray): Signature { + override suspend fun signSmartContract(message: String): ByteArray { val smartWallet = CoinbaseSmartWallet.load( walletAddress, web3j, credentials, DefaultGasProvider() ) - - val replaySafeHash = smartWallet.replaySafeHash(data).send() - Log.d("LOPI1", replaySafeHash.toHex()) + val digest = Signature.newBuilder().build().ethHash(message) + val replaySafeHash = smartWallet.replaySafeHash(digest).send() val signature = Sign.signMessage(replaySafeHash, credentials.ecKeyPair, false) val signatureBytes = signature.r + signature.s + signature.v - Log.d("LOPI2", signatureBytes.toHex()) - val tokens = listOf( Uint(BigInteger.ZERO), DynamicBytes(signatureBytes) ) val encoded = FunctionEncoder.encodeConstructor(tokens) val encodedBytes = Numeric.hexStringToByteArray(encoded) - Log.d("LOPI3", encoded) - return SignatureOuterClass.Signature.newBuilder().also { - it.ecdsaCompact = it.ecdsaCompact.toBuilder().also { builder -> - builder.bytes = encodedBytes.toByteString() - }.build() - }.build() - } - - override suspend fun sign(message: String): Signature { - val digest = Signature.newBuilder().build().ethHash(message) - return sign(digest) - } - - private fun ByteArray.sha256(): ByteArray { - val digest = java.security.MessageDigest.getInstance("SHA-256") - return digest.digest(this) + return encodedBytes } private fun createSmartContractWallet() { - val smartWalletContract = CoinbaseSmartWallet.deploy( + val smartWalletContract = CoinbaseSmartWallet.deploy( web3j, credentials, DefaultGasProvider() @@ -154,7 +121,7 @@ class FakeSCWWallet( val transactionReceipt = factory.createAccount(owners, nonce, BigInteger.ZERO).send() val smartWalletAddress = factory.getAddress(owners, nonce).send() - Log.d("LOPI5", smartWalletAddress) + if (transactionReceipt.isStatusOK) { walletAddress = smartWalletAddress } else { @@ -163,7 +130,6 @@ class FakeSCWWallet( } } - data class Fixtures( val clientOptions: ClientOptions? = ClientOptions( ClientOptions.Api(XMTPEnvironment.LOCAL, isSecure = false) diff --git a/library/src/main/java/org/xmtp/android/library/Client.kt b/library/src/main/java/org/xmtp/android/library/Client.kt index 4137c155e..5e8808477 100644 --- a/library/src/main/java/org/xmtp/android/library/Client.kt +++ b/library/src/main/java/org/xmtp/android/library/Client.kt @@ -342,7 +342,7 @@ class Client() { this.hasV2Client = false val clientOptions = options ?: ClientOptions(enableV3 = true) val accountAddress = - if (contractChainId != null) "eip155:${contractChainId}:${address.lowercase()}" else address.lowercase() + if (contractChainId != null) "eip155:$contractChainId:${address.lowercase()}" else address.lowercase() return try { initializeV3Client(accountAddress, clientOptions) } catch (e: Exception) { @@ -448,17 +448,15 @@ class Client() { } v3Client.signatureRequest()?.let { signatureRequest -> if (account != null) { - account.sign(signatureRequest.signatureText())?.let { - if (account.isSmartContractWallet) { - Log.d("LOPI", it.ecdsaCompact.bytes.toByteArray().toHex()) - Log.d("LOPI4", account.address) - signatureRequest.addScwSignature( - it.ecdsaCompact.bytes.toByteArray(), - account.address.lowercase(), - account.chainId.toULong(), - account.blockNumber?.toULong() - ) - } else { + if (account.isSmartContractWallet) { + signatureRequest.addScwSignature( + account.signSmartContract(signatureRequest.signatureText()), + account.address.lowercase(), + account.chainId.toULong(), + account.blockNumber?.toULong() + ) + } else { + account.sign(signatureRequest.signatureText())?.let { signatureRequest.addEcdsaSignature(it.rawData) } } diff --git a/library/src/main/java/org/xmtp/android/library/SigningKey.kt b/library/src/main/java/org/xmtp/android/library/SigningKey.kt index 0b764bdc8..8276b4e75 100644 --- a/library/src/main/java/org/xmtp/android/library/SigningKey.kt +++ b/library/src/main/java/org/xmtp/android/library/SigningKey.kt @@ -33,9 +33,17 @@ interface SigningKey { get() = null set(_) {} - suspend fun sign(data: ByteArray): SignatureOuterClass.Signature? + suspend fun sign(data: ByteArray): SignatureOuterClass.Signature? { + throw NotImplementedError("sign(ByteArray) is not implemented.") + } + + suspend fun sign(message: String): SignatureOuterClass.Signature? { + throw NotImplementedError("sign(String) is not implemented.") + } - suspend fun sign(message: String): SignatureOuterClass.Signature? + suspend fun signSmartContract(message: String): ByteArray { + throw NotImplementedError("signSmartContract(String) is not implemented.") + } } /**