Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/xmtp/xmtp-android into np/e…
Browse files Browse the repository at this point in the history
…xpose-decrypted-encoded-messages
  • Loading branch information
nplasterer committed Nov 15, 2023
2 parents 5b1d42d + c260ec3 commit d0a584d
Show file tree
Hide file tree
Showing 19 changed files with 726 additions and 167 deletions.
16 changes: 13 additions & 3 deletions example/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,20 @@ plugins {

android {
namespace 'org.xmtp.android.example'
compileSdk 33
compileSdk 34

defaultConfig {
applicationId "org.xmtp.android.example"
minSdk 27
targetSdk 33
targetSdk 34
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
buildConfigField("String", "PROJECT_ID", "\"Your Application ID from https://cloud.walletconnect.com/\"")
}

buildTypes {
Expand Down Expand Up @@ -63,9 +64,18 @@ dependencies {
implementation 'androidx.activity:activity-ktx:1.6.1'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.recyclerview:recyclerview:1.3.0'
implementation 'dev.pinkroom:walletconnectkit:0.3.2'
implementation 'org.web3j:crypto:5.0.0'

// WalletConnect V2: core library + WalletConnectModal
implementation(platform("com.walletconnect:android-bom:1.19.1"))
implementation("com.walletconnect:android-core")
implementation("com.walletconnect:walletconnect-modal")

//Navigation Component
def nav_version = "2.7.5"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"

testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
Expand Down
27 changes: 25 additions & 2 deletions example/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

<queries>
<package android:name="io.metamask"/>
<package android:name="com.wallet.crypto.trustapp"/>
<package android:name="io.gnosis.safe"/>
<package android:name="me.rainbow"/>
<package android:name="im.token.app"/>
<package android:name="io.zerion.android"/>
<package android:name="com.spot.spot"/>
<package android:name="fi.steakwallet.app"/>
<package android:name="vip.mytokenpocket"/>
<package android:name="com.frontierwallet"/>
<package android:name="com.bitkeep.wallet"/>
<package android:name="im.argent.contractwalletclient"/>
<package android:name="com.walletconnect.sample.wallet"/>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="wc" />
Expand All @@ -21,10 +34,12 @@
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name=".ExampleApp"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.XMTPAndroid"
tools:targetApi="31">
tools:targetApi="31"
tools:replace="dataExtractionRules">
<activity
android:name=".MainActivity"
android:exported="true"
Expand All @@ -36,7 +51,15 @@
</activity>
<activity
android:name=".connect.ConnectWalletActivity"
android:exported="false" />
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:scheme="xmtp-example-wc"
android:host="request" />
</intent-filter>
</activity>
<activity
android:name=".conversation.ConversationDetailActivity"
android:exported="false" />
Expand Down
47 changes: 47 additions & 0 deletions example/src/main/java/org/xmtp/android/example/ExampleApp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.xmtp.android.example

import android.app.Application
import com.walletconnect.android.Core
import com.walletconnect.android.CoreClient
import com.walletconnect.android.relay.ConnectionType
import com.walletconnect.wcmodal.client.Modal
import com.walletconnect.wcmodal.client.WalletConnectModal
import timber.log.Timber

const val BASE_LOG_TAG = "WC2"
class ExampleApp: Application() {

override fun onCreate() {
super.onCreate()
val connectionType = ConnectionType.AUTOMATIC
val relayUrl = "relay.walletconnect.com"
val serverUrl = "wss://$relayUrl?projectId=${BuildConfig.PROJECT_ID}"
val appMetaData = Core.Model.AppMetaData(
name = "XMTP Example",
description = "Example app using the xmtp-android SDK",
url = "https://xmtp.org",
icons = listOf("https://avatars.githubusercontent.com/u/82580170?s=48&v=4"),
redirect = "xmtp-example-wc://request"
)

CoreClient.initialize(
metaData = appMetaData,
relayServerUrl = serverUrl,
connectionType = connectionType,
application = this,
onError = {
Timber.tag("$BASE_LOG_TAG CoreClient").d(it.toString())
}
)

WalletConnectModal.initialize(
init = Modal.Params.Init(core = CoreClient),
onSuccess = {
Timber.tag("$BASE_LOG_TAG initialize").d("initialize successfully")
},
onError = { error ->
Timber.tag("$BASE_LOG_TAG initialize").d(error.toString())
}
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.xmtp.android.example.account

import android.net.Uri
import com.walletconnect.wcmodal.client.Modal
import kotlinx.coroutines.flow.first
import org.web3j.crypto.Keys
import org.xmtp.android.example.connect.getPersonalSignBody
import org.xmtp.android.example.extension.requestMethod
import org.xmtp.android.library.SigningKey
import org.xmtp.android.library.messages.SignatureBuilder
import org.xmtp.proto.message.contents.SignatureOuterClass


data class WalletConnectV2Account(
val session: Modal.Model.ApprovedSession,
val chain: String,
private val sendSessionRequestDeepLink: (Uri) -> Unit
) :
SigningKey {
override val address: String
get() = Keys.toChecksumAddress(
session.namespaces.getValue(chain).accounts[0].substringAfterLast(
":"
)
)

override suspend fun sign(data: ByteArray): SignatureOuterClass.Signature? {
return sign(String(data))
}

override suspend fun sign(message: String): SignatureOuterClass.Signature? {
val (parentChain, chainId, account) = session.namespaces.getValue(chain).accounts[0].split(":")
val requestParams = session.namespaces.getValue(chain).methods.find { method ->
method == "personal_sign"
}?.let { method ->
Modal.Params.Request(
sessionTopic = session.topic,
method = method,
params = getPersonalSignBody(message, account),
chainId = "$parentChain:$chainId"
)
}
runCatching {
requestMethod(requestParams!!, sendSessionRequestDeepLink).first().getOrThrow()
}
.onSuccess {
return SignatureBuilder.buildFromSignatureData(it)
}
.onFailure {}

return null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.xmtp.android.example.connect


data class ChainSelectionUi(
val chainName: String,
val chainNamespace: String,
val chainReference: String,
val icon: Int,
val methods: List<String>,
val events: List<String>,
var isSelected: Boolean = false,
) {
val chainId = "${chainNamespace}:${chainReference}"
}

fun Chains.toChainUiState() = ChainSelectionUi(chainName, chainNamespace, chainReference, icon, methods, events)
46 changes: 46 additions & 0 deletions example/src/main/java/org/xmtp/android/example/connect/Chains.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.xmtp.android.example.connect

import androidx.annotation.DrawableRes
import org.xmtp.android.example.R


fun getPersonalSignBody(message:String, account: String): String {
val msg = message.encodeToByteArray()
.joinToString(separator = "", prefix = "0x") { eachByte -> "%02x".format(eachByte) }
return "[\"$msg\", \"$account\"]"
}
enum class Chains(
val chainName: String,
val chainNamespace: String,
val chainReference: String,
@DrawableRes val icon: Int,
val methods: List<String>,
val events: List<String>,
) {
ETHEREUM_MAIN(
chainName = "Ethereum",
chainNamespace = Info.Eth.chain,
chainReference = "1",
icon = R.drawable.ic_ethereum,
methods = Info.Eth.defaultMethods,
events = Info.Eth.defaultEvents,
)
}

sealed class Info {
abstract val chain: String
abstract val defaultEvents: List<String>
abstract val defaultMethods: List<String>

object Eth : Info() {
override val chain = "eip155"
override val defaultEvents: List<String> = listOf("chainChanged", "accountsChanged")
override val defaultMethods: List<String> = listOf(
"eth_sendTransaction",
"personal_sign",
"eth_sign",
"eth_signTypedData"
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ import org.xmtp.android.example.databinding.ActivityConnectWalletBinding

class ConnectWalletActivity : AppCompatActivity() {

companion object {
private const val WC_URI_SCHEME = "wc://wc?uri="
}

private val viewModel: ConnectWalletViewModel by viewModels()
private lateinit var binding: ActivityConnectWalletBinding

override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -33,72 +28,10 @@ class ConnectWalletActivity : AppCompatActivity() {
binding = ActivityConnectWalletBinding.inflate(layoutInflater)
setContentView(binding.root)

lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect(::ensureUiState)
}
}

binding.generateButton.setOnClickListener {
viewModel.generateWallet()
}

val isConnectWalletAvailable = isConnectAvailable()
binding.connectButton.isEnabled = isConnectWalletAvailable
binding.connectError.isVisible = !isConnectWalletAvailable
binding.connectButton.setOnClickListener {
binding.connectButton.start(viewModel.walletConnectKit, ::onConnected, ::onDisconnected)
}
}

private fun onConnected(address: String) {
viewModel.connectWallet()
}

private fun onDisconnected() {
// No-op currently.
}

private fun isConnectAvailable(): Boolean {
val wcIntent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(WC_URI_SCHEME)
}
return wcIntent.resolveActivity(packageManager) != null
}

private fun ensureUiState(uiState: ConnectWalletViewModel.ConnectUiState) {
when (uiState) {
is ConnectWalletViewModel.ConnectUiState.Error -> showError(uiState.message)
ConnectWalletViewModel.ConnectUiState.Loading -> showLoading()
is ConnectWalletViewModel.ConnectUiState.Success -> signIn(
uiState.address,
uiState.encodedKeyData
)
ConnectWalletViewModel.ConnectUiState.Unknown -> Unit
}
}

private fun signIn(address: String, encodedKey: String) {
val accountManager = AccountManager.get(this)
Account(address, resources.getString(R.string.account_type)).also { account ->
accountManager.addAccountExplicitly(account, encodedKey, null)
}
startActivity(Intent(this, MainActivity::class.java))
finish()
}

private fun showError(message: String) {
binding.progress.visibility = View.GONE
binding.generateButton.visibility = View.VISIBLE
binding.connectButton.visibility = View.VISIBLE
binding.connectError.isVisible = !isConnectAvailable()
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}

private fun showLoading() {
binding.progress.visibility = View.VISIBLE
binding.generateButton.visibility = View.GONE
binding.connectButton.visibility = View.GONE
binding.connectError.visibility = View.GONE
}
}
Loading

0 comments on commit d0a584d

Please sign in to comment.