Skip to content

Commit 87b2f29

Browse files
committed
Support URIs that do not contain bridge and key (happening in mobile<>mobile flow)
1 parent 1be921d commit 87b2f29

File tree

4 files changed

+101
-43
lines changed

4 files changed

+101
-43
lines changed

lib/src/main/kotlin/org/walletconnect/Session.kt

Lines changed: 58 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import java.net.URLEncoder
55

66
interface Session {
77
fun init()
8+
89
/**
910
* Send client info to the bridge and wait for a client to connect
1011
*/
@@ -25,29 +26,46 @@ interface Session {
2526
fun removeCallback(cb: Callback)
2627
fun clearCallbacks()
2728

29+
data class FullyQualifiedConfig(
30+
val handshakeTopic: String,
31+
val bridge: String,
32+
val key: String,
33+
val protocol: String = "wc",
34+
val version: Int = 1
35+
)
36+
2837
data class Config(
29-
val handshakeTopic: String,
30-
val bridge: String,
31-
val key: String,
32-
val protocol: String = "wc",
33-
val version: Int = 1
38+
val handshakeTopic: String,
39+
val bridge: String? = null,
40+
val key: String? = null,
41+
val protocol: String = "wc",
42+
val version: Int = 1
3443
) {
35-
fun toWCUri(): String =
36-
"wc:$handshakeTopic@$version?bridge=${URLEncoder.encode(bridge, "UTF-8")}&key=$key"
44+
fun toWCUri() = "wc:$handshakeTopic@$version?bridge=${URLEncoder.encode(bridge, "UTF-8")}&key=$key"
45+
46+
fun isFullyQualifiedConfig() = bridge != null && key != null
47+
fun toFullyQualifiedConfig() = FullyQualifiedConfig(handshakeTopic, bridge!!, key!!, protocol, version)
48+
3749
companion object {
3850
fun fromWCUri(uri: String): Config {
3951
val protocolSeparator = uri.indexOf(':')
4052
val handshakeTopicSeparator = uri.indexOf('@', startIndex = protocolSeparator)
4153
val versionSeparator = uri.indexOf('?')
4254
val protocol = uri.substring(0, protocolSeparator)
4355
val handshakeTopic = uri.substring(protocolSeparator + 1, handshakeTopicSeparator)
44-
val version = Integer.valueOf(uri.substring(handshakeTopicSeparator + 1, versionSeparator))
45-
val params = uri.substring(versionSeparator + 1).split("&").associate {
46-
it.split("=").let { param -> param.first() to URLDecoder.decode(param[1], "UTF-8") }
56+
57+
return if (versionSeparator > 0) {
58+
val version = Integer.valueOf(uri.substring(handshakeTopicSeparator + 1, versionSeparator))
59+
val params = uri.substring(versionSeparator + 1).split("&").associate {
60+
it.split("=").let { param -> param.first() to URLDecoder.decode(param[1], "UTF-8") }
61+
}
62+
val bridge = params["bridge"] ?: throw IllegalArgumentException("Missing bridge param in URI")
63+
val key = params["key"] ?: throw IllegalArgumentException("Missing key param in URI")
64+
Config(handshakeTopic, bridge, key, protocol, version)
65+
} else {
66+
val version = Integer.valueOf(uri.substring(handshakeTopicSeparator + 1))
67+
Config(handshakeTopic, protocol, version = version)
4768
}
48-
val bridge = params["bridge"] ?: throw IllegalArgumentException("Missing bridge param in URI")
49-
val key = params["key"] ?: throw IllegalArgumentException("Missing key param in URI")
50-
return Config(handshakeTopic, bridge, key, protocol, version)
5169
}
5270
}
5371
}
@@ -58,14 +76,14 @@ interface Session {
5876
}
5977

6078
sealed class Status {
61-
object Connected: Status()
62-
object Disconnected: Status()
63-
object Approved: Status()
64-
object Closed: Status()
65-
data class Error(val throwable: Throwable): Status()
79+
object Connected : Status()
80+
object Disconnected : Status()
81+
object Approved : Status()
82+
object Closed : Status()
83+
data class Error(val throwable: Throwable) : Status()
6684
}
6785

68-
data class TransportError(override val cause: Throwable): RuntimeException("Transport exception caused by $cause", cause)
86+
data class TransportError(override val cause: Throwable) : RuntimeException("Transport exception caused by $cause", cause)
6987

7088
interface PayloadAdapter {
7189
fun parse(payload: String, key: String): MethodCall
@@ -84,22 +102,22 @@ interface Session {
84102
fun close()
85103

86104
sealed class Status {
87-
object Connected: Status()
88-
object Disconnected: Status()
89-
data class Error(val throwable: Throwable): Status()
105+
object Connected : Status()
106+
object Disconnected : Status()
107+
data class Error(val throwable: Throwable) : Status()
90108
}
91109

92110
data class Message(
93-
val topic: String,
94-
val type: String,
95-
val payload: String
111+
val topic: String,
112+
val type: String,
113+
val payload: String
96114
)
97115

98116
interface Builder {
99117
fun build(
100-
url: String,
101-
statusHandler: (Status) -> Unit,
102-
messageHandler: (Message) -> Unit
118+
url: String,
119+
statusHandler: (Status) -> Unit,
120+
messageHandler: (Message) -> Unit
103121
): Transport
104122
}
105123

@@ -119,14 +137,14 @@ interface Session {
119137
data class SessionUpdate(val id: Long, val params: SessionParams) : MethodCall(id)
120138

121139
data class SendTransaction(
122-
val id: Long,
123-
val from: String,
124-
val to: String?,
125-
val nonce: String?,
126-
val gasPrice: String?,
127-
val gasLimit: String?,
128-
val value: String,
129-
val data: String
140+
val id: Long,
141+
val from: String,
142+
val to: String?,
143+
val nonce: String?,
144+
val gasPrice: String?,
145+
val gasLimit: String?,
146+
val value: String,
147+
val data: String
130148
) : MethodCall(id)
131149

132150
data class SignMessage(val id: Long, val address: String, val message: String) : MethodCall(id)
@@ -138,10 +156,10 @@ interface Session {
138156

139157
data class PeerData(val id: String, val meta: PeerMeta?)
140158
data class PeerMeta(
141-
val url: String? = null,
142-
val name: String? = null,
143-
val description: String? = null,
144-
val icons: List<String>? = null
159+
val url: String? = null,
160+
val name: String? = null,
161+
val description: String? = null,
162+
val icons: List<String>? = null
145163
)
146164

147165
data class SessionParams(val approved: Boolean, val chainId: Long?, val accounts: List<String>?, val peerData: PeerData?)

lib/src/main/kotlin/org/walletconnect/impls/WCSession.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import java.util.*
88
import java.util.concurrent.ConcurrentHashMap
99

1010
class WCSession(
11-
private val config: Session.Config,
11+
private val config: Session.FullyQualifiedConfig,
1212
private val payloadAdapter: Session.PayloadAdapter,
1313
private val sessionStore: WCSessionStore,
1414
transportBuilder: Session.Transport.Builder,
@@ -298,7 +298,7 @@ interface WCSessionStore {
298298
fun list(): List<State>
299299

300300
data class State(
301-
val config: Session.Config,
301+
val config: Session.FullyQualifiedConfig,
302302
val clientData: Session.PeerData,
303303
val peerData: Session.PeerData?,
304304
val handshakeId: Long?,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.walletconnect
2+
3+
import com.squareup.moshi.Moshi
4+
import okhttp3.OkHttpClient
5+
import org.assertj.core.api.Assertions.assertThat
6+
import org.junit.Test
7+
import org.walletconnect.impls.FileWCSessionStore
8+
import org.walletconnect.impls.MoshiPayloadAdapter
9+
import org.walletconnect.impls.OkHttpTransport
10+
import org.walletconnect.impls.WCSession
11+
import java.io.File
12+
import java.util.concurrent.TimeUnit
13+
14+
class TheUriParser {
15+
16+
@Test
17+
fun canParseNormalURI() {
18+
val uri =
19+
"wc:ffd70e47-8634-4eba-95e9-81d7d1ee3bc3@1?bridge=https%3A%2F%2Fbridge.walletconnect.org&key=10d842ec755f67ed37de894811d2b641e1e752f3a91cec05d64ed4b7735cb8c3"
20+
21+
val config = Session.Config.fromWCUri(uri)
22+
23+
assertThat(config.handshakeTopic).isEqualTo("ffd70e47-8634-4eba-95e9-81d7d1ee3bc3")
24+
assertThat(config.protocol).isEqualTo("wc")
25+
assertThat(config.version).isEqualTo(1)
26+
assertThat(config.key).isEqualTo("10d842ec755f67ed37de894811d2b641e1e752f3a91cec05d64ed4b7735cb8c3")
27+
assertThat(config.bridge).isEqualTo("https://bridge.walletconnect.org")
28+
}
29+
30+
@Test
31+
// used e.g. in mobile to bring the app to the foreground
32+
fun canParseMinimalURI() {
33+
val config = Session.Config.fromWCUri("wc:e5996501-ebbd-4bbe-90af-0d921cf439d4@2")
34+
35+
assertThat(config.handshakeTopic).isEqualTo("e5996501-ebbd-4bbe-90af-0d921cf439d4")
36+
assertThat(config.protocol).isEqualTo("wc")
37+
assertThat(config.version).isEqualTo(2)
38+
}
39+
}
40+

lib/src/test/java/org/walletconnect/WalletConnectBridgeRepositoryIntegrationTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class WalletConnectBridgeRepositoryIntegrationTest {
2525
val uri =
2626
"wc:ffd70e47-8634-4eba-95e9-81d7d1ee3bc3@1?bridge=https%3A%2F%2Fbridge.walletconnect.org&key=10d842ec755f67ed37de894811d2b641e1e752f3a91cec05d64ed4b7735cb8c3"
2727

28-
val config = Session.Config.fromWCUri(uri)
28+
val config = Session.Config.fromWCUri(uri).toFullyQualifiedConfig()
2929
val session = WCSession(
3030
config,
3131
MoshiPayloadAdapter(moshi),

0 commit comments

Comments
 (0)